mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-27 08:56:18 +00:00
Implements spec change https://github.com/ethereum/EIPs/pull/11807 This PR resolves the conflict between the EIP-7928 and EIP-8037. Specifically in contract deployment, EIP-7928 requires to not resolve the deployed account until it's accessed, while in EIP-8037, the early access is required to determine if the account-creation should be charged or not. This PR addresses this conflict by changing the EIP-8037 a bit, unconditionally charge the account creation in CREATE Family (CreateTx, Create/Create2 opcode) and refunds the associated gas cost if the account creation doesn't happen ultimately. Checkout https://hackmd.io/@bFEBbZiVSAO0IURh9qzEFg/BJmFYqCeGl for more details What's more, now the LIFO mechanism is used for refilling the state cost in frame revert, frame halt, state opcode refunds.
1118 lines
30 KiB
Go
1118 lines
30 KiB
Go
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
package vm
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
type (
|
|
executionFunc func(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error)
|
|
gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (GasCosts, error) // last parameter is the requested memory size as a uint64
|
|
intrinsicGasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
|
|
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
|
|
memorySizeFunc func(*Stack) (size uint64, overflow bool)
|
|
|
|
regularGasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error)
|
|
stateGasFunc func(*EVM, *Contract, *Stack) (uint64, error)
|
|
)
|
|
|
|
type operation struct {
|
|
// execute is the operation function
|
|
execute executionFunc
|
|
constantGas uint64
|
|
dynamicGas gasFunc
|
|
// minStack tells how many stack items are required
|
|
minStack int
|
|
// maxStack specifies the max length the stack can have for this operation
|
|
// to not overflow the stack.
|
|
maxStack int
|
|
|
|
// memorySize returns the memory size required for the operation
|
|
memorySize memorySizeFunc
|
|
|
|
// undefined denotes if the instruction is not officially defined in the jump table
|
|
undefined bool
|
|
}
|
|
|
|
var (
|
|
frontierInstructionSet = newFrontierInstructionSet()
|
|
homesteadInstructionSet = newHomesteadInstructionSet()
|
|
tangerineWhistleInstructionSet = newTangerineWhistleInstructionSet()
|
|
spuriousDragonInstructionSet = newSpuriousDragonInstructionSet()
|
|
byzantiumInstructionSet = newByzantiumInstructionSet()
|
|
constantinopleInstructionSet = newConstantinopleInstructionSet()
|
|
istanbulInstructionSet = newIstanbulInstructionSet()
|
|
berlinInstructionSet = newBerlinInstructionSet()
|
|
londonInstructionSet = newLondonInstructionSet()
|
|
mergeInstructionSet = newMergeInstructionSet()
|
|
shanghaiInstructionSet = newShanghaiInstructionSet()
|
|
cancunInstructionSet = newCancunInstructionSet()
|
|
verkleInstructionSet = newVerkleInstructionSet()
|
|
pragueInstructionSet = newPragueInstructionSet()
|
|
osakaInstructionSet = newOsakaInstructionSet()
|
|
amsterdamInstructionSet = newAmsterdamInstructionSet()
|
|
)
|
|
|
|
// JumpTable contains the EVM opcodes supported at a given fork.
|
|
type JumpTable [256]*operation
|
|
|
|
func validate(jt JumpTable) JumpTable {
|
|
for i, op := range jt {
|
|
if op == nil {
|
|
panic(fmt.Sprintf("op %#x is not set", i))
|
|
}
|
|
// The interpreter has an assumption that if the memorySize function is
|
|
// set, then the dynamicGas function is also set. This is a somewhat
|
|
// arbitrary assumption, and can be removed if we need to -- but it
|
|
// allows us to avoid a condition check. As long as we have that assumption
|
|
// in there, this little sanity check prevents us from merging in a
|
|
// change which violates it.
|
|
if op.memorySize != nil && op.dynamicGas == nil {
|
|
panic(fmt.Sprintf("op %v has dynamic memory but not dynamic gas", OpCode(i).String()))
|
|
}
|
|
}
|
|
return jt
|
|
}
|
|
|
|
func newVerkleInstructionSet() JumpTable {
|
|
instructionSet := newShanghaiInstructionSet()
|
|
enable4762(&instructionSet)
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
func newAmsterdamInstructionSet() JumpTable {
|
|
instructionSet := newOsakaInstructionSet()
|
|
enable7843(&instructionSet) // EIP-7843 (SLOTNUM opcode)
|
|
enable8024(&instructionSet) // EIP-8024 (Backward compatible SWAPN, DUPN, EXCHANGE)
|
|
enable8037(&instructionSet) // EIP-8037 (State creation gas cost increase)
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
func newOsakaInstructionSet() JumpTable {
|
|
instructionSet := newPragueInstructionSet()
|
|
enable7939(&instructionSet) // EIP-7939 (CLZ opcode)
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
func newPragueInstructionSet() JumpTable {
|
|
instructionSet := newCancunInstructionSet()
|
|
enable7702(&instructionSet) // EIP-7702 Setcode transaction type
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
func newCancunInstructionSet() JumpTable {
|
|
instructionSet := newShanghaiInstructionSet()
|
|
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)
|
|
enable7516(&instructionSet) // EIP-7516 (BLOBBASEFEE opcode)
|
|
enable1153(&instructionSet) // EIP-1153 "Transient Storage"
|
|
enable5656(&instructionSet) // EIP-5656 (MCOPY opcode)
|
|
enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
func newShanghaiInstructionSet() JumpTable {
|
|
instructionSet := newMergeInstructionSet()
|
|
enable3855(&instructionSet) // PUSH0 instruction
|
|
enable3860(&instructionSet) // Limit and meter initcode
|
|
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
func newMergeInstructionSet() JumpTable {
|
|
instructionSet := newLondonInstructionSet()
|
|
instructionSet[PREVRANDAO] = &operation{
|
|
execute: opRandom,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
}
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newLondonInstructionSet returns the frontier, homestead, byzantium,
|
|
// constantinople, istanbul, petersburg, berlin and london instructions.
|
|
func newLondonInstructionSet() JumpTable {
|
|
instructionSet := newBerlinInstructionSet()
|
|
enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529
|
|
enable3198(&instructionSet) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newBerlinInstructionSet returns the frontier, homestead, byzantium,
|
|
// constantinople, istanbul, petersburg and berlin instructions.
|
|
func newBerlinInstructionSet() JumpTable {
|
|
instructionSet := newIstanbulInstructionSet()
|
|
enable2929(&instructionSet) // Gas cost increases for state access opcodes https://eips.ethereum.org/EIPS/eip-2929
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newIstanbulInstructionSet returns the frontier, homestead, byzantium,
|
|
// constantinople, istanbul and petersburg instructions.
|
|
func newIstanbulInstructionSet() JumpTable {
|
|
instructionSet := newConstantinopleInstructionSet()
|
|
|
|
enable1344(&instructionSet) // ChainID opcode - https://eips.ethereum.org/EIPS/eip-1344
|
|
enable1884(&instructionSet) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884
|
|
enable2200(&instructionSet) // Net metered SSTORE - https://eips.ethereum.org/EIPS/eip-2200
|
|
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newConstantinopleInstructionSet returns the frontier, homestead,
|
|
// byzantium and constantinople instructions.
|
|
func newConstantinopleInstructionSet() JumpTable {
|
|
instructionSet := newByzantiumInstructionSet()
|
|
instructionSet[SHL] = &operation{
|
|
execute: opSHL,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
}
|
|
instructionSet[SHR] = &operation{
|
|
execute: opSHR,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
}
|
|
instructionSet[SAR] = &operation{
|
|
execute: opSAR,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
}
|
|
instructionSet[EXTCODEHASH] = &operation{
|
|
execute: opExtCodeHash,
|
|
constantGas: params.ExtcodeHashGasConstantinople,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
}
|
|
instructionSet[CREATE2] = &operation{
|
|
execute: opCreate2,
|
|
constantGas: params.Create2Gas,
|
|
dynamicGas: gasCreate2,
|
|
minStack: minStack(4, 1),
|
|
maxStack: maxStack(4, 1),
|
|
memorySize: memoryCreate2,
|
|
}
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newByzantiumInstructionSet returns the frontier, homestead and
|
|
// byzantium instructions.
|
|
func newByzantiumInstructionSet() JumpTable {
|
|
instructionSet := newSpuriousDragonInstructionSet()
|
|
instructionSet[STATICCALL] = &operation{
|
|
execute: opStaticCall,
|
|
constantGas: params.CallGasEIP150,
|
|
dynamicGas: gasStaticCall,
|
|
minStack: minStack(6, 1),
|
|
maxStack: maxStack(6, 1),
|
|
memorySize: memoryStaticCall,
|
|
}
|
|
instructionSet[RETURNDATASIZE] = &operation{
|
|
execute: opReturnDataSize,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
}
|
|
instructionSet[RETURNDATACOPY] = &operation{
|
|
execute: opReturnDataCopy,
|
|
constantGas: GasFastestStep,
|
|
dynamicGas: gasReturnDataCopy,
|
|
minStack: minStack(3, 0),
|
|
maxStack: maxStack(3, 0),
|
|
memorySize: memoryReturnDataCopy,
|
|
}
|
|
instructionSet[REVERT] = &operation{
|
|
execute: opRevert,
|
|
dynamicGas: gasRevert,
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
memorySize: memoryRevert,
|
|
}
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// EIP 158 a.k.a Spurious Dragon
|
|
func newSpuriousDragonInstructionSet() JumpTable {
|
|
instructionSet := newTangerineWhistleInstructionSet()
|
|
instructionSet[EXP].dynamicGas = gasExpEIP158
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// EIP 150 a.k.a Tangerine Whistle
|
|
func newTangerineWhistleInstructionSet() JumpTable {
|
|
instructionSet := newHomesteadInstructionSet()
|
|
instructionSet[BALANCE].constantGas = params.BalanceGasEIP150
|
|
instructionSet[EXTCODESIZE].constantGas = params.ExtcodeSizeGasEIP150
|
|
instructionSet[SLOAD].constantGas = params.SloadGasEIP150
|
|
instructionSet[EXTCODECOPY].constantGas = params.ExtcodeCopyBaseEIP150
|
|
instructionSet[CALL].constantGas = params.CallGasEIP150
|
|
instructionSet[CALLCODE].constantGas = params.CallGasEIP150
|
|
instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newHomesteadInstructionSet returns the frontier and homestead
|
|
// instructions that can be executed during the homestead phase.
|
|
func newHomesteadInstructionSet() JumpTable {
|
|
instructionSet := newFrontierInstructionSet()
|
|
instructionSet[DELEGATECALL] = &operation{
|
|
execute: opDelegateCall,
|
|
dynamicGas: gasDelegateCall,
|
|
constantGas: params.CallGasFrontier,
|
|
minStack: minStack(6, 1),
|
|
maxStack: maxStack(6, 1),
|
|
memorySize: memoryDelegateCall,
|
|
}
|
|
return validate(instructionSet)
|
|
}
|
|
|
|
// newFrontierInstructionSet returns the frontier instructions
|
|
// that can be executed during the frontier phase.
|
|
func newFrontierInstructionSet() JumpTable {
|
|
tbl := JumpTable{
|
|
STOP: {
|
|
execute: opStop,
|
|
constantGas: 0,
|
|
minStack: minStack(0, 0),
|
|
maxStack: maxStack(0, 0),
|
|
},
|
|
ADD: {
|
|
execute: opAdd,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
MUL: {
|
|
execute: opMul,
|
|
constantGas: GasFastStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
SUB: {
|
|
execute: opSub,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
DIV: {
|
|
execute: opDiv,
|
|
constantGas: GasFastStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
SDIV: {
|
|
execute: opSdiv,
|
|
constantGas: GasFastStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
MOD: {
|
|
execute: opMod,
|
|
constantGas: GasFastStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
SMOD: {
|
|
execute: opSmod,
|
|
constantGas: GasFastStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
ADDMOD: {
|
|
execute: opAddmod,
|
|
constantGas: GasMidStep,
|
|
minStack: minStack(3, 1),
|
|
maxStack: maxStack(3, 1),
|
|
},
|
|
MULMOD: {
|
|
execute: opMulmod,
|
|
constantGas: GasMidStep,
|
|
minStack: minStack(3, 1),
|
|
maxStack: maxStack(3, 1),
|
|
},
|
|
EXP: {
|
|
execute: opExp,
|
|
dynamicGas: gasExpFrontier,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
SIGNEXTEND: {
|
|
execute: opSignExtend,
|
|
constantGas: GasFastStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
LT: {
|
|
execute: opLt,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
GT: {
|
|
execute: opGt,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
SLT: {
|
|
execute: opSlt,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
SGT: {
|
|
execute: opSgt,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
EQ: {
|
|
execute: opEq,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
ISZERO: {
|
|
execute: opIszero,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
AND: {
|
|
execute: opAnd,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
XOR: {
|
|
execute: opXor,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
OR: {
|
|
execute: opOr,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
NOT: {
|
|
execute: opNot,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
BYTE: {
|
|
execute: opByte,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
},
|
|
KECCAK256: {
|
|
execute: opKeccak256,
|
|
constantGas: params.Keccak256Gas,
|
|
dynamicGas: gasKeccak256,
|
|
minStack: minStack(2, 1),
|
|
maxStack: maxStack(2, 1),
|
|
memorySize: memoryKeccak256,
|
|
},
|
|
ADDRESS: {
|
|
execute: opAddress,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
BALANCE: {
|
|
execute: opBalance,
|
|
constantGas: params.BalanceGasFrontier,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
ORIGIN: {
|
|
execute: opOrigin,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
CALLER: {
|
|
execute: opCaller,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
CALLVALUE: {
|
|
execute: opCallValue,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
CALLDATALOAD: {
|
|
execute: opCallDataLoad,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
CALLDATASIZE: {
|
|
execute: opCallDataSize,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
CALLDATACOPY: {
|
|
execute: opCallDataCopy,
|
|
constantGas: GasFastestStep,
|
|
dynamicGas: gasCallDataCopy,
|
|
minStack: minStack(3, 0),
|
|
maxStack: maxStack(3, 0),
|
|
memorySize: memoryCallDataCopy,
|
|
},
|
|
CODESIZE: {
|
|
execute: opCodeSize,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
CODECOPY: {
|
|
execute: opCodeCopy,
|
|
constantGas: GasFastestStep,
|
|
dynamicGas: gasCodeCopy,
|
|
minStack: minStack(3, 0),
|
|
maxStack: maxStack(3, 0),
|
|
memorySize: memoryCodeCopy,
|
|
},
|
|
GASPRICE: {
|
|
execute: opGasprice,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
EXTCODESIZE: {
|
|
execute: opExtCodeSize,
|
|
constantGas: params.ExtcodeSizeGasFrontier,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
EXTCODECOPY: {
|
|
execute: opExtCodeCopy,
|
|
constantGas: params.ExtcodeCopyBaseFrontier,
|
|
dynamicGas: gasExtCodeCopy,
|
|
minStack: minStack(4, 0),
|
|
maxStack: maxStack(4, 0),
|
|
memorySize: memoryExtCodeCopy,
|
|
},
|
|
BLOCKHASH: {
|
|
execute: opBlockhash,
|
|
constantGas: GasExtStep,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
COINBASE: {
|
|
execute: opCoinbase,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
TIMESTAMP: {
|
|
execute: opTimestamp,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
NUMBER: {
|
|
execute: opNumber,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
DIFFICULTY: {
|
|
execute: opDifficulty,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
GASLIMIT: {
|
|
execute: opGasLimit,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
POP: {
|
|
execute: opPop,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(1, 0),
|
|
maxStack: maxStack(1, 0),
|
|
},
|
|
MLOAD: {
|
|
execute: opMload,
|
|
constantGas: GasFastestStep,
|
|
dynamicGas: gasMLoad,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
memorySize: memoryMLoad,
|
|
},
|
|
MSTORE: {
|
|
execute: opMstore,
|
|
constantGas: GasFastestStep,
|
|
dynamicGas: gasMStore,
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
memorySize: memoryMStore,
|
|
},
|
|
MSTORE8: {
|
|
execute: opMstore8,
|
|
constantGas: GasFastestStep,
|
|
dynamicGas: gasMStore8,
|
|
memorySize: memoryMStore8,
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
},
|
|
SLOAD: {
|
|
execute: opSload,
|
|
constantGas: params.SloadGasFrontier,
|
|
minStack: minStack(1, 1),
|
|
maxStack: maxStack(1, 1),
|
|
},
|
|
SSTORE: {
|
|
execute: opSstore,
|
|
dynamicGas: gasSStore,
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
},
|
|
JUMP: {
|
|
execute: opJump,
|
|
constantGas: GasMidStep,
|
|
minStack: minStack(1, 0),
|
|
maxStack: maxStack(1, 0),
|
|
},
|
|
JUMPI: {
|
|
execute: opJumpi,
|
|
constantGas: GasSlowStep,
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
},
|
|
PC: {
|
|
execute: opPc,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
MSIZE: {
|
|
execute: opMsize,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
GAS: {
|
|
execute: opGas,
|
|
constantGas: GasQuickStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
JUMPDEST: {
|
|
execute: opJumpdest,
|
|
constantGas: params.JumpdestGas,
|
|
minStack: minStack(0, 0),
|
|
maxStack: maxStack(0, 0),
|
|
},
|
|
PUSH1: {
|
|
execute: opPush1,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH2: {
|
|
execute: opPush2,
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH3: {
|
|
execute: makePush(3, 3),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH4: {
|
|
execute: makePush(4, 4),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH5: {
|
|
execute: makePush(5, 5),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH6: {
|
|
execute: makePush(6, 6),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH7: {
|
|
execute: makePush(7, 7),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH8: {
|
|
execute: makePush(8, 8),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH9: {
|
|
execute: makePush(9, 9),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH10: {
|
|
execute: makePush(10, 10),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH11: {
|
|
execute: makePush(11, 11),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH12: {
|
|
execute: makePush(12, 12),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH13: {
|
|
execute: makePush(13, 13),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH14: {
|
|
execute: makePush(14, 14),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH15: {
|
|
execute: makePush(15, 15),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH16: {
|
|
execute: makePush(16, 16),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH17: {
|
|
execute: makePush(17, 17),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH18: {
|
|
execute: makePush(18, 18),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH19: {
|
|
execute: makePush(19, 19),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH20: {
|
|
execute: makePush(20, 20),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH21: {
|
|
execute: makePush(21, 21),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH22: {
|
|
execute: makePush(22, 22),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH23: {
|
|
execute: makePush(23, 23),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH24: {
|
|
execute: makePush(24, 24),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH25: {
|
|
execute: makePush(25, 25),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH26: {
|
|
execute: makePush(26, 26),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH27: {
|
|
execute: makePush(27, 27),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH28: {
|
|
execute: makePush(28, 28),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH29: {
|
|
execute: makePush(29, 29),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH30: {
|
|
execute: makePush(30, 30),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH31: {
|
|
execute: makePush(31, 31),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
PUSH32: {
|
|
execute: makePush(32, 32),
|
|
constantGas: GasFastestStep,
|
|
minStack: minStack(0, 1),
|
|
maxStack: maxStack(0, 1),
|
|
},
|
|
DUP1: {
|
|
execute: makeDup(1),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(1),
|
|
maxStack: maxDupStack(1),
|
|
},
|
|
DUP2: {
|
|
execute: makeDup(2),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(2),
|
|
maxStack: maxDupStack(2),
|
|
},
|
|
DUP3: {
|
|
execute: makeDup(3),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(3),
|
|
maxStack: maxDupStack(3),
|
|
},
|
|
DUP4: {
|
|
execute: makeDup(4),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(4),
|
|
maxStack: maxDupStack(4),
|
|
},
|
|
DUP5: {
|
|
execute: makeDup(5),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(5),
|
|
maxStack: maxDupStack(5),
|
|
},
|
|
DUP6: {
|
|
execute: makeDup(6),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(6),
|
|
maxStack: maxDupStack(6),
|
|
},
|
|
DUP7: {
|
|
execute: makeDup(7),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(7),
|
|
maxStack: maxDupStack(7),
|
|
},
|
|
DUP8: {
|
|
execute: makeDup(8),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(8),
|
|
maxStack: maxDupStack(8),
|
|
},
|
|
DUP9: {
|
|
execute: makeDup(9),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(9),
|
|
maxStack: maxDupStack(9),
|
|
},
|
|
DUP10: {
|
|
execute: makeDup(10),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(10),
|
|
maxStack: maxDupStack(10),
|
|
},
|
|
DUP11: {
|
|
execute: makeDup(11),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(11),
|
|
maxStack: maxDupStack(11),
|
|
},
|
|
DUP12: {
|
|
execute: makeDup(12),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(12),
|
|
maxStack: maxDupStack(12),
|
|
},
|
|
DUP13: {
|
|
execute: makeDup(13),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(13),
|
|
maxStack: maxDupStack(13),
|
|
},
|
|
DUP14: {
|
|
execute: makeDup(14),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(14),
|
|
maxStack: maxDupStack(14),
|
|
},
|
|
DUP15: {
|
|
execute: makeDup(15),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(15),
|
|
maxStack: maxDupStack(15),
|
|
},
|
|
DUP16: {
|
|
execute: makeDup(16),
|
|
constantGas: GasFastestStep,
|
|
minStack: minDupStack(16),
|
|
maxStack: maxDupStack(16),
|
|
},
|
|
SWAP1: {
|
|
execute: opSwap1,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(2),
|
|
maxStack: maxSwapStack(2),
|
|
},
|
|
SWAP2: {
|
|
execute: opSwap2,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(3),
|
|
maxStack: maxSwapStack(3),
|
|
},
|
|
SWAP3: {
|
|
execute: opSwap3,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(4),
|
|
maxStack: maxSwapStack(4),
|
|
},
|
|
SWAP4: {
|
|
execute: opSwap4,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(5),
|
|
maxStack: maxSwapStack(5),
|
|
},
|
|
SWAP5: {
|
|
execute: opSwap5,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(6),
|
|
maxStack: maxSwapStack(6),
|
|
},
|
|
SWAP6: {
|
|
execute: opSwap6,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(7),
|
|
maxStack: maxSwapStack(7),
|
|
},
|
|
SWAP7: {
|
|
execute: opSwap7,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(8),
|
|
maxStack: maxSwapStack(8),
|
|
},
|
|
SWAP8: {
|
|
execute: opSwap8,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(9),
|
|
maxStack: maxSwapStack(9),
|
|
},
|
|
SWAP9: {
|
|
execute: opSwap9,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(10),
|
|
maxStack: maxSwapStack(10),
|
|
},
|
|
SWAP10: {
|
|
execute: opSwap10,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(11),
|
|
maxStack: maxSwapStack(11),
|
|
},
|
|
SWAP11: {
|
|
execute: opSwap11,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(12),
|
|
maxStack: maxSwapStack(12),
|
|
},
|
|
SWAP12: {
|
|
execute: opSwap12,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(13),
|
|
maxStack: maxSwapStack(13),
|
|
},
|
|
SWAP13: {
|
|
execute: opSwap13,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(14),
|
|
maxStack: maxSwapStack(14),
|
|
},
|
|
SWAP14: {
|
|
execute: opSwap14,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(15),
|
|
maxStack: maxSwapStack(15),
|
|
},
|
|
SWAP15: {
|
|
execute: opSwap15,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(16),
|
|
maxStack: maxSwapStack(16),
|
|
},
|
|
SWAP16: {
|
|
execute: opSwap16,
|
|
constantGas: GasFastestStep,
|
|
minStack: minSwapStack(17),
|
|
maxStack: maxSwapStack(17),
|
|
},
|
|
LOG0: {
|
|
execute: makeLog(0),
|
|
dynamicGas: makeGasLog(0),
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
memorySize: memoryLog,
|
|
},
|
|
LOG1: {
|
|
execute: makeLog(1),
|
|
dynamicGas: makeGasLog(1),
|
|
minStack: minStack(3, 0),
|
|
maxStack: maxStack(3, 0),
|
|
memorySize: memoryLog,
|
|
},
|
|
LOG2: {
|
|
execute: makeLog(2),
|
|
dynamicGas: makeGasLog(2),
|
|
minStack: minStack(4, 0),
|
|
maxStack: maxStack(4, 0),
|
|
memorySize: memoryLog,
|
|
},
|
|
LOG3: {
|
|
execute: makeLog(3),
|
|
dynamicGas: makeGasLog(3),
|
|
minStack: minStack(5, 0),
|
|
maxStack: maxStack(5, 0),
|
|
memorySize: memoryLog,
|
|
},
|
|
LOG4: {
|
|
execute: makeLog(4),
|
|
dynamicGas: makeGasLog(4),
|
|
minStack: minStack(6, 0),
|
|
maxStack: maxStack(6, 0),
|
|
memorySize: memoryLog,
|
|
},
|
|
CREATE: {
|
|
execute: opCreate,
|
|
constantGas: params.CreateGas,
|
|
dynamicGas: gasCreate,
|
|
minStack: minStack(3, 1),
|
|
maxStack: maxStack(3, 1),
|
|
memorySize: memoryCreate,
|
|
},
|
|
CALL: {
|
|
execute: opCall,
|
|
constantGas: params.CallGasFrontier,
|
|
dynamicGas: gasCall,
|
|
minStack: minStack(7, 1),
|
|
maxStack: maxStack(7, 1),
|
|
memorySize: memoryCall,
|
|
},
|
|
CALLCODE: {
|
|
execute: opCallCode,
|
|
constantGas: params.CallGasFrontier,
|
|
dynamicGas: gasCallCode,
|
|
minStack: minStack(7, 1),
|
|
maxStack: maxStack(7, 1),
|
|
memorySize: memoryCall,
|
|
},
|
|
RETURN: {
|
|
execute: opReturn,
|
|
dynamicGas: gasReturn,
|
|
minStack: minStack(2, 0),
|
|
maxStack: maxStack(2, 0),
|
|
memorySize: memoryReturn,
|
|
},
|
|
SELFDESTRUCT: {
|
|
execute: opSelfdestruct,
|
|
dynamicGas: gasSelfdestruct,
|
|
minStack: minStack(1, 0),
|
|
maxStack: maxStack(1, 0),
|
|
},
|
|
INVALID: {
|
|
execute: opUndefined,
|
|
minStack: minStack(0, 0),
|
|
maxStack: maxStack(0, 0),
|
|
},
|
|
}
|
|
|
|
// Fill all unassigned slots with opUndefined.
|
|
for i, entry := range tbl {
|
|
if entry == nil {
|
|
tbl[i] = &operation{execute: opUndefined, maxStack: maxStack(0, 0), undefined: true}
|
|
}
|
|
}
|
|
|
|
return validate(tbl)
|
|
}
|
|
|
|
func copyJumpTable(source *JumpTable) *JumpTable {
|
|
dest := *source
|
|
for i, op := range source {
|
|
if op != nil {
|
|
opCopy := *op
|
|
dest[i] = &opCopy
|
|
}
|
|
}
|
|
return &dest
|
|
}
|