From c3ef6c77c24956ebe1156205869259ffb8892486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Fri, 8 Aug 2025 01:01:41 +0300 Subject: [PATCH] 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. --- core/vm/eips.go | 58 ++--- core/vm/evm.go | 81 +++++-- core/vm/instructions.go | 357 +++++++++++++++--------------- core/vm/instructions_test.go | 28 +-- core/vm/interpreter.go | 121 +++------- core/vm/jump_table.go | 2 +- eth/tracers/js/tracer_test.go | 2 +- eth/tracers/logger/logger_test.go | 2 +- 8 files changed, 316 insertions(+), 335 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 7764bd20b6..10ca1fe9ab 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -89,8 +89,8 @@ func enable1884(jt *JumpTable) { } } -func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) +func opSelfBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + balance := evm.StateDB.GetBalance(scope.Contract.Address()) scope.Stack.push(balance) return nil, nil } @@ -108,8 +108,8 @@ func enable1344(jt *JumpTable) { } // opChainID implements CHAINID opcode -func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID) +func opChainID(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + chainId, _ := uint256.FromBig(evm.chainConfig.ChainID) scope.Stack.push(chainId) return nil, nil } @@ -199,28 +199,28 @@ func enable1153(jt *JumpTable) { } // opTload implements TLOAD opcode -func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opTload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { loc := scope.Stack.peek() hash := common.Hash(loc.Bytes32()) - val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash) + val := evm.StateDB.GetTransientState(scope.Contract.Address(), hash) loc.SetBytes(val.Bytes()) return nil, nil } // opTstore implements TSTORE opcode -func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opTstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } loc := scope.Stack.pop() val := scope.Stack.pop() - interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) + evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) return nil, nil } // opBaseFee implements BASEFEE opcode -func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee) +func opBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + baseFee, _ := uint256.FromBig(evm.Context.BaseFee) scope.Stack.push(baseFee) return nil, nil } @@ -237,7 +237,7 @@ func enable3855(jt *JumpTable) { } // opPush0 implements the PUSH0 opcode -func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush0(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int)) return nil, nil } @@ -263,7 +263,7 @@ func enable5656(jt *JumpTable) { } // opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656) -func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMcopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( dst = scope.Stack.pop() src = scope.Stack.pop() @@ -276,10 +276,10 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by } // opBlobHash implements the BLOBHASH opcode -func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opBlobHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { index := scope.Stack.peek() - if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) { - blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()] + if index.LtUint64(uint64(len(evm.TxContext.BlobHashes))) { + blobHash := evm.TxContext.BlobHashes[index.Uint64()] index.SetBytes32(blobHash[:]) } else { index.Clear() @@ -288,14 +288,14 @@ func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } // opBlobBaseFee implements BLOBBASEFEE opcode -func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - blobBaseFee, _ := uint256.FromBig(interpreter.evm.Context.BlobBaseFee) +func opBlobBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + blobBaseFee, _ := uint256.FromBig(evm.Context.BlobBaseFee) scope.Stack.push(blobBaseFee) return nil, nil } // opCLZ implements the CLZ opcode (count leading zero bytes) -func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCLZ(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() x.SetUint64(256 - uint64(x.BitLen())) return nil, nil @@ -342,7 +342,7 @@ func enable6780(jt *JumpTable) { } } -func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( stack = scope.Stack a = stack.pop() @@ -355,10 +355,10 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - code := interpreter.evm.StateDB.GetCode(addr) + code := evm.StateDB.GetCode(addr) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) - consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) + scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -370,7 +370,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC // opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which // need not worry about the adjusted bound logic when adding the PUSHDATA to // the list of access events. -func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = uint64(len(scope.Contract.Code)) integer = new(uint256.Int) @@ -383,8 +383,8 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext // touch next chunk if PUSH1 is at the boundary. if so, *pc has // advanced past this boundary. contractAddr := scope.Contract.Address() - consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) + scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -396,7 +396,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } func makePushEIP4762(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = len(scope.Contract.Code) start = min(codeLen, int(*pc+1)) @@ -411,8 +411,8 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc { if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall { contractAddr := scope.Contract.Address() - consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) + scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } diff --git a/core/vm/evm.go b/core/vm/evm.go index 143b7e08a2..e360187f7b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -95,6 +96,9 @@ type EVM struct { // StateDB gives access to the underlying state StateDB StateDB + // table holds the opcode specific handlers + table *JumpTable + // depth is the current call stack depth int @@ -107,10 +111,6 @@ type EVM struct { // virtual machine configuration options used to initialise the evm Config Config - // global (to this context) ethereum virtual machine used throughout - // the execution of the tx - interpreter *EVMInterpreter - // abort is used to abort the EVM calling operations abort atomic.Bool @@ -124,6 +124,12 @@ type EVM struct { // jumpDests stores results of JUMPDEST analysis. jumpDests JumpDestCache + + hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes + hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes + + readOnly bool // Whether to throw on stateful modifications + returnData []byte // Last CALL's return data for subsequent reuse } // NewEVM constructs an EVM instance with the supplied block context, state @@ -138,9 +144,57 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), jumpDests: newMapJumpDests(), + hasher: crypto.NewKeccakState(), } evm.precompiles = activePrecompiledContracts(evm.chainRules) - evm.interpreter = NewEVMInterpreter(evm) + + switch { + case evm.chainRules.IsOsaka: + evm.table = &osakaInstructionSet + case evm.chainRules.IsVerkle: + // TODO replace with proper instruction set when fork is specified + evm.table = &verkleInstructionSet + case evm.chainRules.IsPrague: + evm.table = &pragueInstructionSet + case evm.chainRules.IsCancun: + evm.table = &cancunInstructionSet + case evm.chainRules.IsShanghai: + evm.table = &shanghaiInstructionSet + case evm.chainRules.IsMerge: + evm.table = &mergeInstructionSet + case evm.chainRules.IsLondon: + evm.table = &londonInstructionSet + case evm.chainRules.IsBerlin: + evm.table = &berlinInstructionSet + case evm.chainRules.IsIstanbul: + evm.table = &istanbulInstructionSet + case evm.chainRules.IsConstantinople: + evm.table = &constantinopleInstructionSet + case evm.chainRules.IsByzantium: + evm.table = &byzantiumInstructionSet + case evm.chainRules.IsEIP158: + evm.table = &spuriousDragonInstructionSet + case evm.chainRules.IsEIP150: + evm.table = &tangerineWhistleInstructionSet + case evm.chainRules.IsHomestead: + evm.table = &homesteadInstructionSet + default: + evm.table = &frontierInstructionSet + } + var extraEips []int + if len(evm.Config.ExtraEips) > 0 { + // Deep-copy jumptable to prevent modification of opcodes in other tables + evm.table = copyJumpTable(evm.table) + } + for _, eip := range evm.Config.ExtraEips { + if err := EnableEIP(eip, evm.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 evm } @@ -176,11 +230,6 @@ func (evm *EVM) Cancelled() bool { return evm.abort.Load() } -// Interpreter returns the current interpreter -func (evm *EVM) Interpreter() *EVMInterpreter { - return evm.interpreter -} - func isSystemCall(caller common.Address) bool { return caller == params.SystemAddress } @@ -245,7 +294,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g contract := NewContract(caller, addr, value, gas, evm.jumpDests) contract.IsSystemCall = isSystemCall(caller) contract.SetCallCode(evm.resolveCodeHash(addr), code) - ret, err = evm.interpreter.Run(contract, input, false) + ret, err = evm.Run(contract, input, false) gas = contract.Gas } } @@ -304,7 +353,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt // The contract is a scoped environment for this execution context only. contract := NewContract(caller, caller, value, gas, evm.jumpDests) contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) - ret, err = evm.interpreter.Run(contract, input, false) + ret, err = evm.Run(contract, input, false) gas = contract.Gas } if err != nil { @@ -348,7 +397,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, // Note: The value refers to the original value from the parent call. contract := NewContract(originCaller, caller, value, gas, evm.jumpDests) contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) - ret, err = evm.interpreter.Run(contract, input, false) + ret, err = evm.Run(contract, input, false) gas = contract.Gas } if err != nil { @@ -403,7 +452,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. - ret, err = evm.interpreter.Run(contract, input, true) + ret, err = evm.Run(contract, input, true) gas = contract.Gas } if err != nil { @@ -524,7 +573,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui // initNewContract runs a new contract's creation code, performs checks on the // resulting code that is to be deployed, and consumes necessary gas. func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]byte, error) { - ret, err := evm.interpreter.Run(contract, nil, false) + ret, err := evm.Run(contract, nil, false) if err != nil { return ret, err } @@ -567,7 +616,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. 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) { - inithash := crypto.HashData(evm.interpreter.hasher, code) + inithash := crypto.HashData(evm.hasher, code) contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:]) return evm.create(caller, code, gas, endowment, contractAddr, CREATE2) } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 63bb6d2d51..fffa65fd6a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -26,67 +26,67 @@ import ( "github.com/holiman/uint256" ) -func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAdd(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Add(&x, y) return nil, nil } -func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSub(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Sub(&x, y) return nil, nil } -func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMul(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Mul(&x, y) return nil, nil } -func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opDiv(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Div(&x, y) return nil, nil } -func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSdiv(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.SDiv(&x, y) return nil, nil } -func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Mod(&x, y) return nil, nil } -func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.SMod(&x, y) return nil, nil } -func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { base, exponent := scope.Stack.pop(), scope.Stack.peek() exponent.Exp(&base, exponent) return nil, nil } -func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSignExtend(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { back, num := scope.Stack.pop(), scope.Stack.peek() num.ExtendSign(num, &back) return nil, nil } -func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opNot(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() x.Not(x) return nil, nil } -func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opLt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Lt(y) { y.SetOne() @@ -96,7 +96,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, return nil, nil } -func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opGt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Gt(y) { y.SetOne() @@ -106,7 +106,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, return nil, nil } -func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSlt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Slt(y) { y.SetOne() @@ -116,7 +116,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } -func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSgt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Sgt(y) { y.SetOne() @@ -126,7 +126,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } -func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opEq(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Eq(y) { y.SetOne() @@ -136,7 +136,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, return nil, nil } -func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opIszero(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() if x.IsZero() { x.SetOne() @@ -146,37 +146,37 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b return nil, nil } -func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAnd(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.And(&x, y) return nil, nil } -func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opOr(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Or(&x, y) return nil, nil } -func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opXor(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Xor(&x, y) return nil, nil } -func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opByte(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { th, val := scope.Stack.pop(), scope.Stack.peek() val.Byte(&th) return nil, nil } -func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAddmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() z.AddMod(&x, &y, z) return nil, nil } -func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMulmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() z.MulMod(&x, &y, z) return nil, nil @@ -185,7 +185,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // opSHL implements Shift Left // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the left by arg1 number of bits. -func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSHL(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := scope.Stack.pop(), scope.Stack.peek() if shift.LtUint64(256) { @@ -199,7 +199,7 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte // opSHR implements Logical Shift Right // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. -func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSHR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := scope.Stack.pop(), scope.Stack.peek() if shift.LtUint64(256) { @@ -213,7 +213,7 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte // opSAR implements Arithmetic Shift Right // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. -func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSAR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { shift, value := scope.Stack.pop(), scope.Stack.peek() if shift.GtUint64(256) { if value.Sign() >= 0 { @@ -229,50 +229,49 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } -func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opKeccak256(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.peek() data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) - interpreter.hasher.Reset() - interpreter.hasher.Write(data) - interpreter.hasher.Read(interpreter.hasherBuf[:]) + evm.hasher.Reset() + evm.hasher.Write(data) + evm.hasher.Read(evm.hasherBuf[:]) - evm := interpreter.evm if evm.Config.EnablePreimageRecording { - evm.StateDB.AddPreimage(interpreter.hasherBuf, data) + evm.StateDB.AddPreimage(evm.hasherBuf, data) } - size.SetBytes(interpreter.hasherBuf[:]) + size.SetBytes(evm.hasherBuf[:]) return nil, nil } -func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAddress(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes())) return nil, nil } -func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) - slot.Set(interpreter.evm.StateDB.GetBalance(address)) + slot.Set(evm.StateDB.GetBalance(address)) return nil, nil } -func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes())) +func opOrigin(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetBytes(evm.Origin.Bytes())) return nil, nil } -func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCaller(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes())) return nil, nil } -func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallValue(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(scope.Contract.value) return nil, nil } -func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallDataLoad(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() if offset, overflow := x.Uint64WithOverflow(); !overflow { data := getData(scope.Contract.Input, offset, 32) @@ -283,12 +282,12 @@ func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext return nil, nil } -func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( memOffset = scope.Stack.pop() dataOffset = scope.Stack.pop() @@ -306,12 +305,12 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext return nil, nil } -func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData)))) +func opReturnDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(evm.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opReturnDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( memOffset = scope.Stack.pop() dataOffset = scope.Stack.pop() @@ -326,25 +325,25 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte var end = dataOffset end.Add(&dataOffset, &length) end64, overflow := end.Uint64WithOverflow() - if overflow || uint64(len(interpreter.returnData)) < end64 { + if overflow || uint64(len(evm.returnData)) < end64 { return nil, ErrReturnDataOutOfBounds } - scope.Memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64]) + scope.Memory.Set(memOffset.Uint64(), length.Uint64(), evm.returnData[offset64:end64]) return nil, nil } -func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() - slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20()))) + slot.SetUint64(uint64(evm.StateDB.GetCodeSize(slot.Bytes20()))) return nil, nil } -func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code)))) return nil, nil } -func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( memOffset = scope.Stack.pop() codeOffset = scope.Stack.pop() @@ -360,7 +359,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ return nil, nil } -func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( stack = scope.Stack a = stack.pop() @@ -373,7 +372,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - code := interpreter.evm.StateDB.GetCode(addr) + code := evm.StateDB.GetCode(addr) codeCopy := getData(code, uint64CodeOffset, length.Uint64()) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) @@ -406,24 +405,24 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // // 6. Caller tries to get the code hash for an account which is marked as deleted, this // account should be regarded as a non-existent account and zero should be returned. -func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) - if interpreter.evm.StateDB.Empty(address) { + if evm.StateDB.Empty(address) { slot.Clear() } else { - slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes()) + slot.SetBytes(evm.StateDB.GetCodeHash(address).Bytes()) } return nil, nil } -func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.GasPrice) +func opGasprice(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v, _ := uint256.FromBig(evm.GasPrice) scope.Stack.push(v) return nil, nil } -func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opBlockhash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { num := scope.Stack.peek() num64, overflow := num.Uint64WithOverflow() if overflow { @@ -432,18 +431,18 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( } var upper, lower uint64 - upper = interpreter.evm.Context.BlockNumber.Uint64() + upper = evm.Context.BlockNumber.Uint64() if upper < 257 { lower = 0 } else { lower = upper - 256 } if num64 >= lower && num64 < upper { - res := interpreter.evm.Context.GetHash(num64) - if witness := interpreter.evm.StateDB.Witness(); witness != nil { + res := evm.Context.GetHash(num64) + if witness := evm.StateDB.Witness(); witness != nil { witness.AddBlockHash(num64) } - if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { + if tracer := evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { tracer.OnBlockHashRead(num64, res) } num.SetBytes(res[:]) @@ -453,83 +452,83 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( return nil, nil } -func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes())) +func opCoinbase(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetBytes(evm.Context.Coinbase.Bytes())) return nil, nil } -func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time)) +func opTimestamp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.Time)) return nil, nil } -func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber) +func opNumber(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v, _ := uint256.FromBig(evm.Context.BlockNumber) scope.Stack.push(v) return nil, nil } -func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty) +func opDifficulty(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v, _ := uint256.FromBig(evm.Context.Difficulty) scope.Stack.push(v) return nil, nil } -func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes()) +func opRandom(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v := new(uint256.Int).SetBytes(evm.Context.Random.Bytes()) scope.Stack.push(v) return nil, nil } -func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit)) +func opGasLimit(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.GasLimit)) return nil, nil } -func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.pop() return nil, nil } -func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { v := scope.Stack.peek() offset := v.Uint64() v.SetBytes(scope.Memory.GetPtr(offset, 32)) return nil, nil } -func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { mStart, val := scope.Stack.pop(), scope.Stack.pop() scope.Memory.Set32(mStart.Uint64(), &val) return nil, nil } -func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMstore8(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { off, val := scope.Stack.pop(), scope.Stack.pop() scope.Memory.store[off.Uint64()] = byte(val.Uint64()) return nil, nil } -func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { loc := scope.Stack.peek() hash := common.Hash(loc.Bytes32()) - val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash) + val := evm.StateDB.GetState(scope.Contract.Address(), hash) loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opSstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } loc := scope.Stack.pop() val := scope.Stack.pop() - interpreter.evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) + evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) return nil, nil } -func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.evm.abort.Load() { +func opJump(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.abort.Load() { return nil, errStopToken } pos := scope.Stack.pop() @@ -540,8 +539,8 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt return nil, nil } -func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.evm.abort.Load() { +func opJumpi(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.abort.Load() { return nil, errStopToken } pos, cond := scope.Stack.pop(), scope.Stack.pop() @@ -554,107 +553,107 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by return nil, nil } -func opJumpdest(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opJumpdest(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPc(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMsize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len()))) return nil, nil } -func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opGas(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas)) return nil, nil } -func opSwap1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap1(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap1() return nil, nil } -func opSwap2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap2() return nil, nil } -func opSwap3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap3(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap3() return nil, nil } -func opSwap4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap4(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap4() return nil, nil } -func opSwap5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap5(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap5() return nil, nil } -func opSwap6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap6(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap6() return nil, nil } -func opSwap7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap7(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap7() return nil, nil } -func opSwap8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap8(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap8() return nil, nil } -func opSwap9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap9(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap9() return nil, nil } -func opSwap10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap10(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap10() return nil, nil } -func opSwap11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap11(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap11() return nil, nil } -func opSwap12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap12(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap12() return nil, nil } -func opSwap13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap13(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap13() return nil, nil } -func opSwap14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap14(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap14() return nil, nil } -func opSwap15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap15(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap15() return nil, nil } -func opSwap16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap16(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap16() return nil, nil } -func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } var ( @@ -663,21 +662,21 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) gas = scope.Contract.Gas ) - if interpreter.evm.chainRules.IsEIP150 { + if evm.chainRules.IsEIP150 { gas -= gas / 64 } // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation) + scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation) - res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value) + res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, &value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { + if evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { stackvalue.Clear() } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stackvalue.Clear() @@ -686,18 +685,18 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { - interpreter.returnData = res // set REVERT data to return data buffer + evm.returnData = res // set REVERT data to return data buffer return res, nil } - interpreter.returnData = nil // clear dirty return data buffer + evm.returnData = nil // clear dirty return data buffer return nil, nil } -func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } var ( @@ -710,10 +709,10 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) + scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas, + res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas, &endowment, &salt) // Push item on the stack based on the returned error. if suberr != nil { @@ -722,35 +721,35 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { - interpreter.returnData = res // set REVERT data to return data buffer + evm.returnData = res // set REVERT data to return data buffer return res, nil } - interpreter.returnData = nil // clear dirty return data buffer + evm.returnData = nil // clear dirty return data buffer return nil, nil } -func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { stack := scope.Stack - // Pop gas. The actual gas in interpreter.evm.callGasTemp. + // Pop gas. The actual gas in evm.callGasTemp. // We can use this as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get the arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - if interpreter.readOnly && !value.IsZero() { + if evm.readOnly && !value.IsZero() { return nil, ErrWriteProtection } if !value.IsZero() { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) + ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() @@ -762,18 +761,18 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. +func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + // Pop gas. The actual gas is in evm.callGasTemp. stack := scope.Stack // We use it as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) @@ -784,7 +783,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) + ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() } else { @@ -795,25 +794,25 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { stack := scope.Stack - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + // Pop gas. The actual gas is in evm.callGasTemp. // We use it as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) + ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) if err != nil { temp.Clear() } else { @@ -824,25 +823,25 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. +func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + // Pop gas. The actual gas is in evm.callGasTemp. stack := scope.Stack // We use it as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) + ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) if err != nil { temp.Clear() } else { @@ -853,69 +852,69 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opReturn(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) return ret, errStopToken } -func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opRevert(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) - interpreter.returnData = ret + evm.returnData = ret return ret, ErrExecutionReverted } -func opUndefined(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opUndefined(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { return nil, &ErrInvalidOpCode{opcode: OpCode(scope.Contract.Code[*pc])} } -func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opStop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { return nil, errStopToken } -func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } beneficiary := scope.Stack.pop() - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) - interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) - if tracer := interpreter.evm.Config.Tracer; tracer != nil { + balance := evm.StateDB.GetBalance(scope.Contract.Address()) + evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) + evm.StateDB.SelfDestruct(scope.Contract.Address()) + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { - tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) } if tracer.OnExit != nil { - tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) + tracer.OnExit(evm.depth, []byte{}, 0, nil, false) } } return nil, errStopToken } -func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } beneficiary := scope.Stack.pop() - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) - interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address()) - if tracer := interpreter.evm.Config.Tracer; tracer != nil { + balance := evm.StateDB.GetBalance(scope.Contract.Address()) + evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) + evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) + evm.StateDB.SelfDestruct6780(scope.Contract.Address()) + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { - tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) } if tracer.OnExit != nil { - tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) + tracer.OnExit(evm.depth, []byte{}, 0, nil, false) } } return nil, errStopToken @@ -925,8 +924,8 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } topics := make([]common.Hash, size) @@ -938,13 +937,13 @@ func makeLog(size int) executionFunc { } d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64()) - interpreter.evm.StateDB.AddLog(&types.Log{ + evm.StateDB.AddLog(&types.Log{ Address: scope.Contract.Address(), Topics: topics, Data: d, // This is a non-consensus field, but assigned here because // core/state doesn't know the current block number. - BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(), + BlockNumber: evm.Context.BlockNumber.Uint64(), }) return nil, nil @@ -952,7 +951,7 @@ func makeLog(size int) executionFunc { } // opPush1 is a specialized version of pushN -func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush1(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = uint64(len(scope.Contract.Code)) integer = new(uint256.Int) @@ -967,7 +966,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by } // opPush2 is a specialized version of pushN -func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = uint64(len(scope.Contract.Code)) integer = new(uint256.Int) @@ -985,7 +984,7 @@ func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = len(scope.Contract.Code) start = min(codeLen, int(*pc+1)) @@ -1005,7 +1004,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.dup(int(size)) return nil, nil } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 8a82de5d8b..cd31829a7e 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -107,7 +107,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected)) stack.push(x) stack.push(y) - opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opFn(&pc, evm, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data)) } @@ -221,7 +221,7 @@ func TestAddMod(t *testing.T) { stack.push(z) stack.push(y) stack.push(x) - opAddmod(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opAddmod(&pc, evm, &ScopeContext{nil, stack, nil}) actual := stack.pop() if actual.Cmp(expected) != 0 { t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual) @@ -247,7 +247,7 @@ func TestWriteExpectedValues(t *testing.T) { y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y)) stack.push(x) stack.push(y) - opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opFn(&pc, evm, &ScopeContext{nil, stack, nil}) actual := stack.pop() result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} } @@ -296,7 +296,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) { for _, arg := range intArgs { stack.push(arg) } - op(&pc, evm.interpreter, scope) + op(&pc, evm, scope) stack.pop() } bench.StopTimer() @@ -528,13 +528,13 @@ func TestOpMstore(t *testing.T) { v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v))) stack.push(new(uint256.Int)) - opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm, &ScopeContext{mem, stack, nil}) if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v { t.Fatalf("Mstore fail, got %v, expected %v", got, v) } stack.push(new(uint256.Int).SetUint64(0x1)) stack.push(new(uint256.Int)) - opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm, &ScopeContext{mem, stack, nil}) if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } @@ -555,7 +555,7 @@ func BenchmarkOpMstore(bench *testing.B) { for i := 0; i < bench.N; i++ { stack.push(value) stack.push(memStart) - opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm, &ScopeContext{mem, stack, nil}) } } @@ -581,14 +581,14 @@ func TestOpTstore(t *testing.T) { stack.push(new(uint256.Int).SetBytes(value)) // push the location to the stack stack.push(new(uint256.Int)) - opTstore(&pc, evm.interpreter, &scopeContext) + opTstore(&pc, evm, &scopeContext) // there should be no elements on the stack after TSTORE if stack.len() != 0 { t.Fatal("stack wrong size") } // push the location to the stack stack.push(new(uint256.Int)) - opTload(&pc, evm.interpreter, &scopeContext) + opTload(&pc, evm, &scopeContext) // there should be one element on the stack after TLOAD if stack.len() != 1 { t.Fatal("stack wrong size") @@ -613,7 +613,7 @@ func BenchmarkOpKeccak256(bench *testing.B) { for i := 0; i < bench.N; i++ { stack.push(uint256.NewInt(32)) stack.push(start) - opKeccak256(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opKeccak256(&pc, evm, &ScopeContext{mem, stack, nil}) } } @@ -707,7 +707,7 @@ func TestRandom(t *testing.T) { stack = newstack() pc = uint64(0) ) - opRandom(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opRandom(&pc, evm, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) } @@ -749,7 +749,7 @@ func TestBlobHash(t *testing.T) { ) evm.SetTxContext(TxContext{BlobHashes: tt.hashes}) stack.push(uint256.NewInt(tt.idx)) - opBlobHash(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opBlobHash(&pc, evm, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) } @@ -889,7 +889,7 @@ func TestOpMCopy(t *testing.T) { mem.Resize(memorySize) } // Do the copy - opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMcopy(&pc, evm, &ScopeContext{mem, stack, nil}) want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) if have := mem.store; !bytes.Equal(want, have) { t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have) @@ -1001,7 +1001,7 @@ func TestOpCLZ(t *testing.T) { } stack.push(val) - opCLZ(&pc, evm.interpreter, &ScopeContext{Stack: stack}) + opCLZ(&pc, evm, &ScopeContext{Stack: stack}) if gotLen := stack.len(); gotLen != 1 { t.Fatalf("stack length = %d; want 1", gotLen) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 34d19008da..a0637a6800 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -22,8 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) @@ -89,93 +87,27 @@ func (ctx *ScopeContext) ContractCode() []byte { return ctx.Contract.Code } -// EVMInterpreter represents an EVM interpreter -type EVMInterpreter struct { - evm *EVM - table *JumpTable - - hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes - hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes - - readOnly bool // Whether to throw on stateful modifications - returnData []byte // Last CALL's return data for subsequent reuse -} - -// NewEVMInterpreter returns a new instance of the Interpreter. -func NewEVMInterpreter(evm *EVM) *EVMInterpreter { - // If jump table was not initialised we set the default one. - var table *JumpTable - switch { - case evm.chainRules.IsOsaka: - table = &osakaInstructionSet - case evm.chainRules.IsVerkle: - // TODO replace with proper instruction set when fork is specified - table = &verkleInstructionSet - case evm.chainRules.IsPrague: - table = &pragueInstructionSet - case evm.chainRules.IsCancun: - table = &cancunInstructionSet - 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 - } - 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, hasher: crypto.NewKeccakState()} -} - // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occurred. // // It's important to note that any errors returned by the interpreter should be // considered a revert-and-consume-all-gas operation except for // ErrExecutionReverted which means revert-and-keep-gas-left. -func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { +func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { // Increment the call depth which is restricted to 1024 - in.evm.depth++ - defer func() { in.evm.depth-- }() + evm.depth++ + defer func() { evm.depth-- }() // Make sure the readOnly is only set if we aren't in readOnly yet. // This also makes sure that the readOnly flag isn't removed for child calls. - if readOnly && !in.readOnly { - in.readOnly = true - defer func() { in.readOnly = false }() + if readOnly && !evm.readOnly { + evm.readOnly = true + defer func() { evm.readOnly = false }() } // Reset the previous call's return data. It's unimportant to preserve the old buffer // as every returning call will return new data anyway. - in.returnData = nil + evm.returnData = nil // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { @@ -184,7 +116,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var ( op OpCode // current opcode - jumpTable *JumpTable = in.table + jumpTable *JumpTable = evm.table mem = NewMemory() // bound memory stack = newstack() // local stack callContext = &ScopeContext{ @@ -198,11 +130,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( pc = uint64(0) // program counter cost uint64 // copies used by tracer - pcCopy uint64 // needed for the deferred EVMLogger - gasCopy uint64 // for EVMLogger to log gas remaining before execution - logged bool // deferred EVMLogger should ignore already logged steps - res []byte // result of the opcode execution function - debug = in.evm.Config.Tracer != nil + pcCopy uint64 // needed for the deferred EVMLogger + gasCopy uint64 // for EVMLogger to log gas remaining before execution + logged bool // deferred EVMLogger should ignore already logged steps + res []byte // result of the opcode execution function + debug = evm.Config.Tracer != nil + isEIP4762 = evm.chainRules.IsEIP4762 ) // Don't move this deferred function, it's placed before the OnOpcode-deferred method, // so that it gets executed _after_: the OnOpcode needs the stacks before @@ -218,11 +151,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if err == nil { return } - if !logged && in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if !logged && evm.Config.Tracer.OnOpcode != nil { + evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err)) } - if logged && in.evm.Config.Tracer.OnFault != nil { - in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + if logged && evm.Config.Tracer.OnFault != nil { + evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err)) } }() } @@ -237,12 +170,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( logged, pcCopy, gasCopy = false, pc, contract.Gas } - if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { + if isEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { // if the PC ends up in a new "chunk" of verkleized code, charge the // associated costs. contractAddr := contract.Address() - consumed, wanted := in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) - contract.UseGas(consumed, in.evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) + consumed, wanted := evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) + contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) if consumed < wanted { return nil, ErrOutOfGas } @@ -287,7 +220,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method can get the proper cost var dynamicCost uint64 - dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) + dynamicCost, err = operation.dynamicGas(evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) @@ -302,11 +235,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Do tracing before potential memory expansion if debug { - if in.evm.Config.Tracer.OnGasChange != nil { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) + if evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } - if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if evm.Config.Tracer.OnOpcode != nil { + evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err)) logged = true } } @@ -315,7 +248,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } // execute the operation - res, err = operation.execute(&pc, in, callContext) + res, err = operation.execute(&pc, evm, callContext) if err != nil { break } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 22eed8754f..d7a4d9da1d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -23,7 +23,7 @@ import ( ) type ( - executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) + executionFunc func(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error) gasFunc 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) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index a12b990a93..7f376a27fc 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -65,7 +65,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) - ret, err := evm.Interpreter().Run(contract, []byte{}, false) + ret, err := evm.Run(contract, []byte{}, false) tracer.OnExit(0, ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 12000b3b9a..acc3069e70 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -52,7 +52,7 @@ func TestStoreCapture(t *testing.T) { contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash logger.OnTxStart(evm.GetVMContext(), nil, common.Address{}) - _, err := evm.Interpreter().Run(contract, []byte{}, false) + _, err := evm.Run(contract, []byte{}, false) if err != nil { t.Fatal(err) }