@ -29,10 +29,7 @@ type Config struct {
Tracer EVMLogger // Opcode logger
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
JumpTable * JumpTable // EVM instruction table, automatically populated if unset
ExtraEips [ ] int // Additional EIPS that are to be enabled
ExtraEips [ ] int // Additional EIPS that are to be enabled
}
// ScopeContext contains the things that are per-call, such as stack and memory,
@ -45,8 +42,8 @@ type ScopeContext struct {
// EVMInterpreter represents an EVM interpreter
type EVMInterpreter struct {
evm * EVM
cfg Config
evm * EVM
table * JumpTable
hasher crypto . KeccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common . Hash // Keccak256 hasher result array shared aross opcodes
@ -56,53 +53,48 @@ type EVMInterpreter struct {
}
// NewEVMInterpreter returns a new instance of the Interpreter.
func NewEVMInterpreter ( evm * EVM , cfg Config ) * EVMInterpreter {
func NewEVMInterpreter ( evm * EVM ) * EVMInterpreter {
// If jump table was not initialised we set the default one.
if cfg . JumpTable == nil {
switch {
case evm . chainRules . IsShanghai :
cfg . JumpTable = & shanghaiInstructionSet
case evm . chainRules . IsMerge :
cfg . JumpTable = & mergeInstructionSet
case evm . chainRules . IsLondon :
cfg . JumpTable = & londonInstructionSet
case evm . chainRules . IsBerlin :
cfg . JumpTable = & berlinInstructionSet
case evm . chainRules . IsIstanbul :
cfg . JumpTable = & istanbulInstructionSet
case evm . chainRules . IsConstantinople :
cfg . JumpTable = & constantinopleInstructionSet
case evm . chainRules . IsByzantium :
cfg . JumpTable = & byzantiumInstructionSet
case evm . chainRules . IsEIP158 :
cfg . JumpTable = & spuriousDragonInstructionSet
case evm . chainRules . IsEIP150 :
cfg . JumpTable = & tangerineWhistleInstructionSet
case evm . chainRules . IsHomestead :
cfg . JumpTable = & homesteadInstructionSet
default :
cfg . JumpTable = & frontierInstructionSet
}
var extraEips [ ] int
if len ( cfg . ExtraEips ) > 0 {
// Deep-copy jumptable to prevent modification of opcodes in other tables
cfg . JumpTable = copyJumpTable ( cfg . JumpTable )
}
for _ , eip := range cfg . ExtraEips {
if err := EnableEIP ( eip , cfg . JumpTable ) ; err != nil {
// Disable it, so caller can check if it's activated or not
log . Error ( "EIP activation failed" , "eip" , eip , "error" , err )
} else {
extraEips = append ( extraEips , eip )
}
}
cfg . ExtraEips = extraEips
var table * JumpTable
switch {
case evm . chainRules . IsShanghai :
table = & shanghaiInstructionSet
case evm . chainRules . IsMerge :
table = & mergeInstructionSet
case evm . chainRules . IsLondon :
table = & londonInstructionSet
case evm . chainRules . IsBerlin :
table = & berlinInstructionSet
case evm . chainRules . IsIstanbul :
table = & istanbulInstructionSet
case evm . chainRules . IsConstantinople :
table = & constantinopleInstructionSet
case evm . chainRules . IsByzantium :
table = & byzantiumInstructionSet
case evm . chainRules . IsEIP158 :
table = & spuriousDragonInstructionSet
case evm . chainRules . IsEIP150 :
table = & tangerineWhistleInstructionSet
case evm . chainRules . IsHomestead :
table = & homesteadInstructionSet
default :
table = & frontierInstructionSet
}
return & EVMInterpreter {
evm : evm ,
cfg : cfg ,
var extraEips [ ] int
if len ( evm . Config . ExtraEips ) > 0 {
// Deep-copy jumptable to prevent modification of opcodes in other tables
table = copyJumpTable ( table )
}
for _ , eip := range evm . Config . ExtraEips {
if err := EnableEIP ( eip , table ) ; err != nil {
// Disable it, so caller can check if it's activated or not
log . Error ( "EIP activation failed" , "eip" , eip , "error" , err )
} else {
extraEips = append ( extraEips , eip )
}
}
evm . Config . ExtraEips = extraEips
return & EVMInterpreter { evm : evm , table : table }
}
// Run loops and evaluates the contract's code with the given input data and returns
@ -160,13 +152,13 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} ( )
contract . Input = input
if in . c fg. Debug {
if in . evm . Con fi g. Debug {
defer func ( ) {
if err != nil {
if ! logged {
in . c fg. Tracer . CaptureState ( pcCopy , op , gasCopy , cost , callContext , in . returnData , in . evm . depth , err )
in . evm . Con fi g. Tracer . CaptureState ( pcCopy , op , gasCopy , cost , callContext , in . returnData , in . evm . depth , err )
} else {
in . c fg. Tracer . CaptureFault ( pcCopy , op , gasCopy , cost , callContext , in . evm . depth , err )
in . evm . Con fi g. Tracer . CaptureFault ( pcCopy , op , gasCopy , cost , callContext , in . evm . depth , err )
}
}
} ( )
@ -176,14 +168,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// the execution of one of the operations or until the done flag is set by the
// parent context.
for {
if in . c fg. Debug {
if in . evm . Con fi g. Debug {
// Capture pre-execution values for tracing.
logged , pcCopy , gasCopy = false , pc , contract . Gas
}
// Get the operation from the jump table and validate the stack to ensure there are
// enough stack items available to perform the operation.
op = contract . GetOp ( pc )
operation := in . cfg . JumpT able[ op ]
operation := in . t able[ op ]
cost = operation . constantGas // For tracing
// Validate stack
if sLen := stack . len ( ) ; sLen < operation . minStack {
@ -221,15 +213,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
return nil , ErrOutOfGas
}
// Do tracing before memory expansion
if in . c fg. Debug {
in . c fg. Tracer . CaptureState ( pc , op , gasCopy , cost , callContext , in . returnData , in . evm . depth , err )
if in . evm . Con fi g. Debug {
in . evm . Con fi g. Tracer . CaptureState ( pc , op , gasCopy , cost , callContext , in . returnData , in . evm . depth , err )
logged = true
}
if memorySize > 0 {
mem . Resize ( memorySize )
}
} else if in . c fg. Debug {
in . c fg. Tracer . CaptureState ( pc , op , gasCopy , cost , callContext , in . returnData , in . evm . depth , err )
} else if in . evm . Con fi g. Debug {
in . evm . Con fi g. Tracer . CaptureState ( pc , op , gasCopy , cost , callContext , in . returnData , in . evm . depth , err )
logged = true
}
// execute the operation