Skip to content

Commit 9f48e58

Browse files
committed
core/vm: improve EVM reusability (ethereum#26341)
1 parent 798f870 commit 9f48e58

File tree

4 files changed

+69
-71
lines changed

4 files changed

+69
-71
lines changed

core/vm/evm.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
142142
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
143143
}
144144

145-
evm.interpreter = NewEVMInterpreter(evm, config)
145+
evm.interpreter = NewEVMInterpreter(evm)
146146
return evm
147147
}
148148

@@ -169,6 +169,12 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
169169
return evm.interpreter
170170
}
171171

172+
// SetBlockContext updates the block context of the EVM.
173+
func (evm *EVM) SetBlockContext(blockCtx BlockContext) {
174+
evm.Context = blockCtx
175+
evm.chainRules = evm.chainConfig.Rules(blockCtx.BlockNumber)
176+
}
177+
172178
// Call executes the contract associated with the addr with the given input as
173179
// parameters. It also handles any necessary value transfer required and takes
174180
// the necessary steps to create accounts and reverses the state in case of an

core/vm/instructions.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,9 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
839839
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
840840
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
841841
interpreter.evm.StateDB.Suicide(scope.Contract.Address())
842-
if interpreter.cfg.Debug {
843-
interpreter.cfg.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
844-
interpreter.cfg.Tracer.CaptureExit([]byte{}, 0, nil)
842+
if interpreter.evm.Config.Debug {
843+
interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
844+
interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil)
845845
}
846846
return nil, errStopToken
847847
}

core/vm/instructions_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func TestAddMod(t *testing.T) {
194194
var (
195195
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
196196
stack = newstack()
197-
evmInterpreter = NewEVMInterpreter(env, env.Config)
197+
evmInterpreter = NewEVMInterpreter(env)
198198
pc = uint64(0)
199199
)
200200
tests := []struct {
@@ -290,7 +290,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
290290
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
291291
stack = newstack()
292292
scope = &ScopeContext{nil, stack, nil}
293-
evmInterpreter = NewEVMInterpreter(env, env.Config)
293+
evmInterpreter = NewEVMInterpreter(env)
294294
)
295295

296296
env.interpreter = evmInterpreter
@@ -531,7 +531,7 @@ func TestOpMstore(t *testing.T) {
531531
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
532532
stack = newstack()
533533
mem = NewMemory()
534-
evmInterpreter = NewEVMInterpreter(env, env.Config)
534+
evmInterpreter = NewEVMInterpreter(env)
535535
)
536536

537537
env.interpreter = evmInterpreter
@@ -557,7 +557,7 @@ func BenchmarkOpMstore(bench *testing.B) {
557557
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
558558
stack = newstack()
559559
mem = NewMemory()
560-
evmInterpreter = NewEVMInterpreter(env, env.Config)
560+
evmInterpreter = NewEVMInterpreter(env)
561561
)
562562

563563
env.interpreter = evmInterpreter
@@ -579,7 +579,7 @@ func BenchmarkOpKeccak256(bench *testing.B) {
579579
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
580580
stack = newstack()
581581
mem = NewMemory()
582-
evmInterpreter = NewEVMInterpreter(env, env.Config)
582+
evmInterpreter = NewEVMInterpreter(env)
583583
)
584584
env.interpreter = evmInterpreter
585585
mem.Resize(32)
@@ -683,7 +683,7 @@ func TestRandom(t *testing.T) {
683683
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
684684
stack = newstack()
685685
pc = uint64(0)
686-
evmInterpreter = NewEVMInterpreter(env, env.Config)
686+
evmInterpreter = NewEVMInterpreter(env)
687687
)
688688
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
689689
if len(stack.data) != 1 {

core/vm/interpreter.go

Lines changed: 53 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ type Config struct {
2929
Tracer EVMLogger // Opcode logger
3030
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
3131
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
32-
33-
JumpTable *JumpTable // EVM instruction table, automatically populated if unset
34-
35-
ExtraEips []int // Additional EIPS that are to be enabled
32+
ExtraEips []int // Additional EIPS that are to be enabled
3633
}
3734

3835
// ScopeContext contains the things that are per-call, such as stack and memory,
@@ -45,8 +42,8 @@ type ScopeContext struct {
4542

4643
// EVMInterpreter represents an EVM interpreter
4744
type EVMInterpreter struct {
48-
evm *EVM
49-
cfg Config
45+
evm *EVM
46+
table *JumpTable
5047

5148
hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
5249
hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes
@@ -56,55 +53,50 @@ type EVMInterpreter struct {
5653
}
5754

5855
// NewEVMInterpreter returns a new instance of the Interpreter.
59-
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
56+
func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
6057
// If jump table was not initialised we set the default one.
61-
if cfg.JumpTable == nil {
62-
switch {
63-
case evm.chainRules.IsEIP1559:
64-
cfg.JumpTable = &eip1559InstructionSet
65-
case evm.chainRules.IsShanghai:
66-
cfg.JumpTable = &shanghaiInstructionSet
67-
case evm.chainRules.IsMerge:
68-
cfg.JumpTable = &mergeInstructionSet
69-
case evm.chainRules.IsLondon:
70-
cfg.JumpTable = &londonInstructionSet
71-
case evm.chainRules.IsBerlin:
72-
cfg.JumpTable = &berlinInstructionSet
73-
case evm.chainRules.IsIstanbul:
74-
cfg.JumpTable = &istanbulInstructionSet
75-
case evm.chainRules.IsConstantinople:
76-
cfg.JumpTable = &constantinopleInstructionSet
77-
case evm.chainRules.IsByzantium:
78-
cfg.JumpTable = &byzantiumInstructionSet
79-
case evm.chainRules.IsEIP158:
80-
cfg.JumpTable = &spuriousDragonInstructionSet
81-
case evm.chainRules.IsEIP150:
82-
cfg.JumpTable = &tangerineWhistleInstructionSet
83-
case evm.chainRules.IsHomestead:
84-
cfg.JumpTable = &homesteadInstructionSet
85-
default:
86-
cfg.JumpTable = &frontierInstructionSet
87-
}
88-
var extraEips []int
89-
if len(cfg.ExtraEips) > 0 {
90-
// Deep-copy jumptable to prevent modification of opcodes in other tables
91-
cfg.JumpTable = copyJumpTable(cfg.JumpTable)
92-
}
93-
for _, eip := range cfg.ExtraEips {
94-
if err := EnableEIP(eip, cfg.JumpTable); err != nil {
95-
// Disable it, so caller can check if it's activated or not
96-
log.Error("EIP activation failed", "eip", eip, "error", err)
97-
} else {
98-
extraEips = append(extraEips, eip)
99-
}
100-
}
101-
cfg.ExtraEips = extraEips
58+
var table *JumpTable
59+
switch {
60+
case evm.chainRules.IsEIP1559:
61+
table = &eip1559InstructionSet
62+
case evm.chainRules.IsShanghai:
63+
table = &shanghaiInstructionSet
64+
case evm.chainRules.IsMerge:
65+
table = &mergeInstructionSet
66+
case evm.chainRules.IsLondon:
67+
table = &londonInstructionSet
68+
case evm.chainRules.IsBerlin:
69+
table = &berlinInstructionSet
70+
case evm.chainRules.IsIstanbul:
71+
table = &istanbulInstructionSet
72+
case evm.chainRules.IsConstantinople:
73+
table = &constantinopleInstructionSet
74+
case evm.chainRules.IsByzantium:
75+
table = &byzantiumInstructionSet
76+
case evm.chainRules.IsEIP158:
77+
table = &spuriousDragonInstructionSet
78+
case evm.chainRules.IsEIP150:
79+
table = &tangerineWhistleInstructionSet
80+
case evm.chainRules.IsHomestead:
81+
table = &homesteadInstructionSet
82+
default:
83+
table = &frontierInstructionSet
10284
}
103-
104-
return &EVMInterpreter{
105-
evm: evm,
106-
cfg: cfg,
85+
var extraEips []int
86+
if len(evm.Config.ExtraEips) > 0 {
87+
// Deep-copy jumptable to prevent modification of opcodes in other tables
88+
table = copyJumpTable(table)
89+
}
90+
for _, eip := range evm.Config.ExtraEips {
91+
if err := EnableEIP(eip, table); err != nil {
92+
// Disable it, so caller can check if it's activated or not
93+
log.Error("EIP activation failed", "eip", eip, "error", err)
94+
} else {
95+
extraEips = append(extraEips, eip)
96+
}
10797
}
98+
evm.Config.ExtraEips = extraEips
99+
return &EVMInterpreter{evm: evm, table: table}
108100
}
109101

110102
// Run loops and evaluates the contract's code with the given input data and returns
@@ -162,13 +154,13 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
162154
}()
163155
contract.Input = input
164156

165-
if in.cfg.Debug {
157+
if in.evm.Config.Debug {
166158
defer func() {
167159
if err != nil {
168160
if !logged {
169-
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
161+
in.evm.Config.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
170162
} else {
171-
in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
163+
in.evm.Config.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
172164
}
173165
}
174166
}()
@@ -178,15 +170,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
178170
// the execution of one of the operations or until the done flag is set by the
179171
// parent context.
180172
for {
181-
if in.cfg.Debug {
173+
if in.evm.Config.Debug {
182174
// Capture pre-execution values for tracing.
183175
logged, pcCopy, gasCopy = false, pc, contract.Gas
184176
}
185177

186178
// Get the operation from the jump table and validate the stack to ensure there are
187179
// enough stack items available to perform the operation.
188180
op = contract.GetOp(pc)
189-
operation := in.cfg.JumpTable[op]
181+
operation := in.table[op]
190182
cost = operation.constantGas // For tracing
191183
// Validate stack
192184
if sLen := stack.len(); sLen < operation.minStack {
@@ -224,15 +216,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
224216
return nil, ErrOutOfGas
225217
}
226218
// Do tracing before memory expansion
227-
if in.cfg.Debug {
228-
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
219+
if in.evm.Config.Debug {
220+
in.evm.Config.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
229221
logged = true
230222
}
231223
if memorySize > 0 {
232224
mem.Resize(memorySize)
233225
}
234-
} else if in.cfg.Debug {
235-
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
226+
} else if in.evm.Config.Debug {
227+
in.evm.Config.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
236228
logged = true
237229
}
238230
// execute the operation

0 commit comments

Comments
 (0)