// Copyright 2015 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package vm import ( "errors" "math/big" "github.com/ethereum/go-ethereum/params" ) type ( executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 stackValidationFunc func(*Stack) error memorySizeFunc func(*Stack) *big.Int ) var errGasUintOverflow = errors.New("gas uint64 overflow") type operation struct { // op is the operation function execute executionFunc // gasCost is the gas function and returns the gas required for execution gasCost gasFunc // validateStack validates the stack (size) for the operation validateStack stackValidationFunc // memorySize returns the memory size required for the operation memorySize memorySizeFunc // halts indicates whether the operation shoult halt further execution // and return halts bool // jumps indicates whether operation made a jump. This prevents the program // counter from further incrementing. jumps bool // valid is used to check whether the retrieved operation is valid and known valid bool } var defaultJumpTable = NewJumpTable() func NewJumpTable() [256]operation { return [256]operation{ STOP: { execute: opStop, gasCost: constGasFunc(0), validateStack: makeStackFunc(0, 0), halts: true, valid: true, }, ADD: { execute: opAdd, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, MUL: { execute: opMul, gasCost: constGasFunc(GasFastStep), validateStack: makeStackFunc(2, 1), valid: true, }, SUB: { execute: opSub, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, DIV: { execute: opDiv, gasCost: constGasFunc(GasFastStep), validateStack: makeStackFunc(2, 1), valid: true, }, SDIV: { execute: opSdiv, gasCost: constGasFunc(GasFastStep), validateStack: makeStackFunc(2, 1), valid: true, }, MOD: { execute: opMod, gasCost: constGasFunc(GasFastStep), validateStack: makeStackFunc(2, 1), valid: true, }, SMOD: { execute: opSmod, gasCost: constGasFunc(GasFastStep), validateStack: makeStackFunc(2, 1), valid: true, }, ADDMOD: { execute: opAddmod, gasCost: constGasFunc(GasMidStep), validateStack: makeStackFunc(3, 1), valid: true, }, MULMOD: { execute: opMulmod, gasCost: constGasFunc(GasMidStep), validateStack: makeStackFunc(3, 1), valid: true, }, EXP: { execute: opExp, gasCost: gasExp, validateStack: makeStackFunc(2, 1), valid: true, }, SIGNEXTEND: { execute: opSignExtend, gasCost: constGasFunc(GasFastStep), validateStack: makeStackFunc(2, 1), valid: true, }, LT: { execute: opLt, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, GT: { execute: opGt, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, SLT: { execute: opSlt, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, SGT: { execute: opSgt, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, EQ: { execute: opEq, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, ISZERO: { execute: opIszero, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(1, 1), valid: true, }, AND: { execute: opAnd, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, XOR: { execute: opXor, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, OR: { execute: opOr, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, NOT: { execute: opNot, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(1, 1), valid: true, }, BYTE: { execute: opByte, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 1), valid: true, }, SHA3: { execute: opSha3, gasCost: gasSha3, validateStack: makeStackFunc(2, 1), memorySize: memorySha3, valid: true, }, ADDRESS: { execute: opAddress, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, BALANCE: { execute: opBalance, gasCost: gasBalance, validateStack: makeStackFunc(1, 1), valid: true, }, ORIGIN: { execute: opOrigin, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, CALLER: { execute: opCaller, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, CALLVALUE: { execute: opCallValue, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, CALLDATALOAD: { execute: opCalldataLoad, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(1, 1), valid: true, }, CALLDATASIZE: { execute: opCalldataSize, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, CALLDATACOPY: { execute: opCalldataCopy, gasCost: gasCalldataCopy, validateStack: makeStackFunc(3, 0), memorySize: memoryCalldataCopy, valid: true, }, CODESIZE: { execute: opCodeSize, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, CODECOPY: { execute: opCodeCopy, gasCost: gasCodeCopy, validateStack: makeStackFunc(3, 0), memorySize: memoryCodeCopy, valid: true, }, GASPRICE: { execute: opGasprice, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, EXTCODESIZE: { execute: opExtCodeSize, gasCost: gasExtCodeSize, validateStack: makeStackFunc(1, 1), valid: true, }, EXTCODECOPY: { execute: opExtCodeCopy, gasCost: gasExtCodeCopy, validateStack: makeStackFunc(4, 0), memorySize: memoryExtCodeCopy, valid: true, }, BLOCKHASH: { execute: opBlockhash, gasCost: constGasFunc(GasExtStep), validateStack: makeStackFunc(1, 1), valid: true, }, COINBASE: { execute: opCoinbase, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, TIMESTAMP: { execute: opTimestamp, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, NUMBER: { execute: opNumber, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, DIFFICULTY: { execute: opDifficulty, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, GASLIMIT: { execute: opGasLimit, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, POP: { execute: opPop, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(1, 0), valid: true, }, MLOAD: { execute: opMload, gasCost: gasMLoad, validateStack: makeStackFunc(1, 1), memorySize: memoryMLoad, valid: true, }, MSTORE: { execute: opMstore, gasCost: gasMStore, validateStack: makeStackFunc(2, 0), memorySize: memoryMStore, valid: true, }, MSTORE8: { execute: opMstore8, gasCost: gasMStore8, memorySize: memoryMStore8, validateStack: makeStackFunc(2, 0), valid: true, }, SLOAD: { execute: opSload, gasCost: gasSLoad, validateStack: makeStackFunc(1, 1), valid: true, }, SSTORE: { execute: opSstore, gasCost: gasSStore, validateStack: makeStackFunc(2, 0), valid: true, }, JUMP: { execute: opJump, gasCost: constGasFunc(GasMidStep), validateStack: makeStackFunc(1, 0), jumps: true, valid: true, }, JUMPI: { execute: opJumpi, gasCost: constGasFunc(GasSlowStep), validateStack: makeStackFunc(2, 0), jumps: true, valid: true, }, PC: { execute: opPc, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, MSIZE: { execute: opMsize, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, GAS: { execute: opGas, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, JUMPDEST: { execute: opJumpdest, gasCost: constGasFunc(params.JumpdestGas), validateStack: makeStackFunc(0, 0), valid: true, }, PUSH1: { execute: makePush(1, big.NewInt(1)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH2: { execute: makePush(2, big.NewInt(2)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH3: { execute: makePush(3, big.NewInt(3)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH4: { execute: makePush(4, big.NewInt(4)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH5: { execute: makePush(5, big.NewInt(5)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH6: { execute: makePush(6, big.NewInt(6)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH7: { execute: makePush(7, big.NewInt(7)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH8: { execute: makePush(8, big.NewInt(8)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH9: { execute: makePush(9, big.NewInt(9)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH10: { execute: makePush(10, big.NewInt(10)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH11: { execute: makePush(11, big.NewInt(11)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH12: { execute: makePush(12, big.NewInt(12)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH13: { execute: makePush(13, big.NewInt(13)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH14: { execute: makePush(14, big.NewInt(14)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH15: { execute: makePush(15, big.NewInt(15)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH16: { execute: makePush(16, big.NewInt(16)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH17: { execute: makePush(17, big.NewInt(17)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH18: { execute: makePush(18, big.NewInt(18)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH19: { execute: makePush(19, big.NewInt(19)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH20: { execute: makePush(20, big.NewInt(20)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH21: { execute: makePush(21, big.NewInt(21)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH22: { execute: makePush(22, big.NewInt(22)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH23: { execute: makePush(23, big.NewInt(23)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH24: { execute: makePush(24, big.NewInt(24)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH25: { execute: makePush(25, big.NewInt(25)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH26: { execute: makePush(26, big.NewInt(26)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH27: { execute: makePush(27, big.NewInt(27)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH28: { execute: makePush(28, big.NewInt(28)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH29: { execute: makePush(29, big.NewInt(29)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH30: { execute: makePush(30, big.NewInt(30)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH31: { execute: makePush(31, big.NewInt(31)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, PUSH32: { execute: makePush(32, big.NewInt(32)), gasCost: gasPush, validateStack: makeStackFunc(0, 1), valid: true, }, DUP1: { execute: makeDup(1), gasCost: gasDup, validateStack: makeDupStackFunc(1), valid: true, }, DUP2: { execute: makeDup(2), gasCost: gasDup, validateStack: makeDupStackFunc(2), valid: true, }, DUP3: { execute: makeDup(3), gasCost: gasDup, validateStack: makeDupStackFunc(3), valid: true, }, DUP4: { execute: makeDup(4), gasCost: gasDup, validateStack: makeDupStackFunc(4), valid: true, }, DUP5: { execute: makeDup(5), gasCost: gasDup, validateStack: makeDupStackFunc(5), valid: true, }, DUP6: { execute: makeDup(6), gasCost: gasDup, validateStack: makeDupStackFunc(6), valid: true, }, DUP7: { execute: makeDup(7), gasCost: gasDup, validateStack: makeDupStackFunc(7), valid: true, }, DUP8: { execute: makeDup(8), gasCost: gasDup, validateStack: makeDupStackFunc(8), valid: true, }, DUP9: { execute: makeDup(9), gasCost: gasDup, validateStack: makeDupStackFunc(9), valid: true, }, DUP10: { execute: makeDup(10), gasCost: gasDup, validateStack: makeDupStackFunc(10), valid: true, }, DUP11: { execute: makeDup(11), gasCost: gasDup, validateStack: makeDupStackFunc(11), valid: true, }, DUP12: { execute: makeDup(12), gasCost: gasDup, validateStack: makeDupStackFunc(12), valid: true, }, DUP13: { execute: makeDup(13), gasCost: gasDup, validateStack: makeDupStackFunc(13), valid: true, }, DUP14: { execute: makeDup(14), gasCost: gasDup, validateStack: makeDupStackFunc(14), valid: true, }, DUP15: { execute: makeDup(15), gasCost: gasDup, validateStack: makeDupStackFunc(15), valid: true, }, DUP16: { execute: makeDup(16), gasCost: gasDup, validateStack: makeDupStackFunc(16), valid: true, }, SWAP1: { execute: makeSwap(1), gasCost: gasSwap, validateStack: makeSwapStackFunc(2), valid: true, }, SWAP2: { execute: makeSwap(2), gasCost: gasSwap, validateStack: makeSwapStackFunc(3), valid: true, }, SWAP3: { execute: makeSwap(3), gasCost: gasSwap, validateStack: makeSwapStackFunc(4), valid: true, }, SWAP4: { execute: makeSwap(4), gasCost: gasSwap, validateStack: makeSwapStackFunc(5), valid: true, }, SWAP5: { execute: makeSwap(5), gasCost: gasSwap, validateStack: makeSwapStackFunc(6), valid: true, }, SWAP6: { execute: makeSwap(6), gasCost: gasSwap, validateStack: makeSwapStackFunc(7), valid: true, }, SWAP7: { execute: makeSwap(7), gasCost: gasSwap, validateStack: makeSwapStackFunc(8), valid: true, }, SWAP8: { execute: makeSwap(8), gasCost: gasSwap, validateStack: makeSwapStackFunc(9), valid: true, }, SWAP9: { execute: makeSwap(9), gasCost: gasSwap, validateStack: makeSwapStackFunc(10), valid: true, }, SWAP10: { execute: makeSwap(10), gasCost: gasSwap, validateStack: makeSwapStackFunc(11), valid: true, }, SWAP11: { execute: makeSwap(11), gasCost: gasSwap, validateStack: makeSwapStackFunc(12), valid: true, }, SWAP12: { execute: makeSwap(12), gasCost: gasSwap, validateStack: makeSwapStackFunc(13), valid: true, }, SWAP13: { execute: makeSwap(13), gasCost: gasSwap, validateStack: makeSwapStackFunc(14), valid: true, }, SWAP14: { execute: makeSwap(14), gasCost: gasSwap, validateStack: makeSwapStackFunc(15), valid: true, }, SWAP15: { execute: makeSwap(15), gasCost: gasSwap, validateStack: makeSwapStackFunc(16), valid: true, }, SWAP16: { execute: makeSwap(16), gasCost: gasSwap, validateStack: makeSwapStackFunc(17), valid: true, }, LOG0: { execute: makeLog(0), gasCost: makeGasLog(0), validateStack: makeStackFunc(2, 0), memorySize: memoryLog, valid: true, }, LOG1: { execute: makeLog(1), gasCost: makeGasLog(1), validateStack: makeStackFunc(3, 0), memorySize: memoryLog, valid: true, }, LOG2: { execute: makeLog(2), gasCost: makeGasLog(2), validateStack: makeStackFunc(4, 0), memorySize: memoryLog, valid: true, }, LOG3: { execute: makeLog(3), gasCost: makeGasLog(3), validateStack: makeStackFunc(5, 0), memorySize: memoryLog, valid: true, }, LOG4: { execute: makeLog(4), gasCost: makeGasLog(4), validateStack: makeStackFunc(6, 0), memorySize: memoryLog, valid: true, }, CREATE: { execute: opCreate, gasCost: gasCreate, validateStack: makeStackFunc(3, 1), memorySize: memoryCreate, valid: true, }, CALL: { execute: opCall, gasCost: gasCall, validateStack: makeStackFunc(7, 1), memorySize: memoryCall, valid: true, }, CALLCODE: { execute: opCallCode, gasCost: gasCallCode, validateStack: makeStackFunc(7, 1), memorySize: memoryCall, valid: true, }, RETURN: { execute: opReturn, gasCost: gasReturn, validateStack: makeStackFunc(2, 0), memorySize: memoryReturn, halts: true, valid: true, }, DELEGATECALL: { execute: opDelegateCall, gasCost: gasDelegateCall, validateStack: makeStackFunc(6, 1), memorySize: memoryDelegateCall, valid: true, }, SELFDESTRUCT: { execute: opSuicide, gasCost: gasSuicide, validateStack: makeStackFunc(1, 0), halts: true, valid: true, }, } }