core/vm: polish RETURNDATA, add missing returns to CALL*
This commit is contained in:
parent
9bd6068fef
commit
4e0fea4d30
@ -261,9 +261,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||
// Make sure the readonly is only set if we aren't in readonly yet
|
||||
// this makes also sure that the readonly flag isn't removed for
|
||||
// child calls.
|
||||
if !evm.interpreter.readonly {
|
||||
evm.interpreter.readonly = true
|
||||
defer func() { evm.interpreter.readonly = false }()
|
||||
if !evm.interpreter.readOnly {
|
||||
evm.interpreter.readOnly = true
|
||||
defer func() { evm.interpreter.readOnly = false }()
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -65,7 +65,7 @@ func constGasFunc(gas uint64) gasFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -29,9 +29,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
bigZero = new(big.Int)
|
||||
errWriteProtection = errors.New("evm: write protection")
|
||||
errReadOutOfBound = errors.New("evm: read out of bound")
|
||||
bigZero = new(big.Int)
|
||||
errWriteProtection = errors.New("evm: write protection")
|
||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||
)
|
||||
|
||||
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
@ -243,6 +243,7 @@ func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(x.Or(x, y))
|
||||
@ -250,6 +251,7 @@ func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(x.Xor(x, y))
|
||||
@ -269,6 +271,7 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||
evm.interpreter.intPool.put(th)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||
if z.Cmp(bigZero) > 0 {
|
||||
@ -282,6 +285,7 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||
evm.interpreter.intPool.put(y, z)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||
if z.Cmp(bigZero) > 0 {
|
||||
@ -339,25 +343,25 @@ func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCalldataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCalldataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCallDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
l = stack.pop()
|
||||
memOffset = stack.pop()
|
||||
dataOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
)
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), getDataBig(contract.Input, cOff, l))
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length))
|
||||
|
||||
evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
evm.interpreter.intPool.put(memOffset, dataOffset, length)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -368,17 +372,17 @@ func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
|
||||
|
||||
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
l = stack.pop()
|
||||
memOffset = stack.pop()
|
||||
dataOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
)
|
||||
defer evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
defer evm.interpreter.intPool.put(memOffset, dataOffset, length)
|
||||
|
||||
cEnd := new(big.Int).Add(cOff, l)
|
||||
if cEnd.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < cEnd.Uint64() {
|
||||
return nil, errReadOutOfBound
|
||||
end := new(big.Int).Add(dataOffset, length)
|
||||
if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() {
|
||||
return nil, errReturnDataOutOfBounds
|
||||
}
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), evm.interpreter.returnData[cOff.Uint64():cEnd.Uint64()])
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), evm.interpreter.returnData[dataOffset.Uint64():end.Uint64()])
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
@ -401,31 +405,28 @@ func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||
|
||||
func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
l = stack.pop()
|
||||
memOffset = stack.pop()
|
||||
codeOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
)
|
||||
codeCopy := getDataBig(contract.Code, cOff, l)
|
||||
codeCopy := getDataBig(contract.Code, codeOffset, length)
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
evm.interpreter.intPool.put(memOffset, codeOffset, length)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
addr = common.BigToAddress(stack.pop())
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
l = stack.pop()
|
||||
addr = common.BigToAddress(stack.pop())
|
||||
memOffset = stack.pop()
|
||||
codeOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
)
|
||||
codeCopy := getDataBig(evm.StateDB.GetCode(addr), cOff, l)
|
||||
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
codeCopy := getDataBig(evm.StateDB.GetCode(addr), codeOffset, length)
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(memOffset, codeOffset, length)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -530,6 +531,7 @@ func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||
evm.interpreter.intPool.put(pos)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
pos, cond := stack.pop(), stack.pop()
|
||||
if cond.Sign() != 0 {
|
||||
@ -545,6 +547,7 @@ func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St
|
||||
evm.interpreter.intPool.put(pos, cond)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -59,9 +59,8 @@ type Interpreter struct {
|
||||
gasTable params.GasTable
|
||||
intPool *intPool
|
||||
|
||||
readonly bool
|
||||
// returnData contains the last call's return data
|
||||
returnData []byte
|
||||
readOnly bool // Whether to throw on stateful modifications
|
||||
returnData []byte // Last CALL's return data for subsequent reuse
|
||||
}
|
||||
|
||||
// NewInterpreter returns a new instance of the Interpreter.
|
||||
@ -90,7 +89,7 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
|
||||
|
||||
func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
|
||||
if in.evm.chainRules.IsMetropolis {
|
||||
if in.readonly {
|
||||
if in.readOnly {
|
||||
// If the interpreter is operating in readonly mode, make sure no
|
||||
// state-modifying operation is performed. The 3rd stack item
|
||||
// for a call operation is the value. Transfering value from one
|
||||
@ -221,7 +220,7 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
|
||||
}
|
||||
// if the operation clears the return data (e.g. it has returning data)
|
||||
// set the last return to the result of the operation.
|
||||
if operation.clearsReturndata {
|
||||
if operation.returns {
|
||||
in.returnData = res
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ type operation struct {
|
||||
valid bool
|
||||
// reverts determined whether the operation reverts state
|
||||
reverts bool
|
||||
// clearsReturndata determines whether the opertions clears the return data
|
||||
clearsReturndata bool
|
||||
// returns determines whether the opertions sets the return data
|
||||
returns bool
|
||||
}
|
||||
|
||||
var (
|
||||
@ -74,6 +74,7 @@ func NewMetropolisInstructionSet() [256]operation {
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryStaticCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
}
|
||||
instructionSet[RETURNDATASIZE] = operation{
|
||||
execute: opReturnDataSize,
|
||||
@ -101,6 +102,7 @@ func NewHomesteadInstructionSet() [256]operation {
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryDelegateCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
}
|
||||
return instructionSet
|
||||
}
|
||||
@ -286,22 +288,22 @@ func NewFrontierInstructionSet() [256]operation {
|
||||
valid: true,
|
||||
},
|
||||
CALLDATALOAD: {
|
||||
execute: opCalldataLoad,
|
||||
execute: opCallDataLoad,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
},
|
||||
CALLDATASIZE: {
|
||||
execute: opCalldataSize,
|
||||
execute: opCallDataSize,
|
||||
gasCost: constGasFunc(GasQuickStep),
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
valid: true,
|
||||
},
|
||||
CALLDATACOPY: {
|
||||
execute: opCalldataCopy,
|
||||
gasCost: gasCalldataCopy,
|
||||
execute: opCallDataCopy,
|
||||
gasCost: gasCallDataCopy,
|
||||
validateStack: makeStackFunc(3, 0),
|
||||
memorySize: memoryCalldataCopy,
|
||||
memorySize: memoryCallDataCopy,
|
||||
valid: true,
|
||||
},
|
||||
CODESIZE: {
|
||||
@ -876,29 +878,29 @@ func NewFrontierInstructionSet() [256]operation {
|
||||
writes: true,
|
||||
},
|
||||
CREATE: {
|
||||
execute: opCreate,
|
||||
gasCost: gasCreate,
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
memorySize: memoryCreate,
|
||||
valid: true,
|
||||
writes: true,
|
||||
clearsReturndata: true,
|
||||
execute: opCreate,
|
||||
gasCost: gasCreate,
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
memorySize: memoryCreate,
|
||||
valid: true,
|
||||
writes: true,
|
||||
returns: true,
|
||||
},
|
||||
CALL: {
|
||||
execute: opCall,
|
||||
gasCost: gasCall,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
clearsReturndata: true,
|
||||
execute: opCall,
|
||||
gasCost: gasCall,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
},
|
||||
CALLCODE: {
|
||||
execute: opCallCode,
|
||||
gasCost: gasCallCode,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
clearsReturndata: true,
|
||||
execute: opCallCode,
|
||||
gasCost: gasCallCode,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
},
|
||||
RETURN: {
|
||||
execute: opReturn,
|
||||
|
@ -22,7 +22,6 @@ import "fmt"
|
||||
type Memory struct {
|
||||
store []byte
|
||||
lastGasCost uint64
|
||||
lastReturn []byte
|
||||
}
|
||||
|
||||
func NewMemory() *Memory {
|
||||
|
@ -26,7 +26,7 @@ func memorySha3(stack *Stack) *big.Int {
|
||||
return calcMemSize(stack.Back(0), stack.Back(1))
|
||||
}
|
||||
|
||||
func memoryCalldataCopy(stack *Stack) *big.Int {
|
||||
func memoryCallDataCopy(stack *Stack) *big.Int {
|
||||
return calcMemSize(stack.Back(0), stack.Back(2))
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user