core/vm: remove pointers from JumpTable

This commit is contained in:
Ömer Faruk IRMAK 2025-06-22 14:14:10 +03:00
parent 27d6bed930
commit e5b7430e92
3 changed files with 61 additions and 80 deletions

View file

@ -81,7 +81,7 @@ func enable1884(jt *JumpTable) {
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884 jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
// New opcode // New opcode
jt[SELFBALANCE] = &operation{ jt[SELFBALANCE] = operation{
execute: opSelfBalance, execute: opSelfBalance,
constantGas: GasFastStep, constantGas: GasFastStep,
} }
@ -96,7 +96,7 @@ func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
// - Adds an opcode that returns the current chains EIP-155 unique identifier // - Adds an opcode that returns the current chains EIP-155 unique identifier
func enable1344(jt *JumpTable) { func enable1344(jt *JumpTable) {
// New opcode // New opcode
jt[CHAINID] = &operation{ jt[CHAINID] = operation{
execute: opChainID, execute: opChainID,
constantGas: GasQuickStep, constantGas: GasQuickStep,
} }
@ -165,7 +165,7 @@ func enable3529(jt *JumpTable) {
// - Adds an opcode that returns the current block's base fee. // - Adds an opcode that returns the current block's base fee.
func enable3198(jt *JumpTable) { func enable3198(jt *JumpTable) {
// New opcode // New opcode
jt[BASEFEE] = &operation{ jt[BASEFEE] = operation{
execute: opBaseFee, execute: opBaseFee,
constantGas: GasQuickStep, constantGas: GasQuickStep,
} }
@ -175,12 +175,12 @@ func enable3198(jt *JumpTable) {
// - Adds TLOAD that reads from transient storage // - Adds TLOAD that reads from transient storage
// - Adds TSTORE that writes to transient storage // - Adds TSTORE that writes to transient storage
func enable1153(jt *JumpTable) { func enable1153(jt *JumpTable) {
jt[TLOAD] = &operation{ jt[TLOAD] = operation{
execute: opTload, execute: opTload,
constantGas: params.WarmStorageReadCostEIP2929, constantGas: params.WarmStorageReadCostEIP2929,
} }
jt[TSTORE] = &operation{ jt[TSTORE] = operation{
execute: opTstore, execute: opTstore,
constantGas: params.WarmStorageReadCostEIP2929, constantGas: params.WarmStorageReadCostEIP2929,
} }
@ -222,7 +222,7 @@ func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
// enable3855 applies EIP-3855 (PUSH0 opcode) // enable3855 applies EIP-3855 (PUSH0 opcode)
func enable3855(jt *JumpTable) { func enable3855(jt *JumpTable) {
// New opcode // New opcode
jt[PUSH0] = &operation{ jt[PUSH0] = operation{
execute: opPush0, execute: opPush0,
constantGas: GasQuickStep, constantGas: GasQuickStep,
} }
@ -243,7 +243,7 @@ func enable3860(jt *JumpTable) {
// enable5656 enables EIP-5656 (MCOPY opcode) // enable5656 enables EIP-5656 (MCOPY opcode)
// https://eips.ethereum.org/EIPS/eip-5656 // https://eips.ethereum.org/EIPS/eip-5656
func enable5656(jt *JumpTable) { func enable5656(jt *JumpTable) {
jt[MCOPY] = &operation{ jt[MCOPY] = operation{
execute: opMcopy, execute: opMcopy,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
@ -314,7 +314,7 @@ func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
// enable4844 applies EIP-4844 (BLOBHASH opcode) // enable4844 applies EIP-4844 (BLOBHASH opcode)
func enable4844(jt *JumpTable) { func enable4844(jt *JumpTable) {
jt[BLOBHASH] = &operation{ jt[BLOBHASH] = operation{
execute: opBlobHash, execute: opBlobHash,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
@ -322,7 +322,7 @@ func enable4844(jt *JumpTable) {
// enable7939 enables EIP-7939 (CLZ opcode) // enable7939 enables EIP-7939 (CLZ opcode)
func enable7939(jt *JumpTable) { func enable7939(jt *JumpTable) {
jt[CLZ] = &operation{ jt[CLZ] = operation{
execute: opCLZ, execute: opCLZ,
constantGas: GasFastStep, constantGas: GasFastStep,
} }
@ -330,7 +330,7 @@ func enable7939(jt *JumpTable) {
// enable7516 applies EIP-7516 (BLOBBASEFEE opcode) // enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
func enable7516(jt *JumpTable) { func enable7516(jt *JumpTable) {
jt[BLOBBASEFEE] = &operation{ jt[BLOBBASEFEE] = operation{
execute: opBlobBaseFee, execute: opBlobBaseFee,
constantGas: GasQuickStep, constantGas: GasQuickStep,
} }
@ -338,7 +338,7 @@ func enable7516(jt *JumpTable) {
// enable6780 applies EIP-6780 (deactivate SELFDESTRUCT) // enable6780 applies EIP-6780 (deactivate SELFDESTRUCT)
func enable6780(jt *JumpTable) { func enable6780(jt *JumpTable) {
jt[SELFDESTRUCT] = &operation{ jt[SELFDESTRUCT] = operation{
execute: opSelfdestructEIP6780, execute: opSelfdestructEIP6780,
constantGas: params.SelfdestructGasEIP150, constantGas: params.SelfdestructGasEIP150,
} }
@ -440,71 +440,71 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
} }
func enable4762(jt *JumpTable) { func enable4762(jt *JumpTable) {
jt[SSTORE] = &operation{ jt[SSTORE] = operation{
execute: opSstoreEIP4762, execute: opSstoreEIP4762,
} }
jt[SLOAD] = &operation{ jt[SLOAD] = operation{
execute: opSLoadEIP4762, execute: opSLoadEIP4762,
} }
jt[BALANCE] = &operation{ jt[BALANCE] = operation{
execute: opBalanceEIP4762, execute: opBalanceEIP4762,
} }
jt[EXTCODESIZE] = &operation{ jt[EXTCODESIZE] = operation{
execute: opExtCodeSizeEIP4762, execute: opExtCodeSizeEIP4762,
} }
jt[EXTCODEHASH] = &operation{ jt[EXTCODEHASH] = operation{
execute: opExtCodeHashEIP4762, execute: opExtCodeHashEIP4762,
} }
jt[EXTCODECOPY] = &operation{ jt[EXTCODECOPY] = operation{
execute: opExtCodeCopyEIP4762, execute: opExtCodeCopyEIP4762,
} }
jt[CODECOPY] = &operation{ jt[CODECOPY] = operation{
execute: opCodeCopyEIP4762, execute: opCodeCopyEIP4762,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
jt[SELFDESTRUCT] = &operation{ jt[SELFDESTRUCT] = operation{
execute: opSelfdestructEIP4762, execute: opSelfdestructEIP4762,
constantGas: params.SelfdestructGasEIP150, constantGas: params.SelfdestructGasEIP150,
} }
jt[CREATE] = &operation{ jt[CREATE] = operation{
execute: opCreateEIP3860, execute: opCreateEIP3860,
constantGas: params.CreateNGasEip4762, constantGas: params.CreateNGasEip4762,
} }
jt[CREATE2] = &operation{ jt[CREATE2] = operation{
execute: opCreate2EIP3860, execute: opCreate2EIP3860,
constantGas: params.CreateNGasEip4762, constantGas: params.CreateNGasEip4762,
} }
jt[CALL] = &operation{ jt[CALL] = operation{
execute: opCallEIP4762, execute: opCallEIP4762,
} }
jt[CALLCODE] = &operation{ jt[CALLCODE] = operation{
execute: opCallCodeEIP4762, execute: opCallCodeEIP4762,
} }
jt[STATICCALL] = &operation{ jt[STATICCALL] = operation{
execute: opStaticCallEIP4762, execute: opStaticCallEIP4762,
} }
jt[DELEGATECALL] = &operation{ jt[DELEGATECALL] = operation{
execute: opDelegateCallEIP4762, execute: opDelegateCallEIP4762,
} }
jt[PUSH1] = &operation{ jt[PUSH1] = operation{
execute: opPush1EIP4762, execute: opPush1EIP4762,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
for i := 1; i < 32; i++ { for i := 1; i < 32; i++ {
jt[PUSH1+OpCode(i)] = &operation{ jt[PUSH1+OpCode(i)] = operation{
execute: makePushEIP4762(uint64(i+1), i+1), execute: makePushEIP4762(uint64(i+1), i+1),
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }

View file

@ -149,8 +149,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
} }
} }
if evm.Config.Tracer.HooksVM() { if evm.Config.Tracer.HooksVM() {
for _, op := range table { for i := range table {
op.execute = executeWithTracer(&evm.Config.Tracer, op.execute) table[i].execute = executeWithTracer(&evm.Config.Tracer, table[i].execute)
} }
} }
@ -163,7 +163,7 @@ func executeWithTracer(tracer *tracing.Hooks, execF executionFunc) executionFunc
return func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
pcCopy := *pc pcCopy := *pc
op := callContext.Contract.GetOp(pcCopy) op := callContext.Contract.GetOp(pcCopy)
operation := interpreter.table[op] operation := &interpreter.table[op]
cost := operation.constantGas cost := operation.constantGas
gasCopy := callContext.Contract.Gas + cost gasCopy := callContext.Contract.Gas + cost
@ -263,7 +263,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// Get the operation from the jump table // Get the operation from the jump table
op = contract.GetOp(pc) op = contract.GetOp(pc)
operation := jumpTable[op] operation := &jumpTable[op]
cost = operation.constantGas // For tracing cost = operation.constantGas // For tracing
// for tracing: this gas consumption event is emitted in the executeWithTracer wrapper. // for tracing: this gas consumption event is emitted in the executeWithTracer wrapper.
if contract.Gas < cost { if contract.Gas < cost {

View file

@ -17,8 +17,6 @@
package vm package vm
import ( import (
"fmt"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -28,8 +26,6 @@ type operation struct {
// execute is the operation function // execute is the operation function
execute executionFunc execute executionFunc
constantGas uint64 constantGas uint64
// undefined denotes if the instruction is not officially defined in the jump table
undefined bool
} }
var ( var (
@ -51,33 +47,24 @@ var (
) )
// JumpTable contains the EVM opcodes supported at a given fork. // JumpTable contains the EVM opcodes supported at a given fork.
type JumpTable [256]*operation 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))
}
}
return jt
}
func newVerkleInstructionSet() JumpTable { func newVerkleInstructionSet() JumpTable {
instructionSet := newShanghaiInstructionSet() instructionSet := newShanghaiInstructionSet()
enable4762(&instructionSet) enable4762(&instructionSet)
return validate(instructionSet) return instructionSet
} }
func newOsakaInstructionSet() JumpTable { func newOsakaInstructionSet() JumpTable {
instructionSet := newPragueInstructionSet() instructionSet := newPragueInstructionSet()
enable7939(&instructionSet) // EIP-7939 (CLZ opcode) enable7939(&instructionSet) // EIP-7939 (CLZ opcode)
return validate(instructionSet) return instructionSet
} }
func newPragueInstructionSet() JumpTable { func newPragueInstructionSet() JumpTable {
instructionSet := newCancunInstructionSet() instructionSet := newCancunInstructionSet()
enable7702(&instructionSet) // EIP-7702 Setcode transaction type enable7702(&instructionSet) // EIP-7702 Setcode transaction type
return validate(instructionSet) return instructionSet
} }
func newCancunInstructionSet() JumpTable { func newCancunInstructionSet() JumpTable {
@ -87,7 +74,7 @@ func newCancunInstructionSet() JumpTable {
enable1153(&instructionSet) // EIP-1153 "Transient Storage" enable1153(&instructionSet) // EIP-1153 "Transient Storage"
enable5656(&instructionSet) // EIP-5656 (MCOPY opcode) enable5656(&instructionSet) // EIP-5656 (MCOPY opcode)
enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction
return validate(instructionSet) return instructionSet
} }
func newShanghaiInstructionSet() JumpTable { func newShanghaiInstructionSet() JumpTable {
@ -95,16 +82,16 @@ func newShanghaiInstructionSet() JumpTable {
enable3855(&instructionSet) // PUSH0 instruction enable3855(&instructionSet) // PUSH0 instruction
enable3860(&instructionSet) // Limit and meter initcode enable3860(&instructionSet) // Limit and meter initcode
return validate(instructionSet) return instructionSet
} }
func newMergeInstructionSet() JumpTable { func newMergeInstructionSet() JumpTable {
instructionSet := newLondonInstructionSet() instructionSet := newLondonInstructionSet()
instructionSet[PREVRANDAO] = &operation{ instructionSet[PREVRANDAO] = operation{
execute: opRandom, execute: opRandom,
constantGas: GasQuickStep, constantGas: GasQuickStep,
} }
return validate(instructionSet) return instructionSet
} }
// newLondonInstructionSet returns the frontier, homestead, byzantium, // newLondonInstructionSet returns the frontier, homestead, byzantium,
@ -113,7 +100,7 @@ func newLondonInstructionSet() JumpTable {
instructionSet := newBerlinInstructionSet() instructionSet := newBerlinInstructionSet()
enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529 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 enable3198(&instructionSet) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198
return validate(instructionSet) return instructionSet
} }
// newBerlinInstructionSet returns the frontier, homestead, byzantium, // newBerlinInstructionSet returns the frontier, homestead, byzantium,
@ -121,7 +108,7 @@ func newLondonInstructionSet() JumpTable {
func newBerlinInstructionSet() JumpTable { func newBerlinInstructionSet() JumpTable {
instructionSet := newIstanbulInstructionSet() instructionSet := newIstanbulInstructionSet()
enable2929(&instructionSet) // Gas cost increases for state access opcodes https://eips.ethereum.org/EIPS/eip-2929 enable2929(&instructionSet) // Gas cost increases for state access opcodes https://eips.ethereum.org/EIPS/eip-2929
return validate(instructionSet) return instructionSet
} }
// newIstanbulInstructionSet returns the frontier, homestead, byzantium, // newIstanbulInstructionSet returns the frontier, homestead, byzantium,
@ -133,63 +120,63 @@ func newIstanbulInstructionSet() JumpTable {
enable1884(&instructionSet) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884 enable1884(&instructionSet) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884
enable2200(&instructionSet) // Net metered SSTORE - https://eips.ethereum.org/EIPS/eip-2200 enable2200(&instructionSet) // Net metered SSTORE - https://eips.ethereum.org/EIPS/eip-2200
return validate(instructionSet) return instructionSet
} }
// newConstantinopleInstructionSet returns the frontier, homestead, // newConstantinopleInstructionSet returns the frontier, homestead,
// byzantium and constantinople instructions. // byzantium and constantinople instructions.
func newConstantinopleInstructionSet() JumpTable { func newConstantinopleInstructionSet() JumpTable {
instructionSet := newByzantiumInstructionSet() instructionSet := newByzantiumInstructionSet()
instructionSet[SHL] = &operation{ instructionSet[SHL] = operation{
execute: opSHL, execute: opSHL,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
instructionSet[SHR] = &operation{ instructionSet[SHR] = operation{
execute: opSHR, execute: opSHR,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
instructionSet[SAR] = &operation{ instructionSet[SAR] = operation{
execute: opSAR, execute: opSAR,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
instructionSet[EXTCODEHASH] = &operation{ instructionSet[EXTCODEHASH] = operation{
execute: opExtCodeHashConstantinople, execute: opExtCodeHashConstantinople,
constantGas: params.ExtcodeHashGasConstantinople, constantGas: params.ExtcodeHashGasConstantinople,
} }
instructionSet[CREATE2] = &operation{ instructionSet[CREATE2] = operation{
execute: opCreate2Constantinople, execute: opCreate2Constantinople,
constantGas: params.Create2Gas, constantGas: params.Create2Gas,
} }
return validate(instructionSet) return instructionSet
} }
// newByzantiumInstructionSet returns the frontier, homestead and // newByzantiumInstructionSet returns the frontier, homestead and
// byzantium instructions. // byzantium instructions.
func newByzantiumInstructionSet() JumpTable { func newByzantiumInstructionSet() JumpTable {
instructionSet := newSpuriousDragonInstructionSet() instructionSet := newSpuriousDragonInstructionSet()
instructionSet[STATICCALL] = &operation{ instructionSet[STATICCALL] = operation{
execute: opStaticCallByzantium, execute: opStaticCallByzantium,
constantGas: params.CallGasEIP150, constantGas: params.CallGasEIP150,
} }
instructionSet[RETURNDATASIZE] = &operation{ instructionSet[RETURNDATASIZE] = operation{
execute: opReturnDataSize, execute: opReturnDataSize,
constantGas: GasQuickStep, constantGas: GasQuickStep,
} }
instructionSet[RETURNDATACOPY] = &operation{ instructionSet[RETURNDATACOPY] = operation{
execute: opReturnDataCopy, execute: opReturnDataCopy,
constantGas: GasFastestStep, constantGas: GasFastestStep,
} }
instructionSet[REVERT] = &operation{ instructionSet[REVERT] = operation{
execute: opRevert, execute: opRevert,
} }
return validate(instructionSet) return instructionSet
} }
// EIP 158 a.k.a Spurious Dragon // EIP 158 a.k.a Spurious Dragon
func newSpuriousDragonInstructionSet() JumpTable { func newSpuriousDragonInstructionSet() JumpTable {
instructionSet := newTangerineWhistleInstructionSet() instructionSet := newTangerineWhistleInstructionSet()
instructionSet[EXP].execute = opExpEIP158 instructionSet[EXP].execute = opExpEIP158
return validate(instructionSet) return instructionSet
} }
// EIP 150 a.k.a Tangerine Whistle // EIP 150 a.k.a Tangerine Whistle
@ -202,18 +189,18 @@ func newTangerineWhistleInstructionSet() JumpTable {
instructionSet[CALL].constantGas = params.CallGasEIP150 instructionSet[CALL].constantGas = params.CallGasEIP150
instructionSet[CALLCODE].constantGas = params.CallGasEIP150 instructionSet[CALLCODE].constantGas = params.CallGasEIP150
instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150 instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150
return validate(instructionSet) return instructionSet
} }
// newHomesteadInstructionSet returns the frontier and homestead // newHomesteadInstructionSet returns the frontier and homestead
// instructions that can be executed during the homestead phase. // instructions that can be executed during the homestead phase.
func newHomesteadInstructionSet() JumpTable { func newHomesteadInstructionSet() JumpTable {
instructionSet := newFrontierInstructionSet() instructionSet := newFrontierInstructionSet()
instructionSet[DELEGATECALL] = &operation{ instructionSet[DELEGATECALL] = operation{
execute: opDelegateCallHomestead, execute: opDelegateCallHomestead,
constantGas: params.CallGasFrontier, constantGas: params.CallGasFrontier,
} }
return validate(instructionSet) return instructionSet
} }
// newFrontierInstructionSet returns the frontier instructions // newFrontierInstructionSet returns the frontier instructions
@ -733,22 +720,16 @@ func newFrontierInstructionSet() JumpTable {
} }
// Fill all unassigned slots with opUndefined. // Fill all unassigned slots with opUndefined.
for i, entry := range tbl { for i := range tbl {
if entry == nil { if tbl[i].execute == nil {
tbl[i] = &operation{execute: opUndefined, undefined: true} tbl[i] = operation{execute: opUndefined}
} }
} }
return validate(tbl) return tbl
} }
func copyJumpTable(source *JumpTable) *JumpTable { func copyJumpTable(source *JumpTable) *JumpTable {
dest := *source dest := *source
for i, op := range source {
if op != nil {
opCopy := *op
dest[i] = &opCopy
}
}
return &dest return &dest
} }