From 4e0fea4d30e922c1cc0e8e2f33e5ad8ae55053d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 16 Aug 2017 13:36:48 +0300 Subject: [PATCH] core/vm: polish RETURNDATA, add missing returns to CALL* --- core/vm/evm.go | 6 ++-- core/vm/gas_table.go | 2 +- core/vm/instructions.go | 73 +++++++++++++++++++++-------------------- core/vm/interpreter.go | 9 +++-- core/vm/jump_table.go | 54 +++++++++++++++--------------- core/vm/memory.go | 1 - core/vm/memory_table.go | 2 +- 7 files changed, 75 insertions(+), 72 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index cc4214a163..448acd469d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -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 ( diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 6cdbc5c39b..a6346bd806 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -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 diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 0dd9af0968..4d6197912f 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -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 } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1c7481bc5d..954839f2e3 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -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 } } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 7fb11021f0..2d238f7a16 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -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, diff --git a/core/vm/memory.go b/core/vm/memory.go index 6dbee94eff..99a84d2271 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -22,7 +22,6 @@ import "fmt" type Memory struct { store []byte lastGasCost uint64 - lastReturn []byte } func NewMemory() *Memory { diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 9f6533bbce..f1b671adcf 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -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)) }