Skip to content

Commit c3ef6c7

Browse files
authored
core/vm: fold EVMInterpreter into EVM (#32352)
The separation serves no purpose atm, and the circular dependency that EVM and EVMInterpreter had was begging for them to be merged.
1 parent 888b71b commit c3ef6c7

File tree

8 files changed

+316
-335
lines changed

8 files changed

+316
-335
lines changed

core/vm/eips.go

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ func enable1884(jt *JumpTable) {
8989
}
9090
}
9191

92-
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
93-
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
92+
func opSelfBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
93+
balance := evm.StateDB.GetBalance(scope.Contract.Address())
9494
scope.Stack.push(balance)
9595
return nil, nil
9696
}
@@ -108,8 +108,8 @@ func enable1344(jt *JumpTable) {
108108
}
109109

110110
// opChainID implements CHAINID opcode
111-
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
112-
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
111+
func opChainID(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
112+
chainId, _ := uint256.FromBig(evm.chainConfig.ChainID)
113113
scope.Stack.push(chainId)
114114
return nil, nil
115115
}
@@ -199,28 +199,28 @@ func enable1153(jt *JumpTable) {
199199
}
200200

201201
// opTload implements TLOAD opcode
202-
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
202+
func opTload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
203203
loc := scope.Stack.peek()
204204
hash := common.Hash(loc.Bytes32())
205-
val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
205+
val := evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
206206
loc.SetBytes(val.Bytes())
207207
return nil, nil
208208
}
209209

210210
// opTstore implements TSTORE opcode
211-
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
212-
if interpreter.readOnly {
211+
func opTstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
212+
if evm.readOnly {
213213
return nil, ErrWriteProtection
214214
}
215215
loc := scope.Stack.pop()
216216
val := scope.Stack.pop()
217-
interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
217+
evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
218218
return nil, nil
219219
}
220220

221221
// opBaseFee implements BASEFEE opcode
222-
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
223-
baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee)
222+
func opBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
223+
baseFee, _ := uint256.FromBig(evm.Context.BaseFee)
224224
scope.Stack.push(baseFee)
225225
return nil, nil
226226
}
@@ -237,7 +237,7 @@ func enable3855(jt *JumpTable) {
237237
}
238238

239239
// opPush0 implements the PUSH0 opcode
240-
func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
240+
func opPush0(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
241241
scope.Stack.push(new(uint256.Int))
242242
return nil, nil
243243
}
@@ -263,7 +263,7 @@ func enable5656(jt *JumpTable) {
263263
}
264264

265265
// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
266-
func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
266+
func opMcopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
267267
var (
268268
dst = scope.Stack.pop()
269269
src = scope.Stack.pop()
@@ -276,10 +276,10 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
276276
}
277277

278278
// opBlobHash implements the BLOBHASH opcode
279-
func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
279+
func opBlobHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
280280
index := scope.Stack.peek()
281-
if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) {
282-
blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()]
281+
if index.LtUint64(uint64(len(evm.TxContext.BlobHashes))) {
282+
blobHash := evm.TxContext.BlobHashes[index.Uint64()]
283283
index.SetBytes32(blobHash[:])
284284
} else {
285285
index.Clear()
@@ -288,14 +288,14 @@ func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
288288
}
289289

290290
// opBlobBaseFee implements BLOBBASEFEE opcode
291-
func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
292-
blobBaseFee, _ := uint256.FromBig(interpreter.evm.Context.BlobBaseFee)
291+
func opBlobBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
292+
blobBaseFee, _ := uint256.FromBig(evm.Context.BlobBaseFee)
293293
scope.Stack.push(blobBaseFee)
294294
return nil, nil
295295
}
296296

297297
// opCLZ implements the CLZ opcode (count leading zero bytes)
298-
func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
298+
func opCLZ(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
299299
x := scope.Stack.peek()
300300
x.SetUint64(256 - uint64(x.BitLen()))
301301
return nil, nil
@@ -342,7 +342,7 @@ func enable6780(jt *JumpTable) {
342342
}
343343
}
344344

345-
func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
345+
func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
346346
var (
347347
stack = scope.Stack
348348
a = stack.pop()
@@ -355,10 +355,10 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
355355
uint64CodeOffset = math.MaxUint64
356356
}
357357
addr := common.Address(a.Bytes20())
358-
code := interpreter.evm.StateDB.GetCode(addr)
358+
code := evm.StateDB.GetCode(addr)
359359
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
360-
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
361-
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
360+
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
361+
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
362362
if consumed < wanted {
363363
return nil, ErrOutOfGas
364364
}
@@ -370,7 +370,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
370370
// opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which
371371
// need not worry about the adjusted bound logic when adding the PUSHDATA to
372372
// the list of access events.
373-
func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
373+
func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
374374
var (
375375
codeLen = uint64(len(scope.Contract.Code))
376376
integer = new(uint256.Int)
@@ -383,8 +383,8 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
383383
// touch next chunk if PUSH1 is at the boundary. if so, *pc has
384384
// advanced past this boundary.
385385
contractAddr := scope.Contract.Address()
386-
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
387-
scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
386+
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
387+
scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified)
388388
if consumed < wanted {
389389
return nil, ErrOutOfGas
390390
}
@@ -396,7 +396,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
396396
}
397397

398398
func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
399-
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
399+
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
400400
var (
401401
codeLen = len(scope.Contract.Code)
402402
start = min(codeLen, int(*pc+1))
@@ -411,8 +411,8 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
411411

412412
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
413413
contractAddr := scope.Contract.Address()
414-
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
415-
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
414+
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
415+
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
416416
if consumed < wanted {
417417
return nil, ErrOutOfGas
418418
}

core/vm/evm.go

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/ethereum/go-ethereum/core/tracing"
2727
"github.com/ethereum/go-ethereum/core/types"
2828
"github.com/ethereum/go-ethereum/crypto"
29+
"github.com/ethereum/go-ethereum/log"
2930
"github.com/ethereum/go-ethereum/params"
3031
"github.com/holiman/uint256"
3132
)
@@ -95,6 +96,9 @@ type EVM struct {
9596
// StateDB gives access to the underlying state
9697
StateDB StateDB
9798

99+
// table holds the opcode specific handlers
100+
table *JumpTable
101+
98102
// depth is the current call stack
99103
depth int
100104

@@ -107,10 +111,6 @@ type EVM struct {
107111
// virtual machine configuration options used to initialise the evm
108112
Config Config
109113

110-
// global (to this context) ethereum virtual machine used throughout
111-
// the execution of the tx
112-
interpreter *EVMInterpreter
113-
114114
// abort is used to abort the EVM calling operations
115115
abort atomic.Bool
116116

@@ -124,6 +124,12 @@ type EVM struct {
124124

125125
// jumpDests stores results of JUMPDEST analysis.
126126
jumpDests JumpDestCache
127+
128+
hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
129+
hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes
130+
131+
readOnly bool // Whether to throw on stateful modifications
132+
returnData []byte // Last CALL's return data for subsequent reuse
127133
}
128134

129135
// NewEVM constructs an EVM instance with the supplied block context, state
@@ -138,9 +144,57 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon
138144
chainConfig: chainConfig,
139145
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
140146
jumpDests: newMapJumpDests(),
147+
hasher: crypto.NewKeccakState(),
141148
}
142149
evm.precompiles = activePrecompiledContracts(evm.chainRules)
143-
evm.interpreter = NewEVMInterpreter(evm)
150+
151+
switch {
152+
case evm.chainRules.IsOsaka:
153+
evm.table = &osakaInstructionSet
154+
case evm.chainRules.IsVerkle:
155+
// TODO replace with proper instruction set when fork is specified
156+
evm.table = &verkleInstructionSet
157+
case evm.chainRules.IsPrague:
158+
evm.table = &pragueInstructionSet
159+
case evm.chainRules.IsCancun:
160+
evm.table = &cancunInstructionSet
161+
case evm.chainRules.IsShanghai:
162+
evm.table = &shanghaiInstructionSet
163+
case evm.chainRules.IsMerge:
164+
evm.table = &mergeInstructionSet
165+
case evm.chainRules.IsLondon:
166+
evm.table = &londonInstructionSet
167+
case evm.chainRules.IsBerlin:
168+
evm.table = &berlinInstructionSet
169+
case evm.chainRules.IsIstanbul:
170+
evm.table = &istanbulInstructionSet
171+
case evm.chainRules.IsConstantinople:
172+
evm.table = &constantinopleInstructionSet
173+
case evm.chainRules.IsByzantium:
174+
evm.table = &byzantiumInstructionSet
175+
case evm.chainRules.IsEIP158:
176+
evm.table = &spuriousDragonInstructionSet
177+
case evm.chainRules.IsEIP150:
178+
evm.table = &tangerineWhistleInstructionSet
179+
case evm.chainRules.IsHomestead:
180+
evm.table = &homesteadInstructionSet
181+
default:
182+
evm.table = &frontierInstructionSet
183+
}
184+
var extraEips []int
185+
if len(evm.Config.ExtraEips) > 0 {
186+
// Deep-copy jumptable to prevent modification of opcodes in other tables
187+
evm.table = copyJumpTable(evm.table)
188+
}
189+
for _, eip := range evm.Config.ExtraEips {
190+
if err := EnableEIP(eip, evm.table); err != nil {
191+
// Disable it, so caller can check if it's activated or not
192+
log.Error("EIP activation failed", "eip", eip, "error", err)
193+
} else {
194+
extraEips = append(extraEips, eip)
195+
}
196+
}
197+
evm.Config.ExtraEips = extraEips
144198
return evm
145199
}
146200

@@ -176,11 +230,6 @@ func (evm *EVM) Cancelled() bool {
176230
return evm.abort.Load()
177231
}
178232

179-
// Interpreter returns the current interpreter
180-
func (evm *EVM) Interpreter() *EVMInterpreter {
181-
return evm.interpreter
182-
}
183-
184233
func isSystemCall(caller common.Address) bool {
185234
return caller == params.SystemAddress
186235
}
@@ -245,7 +294,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
245294
contract := NewContract(caller, addr, value, gas, evm.jumpDests)
246295
contract.IsSystemCall = isSystemCall(caller)
247296
contract.SetCallCode(evm.resolveCodeHash(addr), code)
248-
ret, err = evm.interpreter.Run(contract, input, false)
297+
ret, err = evm.Run(contract, input, false)
249298
gas = contract.Gas
250299
}
251300
}
@@ -304,7 +353,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
304353
// The contract is a scoped environment for this execution context only.
305354
contract := NewContract(caller, caller, value, gas, evm.jumpDests)
306355
contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr))
307-
ret, err = evm.interpreter.Run(contract, input, false)
356+
ret, err = evm.Run(contract, input, false)
308357
gas = contract.Gas
309358
}
310359
if err != nil {
@@ -348,7 +397,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
348397
// Note: The value refers to the original value from the parent call.
349398
contract := NewContract(originCaller, caller, value, gas, evm.jumpDests)
350399
contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr))
351-
ret, err = evm.interpreter.Run(contract, input, false)
400+
ret, err = evm.Run(contract, input, false)
352401
gas = contract.Gas
353402
}
354403
if err != nil {
@@ -403,7 +452,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
403452
// When an error was returned by the EVM or when setting the creation code
404453
// above we revert to the snapshot and consume any gas remaining. Additionally
405454
// when we're in Homestead this also counts for code storage gas errors.
406-
ret, err = evm.interpreter.Run(contract, input, true)
455+
ret, err = evm.Run(contract, input, true)
407456
gas = contract.Gas
408457
}
409458
if err != nil {
@@ -524,7 +573,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
524573
// initNewContract runs a new contract's creation code, performs checks on the
525574
// resulting code that is to be deployed, and consumes necessary gas.
526575
func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]byte, error) {
527-
ret, err := evm.interpreter.Run(contract, nil, false)
576+
ret, err := evm.Run(contract, nil, false)
528577
if err != nil {
529578
return ret, err
530579
}
@@ -567,7 +616,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui
567616
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
568617
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
569618
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
570-
inithash := crypto.HashData(evm.interpreter.hasher, code)
619+
inithash := crypto.HashData(evm.hasher, code)
571620
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
572621
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
573622
}

0 commit comments

Comments
 (0)