From 9bd6068fefe5687735bed342f3545f515fa717c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Wed, 16 Aug 2017 13:07:33 +0300 Subject: [PATCH 1/3] core/vm: implement RETURNDATA metropolis opcodes --- core/vm/gas_table.go | 26 ++++ core/vm/instructions.go | 23 +++ core/vm/interpreter.go | 14 +- core/vm/jump_table.go | 50 ++++--- core/vm/memory_table.go | 4 + core/vm/opcodes.go | 307 ++++++++++++++++++++-------------------- 6 files changed, 253 insertions(+), 171 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 8a6c2741de..6cdbc5c39b 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -91,6 +91,32 @@ func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } +func gasReturnDataCopy(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 + } + + var overflow bool + if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { + return 0, errGasUintOverflow + } + + words, overflow := bigUint64(stack.Back(2)) + if overflow { + return 0, errGasUintOverflow + } + + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, errGasUintOverflow + } + + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index aaa8d7945e..0dd9af0968 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -31,6 +31,7 @@ import ( var ( bigZero = new(big.Int) errWriteProtection = errors.New("evm: write protection") + errReadOutOfBound = errors.New("evm: read out of bound") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -360,6 +361,28 @@ func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st return nil, nil } +func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData)))) + return nil, nil +} + +func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + mOff = stack.pop() + cOff = stack.pop() + l = stack.pop() + ) + defer evm.interpreter.intPool.put(mOff, cOff, l) + + cEnd := new(big.Int).Add(cOff, l) + if cEnd.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < cEnd.Uint64() { + return nil, errReadOutOfBound + } + memory.Set(mOff.Uint64(), l.Uint64(), evm.interpreter.returnData[cOff.Uint64():cEnd.Uint64()]) + + return nil, nil +} + func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { a := stack.pop() diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 661ada6910..1c7481bc5d 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -60,6 +60,8 @@ type Interpreter struct { intPool *intPool readonly bool + // returnData contains the last call's return data + returnData []byte } // NewInterpreter returns a new instance of the Interpreter. @@ -113,6 +115,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret in.evm.depth++ defer func() { in.evm.depth-- }() + // Reset the previous call's return data. It's unimportant to preserve the old buffer + // as every returning call will return new data anyway. + in.returnData = nil + // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { return nil, nil @@ -213,10 +219,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret case !operation.jumps: pc++ } - // if the operation returned a value make sure that is also set - // the last return data. - if res != nil { - mem.lastReturn = 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 { + in.returnData = res } } return nil, nil diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index f6e8dae665..7fb11021f0 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -53,6 +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 } var ( @@ -73,6 +75,19 @@ func NewMetropolisInstructionSet() [256]operation { memorySize: memoryStaticCall, valid: true, } + instructionSet[RETURNDATASIZE] = operation{ + execute: opReturnDataSize, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + } + instructionSet[RETURNDATACOPY] = operation{ + execute: opReturnDataCopy, + gasCost: gasReturnDataCopy, + validateStack: makeStackFunc(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, + } return instructionSet } @@ -861,26 +876,29 @@ func NewFrontierInstructionSet() [256]operation { writes: true, }, CREATE: { - execute: opCreate, - gasCost: gasCreate, - validateStack: makeStackFunc(3, 1), - memorySize: memoryCreate, - valid: true, - writes: true, + execute: opCreate, + gasCost: gasCreate, + validateStack: makeStackFunc(3, 1), + memorySize: memoryCreate, + valid: true, + writes: true, + clearsReturndata: true, }, CALL: { - execute: opCall, - gasCost: gasCall, - validateStack: makeStackFunc(7, 1), - memorySize: memoryCall, - valid: true, + execute: opCall, + gasCost: gasCall, + validateStack: makeStackFunc(7, 1), + memorySize: memoryCall, + valid: true, + clearsReturndata: true, }, CALLCODE: { - execute: opCallCode, - gasCost: gasCallCode, - validateStack: makeStackFunc(7, 1), - memorySize: memoryCall, - valid: true, + execute: opCallCode, + gasCost: gasCallCode, + validateStack: makeStackFunc(7, 1), + memorySize: memoryCall, + valid: true, + clearsReturndata: true, }, RETURN: { execute: opReturn, diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 9d293a2f2c..9f6533bbce 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -30,6 +30,10 @@ func memoryCalldataCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } +func memoryReturnDataCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(2)) +} + func memoryCodeCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 51925e8ddd..be87cae18b 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -82,10 +82,11 @@ const ( GASPRICE EXTCODESIZE EXTCODECOPY + RETURNDATASIZE + RETURNDATACOPY ) const ( - // 0x40 range - block operations BLOCKHASH OpCode = 0x40 + iota COINBASE @@ -239,27 +240,29 @@ var opCodeToString = map[OpCode]string{ SHA3: "SHA3", // 0x30 range - closure state - ADDRESS: "ADDRESS", - BALANCE: "BALANCE", - ORIGIN: "ORIGIN", - CALLER: "CALLER", - CALLVALUE: "CALLVALUE", - CALLDATALOAD: "CALLDATALOAD", - CALLDATASIZE: "CALLDATASIZE", - CALLDATACOPY: "CALLDATACOPY", - CODESIZE: "CODESIZE", - CODECOPY: "CODECOPY", - GASPRICE: "GASPRICE", + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", + GASPRICE: "GASPRICE", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", + RETURNDATASIZE: "RETURNDATASIZE", + RETURNDATACOPY: "RETURNDATACOPY", // 0x40 range - block operations - BLOCKHASH: "BLOCKHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", - EXTCODESIZE: "EXTCODESIZE", - EXTCODECOPY: "EXTCODECOPY", + BLOCKHASH: "BLOCKHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution POP: "POP", @@ -374,137 +377,139 @@ func (o OpCode) String() string { } var stringToOp = map[string]OpCode{ - "STOP": STOP, - "ADD": ADD, - "MUL": MUL, - "SUB": SUB, - "DIV": DIV, - "SDIV": SDIV, - "MOD": MOD, - "SMOD": SMOD, - "EXP": EXP, - "NOT": NOT, - "LT": LT, - "GT": GT, - "SLT": SLT, - "SGT": SGT, - "EQ": EQ, - "ISZERO": ISZERO, - "SIGNEXTEND": SIGNEXTEND, - "AND": AND, - "OR": OR, - "XOR": XOR, - "BYTE": BYTE, - "ADDMOD": ADDMOD, - "MULMOD": MULMOD, - "SHA3": SHA3, - "ADDRESS": ADDRESS, - "BALANCE": BALANCE, - "ORIGIN": ORIGIN, - "CALLER": CALLER, - "CALLVALUE": CALLVALUE, - "CALLDATALOAD": CALLDATALOAD, - "CALLDATASIZE": CALLDATASIZE, - "CALLDATACOPY": CALLDATACOPY, - "DELEGATECALL": DELEGATECALL, - "STATICCALL": STATICCALL, - "CODESIZE": CODESIZE, - "CODECOPY": CODECOPY, - "GASPRICE": GASPRICE, - "BLOCKHASH": BLOCKHASH, - "COINBASE": COINBASE, - "TIMESTAMP": TIMESTAMP, - "NUMBER": NUMBER, - "DIFFICULTY": DIFFICULTY, - "GASLIMIT": GASLIMIT, - "EXTCODESIZE": EXTCODESIZE, - "EXTCODECOPY": EXTCODECOPY, - "POP": POP, - "MLOAD": MLOAD, - "MSTORE": MSTORE, - "MSTORE8": MSTORE8, - "SLOAD": SLOAD, - "SSTORE": SSTORE, - "JUMP": JUMP, - "JUMPI": JUMPI, - "PC": PC, - "MSIZE": MSIZE, - "GAS": GAS, - "JUMPDEST": JUMPDEST, - "PUSH1": PUSH1, - "PUSH2": PUSH2, - "PUSH3": PUSH3, - "PUSH4": PUSH4, - "PUSH5": PUSH5, - "PUSH6": PUSH6, - "PUSH7": PUSH7, - "PUSH8": PUSH8, - "PUSH9": PUSH9, - "PUSH10": PUSH10, - "PUSH11": PUSH11, - "PUSH12": PUSH12, - "PUSH13": PUSH13, - "PUSH14": PUSH14, - "PUSH15": PUSH15, - "PUSH16": PUSH16, - "PUSH17": PUSH17, - "PUSH18": PUSH18, - "PUSH19": PUSH19, - "PUSH20": PUSH20, - "PUSH21": PUSH21, - "PUSH22": PUSH22, - "PUSH23": PUSH23, - "PUSH24": PUSH24, - "PUSH25": PUSH25, - "PUSH26": PUSH26, - "PUSH27": PUSH27, - "PUSH28": PUSH28, - "PUSH29": PUSH29, - "PUSH30": PUSH30, - "PUSH31": PUSH31, - "PUSH32": PUSH32, - "DUP1": DUP1, - "DUP2": DUP2, - "DUP3": DUP3, - "DUP4": DUP4, - "DUP5": DUP5, - "DUP6": DUP6, - "DUP7": DUP7, - "DUP8": DUP8, - "DUP9": DUP9, - "DUP10": DUP10, - "DUP11": DUP11, - "DUP12": DUP12, - "DUP13": DUP13, - "DUP14": DUP14, - "DUP15": DUP15, - "DUP16": DUP16, - "SWAP1": SWAP1, - "SWAP2": SWAP2, - "SWAP3": SWAP3, - "SWAP4": SWAP4, - "SWAP5": SWAP5, - "SWAP6": SWAP6, - "SWAP7": SWAP7, - "SWAP8": SWAP8, - "SWAP9": SWAP9, - "SWAP10": SWAP10, - "SWAP11": SWAP11, - "SWAP12": SWAP12, - "SWAP13": SWAP13, - "SWAP14": SWAP14, - "SWAP15": SWAP15, - "SWAP16": SWAP16, - "LOG0": LOG0, - "LOG1": LOG1, - "LOG2": LOG2, - "LOG3": LOG3, - "LOG4": LOG4, - "CREATE": CREATE, - "CALL": CALL, - "RETURN": RETURN, - "CALLCODE": CALLCODE, - "SELFDESTRUCT": SELFDESTRUCT, + "STOP": STOP, + "ADD": ADD, + "MUL": MUL, + "SUB": SUB, + "DIV": DIV, + "SDIV": SDIV, + "MOD": MOD, + "SMOD": SMOD, + "EXP": EXP, + "NOT": NOT, + "LT": LT, + "GT": GT, + "SLT": SLT, + "SGT": SGT, + "EQ": EQ, + "ISZERO": ISZERO, + "SIGNEXTEND": SIGNEXTEND, + "AND": AND, + "OR": OR, + "XOR": XOR, + "BYTE": BYTE, + "ADDMOD": ADDMOD, + "MULMOD": MULMOD, + "SHA3": SHA3, + "ADDRESS": ADDRESS, + "BALANCE": BALANCE, + "ORIGIN": ORIGIN, + "CALLER": CALLER, + "CALLVALUE": CALLVALUE, + "CALLDATALOAD": CALLDATALOAD, + "CALLDATASIZE": CALLDATASIZE, + "CALLDATACOPY": CALLDATACOPY, + "DELEGATECALL": DELEGATECALL, + "STATICCALL": STATICCALL, + "CODESIZE": CODESIZE, + "CODECOPY": CODECOPY, + "GASPRICE": GASPRICE, + "EXTCODESIZE": EXTCODESIZE, + "EXTCODECOPY": EXTCODECOPY, + "RETURNDATASIZE": RETURNDATASIZE, + "RETURNDATACOPY": RETURNDATACOPY, + "BLOCKHASH": BLOCKHASH, + "COINBASE": COINBASE, + "TIMESTAMP": TIMESTAMP, + "NUMBER": NUMBER, + "DIFFICULTY": DIFFICULTY, + "GASLIMIT": GASLIMIT, + "POP": POP, + "MLOAD": MLOAD, + "MSTORE": MSTORE, + "MSTORE8": MSTORE8, + "SLOAD": SLOAD, + "SSTORE": SSTORE, + "JUMP": JUMP, + "JUMPI": JUMPI, + "PC": PC, + "MSIZE": MSIZE, + "GAS": GAS, + "JUMPDEST": JUMPDEST, + "PUSH1": PUSH1, + "PUSH2": PUSH2, + "PUSH3": PUSH3, + "PUSH4": PUSH4, + "PUSH5": PUSH5, + "PUSH6": PUSH6, + "PUSH7": PUSH7, + "PUSH8": PUSH8, + "PUSH9": PUSH9, + "PUSH10": PUSH10, + "PUSH11": PUSH11, + "PUSH12": PUSH12, + "PUSH13": PUSH13, + "PUSH14": PUSH14, + "PUSH15": PUSH15, + "PUSH16": PUSH16, + "PUSH17": PUSH17, + "PUSH18": PUSH18, + "PUSH19": PUSH19, + "PUSH20": PUSH20, + "PUSH21": PUSH21, + "PUSH22": PUSH22, + "PUSH23": PUSH23, + "PUSH24": PUSH24, + "PUSH25": PUSH25, + "PUSH26": PUSH26, + "PUSH27": PUSH27, + "PUSH28": PUSH28, + "PUSH29": PUSH29, + "PUSH30": PUSH30, + "PUSH31": PUSH31, + "PUSH32": PUSH32, + "DUP1": DUP1, + "DUP2": DUP2, + "DUP3": DUP3, + "DUP4": DUP4, + "DUP5": DUP5, + "DUP6": DUP6, + "DUP7": DUP7, + "DUP8": DUP8, + "DUP9": DUP9, + "DUP10": DUP10, + "DUP11": DUP11, + "DUP12": DUP12, + "DUP13": DUP13, + "DUP14": DUP14, + "DUP15": DUP15, + "DUP16": DUP16, + "SWAP1": SWAP1, + "SWAP2": SWAP2, + "SWAP3": SWAP3, + "SWAP4": SWAP4, + "SWAP5": SWAP5, + "SWAP6": SWAP6, + "SWAP7": SWAP7, + "SWAP8": SWAP8, + "SWAP9": SWAP9, + "SWAP10": SWAP10, + "SWAP11": SWAP11, + "SWAP12": SWAP12, + "SWAP13": SWAP13, + "SWAP14": SWAP14, + "SWAP15": SWAP15, + "SWAP16": SWAP16, + "LOG0": LOG0, + "LOG1": LOG1, + "LOG2": LOG2, + "LOG3": LOG3, + "LOG4": LOG4, + "CREATE": CREATE, + "CALL": CALL, + "RETURN": RETURN, + "CALLCODE": CALLCODE, + "SELFDESTRUCT": SELFDESTRUCT, } func StringToOp(str string) OpCode { 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 2/3] 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) - - memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) + codeCopy := getDataBig(contract.Code, codeOffset, length) + memory.Set(memOffset.Uint64(), length.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)) } From 64d199edf2c152072df92f31313e2c157d38c520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 16 Aug 2017 13:41:51 +0300 Subject: [PATCH 3/3] tests: pull in latest tests from upstream --- tests/testdata | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testdata b/tests/testdata index 815151e4ce..85f6d7cc01 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 815151e4cea4e73328f8586b4e61c3d7e1e9e543 +Subproject commit 85f6d7cc01b6bd04e071f5ba579fc675cfd2043b