core/vm: implemented RETURNDATA{COPY, SIZE}

This commit is contained in:
Jeffrey Wilcke 2017-03-09 22:20:48 +01:00
parent 1e5725f03b
commit 5f972398ae
7 changed files with 220 additions and 136 deletions

View file

@ -71,6 +71,32 @@ func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St
return gas, nil 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) { func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var ( var (
y, x = stack.Back(1), stack.Back(0) y, x = stack.Back(1), stack.Back(0)

View file

@ -604,7 +604,7 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
contract.Gas += returnGas contract.Gas += returnGas
evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
return nil, nil return ret, nil
} }
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@ -637,7 +637,7 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
contract.Gas += returnGas contract.Gas += returnGas
evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
return nil, nil return ret, nil
} }
func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@ -671,7 +671,7 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
contract.Gas += returnGas contract.Gas += returnGas
evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
return nil, nil return ret, nil
} }
func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@ -696,7 +696,7 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
contract.Gas += returnGas contract.Gas += returnGas
evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize) evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize)
return nil, nil return ret, nil
} }
func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@ -704,6 +704,7 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
ret := memory.GetPtr(offset.Int64(), size.Int64()) ret := memory.GetPtr(offset.Int64(), size.Int64())
evm.interpreter.intPool.put(offset, size) evm.interpreter.intPool.put(offset, size)
return ret, nil return ret, nil
} }
@ -734,6 +735,31 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
return nil, nil return nil, nil
} }
func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", RETURNDATASIZE)
}
stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(memory.lastReturn))))
return nil, nil
}
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", RETURNDATACOPY)
}
var (
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
)
memory.Set(mOff.Uint64(), l.Uint64(), getData(memory.lastReturn, cOff, l))
evm.interpreter.intPool.put(mOff, cOff, l)
return nil, nil
}
// following functions are used by the instruction jump table // following functions are used by the instruction jump table
// make log instruction function // make log instruction function

View file

@ -216,6 +216,11 @@ func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
case !operation.jumps: case !operation.jumps:
pc++ pc++
} }
// if the operation returned a value make sure that is also set
// the last return data.
if res != nil {
mem.lastReturn = ret
}
} }
return nil, nil return nil, nil
} }

View file

@ -829,6 +829,19 @@ func NewJumpTable() [256]operation {
memorySize: memoryLog, memorySize: memoryLog,
valid: true, valid: true,
}, },
RETURNDATASIZE: {
execute: opReturnDataSize,
gasCost: constGasFunc(0), // TODO
validateStack: makeStackFunc(0, 1),
valid: true,
},
RETURNDATACOPY: {
execute: opReturnDataCopy,
gasCost: gasReturnDataCopy,
validateStack: makeStackFunc(3, 0),
memorySize: memoryReturnDataCopy,
valid: true,
},
CREATE: { CREATE: {
execute: opCreate, execute: opCreate,
gasCost: gasCreate, gasCost: gasCreate,

View file

@ -22,6 +22,7 @@ import "fmt"
type Memory struct { type Memory struct {
store []byte store []byte
lastGasCost uint64 lastGasCost uint64
lastReturn []byte
} }
func NewMemory() *Memory { func NewMemory() *Memory {

View file

@ -14,6 +14,10 @@ func memoryCalldataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2)) 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 { func memoryCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2)) return calcMemSize(stack.Back(0), stack.Back(2))
} }

View file

@ -194,6 +194,11 @@ const (
SWAP SWAP
) )
const (
RETURNDATASIZE OpCode = 0xd0 + iota
RETURNDATACOPY
)
const ( const (
// 0xf0 range - closures // 0xf0 range - closures
CREATE OpCode = 0xf0 + iota CREATE OpCode = 0xf0 + iota
@ -351,6 +356,8 @@ var opCodeToString = map[OpCode]string{
LOG3: "LOG3", LOG3: "LOG3",
LOG4: "LOG4", LOG4: "LOG4",
RETURNDATASIZE: "RETURNDATASIZE",
RETURNDATACOPY: "RETURNDATACOPY",
// 0xf0 range // 0xf0 range
CREATE: "CREATE", CREATE: "CREATE",
CALL: "CALL", CALL: "CALL",
@ -376,138 +383,140 @@ func (o OpCode) String() string {
} }
var stringToOp = map[string]OpCode{ var stringToOp = map[string]OpCode{
"STOP": STOP, "STOP": STOP,
"ADD": ADD, "ADD": ADD,
"MUL": MUL, "MUL": MUL,
"SUB": SUB, "SUB": SUB,
"DIV": DIV, "DIV": DIV,
"SDIV": SDIV, "SDIV": SDIV,
"MOD": MOD, "MOD": MOD,
"SMOD": SMOD, "SMOD": SMOD,
"EXP": EXP, "EXP": EXP,
"NOT": NOT, "NOT": NOT,
"LT": LT, "LT": LT,
"GT": GT, "GT": GT,
"SLT": SLT, "SLT": SLT,
"SGT": SGT, "SGT": SGT,
"EQ": EQ, "EQ": EQ,
"ISZERO": ISZERO, "ISZERO": ISZERO,
"SIGNEXTEND": SIGNEXTEND, "SIGNEXTEND": SIGNEXTEND,
"AND": AND, "AND": AND,
"OR": OR, "OR": OR,
"XOR": XOR, "XOR": XOR,
"BYTE": BYTE, "BYTE": BYTE,
"ADDMOD": ADDMOD, "ADDMOD": ADDMOD,
"MULMOD": MULMOD, "MULMOD": MULMOD,
"SHA3": SHA3, "SHA3": SHA3,
"ADDRESS": ADDRESS, "ADDRESS": ADDRESS,
"BALANCE": BALANCE, "BALANCE": BALANCE,
"ORIGIN": ORIGIN, "ORIGIN": ORIGIN,
"CALLER": CALLER, "CALLER": CALLER,
"CALLVALUE": CALLVALUE, "CALLVALUE": CALLVALUE,
"CALLDATALOAD": CALLDATALOAD, "CALLDATALOAD": CALLDATALOAD,
"CALLDATASIZE": CALLDATASIZE, "CALLDATASIZE": CALLDATASIZE,
"CALLDATACOPY": CALLDATACOPY, "CALLDATACOPY": CALLDATACOPY,
"DELEGATECALL": DELEGATECALL, "DELEGATECALL": DELEGATECALL,
"STATIC_CALL": STATIC_CALL, "STATIC_CALL": STATIC_CALL,
"CODESIZE": CODESIZE, "CODESIZE": CODESIZE,
"CODECOPY": CODECOPY, "CODECOPY": CODECOPY,
"GASPRICE": GASPRICE, "GASPRICE": GASPRICE,
"BLOCKHASH": BLOCKHASH, "BLOCKHASH": BLOCKHASH,
"COINBASE": COINBASE, "COINBASE": COINBASE,
"TIMESTAMP": TIMESTAMP, "TIMESTAMP": TIMESTAMP,
"NUMBER": NUMBER, "NUMBER": NUMBER,
"DIFFICULTY": DIFFICULTY, "DIFFICULTY": DIFFICULTY,
"GASLIMIT": GASLIMIT, "GASLIMIT": GASLIMIT,
"EXTCODESIZE": EXTCODESIZE, "EXTCODESIZE": EXTCODESIZE,
"EXTCODECOPY": EXTCODECOPY, "EXTCODECOPY": EXTCODECOPY,
"POP": POP, "POP": POP,
"MLOAD": MLOAD, "MLOAD": MLOAD,
"MSTORE": MSTORE, "MSTORE": MSTORE,
"MSTORE8": MSTORE8, "MSTORE8": MSTORE8,
"SLOAD": SLOAD, "SLOAD": SLOAD,
"SSTORE": SSTORE, "SSTORE": SSTORE,
"JUMP": JUMP, "JUMP": JUMP,
"JUMPI": JUMPI, "JUMPI": JUMPI,
"PC": PC, "PC": PC,
"MSIZE": MSIZE, "MSIZE": MSIZE,
"GAS": GAS, "GAS": GAS,
"JUMPDEST": JUMPDEST, "JUMPDEST": JUMPDEST,
"PUSH1": PUSH1, "PUSH1": PUSH1,
"PUSH2": PUSH2, "PUSH2": PUSH2,
"PUSH3": PUSH3, "PUSH3": PUSH3,
"PUSH4": PUSH4, "PUSH4": PUSH4,
"PUSH5": PUSH5, "PUSH5": PUSH5,
"PUSH6": PUSH6, "PUSH6": PUSH6,
"PUSH7": PUSH7, "PUSH7": PUSH7,
"PUSH8": PUSH8, "PUSH8": PUSH8,
"PUSH9": PUSH9, "PUSH9": PUSH9,
"PUSH10": PUSH10, "PUSH10": PUSH10,
"PUSH11": PUSH11, "PUSH11": PUSH11,
"PUSH12": PUSH12, "PUSH12": PUSH12,
"PUSH13": PUSH13, "PUSH13": PUSH13,
"PUSH14": PUSH14, "PUSH14": PUSH14,
"PUSH15": PUSH15, "PUSH15": PUSH15,
"PUSH16": PUSH16, "PUSH16": PUSH16,
"PUSH17": PUSH17, "PUSH17": PUSH17,
"PUSH18": PUSH18, "PUSH18": PUSH18,
"PUSH19": PUSH19, "PUSH19": PUSH19,
"PUSH20": PUSH20, "PUSH20": PUSH20,
"PUSH21": PUSH21, "PUSH21": PUSH21,
"PUSH22": PUSH22, "PUSH22": PUSH22,
"PUSH23": PUSH23, "PUSH23": PUSH23,
"PUSH24": PUSH24, "PUSH24": PUSH24,
"PUSH25": PUSH25, "PUSH25": PUSH25,
"PUSH26": PUSH26, "PUSH26": PUSH26,
"PUSH27": PUSH27, "PUSH27": PUSH27,
"PUSH28": PUSH28, "PUSH28": PUSH28,
"PUSH29": PUSH29, "PUSH29": PUSH29,
"PUSH30": PUSH30, "PUSH30": PUSH30,
"PUSH31": PUSH31, "PUSH31": PUSH31,
"PUSH32": PUSH32, "PUSH32": PUSH32,
"DUP1": DUP1, "DUP1": DUP1,
"DUP2": DUP2, "DUP2": DUP2,
"DUP3": DUP3, "DUP3": DUP3,
"DUP4": DUP4, "DUP4": DUP4,
"DUP5": DUP5, "DUP5": DUP5,
"DUP6": DUP6, "DUP6": DUP6,
"DUP7": DUP7, "DUP7": DUP7,
"DUP8": DUP8, "DUP8": DUP8,
"DUP9": DUP9, "DUP9": DUP9,
"DUP10": DUP10, "DUP10": DUP10,
"DUP11": DUP11, "DUP11": DUP11,
"DUP12": DUP12, "DUP12": DUP12,
"DUP13": DUP13, "DUP13": DUP13,
"DUP14": DUP14, "DUP14": DUP14,
"DUP15": DUP15, "DUP15": DUP15,
"DUP16": DUP16, "DUP16": DUP16,
"SWAP1": SWAP1, "SWAP1": SWAP1,
"SWAP2": SWAP2, "SWAP2": SWAP2,
"SWAP3": SWAP3, "SWAP3": SWAP3,
"SWAP4": SWAP4, "SWAP4": SWAP4,
"SWAP5": SWAP5, "SWAP5": SWAP5,
"SWAP6": SWAP6, "SWAP6": SWAP6,
"SWAP7": SWAP7, "SWAP7": SWAP7,
"SWAP8": SWAP8, "SWAP8": SWAP8,
"SWAP9": SWAP9, "SWAP9": SWAP9,
"SWAP10": SWAP10, "SWAP10": SWAP10,
"SWAP11": SWAP11, "SWAP11": SWAP11,
"SWAP12": SWAP12, "SWAP12": SWAP12,
"SWAP13": SWAP13, "SWAP13": SWAP13,
"SWAP14": SWAP14, "SWAP14": SWAP14,
"SWAP15": SWAP15, "SWAP15": SWAP15,
"SWAP16": SWAP16, "SWAP16": SWAP16,
"LOG0": LOG0, "LOG0": LOG0,
"LOG1": LOG1, "LOG1": LOG1,
"LOG2": LOG2, "LOG2": LOG2,
"LOG3": LOG3, "LOG3": LOG3,
"LOG4": LOG4, "LOG4": LOG4,
"CREATE": CREATE, "CREATE": CREATE,
"CALL": CALL, "CALL": CALL,
"RETURN": RETURN, "RETURN": RETURN,
"REVERT": REVERT, "REVERT": REVERT,
"CALLCODE": CALLCODE, "CALLCODE": CALLCODE,
"SELFDESTRUCT": SELFDESTRUCT, "SELFDESTRUCT": SELFDESTRUCT,
"RETURNDATASIZE": RETURNDATASIZE,
"RETURNDATACOPY": RETURNDATACOPY,
} }
func StringToOp(str string) OpCode { func StringToOp(str string) OpCode {