diff --git a/execution/tracing/tracers/js/tracer_test.go b/execution/tracing/tracers/js/tracer_test.go
index 0857ddf9bf3..351f122696e 100644
--- a/execution/tracing/tracers/js/tracer_test.go
+++ b/execution/tracing/tracers/js/tracer_test.go
@@ -63,7 +63,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *chain.Config,
tracer.OnTxStart(env.GetVMContext(), types.NewTransaction(0, accounts.ZeroAddress.Value(), nil, gasLimit, nil, nil), contract.Caller())
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), false, []byte{}, startGas, value, contractCode)
- ret, endGas, err := env.Interpreter().Run(contract, startGas, []byte{}, false)
+ ret, endGas, err := env.Run(contract, startGas, []byte{}, false)
tracer.OnExit(0, ret, startGas-endGas, err, true)
// Rest gas assumes no refund
tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - endGas}, nil)
diff --git a/execution/tracing/tracers/logger/logger_test.go b/execution/tracing/tracers/logger/logger_test.go
index 17b335c27e3..0d858a6f69d 100644
--- a/execution/tracing/tracers/logger/logger_test.go
+++ b/execution/tracing/tracers/logger/logger_test.go
@@ -63,7 +63,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, accounts.ZeroAddress)
- _, _, err := evm.Interpreter().Run(contract, 100000, []byte{}, false)
+ _, _, err := evm.Run(contract, 100000, []byte{}, false)
if err != nil {
t.Fatal(err)
}
diff --git a/execution/vm/eips.go b/execution/vm/eips.go
index 32326b03d0c..34afa7623ab 100644
--- a/execution/vm/eips.go
+++ b/execution/vm/eips.go
@@ -94,8 +94,8 @@ func enable1884(jt *JumpTable) {
}
}
-func opSelfBalance(pc uint64, interpreter *EVMInterpreter, callContext *CallContext) (uint64, []byte, error) {
- balance, err := interpreter.evm.IntraBlockState().GetBalance(callContext.Contract.Address())
+func opSelfBalance(pc uint64, evm *EVM, callContext *CallContext) (uint64, []byte, error) {
+ balance, err := evm.IntraBlockState().GetBalance(callContext.Contract.Address())
if err != nil {
return pc, nil, err
}
@@ -116,8 +116,8 @@ func enable1344(jt *JumpTable) {
}
// opChainID implements CHAINID opcode
-func opChainID(pc uint64, interpreter *EVMInterpreter, callContext *CallContext) (uint64, []byte, error) {
- chainId, _ := uint256.FromBig(interpreter.evm.ChainRules().ChainID)
+func opChainID(pc uint64, evm *EVM, callContext *CallContext) (uint64, []byte, error) {
+ chainId, _ := uint256.FromBig(evm.ChainRules().ChainID)
callContext.Stack.push(*chainId)
return pc, nil, nil
}
@@ -203,28 +203,28 @@ func enable1153(jt *JumpTable) {
}
// opTload implements TLOAD opcode
-func opTload(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opTload(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
loc := scope.Stack.peek()
key := accounts.InternKey(loc.Bytes32())
- val := interpreter.evm.IntraBlockState().GetTransientState(scope.Contract.Address(), key)
+ val := evm.IntraBlockState().GetTransientState(scope.Contract.Address(), key)
loc.SetBytes(val.Bytes())
return pc, nil, nil
}
// opTstore implements TSTORE opcode
-func opTstore(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+func opTstore(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
loc := scope.Stack.pop()
val := scope.Stack.pop()
- interpreter.evm.IntraBlockState().SetTransientState(scope.Contract.Address(), accounts.InternKey(loc.Bytes32()), val)
+ evm.IntraBlockState().SetTransientState(scope.Contract.Address(), accounts.InternKey(loc.Bytes32()), val)
return pc, nil, nil
}
// opBaseFee implements BASEFEE opcode
-func opBaseFee(pc uint64, interpreter *EVMInterpreter, callContext *CallContext) (uint64, []byte, error) {
- baseFee := interpreter.evm.Context.BaseFee
+func opBaseFee(pc uint64, evm *EVM, callContext *CallContext) (uint64, []byte, error) {
+ baseFee := evm.Context.BaseFee
callContext.Stack.push(baseFee)
return pc, nil, nil
}
@@ -241,7 +241,7 @@ func enable3855(jt *JumpTable) {
}
// opPush0 implements the PUSH0 opcode
-func opPush0(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opPush0(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.push(uint256.Int{})
return pc, nil, nil
}
@@ -265,10 +265,10 @@ func enable4844(jt *JumpTable) {
}
// opBlobHash implements the BLOBHASH opcode
-func opBlobHash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opBlobHash(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
idx := scope.Stack.peek()
- if idx.LtUint64(uint64(len(interpreter.evm.BlobHashes))) {
- hash := interpreter.evm.BlobHashes[idx.Uint64()]
+ if idx.LtUint64(uint64(len(evm.BlobHashes))) {
+ hash := evm.BlobHashes[idx.Uint64()]
idx.SetBytes(hash.Bytes())
} else {
idx.Clear()
@@ -276,7 +276,7 @@ func opBlobHash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uin
return pc, nil, nil
}
-func opCLZ(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCLZ(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x := scope.Stack.peek()
// count leading zero bits in x
x.SetUint64(256 - uint64(x.BitLen()))
@@ -297,7 +297,7 @@ func enable5656(jt *JumpTable) {
}
// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
-func opMcopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMcopy(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
dst = scope.Stack.pop()
src = scope.Stack.pop()
@@ -315,8 +315,8 @@ func enable6780(jt *JumpTable) {
}
// opBlobBaseFee implements the BLOBBASEFEE opcode
-func opBlobBaseFee(pc uint64, interpreter *EVMInterpreter, callContext *CallContext) (uint64, []byte, error) {
- blobBaseFee := interpreter.evm.Context.BlobBaseFee
+func opBlobBaseFee(pc uint64, evm *EVM, callContext *CallContext) (uint64, []byte, error) {
+ blobBaseFee := evm.Context.BlobBaseFee
callContext.Stack.push(blobBaseFee)
return pc, nil, nil
}
diff --git a/execution/vm/evm.go b/execution/vm/evm.go
index 8298af66037..eabcba9249f 100644
--- a/execution/vm/evm.go
+++ b/execution/vm/evm.go
@@ -26,6 +26,7 @@ import (
"github.com/holiman/uint256"
+ "github.com/erigontech/erigon/common"
"github.com/erigontech/erigon/common/crypto"
"github.com/erigontech/erigon/common/dbg"
"github.com/erigontech/erigon/common/u256"
@@ -64,6 +65,12 @@ type EVM struct {
// IntraBlockState gives access to the underlying state
intraBlockState *state.IntraBlockState
+ // table holds the opcode specific handlers
+ jt *JumpTable
+
+ // depth is the current call stack
+ depth int
+
// chainConfig contains information about the current chain
chainConfig *chain.Config
// chain rules contains the chain rules for the current epoch
@@ -71,9 +78,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 Interpreter
// abort is used to abort the EVM calling operations
abort atomic.Bool
// callGasTemp holds the gas available for the current call. This is needed because the
@@ -82,6 +86,12 @@ type EVM struct {
callGasTemp uint64
// optional overridden set of precompiled contracts
precompiles PrecompiledContracts
+
+ hasher 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 returns a new EVM. The returned EVM is not thread safe and should
@@ -100,7 +110,7 @@ func NewEVM(blockCtx evmtypes.BlockContext, txCtx evmtypes.TxContext, ibs *state
chainConfig: chainConfig,
chainRules: blockCtx.Rules(chainConfig),
}
- evm.interpreter = NewEVMInterpreter(evm, vmConfig)
+ evm.jt = jumpTable(evm.chainRules, vmConfig)
return evm
}
@@ -127,7 +137,9 @@ func (evm *EVM) ResetBetweenBlocks(blockCtx evmtypes.BlockContext, txCtx evmtype
evm.config = vmConfig
evm.chainRules = chainRules
- evm.interpreter = NewEVMInterpreter(evm, vmConfig)
+ evm.depth = 0
+ evm.returnData = nil
+ evm.jt = jumpTable(chainRules, vmConfig)
// ensure the evm is reset to be used again
evm.abort.Store(false)
@@ -155,17 +167,12 @@ func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) {
evm.precompiles = precompiles
}
-// Interpreter returns the current interpreter
-func (evm *EVM) Interpreter() Interpreter {
- return evm.interpreter
-}
-
func (evm *EVM) call(typ OpCode, caller accounts.Address, callerAddress accounts.Address, addr accounts.Address, input []byte, gas uint64, value uint256.Int, bailout bool) (ret []byte, leftOverGas uint64, err error) {
if evm.abort.Load() {
return ret, leftOverGas, nil
}
- depth := evm.interpreter.Depth()
+ depth := evm.depth
version := evm.intraBlockState.Version()
if (dbg.TraceTransactionIO && !dbg.TraceInstructions) && (evm.intraBlockState.Trace() || dbg.TraceAccount(caller.Handle())) {
@@ -283,7 +290,7 @@ func (evm *EVM) call(typ OpCode, caller accounts.Address, callerAddress accounts
if typ == STATICCALL {
readOnly = true
}
- ret, gas, err = evm.interpreter.Run(contract, gas, input, readOnly)
+ ret, gas, err = evm.Run(contract, gas, input, readOnly)
}
// 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
@@ -370,7 +377,7 @@ func (evm *EVM) create(caller accounts.Address, codeAndHash *codeAndHash, gasRem
}()
}
- depth := evm.interpreter.Depth()
+ depth := evm.depth
// BAL: record target address even on failed CREATE/CREATE2 calls
evm.intraBlockState.MarkAddressAccess(address)
@@ -458,7 +465,7 @@ func (evm *EVM) create(caller accounts.Address, codeAndHash *codeAndHash, gasRem
return nil, address, gasRemaining, nil
}
- ret, gasRemaining, err = evm.interpreter.Run(contract, gasRemaining, nil, false)
+ ret, gasRemaining, err = evm.Run(contract, gasRemaining, nil, false)
// EIP-170: Contract code size limit
if err == nil && evm.chainRules.IsSpuriousDragon && len(ret) > evm.maxCodeSize() {
@@ -605,8 +612,3 @@ func (evm *EVM) captureEnd(depth int, typ OpCode, startGas uint64, leftOverGas u
tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
}
}
-
-// Depth returns the current depth
-func (evm *EVM) Depth() int {
- return evm.interpreter.Depth()
-}
diff --git a/execution/vm/evm_test.go b/execution/vm/evm_test.go
deleted file mode 100644
index 82ea3721fb3..00000000000
--- a/execution/vm/evm_test.go
+++ /dev/null
@@ -1,436 +0,0 @@
-// Copyright 2024 The Erigon Authors
-// This file is part of Erigon.
-//
-// Erigon is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Erigon is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with Erigon. If not, see .
-
-package vm
-
-import (
- "fmt"
- "strings"
- "testing"
-
- "github.com/holiman/uint256"
- "github.com/stretchr/testify/require"
- "pgregory.net/rapid"
-
- "github.com/erigontech/erigon/execution/chain"
- "github.com/erigontech/erigon/execution/types/accounts"
- "github.com/erigontech/erigon/execution/vm/evmtypes"
-)
-
-func TestEVMWithNoBaseFeeAndNoTxGasPrice(t *testing.T) {
- t.Parallel()
- vmConfig := Config{NoBaseFee: true}
- evm := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, vmConfig)
- require.NotNil(t, evm)
-}
-
-func TestInterpreterReadonly(t *testing.T) {
- t.Parallel()
- //c := NewJumpDestCache(128)
- rapid.Check(t, func(t *rapid.T) {
- env := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
-
- isEVMSliceTest := rapid.SliceOfN(rapid.Bool(), 1, -1).Draw(t, "tevm")
- readOnlySliceTest := rapid.SliceOfN(rapid.Bool(), len(isEVMSliceTest), len(isEVMSliceTest)).Draw(t, "readonly")
-
- isEVMCalled := make([]bool, len(isEVMSliceTest))
- readOnlies := make([]*readOnlyState, len(readOnlySliceTest))
- currentIdx := new(int)
- *currentIdx = -1
-
- evmInterpreter := &testVM{
- readonlyGetSetter: env.interpreter.(*EVMInterpreter),
-
- recordedReadOnlies: &readOnlies,
- recordedIsEVMCalled: &isEVMCalled,
-
- env: env,
- isEVMSliceTest: isEVMSliceTest,
- readOnlySliceTest: readOnlySliceTest,
- currentIdx: currentIdx,
- }
-
- env.interpreter = evmInterpreter
-
- dummyContract := NewContract(
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- uint256.Int{},
- //c,
- )
-
- newTestSequential(env, currentIdx, readOnlySliceTest, isEVMSliceTest).Run(dummyContract, nil, false)
-
- var gotReadonly bool
- var firstReadOnly int
-
- // properties-invariants
-
- if len(readOnlies) != len(readOnlySliceTest) {
- t.Fatalf("expected static calls the same stack length as generated. got %d, expected %d", len(readOnlies), len(readOnlySliceTest))
- }
-
- if len(isEVMCalled) != len(isEVMSliceTest) {
- t.Fatalf("expected VM calls the same stack length as generated. got %d, expected %d", len(isEVMCalled), len(isEVMSliceTest))
- }
-
- if *currentIdx != len(readOnlies) {
- t.Fatalf("expected VM calls the same amount of calls as generated calls. got %d, expected %d", *currentIdx, len(readOnlies))
- }
-
- for i, readOnly := range readOnlies {
-
- if readOnly.outer != readOnlySliceTest[i] {
- t.Fatalf("outer readOnly appeared in %d index, got readOnly %t, expected %t",
- i, readOnly.outer, readOnlySliceTest[i])
- }
-
- if i > 0 {
- if readOnly.before != readOnlies[i-1].in {
- t.Fatalf("before readOnly appeared in %d index, got readOnly %t, expected %t",
- i, readOnly.before, readOnlies[i-1].in)
- }
- }
-
- if readOnly.in && !gotReadonly {
- gotReadonly = true
- firstReadOnly = i
- }
-
- if gotReadonly {
- if !readOnly.in {
- t.Fatalf("readOnly appeared in %d index, got non-readOnly in %d: %v",
- firstReadOnly, i, trace(isEVMCalled, readOnlies))
- }
-
- switch {
- case i < firstReadOnly:
- if readOnly.after != false {
- t.Fatalf("after readOnly appeared in %d index(first readonly %d, case firstReadOnly:
- if readOnly.after != true {
- t.Fatalf("after readOnly appeared in %d index(first readonly %d, case >firstReadOnly), got readOnly %t, expected %t",
- i, firstReadOnly, readOnly.after, true)
- }
- }
- } else {
- if readOnly.after != false {
- t.Fatalf("after readOnly didn't appear. %d index, got readOnly %t, expected %t",
- i, readOnly.after, false)
- }
- }
- }
- })
-}
-
-func TestReadonlyBasicCases(t *testing.T) {
- t.Parallel()
- // c := NewJumpDestCache(128)
-
- cases := []struct {
- testName string
- readonlySliceTest []bool
-
- expectedReadonlySlice []readOnlyState
- }{
- {
- "simple non-readonly",
- []bool{false},
-
- []readOnlyState{
- {
- false,
- false,
- false,
- false,
- },
- },
- },
- {
- "simple readonly",
- []bool{true},
-
- []readOnlyState{
- {
- true,
- true,
- true,
- false,
- },
- },
- },
-
- {
- "2 calls non-readonly",
- []bool{false, false},
-
- []readOnlyState{
- {
- false,
- false,
- false,
- false,
- },
- {
- false,
- false,
- false,
- false,
- },
- },
- },
-
- {
- "2 calls true,false",
- []bool{true, false},
-
- []readOnlyState{
- {
- true,
- true,
- true,
- false,
- },
- {
- true,
- true,
- true,
- true,
- },
- },
- },
- {
- "2 calls false,true",
- []bool{false, true},
-
- []readOnlyState{
- {
- false,
- false,
- false,
- false,
- },
- {
- true,
- true,
- true,
- false,
- },
- },
- },
- {
- "2 calls readonly",
- []bool{true, true},
-
- []readOnlyState{
- {
- true,
- true,
- true,
- true,
- },
- {
- true,
- true,
- true,
- true,
- },
- },
- },
- }
-
- type evmsParamsTest struct {
- emvs []bool
- suffix string
- }
-
- evmsTest := make([]evmsParamsTest, len(cases))
-
- // fill all possible isEVM combinations
- for i, testCase := range cases {
- isEVMSliceTest := make([]bool, len(testCase.readonlySliceTest))
-
- copy(isEVMSliceTest, testCase.readonlySliceTest)
- evmsTest[i].emvs = isEVMSliceTest
-
- var suffix strings.Builder
- suffix.WriteString("-isEVMSliceTest")
- for _, evmParam := range testCase.readonlySliceTest {
- if evmParam {
- suffix.WriteString("-true")
- } else {
- suffix.WriteString("-false")
- }
- }
-
- evmsTest[i].suffix = suffix.String()
- }
-
- for _, testCase := range cases {
- for _, evmsParams := range evmsTest {
-
- testcase := testCase
- evmsTestcase := evmsParams
-
- if len(testcase.readonlySliceTest) != len(evmsTestcase.emvs) {
- continue
- }
-
- t.Run(testcase.testName+evmsTestcase.suffix, func(t *testing.T) {
- t.Parallel()
- readonlySliceTest := testcase.readonlySliceTest
-
- env := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
-
- readonliesGot := make([]*readOnlyState, len(testcase.readonlySliceTest))
- isEVMGot := make([]bool, len(evmsTestcase.emvs))
-
- currentIdx := new(int)
- *currentIdx = -1
-
- evmInterpreter := &testVM{
- readonlyGetSetter: env.interpreter.(*EVMInterpreter),
-
- recordedReadOnlies: &readonliesGot,
- recordedIsEVMCalled: &isEVMGot,
-
- env: env,
- isEVMSliceTest: evmsTestcase.emvs,
- readOnlySliceTest: testcase.readonlySliceTest,
- currentIdx: currentIdx,
- }
-
- env.interpreter = evmInterpreter
-
- dummyContract := NewContract(
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- uint256.Int{},
- //c,
- )
-
- newTestSequential(env, currentIdx, readonlySliceTest, evmsTestcase.emvs).Run(dummyContract, nil, false)
-
- if len(readonliesGot) != len(readonlySliceTest) {
- t.Fatalf("expected static calls the same stack length as generated. got %d, expected %d - %v", len(readonliesGot), len(readonlySliceTest), readonlySliceTest)
- }
-
- if len(isEVMGot) != len(evmsTestcase.emvs) {
- t.Fatalf("expected VM calls the same stack length as generated. got %d, expected %d - %v, readonly %v", len(isEVMGot), len(evmsTestcase.emvs), evmsTestcase.emvs, readonlySliceTest)
- }
-
- if *currentIdx != len(readonlySliceTest) {
- t.Fatalf("expected VM calls the same amount of calls as generated calls. got %d, expected %d", *currentIdx, len(readonlySliceTest))
- }
-
- var gotReadonly bool
- var firstReadOnly int
-
- for callIndex, readOnly := range readonliesGot {
- if readOnly.outer != readonlySliceTest[callIndex] {
- t.Fatalf("outer readOnly appeared in %d index, got readOnly %t, expected %t. Test EVMs %v; test readonly %v",
- callIndex, readOnly.outer, readonlySliceTest[callIndex], evmsTestcase.emvs, readonlySliceTest)
- }
-
- if callIndex > 0 {
- if readOnly.before != readonliesGot[callIndex-1].in {
- t.Fatalf("before readOnly appeared in %d index, got readOnly %t, expected %t. Test EVMs %v; test readonly %v",
- callIndex, readOnly.before, readonliesGot[callIndex-1].in, evmsTestcase.emvs, readonlySliceTest)
- }
- }
-
- if readOnly.in && !gotReadonly {
- gotReadonly = true
- firstReadOnly = callIndex
- }
-
- if gotReadonly {
- if !readOnly.in {
- t.Fatalf("readOnly appeared in %d index, got non-readOnly in %d: %v. Test EVMs %v; test readonly %v",
- firstReadOnly, callIndex, trace(isEVMGot, readonliesGot), evmsTestcase.emvs, readonlySliceTest)
- }
-
- switch {
- case callIndex < firstReadOnly:
- if readOnly.after != false {
- t.Fatalf("after readOnly appeared in %d index(first readonly %d, case firstReadOnly:
- if readOnly.after != true {
- t.Fatalf("after readOnly appeared in %d index(first readonly %d, case >firstReadOnly), got readOnly %t, expected %t. Test EVMs %v; test readonly %v",
- callIndex, firstReadOnly, readOnly.after, true, evmsTestcase.emvs, readonlySliceTest)
- }
- }
- } else {
- if readOnly.after != false {
- t.Fatalf("after readOnly didn't appear. %d index, got readOnly %t, expected %t. Test EVMs %v; test readonly %v",
- callIndex, readOnly.after, false, evmsTestcase.emvs, readonlySliceTest)
- }
- }
- }
- })
- }
- }
-}
-
-type testSequential struct {
- env *EVM
- currentIdx *int
- readOnlys []bool
- isEVMCalled []bool
-}
-
-func newTestSequential(env *EVM, currentIdx *int, readonlies []bool, isEVMCalled []bool) *testSequential {
- return &testSequential{env, currentIdx, readonlies, isEVMCalled}
-}
-
-func (st *testSequential) Run(_ *Contract, _ []byte, _ bool) ([]byte, uint64, error) {
- *st.currentIdx++
- //c := NewJumpDestCache(16)
- nextContract := *NewContract(
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- uint256.Int{},
- //c,
- )
-
- return st.env.interpreter.Run(nextContract, 0, nil, st.readOnlys[*st.currentIdx])
-}
-
-func trace(isEVMSlice []bool, readOnlySlice []*readOnlyState) string {
- var res strings.Builder
- res.WriteString("trace:\n")
- for i := 0; i < len(isEVMSlice); i++ {
- res.WriteString(fmt.Sprintf("%d: EVM %t, readonly %t\n", i, isEVMSlice[i], readOnlySlice[i].in))
- }
- return res.String()
-}
diff --git a/execution/vm/instructions.go b/execution/vm/instructions.go
index 51995a68bda..29fb8bea0c6 100644
--- a/execution/vm/instructions.go
+++ b/execution/vm/instructions.go
@@ -36,7 +36,7 @@ import (
"github.com/erigontech/erigon/execution/types/accounts"
)
-func opAdd(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opAdd(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Add(&x, y)
return pc, nil, nil
@@ -47,7 +47,7 @@ func stAdd(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", ADD, &x, &y)
}
-func opSub(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSub(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Sub(&x, y)
return pc, nil, nil
@@ -58,7 +58,7 @@ func stSub(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", SUB, &x, &y)
}
-func opMul(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMul(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Mul(&x, y)
return pc, nil, nil
@@ -69,7 +69,7 @@ func stMul(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", MUL, &x, &y)
}
-func opDiv(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opDiv(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Div(&x, y)
return pc, nil, nil
@@ -80,7 +80,7 @@ func stDiv(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", DIV, &x, &y)
}
-func opSdiv(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSdiv(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.SDiv(&x, y)
return pc, nil, nil
@@ -91,7 +91,7 @@ func stSdiv(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", SDIV, &x, &y)
}
-func opMod(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMod(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Mod(&x, y)
return pc, nil, nil
@@ -102,7 +102,7 @@ func stMod(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", MOD, &x, &y)
}
-func opSmod(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSmod(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.SMod(&x, y)
return pc, nil, nil
@@ -113,7 +113,7 @@ func stSmod(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", SMOD, &x, &y)
}
-func opExp(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opExp(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
base, exponent := scope.Stack.pop(), scope.Stack.peek()
switch {
case exponent.IsZero():
@@ -142,13 +142,13 @@ func opExp(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
return pc, nil, nil
}
-func opSignExtend(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSignExtend(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
back, num := scope.Stack.pop(), scope.Stack.peek()
num.ExtendSign(num, &back)
return pc, nil, nil
}
-func opNot(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opNot(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x := scope.Stack.peek()
x.Not(x)
return pc, nil, nil
@@ -159,7 +159,7 @@ func stNot(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d", NOT.String(), x)
}
-func opLt(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opLt(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Lt(y) {
y.SetOne()
@@ -174,7 +174,7 @@ func stLt(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", LT, &x, &y)
}
-func opGt(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opGt(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Gt(y) {
y.SetOne()
@@ -189,7 +189,7 @@ func stGt(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", GT, &x, &y)
}
-func opSlt(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSlt(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Slt(y) {
y.SetOne()
@@ -204,7 +204,7 @@ func stSlt(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", SLT, &x, &y)
}
-func opSgt(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSgt(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Sgt(y) {
y.SetOne()
@@ -219,7 +219,7 @@ func stSgt(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", SGT, &x, &y)
}
-func opEq(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opEq(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Eq(y) {
y.SetOne()
@@ -234,7 +234,7 @@ func stEq(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", EQ, &x, &y)
}
-func opIszero(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opIszero(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x := scope.Stack.peek()
if x.IsZero() {
x.SetOne()
@@ -249,7 +249,7 @@ func stIsZero(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d", ISZERO, &x)
}
-func opAnd(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opAnd(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.And(&x, y)
return pc, nil, nil
@@ -260,7 +260,7 @@ func stAnd(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", AND, &x, &y)
}
-func opOr(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opOr(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Or(&x, y)
return pc, nil, nil
@@ -271,7 +271,7 @@ func stOr(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", OR, &x, &y)
}
-func opXor(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opXor(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Xor(&x, y)
return pc, nil, nil
@@ -282,13 +282,13 @@ func stXor(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", XOR, &x, &y)
}
-func opByte(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opByte(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
th, val := scope.Stack.pop(), scope.Stack.peek()
val.Byte(&th)
return pc, nil, nil
}
-func opAddmod(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opAddmod(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
z.AddMod(&x, &y, z)
return pc, nil, nil
@@ -299,7 +299,7 @@ func stAddmod(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d %d", ADDMOD, &x, &y, &z)
}
-func opMulmod(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMulmod(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
z.MulMod(&x, &y, z)
return pc, nil, nil
@@ -313,7 +313,7 @@ func stMulmod(_ uint64, scope *CallContext) string {
// 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 *CallContext) (uint64, []byte, error) {
+func opSHL(pc uint64, evm *EVM, scope *CallContext) (uint64, []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) {
@@ -327,7 +327,7 @@ func opSHL(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
// 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 *CallContext) (uint64, []byte, error) {
+func opSHR(pc uint64, evm *EVM, scope *CallContext) (uint64, []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) {
@@ -341,7 +341,7 @@ func opSHR(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
// 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 *CallContext) (uint64, []byte, error) {
+func opSAR(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.GtUint64(255) {
if value.Sign() >= 0 {
@@ -357,33 +357,34 @@ func opSAR(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
return pc, nil, nil
}
-func opKeccak256(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opKeccak256(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.peek()
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
- if interpreter.hasher == nil {
- interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
+ if evm.hasher == nil {
+ evm.hasher = sha3.NewLegacyKeccak256().(keccakState)
} else {
- interpreter.hasher.Reset()
+ evm.hasher.Reset()
}
- interpreter.hasher.Write(data)
- if _, err := interpreter.hasher.Read(interpreter.hasherBuf[:]); err != nil {
+ evm.hasher.Write(data)
+ if _, err := evm.hasher.Read(evm.hasherBuf[:]); err != nil {
panic(err)
}
- size.SetBytes(interpreter.hasherBuf[:])
+ size.SetBytes(evm.hasherBuf[:])
return pc, nil, nil
}
-func opAddress(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+
+func opAddress(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
addrVal := scope.Contract.Address().Value()
scope.Stack.push(*new(uint256.Int).SetBytes(addrVal[:]))
return pc, nil, nil
}
-func opBalance(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opBalance(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
slot := scope.Stack.peek()
address := accounts.InternAddress(slot.Bytes20())
- balance, err := interpreter.evm.IntraBlockState().GetBalance(address)
+ balance, err := evm.IntraBlockState().GetBalance(address)
if err != nil {
return pc, nil, fmt.Errorf("%w: %w", ErrIntraBlockStateFailed, err)
}
@@ -391,8 +392,8 @@ func opBalance(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint
return pc, nil, nil
}
-func opOrigin(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if origin := interpreter.evm.Origin; origin.IsNil() {
+func opOrigin(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if origin := evm.Origin; origin.IsNil() {
scope.Stack.push(uint256.Int{})
} else {
originVal := origin.Value()
@@ -400,7 +401,7 @@ func opOrigin(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint6
}
return pc, nil, nil
}
-func opCaller(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCaller(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
if caller := scope.Contract.Caller(); caller.IsNil() {
scope.Stack.push(uint256.Int{})
} else {
@@ -415,12 +416,12 @@ func stCaller(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s (%d)", CALLER, new(uint256.Int).SetBytes(caller[:]))
}
-func opCallValue(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCallValue(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.push(scope.Contract.value)
return pc, nil, nil
}
-func opCallDataLoad(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCallDataLoad(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
x := scope.Stack.peek()
if offset, overflow := x.Uint64WithOverflow(); !overflow {
data := getData(scope.input, offset, 32)
@@ -441,7 +442,7 @@ func stCallDataLoad(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d (%x)", CALLDATALOAD, &x, data)
}
-func opCallDataSize(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCallDataSize(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.push(*new(uint256.Int).SetUint64(uint64(len(scope.input))))
return pc, nil, nil
}
@@ -450,7 +451,7 @@ func stCallDataSize(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s (%d)", CALLDATASIZE, new(uint256.Int).SetUint64(uint64(len(scope.input))))
}
-func opCallDataCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCallDataCopy(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
memOffset = scope.Stack.pop()
dataOffset = scope.Stack.pop()
@@ -480,12 +481,12 @@ func stCallDataCopy(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d %d (%x)", CALLDATACOPY, memOffset.Uint64(), dataOffset64, length.Uint64(), getData(scope.input, dataOffset64, length.Uint64()))
}
-func opReturnDataSize(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- scope.Stack.push(*new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
+func opReturnDataSize(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ scope.Stack.push(*new(uint256.Int).SetUint64(uint64(len(evm.returnData))))
return pc, nil, nil
}
-func opReturnDataCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opReturnDataCopy(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
memOffset = scope.Stack.pop()
dataOffset = scope.Stack.pop()
@@ -504,10 +505,10 @@ func opReturnDataCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext
}
end64, overflow := end.Uint64WithOverflow()
- if overflow || uint64(len(interpreter.returnData)) < end64 {
+ if overflow || uint64(len(evm.returnData)) < end64 {
return pc, 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 pc, nil, nil
}
@@ -538,10 +539,10 @@ func stReturnDataCopy(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d %d", RETURNDATACOPY, memOffset.Uint64(), offset64, length.Uint64())
}
-func opExtCodeSize(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opExtCodeSize(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
slot := scope.Stack.peek()
addr := accounts.InternAddress(slot.Bytes20())
- codeSize, err := interpreter.evm.IntraBlockState().GetCodeSize(addr)
+ codeSize, err := evm.IntraBlockState().GetCodeSize(addr)
if err != nil {
return pc, nil, fmt.Errorf("%w: %w", ErrIntraBlockStateFailed, err)
}
@@ -549,14 +550,14 @@ func opExtCodeSize(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (
return pc, nil, nil
}
-func opCodeSize(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCodeSize(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
l := new(uint256.Int)
l.SetUint64(uint64(len(scope.Contract.Code)))
scope.Stack.push(*l)
return pc, nil, nil
}
-func opCodeCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCodeCopy(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
memOffset = scope.Stack.pop()
codeOffset = scope.Stack.pop()
@@ -571,7 +572,7 @@ func opCodeCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uin
return pc, nil, nil
}
-func opExtCodeCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opExtCodeCopy(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
stack = &scope.Stack
a = stack.pop()
@@ -582,7 +583,7 @@ func opExtCodeCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (
addr := accounts.InternAddress(a.Bytes20())
len64 := length.Uint64()
- code, err := interpreter.evm.IntraBlockState().GetCode(addr)
+ code, err := evm.IntraBlockState().GetCode(addr)
if err != nil {
return pc, nil, fmt.Errorf("%w: %w", ErrIntraBlockStateFailed, err)
}
@@ -629,11 +630,11 @@ func opExtCodeCopy(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (
// (7) Caller tries to get the code hash of a delegated account, the result should be
//
// equal the result of calling extcodehash on the account directly.
-func opExtCodeHash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opExtCodeHash(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
slot := scope.Stack.peek()
address := accounts.InternAddress(slot.Bytes20())
- empty, err := interpreter.evm.IntraBlockState().Empty(address)
+ empty, err := evm.IntraBlockState().Empty(address)
if err != nil {
return pc, nil, err
}
@@ -641,7 +642,7 @@ func opExtCodeHash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (
slot.Clear()
} else {
var codeHash accounts.CodeHash
- codeHash, err = interpreter.evm.IntraBlockState().GetCodeHash(address)
+ codeHash, err = evm.IntraBlockState().GetCodeHash(address)
if err != nil {
return pc, nil, fmt.Errorf("%w: %w", ErrIntraBlockStateFailed, err)
}
@@ -651,13 +652,13 @@ func opExtCodeHash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (
return pc, nil, nil
}
-func opGasprice(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- scope.Stack.push(interpreter.evm.GasPrice)
+func opGasprice(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ scope.Stack.push(evm.GasPrice)
return pc, nil, nil
}
// opBlockhash executes the BLOCKHASH opcode
-func opBlockhash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opBlockhash(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
arg := scope.Stack.peek()
arg64, overflow := arg.Uint64WithOverflow()
if overflow {
@@ -665,14 +666,14 @@ func opBlockhash(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (ui
return pc, nil, nil
}
var upper, lower uint64
- upper = interpreter.evm.Context.BlockNumber
+ upper = evm.Context.BlockNumber
if upper <= params.BlockHashOldWindow {
lower = 0
} else {
lower = upper - params.BlockHashOldWindow
}
if arg64 >= lower && arg64 < upper {
- hash, err := interpreter.evm.Context.GetHash(arg64)
+ hash, err := evm.Context.GetHash(arg64)
if err != nil {
arg.Clear()
return pc, nil, err
@@ -690,8 +691,8 @@ func stBlockhash(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d", BLOCKHASH, &x)
}
-func opCoinbase(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if coinbase := interpreter.evm.Context.Coinbase; coinbase.IsNil() {
+func opCoinbase(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if coinbase := evm.Context.Coinbase; coinbase.IsNil() {
scope.Stack.push(uint256.Int{})
} else {
coinbaseValue := coinbase.Value()
@@ -700,49 +701,49 @@ func opCoinbase(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uin
return pc, nil, nil
}
-func opTimestamp(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- v := new(uint256.Int).SetUint64(interpreter.evm.Context.Time)
+func opTimestamp(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ v := new(uint256.Int).SetUint64(evm.Context.Time)
scope.Stack.push(*v)
return pc, nil, nil
}
-func opNumber(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- v := new(uint256.Int).SetUint64(interpreter.evm.Context.BlockNumber)
+func opNumber(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ v := new(uint256.Int).SetUint64(evm.Context.BlockNumber)
scope.Stack.push(*v)
return pc, nil, nil
}
-func opDifficulty(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opDifficulty(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var v *uint256.Int
- if interpreter.evm.Context.PrevRanDao != nil {
+ if evm.Context.PrevRanDao != nil {
// EIP-4399: Supplant DIFFICULTY opcode with PREVRANDAO
- v = new(uint256.Int).SetBytes(interpreter.evm.Context.PrevRanDao.Bytes())
+ v = new(uint256.Int).SetBytes(evm.Context.PrevRanDao.Bytes())
} else {
var overflow bool
- v, overflow = uint256.FromBig(interpreter.evm.Context.Difficulty)
+ v, overflow = uint256.FromBig(evm.Context.Difficulty)
if overflow {
- return pc, nil, errors.New("interpreter.evm.Context.Difficulty higher than 2^256-1")
+ return pc, nil, errors.New("evm.Context.Difficulty higher than 2^256-1")
}
}
scope.Stack.push(*v)
return pc, nil, nil
}
-func opGasLimit(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.evm.Context.MaxGasLimit {
+func opGasLimit(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.Context.MaxGasLimit {
scope.Stack.push(*new(uint256.Int).SetAllOne())
} else {
- scope.Stack.push(*new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
+ scope.Stack.push(*new(uint256.Int).SetUint64(evm.Context.GasLimit))
}
return pc, nil, nil
}
-func opPop(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opPop(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.pop()
return pc, nil, nil
}
-func opMload(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMload(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
v := scope.Stack.peek()
offset := v.Uint64()
v.SetBytes(scope.Memory.GetPtr(offset, 32))
@@ -755,7 +756,7 @@ func stMload(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d (%d)", MLOAD, offset, (&uint256.Int{}).SetBytes(scope.Memory.GetPtr(offset, 32)))
}
-func opMstore(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMstore(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
mStart, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.Set32(mStart.Uint64(), &val)
return pc, nil, nil
@@ -766,15 +767,15 @@ func stMstore(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d", MSTORE, mStart.Uint64(), &val)
}
-func opMstore8(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMstore8(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
off, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.store[off.Uint64()] = byte(val.Uint64())
return pc, nil, nil
}
-func opSload(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (_ uint64, _ []byte, err error) {
+func opSload(pc uint64, evm *EVM, scope *CallContext) (_ uint64, _ []byte, err error) {
loc := scope.Stack.peek()
- *loc, err = interpreter.evm.IntraBlockState().GetState(scope.Contract.Address(), accounts.InternKey(loc.Bytes32()))
+ *loc, err = evm.IntraBlockState().GetState(scope.Contract.Address(), accounts.InternKey(loc.Bytes32()))
return pc, nil, err
}
@@ -783,13 +784,13 @@ func stSload(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %x", SLOAD, loc)
}
-func opSstore(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+func opSstore(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
loc := scope.Stack.pop()
val := scope.Stack.pop()
- return pc, nil, interpreter.evm.IntraBlockState().SetState(scope.Contract.Address(), accounts.InternKey(loc.Bytes32()), val)
+ return pc, nil, evm.IntraBlockState().SetState(scope.Contract.Address(), accounts.InternKey(loc.Bytes32()), val)
}
func stSstore(_ uint64, scope *CallContext) string {
@@ -797,19 +798,19 @@ func stSstore(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %x %d", SSTORE, loc.Bytes32(), &val)
}
-func opJump(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opJump(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
pos := scope.Stack.pop()
if valid, usedBitmap := scope.Contract.validJumpdest(pos); !valid {
if usedBitmap {
- if interpreter.cfg.TraceJumpDest {
+ if evm.config.TraceJumpDest {
log.Debug("Code Bitmap used for detecting invalid jump",
- "tx", fmt.Sprintf("0x%x", interpreter.evm.TxHash),
- "block_num", interpreter.evm.Context.BlockNumber,
+ "tx", fmt.Sprintf("0x%x", evm.TxHash),
+ "block_num", evm.Context.BlockNumber,
)
} else {
// This is "cheaper" version because it does not require calculation of txHash for each transaction
log.Debug("Code Bitmap used for detecting invalid jump",
- "block_num", interpreter.evm.Context.BlockNumber,
+ "block_num", evm.Context.BlockNumber,
)
}
}
@@ -824,20 +825,20 @@ func stJump(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d", JUMP, pos)
}
-func opJumpi(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opJumpi(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
pos, cond := scope.Stack.pop(), scope.Stack.pop()
if !cond.IsZero() {
if valid, usedBitmap := scope.Contract.validJumpdest(pos); !valid {
if usedBitmap {
- if interpreter.cfg.TraceJumpDest {
+ if evm.config.TraceJumpDest {
log.Warn("Code Bitmap used for detecting invalid jump",
- "tx", fmt.Sprintf("0x%x", interpreter.evm.TxHash),
- "block_num", interpreter.evm.Context.BlockNumber,
+ "tx", fmt.Sprintf("0x%x", evm.TxHash),
+ "block_num", evm.Context.BlockNumber,
)
} else {
// This is "cheaper" version because it does not require calculation of txHash for each transaction
log.Warn("Code Bitmap used for detecting invalid jump",
- "block_num", interpreter.evm.Context.BlockNumber,
+ "block_num", evm.Context.BlockNumber,
)
}
}
@@ -853,11 +854,11 @@ func stJumpi(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %v %d", JUMPI, !cond.IsZero(), &pos)
}
-func opJumpdest(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opJumpdest(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
return pc, nil, nil
}
-func opPc(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opPc(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.push(*new(uint256.Int).SetUint64(pc))
return pc, nil, nil
}
@@ -866,12 +867,12 @@ func stPc(pc uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d", PC, pc)
}
-func opMsize(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opMsize(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.push(*new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
return pc, nil, nil
}
-func opGas(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opGas(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.push(*new(uint256.Int).SetUint64(scope.gas))
return pc, nil, nil
}
@@ -880,88 +881,88 @@ func stGas(pc uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d", GAS, scope.gas)
}
-func opSwap1(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap1(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(1)
return pc, nil, nil
}
-func opSwap2(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap2(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(2)
return pc, nil, nil
}
-func opSwap3(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap3(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(3)
return pc, nil, nil
}
-func opSwap4(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap4(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(4)
return pc, nil, nil
}
-func opSwap5(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap5(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(5)
return pc, nil, nil
}
-func opSwap6(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap6(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(6)
return pc, nil, nil
}
-func opSwap7(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap7(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(7)
return pc, nil, nil
}
-func opSwap8(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap8(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(8)
return pc, nil, nil
}
-func opSwap9(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap9(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(9)
return pc, nil, nil
}
-func opSwap10(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap10(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(10)
return pc, nil, nil
}
-func opSwap11(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap11(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(11)
return pc, nil, nil
}
-func opSwap12(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap12(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(12)
return pc, nil, nil
}
-func opSwap13(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap13(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(13)
return pc, nil, nil
}
-func opSwap14(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap14(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(14)
return pc, nil, nil
}
-func opSwap15(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap15(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(15)
return pc, nil, nil
}
-func opSwap16(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwap16(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.swap(16)
return pc, nil, nil
}
-func opCreate(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+func opCreate(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
var (
@@ -971,21 +972,21 @@ func opCreate(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint6
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
gas = scope.gas
)
- if interpreter.evm.ChainRules().IsTangerineWhistle {
+ if evm.ChainRules().IsTangerineWhistle {
gas -= gas / 64
}
// reuse size int for stackvalue
stackvalue := size
- scope.useGas(gas, interpreter.evm.Config().Tracer, tracing.GasChangeCallContractCreation)
+ scope.useGas(gas, evm.Config().Tracer, tracing.GasChangeCallContractCreation)
- res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, value, false)
+ res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, value, false)
// 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()
@@ -994,13 +995,13 @@ func opCreate(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint6
stackvalue.SetBytes(addrVal[:])
}
- scope.refundGas(returnGas, interpreter.evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
+ scope.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 pc, res, nil
}
- interpreter.returnData = nil // clear dirty return data buffer
+ evm.returnData = nil // clear dirty return data buffer
return pc, nil, nil
}
@@ -1016,8 +1017,8 @@ func stCreate(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %x %d", CREATE.String(), &value, input, &scope.gas)
}
-func opCreate2(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+func opCreate2(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
var (
@@ -1030,10 +1031,10 @@ func opCreate2(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint
// Apply EIP150
gas -= gas / 64
- scope.useGas(gas, interpreter.evm.Config().Tracer, tracing.GasChangeCallContractCreation2)
+ scope.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, endowment, &salt, false)
+ res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas, endowment, &salt, false)
// Push item on the stack based on the returned error.
if suberr != nil {
@@ -1044,13 +1045,13 @@ func opCreate2(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint
}
scope.Stack.push(stackValue)
- scope.refundGas(returnGas, interpreter.evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
+ scope.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 pc, res, nil
}
- interpreter.returnData = nil // clear dirty return data buffer
+ evm.returnData = nil // clear dirty return data buffer
return pc, nil, nil
}
@@ -1066,12 +1067,12 @@ func stCreate2(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %d %d %x %d", CREATE2.String(), &endowment, &salt, input, &scope.gas)
}
-func opCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opCall(pc uint64, evm *EVM, scope *CallContext) (uint64, []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 := accounts.InternAddress(addr.Bytes20())
@@ -1079,13 +1080,13 @@ func opCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
if !value.IsZero() {
- if interpreter.readOnly {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
gas += params.CallStipend
}
- ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, value, false /* bailout */)
+ ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, value, false /* bailout */)
if err != nil {
temp.Clear()
@@ -1098,9 +1099,9 @@ func opCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.refundGas(returnGas, interpreter.evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
+ scope.refundGas(returnGas, evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
- interpreter.returnData = ret
+ evm.returnData = ret
return pc, ret, nil
}
@@ -1114,12 +1115,12 @@ func stCall(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %x %x", CALL.String(), toAddr, args)
}
-func opCallCode(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
+func opCallCode(pc uint64, evm *EVM, scope *CallContext) (uint64, []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 := accounts.InternAddress(addr.Bytes20())
@@ -1130,7 +1131,7 @@ func opCallCode(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uin
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 {
@@ -1142,9 +1143,9 @@ func opCallCode(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uin
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.refundGas(returnGas, interpreter.evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
+ scope.refundGas(returnGas, evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
- interpreter.returnData = ret
+ evm.returnData = ret
return pc, ret, nil
}
@@ -1158,19 +1159,19 @@ func stCallCode(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %x %x", CALLCODE.String(), toAddr, args)
}
-func opDelegateCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opDelegateCall(pc uint64, evm *EVM, scope *CallContext) (uint64, []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 := accounts.InternAddress(addr.Bytes20())
// Get arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
- ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract.addr, scope.Contract.caller, toAddr, args, scope.Contract.value, gas)
+ ret, returnGas, err := evm.DelegateCall(scope.Contract.addr, scope.Contract.caller, toAddr, args, scope.Contract.value, gas)
if err != nil {
temp.Clear()
} else {
@@ -1182,9 +1183,9 @@ func opDelegateCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.refundGas(returnGas, interpreter.evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
+ scope.refundGas(returnGas, evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
- interpreter.returnData = ret
+ evm.returnData = ret
return pc, ret, nil
}
@@ -1198,19 +1199,19 @@ func stDelegateCall(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %x %x", DELEGATECALL.String(), toAddr, args)
}
-func opStaticCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
+func opStaticCall(pc uint64, evm *EVM, scope *CallContext) (uint64, []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 := accounts.InternAddress(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 {
@@ -1221,9 +1222,9 @@ func opStaticCall(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (u
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.refundGas(returnGas, interpreter.evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
+ scope.refundGas(returnGas, evm.config.Tracer, tracing.GasChangeCallLeftOverRefunded)
- interpreter.returnData = ret
+ evm.returnData = ret
return pc, ret, nil
}
@@ -1237,35 +1238,35 @@ func stStaticCall(_ uint64, scope *CallContext) string {
return fmt.Sprintf("%s %x %x", STATICCALL.String(), toAddr, args)
}
-func opReturn(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opReturn(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
return pc, ret, errStopToken
}
-func opRevert(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opRevert(pc uint64, evm *EVM, scope *CallContext) (uint64, []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 pc, ret, ErrExecutionReverted
}
-func opUndefined(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opUndefined(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
return pc, nil, &ErrInvalidOpCode{opcode: OpCode(scope.Contract.Code[pc])}
}
-func opStop(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opStop(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
return pc, nil, errStopToken
}
-func opSelfdestruct(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+func opSelfdestruct(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
beneficiary := scope.Stack.pop()
self := scope.Contract.Address()
beneficiaryAddr := accounts.InternAddress(beneficiary.Bytes20())
- ibs := interpreter.evm.IntraBlockState()
+ ibs := evm.IntraBlockState()
balance, err := ibs.GetBalance(self)
if err != nil {
return pc, nil, err
@@ -1273,23 +1274,24 @@ func opSelfdestruct(pc uint64, interpreter *EVMInterpreter, scope *CallContext)
ibs.AddBalance(beneficiaryAddr, balance, tracing.BalanceIncreaseSelfdestruct)
ibs.Selfdestruct(self)
- if interpreter.evm.Config().Tracer != nil && interpreter.evm.Config().Tracer.OnEnter != nil {
- interpreter.evm.Config().Tracer.OnEnter(interpreter.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiaryAddr, false, []byte{}, 0, balance, nil)
+ tracer := evm.Config().Tracer
+ if tracer != nil && tracer.OnEnter != nil {
+ tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiaryAddr, false, []byte{}, 0, balance, nil)
}
- if interpreter.evm.Config().Tracer != nil && interpreter.evm.Config().Tracer.OnExit != nil {
- interpreter.evm.Config().Tracer.OnExit(interpreter.depth, []byte{}, 0, nil, false)
+ if tracer != nil && tracer.OnExit != nil {
+ tracer.OnExit(evm.depth, []byte{}, 0, nil, false)
}
return pc, nil, errStopToken
}
-func opSelfdestruct6780(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+func opSelfdestruct6780(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
beneficiary := scope.Stack.pop()
self := scope.Contract.Address()
beneficiaryAddr := accounts.InternAddress(beneficiary.Bytes20())
- ibs := interpreter.evm.IntraBlockState()
+ ibs := evm.IntraBlockState()
balance, err := ibs.GetBalance(self)
if err != nil {
return pc, nil, err
@@ -1311,18 +1313,19 @@ func opSelfdestruct6780(pc uint64, interpreter *EVMInterpreter, scope *CallConte
ibs.SubBalance(self, balance, tracing.BalanceDecreaseSelfdestruct)
ibs.AddBalance(beneficiaryAddr, balance, tracing.BalanceIncreaseSelfdestruct)
}
- if interpreter.evm.ChainRules().IsAmsterdam && !balance.IsZero() { // EIP-7708
+ if evm.ChainRules().IsAmsterdam && !balance.IsZero() { // EIP-7708
if self != beneficiaryAddr {
ibs.AddLog(misc.EthTransferLog(self.Value(), beneficiaryAddr.Value(), balance))
} else if newContract {
ibs.AddLog(misc.EthTransferLog(self.Value(), common.Address{}, balance))
}
}
- if interpreter.evm.Config().Tracer != nil && interpreter.evm.Config().Tracer.OnEnter != nil {
- interpreter.cfg.Tracer.OnEnter(interpreter.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiaryAddr, false, []byte{}, 0, balance, nil)
+ tracer := evm.Config().Tracer
+ if tracer != nil && tracer.OnEnter != nil {
+ tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiaryAddr, false, []byte{}, 0, balance, nil)
}
- if interpreter.evm.Config().Tracer != nil && interpreter.evm.Config().Tracer.OnExit != nil {
- interpreter.cfg.Tracer.OnExit(interpreter.depth, []byte{}, 0, nil, false)
+ if tracer != nil && tracer.OnExit != nil {
+ tracer.OnExit(evm.depth, []byte{}, 0, nil, false)
}
return pc, nil, errStopToken
}
@@ -1348,7 +1351,7 @@ func decodePair(x byte) (int, int) {
return r + 1, 29 - q
}
-func opDupN(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opDupN(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
code := scope.Contract.Code
pc++
x := byte(0) // see https://github.com/ethereum/EIPs/pull/11085
@@ -1372,7 +1375,7 @@ func opDupN(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64,
return pc, nil, nil
}
-func opSwapN(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opSwapN(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
code := scope.Contract.Code
pc++
x := byte(0) // see https://github.com/ethereum/EIPs/pull/11085
@@ -1396,7 +1399,7 @@ func opSwapN(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64
return pc, nil, nil
}
-func opExchange(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opExchange(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
code := scope.Contract.Code
pc++
x := byte(0) // see https://github.com/ethereum/EIPs/pull/11085
@@ -1429,8 +1432,8 @@ func opExchange(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uin
// make log instruction function
func makeLog(size int) executionFunc {
- return func(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
- if interpreter.readOnly {
+ return func(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
+ if evm.readOnly {
return pc, nil, ErrWriteProtection
}
topics := make([]common.Hash, size)
@@ -1442,13 +1445,13 @@ func makeLog(size int) executionFunc {
}
d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64())
- interpreter.evm.IntraBlockState().AddLog(&types.Log{
+ evm.IntraBlockState().AddLog(&types.Log{
Address: scope.Contract.Address().Value(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// execution/state doesn't know the current block number.
- BlockNumber: interpreter.evm.Context.BlockNumber,
+ BlockNumber: evm.Context.BlockNumber,
})
return pc, nil, nil
@@ -1456,7 +1459,7 @@ func makeLog(size int) executionFunc {
}
// opPush1 is a specialized version of pushN
-func opPush1(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opPush1(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
codeLen = uint64(len(scope.Contract.Code))
integer = new(uint256.Int)
@@ -1484,7 +1487,7 @@ func stPush1(pc uint64, scope *CallContext) string {
}
// opPush2 is a specialized version of pushN
-func opPush2(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+func opPush2(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
var (
codeLen = uint64(len(scope.Contract.Code))
integer = new(uint256.Int)
@@ -1502,7 +1505,7 @@ func opPush2(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64
// make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc {
- return func(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+ return func(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
codeLen := len(scope.Contract.Code)
startMin := min(int(pc+1), codeLen)
@@ -1535,7 +1538,7 @@ func makePushStringer(size uint64, pushByteSize int) stringer {
// make dup instruction function
func makeDup(size int) executionFunc {
- return func(pc uint64, interpreter *EVMInterpreter, scope *CallContext) (uint64, []byte, error) {
+ return func(pc uint64, evm *EVM, scope *CallContext) (uint64, []byte, error) {
scope.Stack.dup(size)
return pc, nil, nil
}
diff --git a/execution/vm/instructions_test.go b/execution/vm/instructions_test.go
index eee1a5cec5f..c72ae43fdea 100644
--- a/execution/vm/instructions_test.go
+++ b/execution/vm/instructions_test.go
@@ -111,10 +111,9 @@ func init() {
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- pc = uint64(0)
- evmInterpreter = env.interpreter.(*EVMInterpreter)
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
+ pc = uint64(0)
)
for i, test := range tests {
@@ -123,7 +122,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
callContext.Stack.push(x)
callContext.Stack.push(y)
- opFn(pc, evmInterpreter, callContext)
+ opFn(pc, evm, callContext)
if len(callContext.Stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(callContext.Stack.data))
}
@@ -215,10 +214,9 @@ func TestSAR(t *testing.T) {
func TestAddMod(t *testing.T) {
t.Parallel()
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- evmInterpreter = NewEVMInterpreter(env, env.Config())
- pc = uint64(0)
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
+ pc = uint64(0)
)
tests := []struct {
x string
@@ -243,7 +241,7 @@ func TestAddMod(t *testing.T) {
callContext.Stack.push(z)
callContext.Stack.push(y)
callContext.Stack.push(x)
- opAddmod(pc, evmInterpreter, callContext)
+ opAddmod(pc, evm, callContext)
actual := callContext.Stack.pop()
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
@@ -254,10 +252,9 @@ func TestAddMod(t *testing.T) {
// getResult is a convenience function to generate the expected values
// func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
// var (
-// env = NewEVM(BlockContext{}, TxContext{}, nil, chain.TestChainConfig, Config{})
+// evm = NewEVM(BlockContext{}, TxContext{}, nil, chain.TestChainConfig, Config{})
// stack = stack.New()
// pc = uint64(0)
-// interpreter = env.interpreter.(*EVMInterpreter)
// )
// result := make([]TwoOperandTestcase, len(args))
// for i, param := range args {
@@ -265,7 +262,7 @@ func TestAddMod(t *testing.T) {
// y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
// stack.push(x)
// stack.push(y)
-// opFn(&pc, interpreter, &callCtx{nil, stack, nil})
+// opFn(&pc, evm, &callCtx{nil, stack, nil})
// actual := stack.pop()
// result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
// }
@@ -303,12 +300,10 @@ func TestJsonTestcases(t *testing.T) {
func opBenchmark(b *testing.B, op executionFunc, args ...string) {
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- evmInterpreter = NewEVMInterpreter(env, env.Config())
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
)
- env.interpreter = evmInterpreter
// convert args
byteArgs := make([][]byte, len(args))
for i, arg := range args {
@@ -321,7 +316,7 @@ func opBenchmark(b *testing.B, op executionFunc, args ...string) {
a := *new(uint256.Int).SetBytes(arg)
callContext.Stack.push(a)
}
- op(pc, evmInterpreter, callContext)
+ op(pc, evm, callContext)
callContext.Stack.pop()
}
}
@@ -537,24 +532,22 @@ func BenchmarkOpIsZero(b *testing.B) {
func TestOpMstore(t *testing.T) {
t.Parallel()
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- evmInterpreter = NewEVMInterpreter(env, env.Config())
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
)
- env.interpreter = evmInterpreter
callContext.Memory.Resize(64)
pc := uint64(0)
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
callContext.Stack.push(*new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
callContext.Stack.push(*new(uint256.Int))
- opMstore(pc, evmInterpreter, callContext)
+ opMstore(pc, evm, callContext)
if got := common.Bytes2Hex(callContext.Memory.GetCopy(0, 32)); got != v {
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
}
callContext.Stack.push(*new(uint256.Int).SetOne())
callContext.Stack.push(*new(uint256.Int))
- opMstore(pc, evmInterpreter, callContext)
+ opMstore(pc, evm, callContext)
if common.Bytes2Hex(callContext.Memory.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
t.Fatalf("Mstore failed to overwrite previous value")
}
@@ -562,12 +555,10 @@ func TestOpMstore(t *testing.T) {
func BenchmarkOpMstore(bench *testing.B) {
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- evmInterpreter = NewEVMInterpreter(env, env.Config())
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
)
- env.interpreter = evmInterpreter
callContext.Memory.Resize(64)
pc := uint64(0)
memStart := *new(uint256.Int)
@@ -576,36 +567,34 @@ func BenchmarkOpMstore(bench *testing.B) {
for bench.Loop() {
callContext.Stack.push(value)
callContext.Stack.push(memStart)
- opMstore(pc, evmInterpreter, callContext)
+ opMstore(pc, evm, callContext)
}
}
func TestOpTstore(t *testing.T) {
t.Parallel()
var (
- state = state.New(nil)
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, state, chain.TestChainConfig, Config{})
- evmInterpreter = NewEVMInterpreter(env, env.Config())
- caller = accounts.ZeroAddress
- to = accounts.InternAddress(common.Address{1})
- callContext = &CallContext{Contract: *NewContract(caller, caller, to, uint256.Int{})}
- value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
+ state = state.New(nil)
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, state, chain.TestChainConfig, Config{})
+ caller = accounts.ZeroAddress
+ to = accounts.InternAddress(common.Address{1})
+ callContext = &CallContext{Contract: *NewContract(caller, caller, to, uint256.Int{})}
+ value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
)
- env.interpreter = evmInterpreter
pc := uint64(0)
// push the value to the stack
callContext.Stack.push(*new(uint256.Int).SetBytes(value))
// push the location to the stack
callContext.Stack.push(*new(uint256.Int))
- opTstore(pc, evmInterpreter, callContext)
+ opTstore(pc, evm, callContext)
// there should be no elements on the stack after TSTORE
if callContext.Stack.len() != 0 {
t.Fatal("stack wrong size")
}
// push the location to the stack
callContext.Stack.push(*new(uint256.Int))
- opTload(pc, evmInterpreter, callContext)
+ opTload(pc, evm, callContext)
// there should be one element on the stack after TLOAD
if callContext.Stack.len() != 1 {
t.Fatal("stack wrong size")
@@ -618,11 +607,9 @@ func TestOpTstore(t *testing.T) {
func BenchmarkOpKeccak256(bench *testing.B) {
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- evmInterpreter = NewEVMInterpreter(env, env.Config())
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
)
- env.interpreter = evmInterpreter
callContext.Memory.Resize(32)
pc := uint64(0)
start := uint256.Int{}
@@ -630,7 +617,7 @@ func BenchmarkOpKeccak256(bench *testing.B) {
for bench.Loop() {
callContext.Stack.push(*uint256.NewInt(32))
callContext.Stack.push(start)
- opKeccak256(pc, evmInterpreter, callContext)
+ opKeccak256(pc, evm, callContext)
}
}
@@ -792,10 +779,9 @@ func TestOpMCopy(t *testing.T) {
},
} {
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- pc = uint64(0)
- evmInterpreter = NewEVMInterpreter(env, env.Config())
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
+ pc = uint64(0)
)
data := common.FromHex(strings.ReplaceAll(tc.pre, " ", ""))
// Set pre
@@ -825,7 +811,7 @@ func TestOpMCopy(t *testing.T) {
}
// and the dynamic cost
var haveGas uint64
- if dynamicCost, err := gasMcopy(env, callContext, 0, memorySize); err != nil {
+ if dynamicCost, err := gasMcopy(evm, callContext, 0, memorySize); err != nil {
t.Error(err)
} else {
haveGas = GasFastestStep + dynamicCost
@@ -835,7 +821,7 @@ func TestOpMCopy(t *testing.T) {
callContext.Memory.Resize(memorySize)
}
// Do the copy
- opMcopy(pc, evmInterpreter, callContext)
+ opMcopy(pc, evm, callContext)
want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
if have := callContext.Memory.store; !bytes.Equal(want, have) {
t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have)
@@ -862,9 +848,8 @@ func TestOpCLZ(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var (
- env = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- callContext = &CallContext{}
- evmInterpreter = NewEVMInterpreter(env, env.Config())
+ evm = NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ callContext = &CallContext{}
)
pc := uint64(0)
@@ -877,7 +862,7 @@ func TestOpCLZ(t *testing.T) {
}
callContext.Stack.push(*val)
- opCLZ(pc, evmInterpreter, callContext)
+ opCLZ(pc, evm, callContext)
if gotLen := callContext.Stack.len(); gotLen != 1 {
t.Fatalf("stack length = %d; want 1", gotLen)
@@ -897,10 +882,9 @@ func TestPush(t *testing.T) {
code := common.FromHex("0011223344556677889900aabbccddeeff0102030405060708090a0b0c0d0e0ff1e1d1c1b1a19181716151413121")
push32 := makePush(32, 32)
- env := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
+ evm := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
callContext := &CallContext{}
callContext.Contract.Code = code
- evmInterpreter := NewEVMInterpreter(env, env.Config())
for i, want := range []string{
"0x11223344556677889900aabbccddeeff0102030405060708090a0b0c0d0e0ff1",
@@ -951,7 +935,7 @@ func TestPush(t *testing.T) {
"0x0",
} {
pc := uint64(i)
- push32(pc, evmInterpreter, callContext)
+ push32(pc, evm, callContext)
res := callContext.Stack.pop()
if have := res.Hex(); have != want {
t.Fatalf("case %d, have %v want %v", i, have, want)
@@ -960,8 +944,7 @@ func TestPush(t *testing.T) {
}
func TestEIP8024_Execution(t *testing.T) {
- env := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
- evmInterpreter := NewEVMInterpreter(env, env.Config())
+ evm := NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chain.TestChainConfig, Config{})
tests := []struct {
name string
@@ -1078,22 +1061,22 @@ func TestEIP8024_Execution(t *testing.T) {
case 0x00:
return
case 0x60:
- pc, _, err = opPush1(pc, evmInterpreter, callContext)
+ pc, _, err = opPush1(pc, evm, callContext)
case 0x80:
dup1 := makeDup(1)
- pc, _, err = dup1(pc, evmInterpreter, callContext)
+ pc, _, err = dup1(pc, evm, callContext)
case 0x56:
- pc, _, err = opJump(pc, evmInterpreter, callContext)
+ pc, _, err = opJump(pc, evm, callContext)
case 0x5b:
- pc, _, err = opJumpdest(pc, evmInterpreter, callContext)
+ pc, _, err = opJumpdest(pc, evm, callContext)
case 0xe6:
- pc, _, err = opDupN(pc, evmInterpreter, callContext)
+ pc, _, err = opDupN(pc, evm, callContext)
case 0x15:
- pc, _, err = opIszero(pc, evmInterpreter, callContext)
+ pc, _, err = opIszero(pc, evm, callContext)
case 0xe7:
- pc, _, err = opSwapN(pc, evmInterpreter, callContext)
+ pc, _, err = opSwapN(pc, evm, callContext)
case 0xe8:
- pc, _, err = opExchange(pc, evmInterpreter, callContext)
+ pc, _, err = opExchange(pc, evm, callContext)
default:
err = &ErrInvalidOpCode{opcode: OpCode(op)}
}
diff --git a/execution/vm/interpreter.go b/execution/vm/interpreter.go
index c07ddc16516..c6794fc4774 100644
--- a/execution/vm/interpreter.go
+++ b/execution/vm/interpreter.go
@@ -28,7 +28,6 @@ import (
"github.com/holiman/uint256"
- "github.com/erigontech/erigon/common"
"github.com/erigontech/erigon/common/dbg"
"github.com/erigontech/erigon/common/log/v3"
"github.com/erigontech/erigon/common/math"
@@ -55,19 +54,6 @@ func (vmConfig *Config) HasEip3860(rules *chain.Rules) bool {
return slices.Contains(vmConfig.ExtraEips, 3860) || rules.IsShanghai
}
-// Interpreter is used to run Ethereum based contracts and will utilise the
-// passed environment to query external sources for state information.
-// The Interpreter will run the byte code VM based on the passed
-// configuration.
-type Interpreter interface {
- // 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.
- Run(contract Contract, gas uint64, input []byte, static bool) ([]byte, uint64, error)
- Depth() int // `Depth` returns the current call stack's depth.
- IncDepth() // Increments the current call stack's depth.
- DecDepth() // Decrements the current call stack's depth
-}
-
// CallContext contains the things that are per-call, such as stack and memory,
// but not transients like pc and gas
type CallContext struct {
@@ -193,34 +179,6 @@ type keccakState interface {
Read([]byte) (int, error)
}
-// structcheck doesn't see embedding
-//
-//nolint:structcheck
-type VM struct {
- evm *EVM
- cfg Config
-
- hasher 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
-}
-
-func (vm *VM) setReadonly(outerReadonly bool) func() {
- if outerReadonly && !vm.readOnly {
- vm.readOnly = true
- return func() {
- vm.readOnly = false
- }
- }
- return func() {}
-}
-
-func (vm *VM) getReadonly() bool {
- return vm.readOnly
-}
-
func copyJumpTable(jt *JumpTable) *JumpTable {
var copy JumpTable
for i, op := range jt {
@@ -232,46 +190,38 @@ func copyJumpTable(jt *JumpTable) *JumpTable {
return ©
}
-// EVMInterpreter represents an EVM interpreter
-type EVMInterpreter struct {
- *VM
- jt *JumpTable // EVM instruction table
- depth int
-}
-
-// NewEVMInterpreter returns a new instance of the Interpreter.
-func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
+func jumpTable(chainRules *chain.Rules, cfg Config) *JumpTable {
var jt *JumpTable
switch {
- case evm.chainRules.IsAmsterdam:
+ case chainRules.IsAmsterdam:
jt = &amsterdamInstructionSet
- case evm.chainRules.IsOsaka:
+ case chainRules.IsOsaka:
jt = &osakaInstructionSet
- case evm.ChainRules().IsBhilai:
+ case chainRules.IsBhilai:
jt = &bhilaiInstructionSet
- case evm.ChainRules().IsPrague:
+ case chainRules.IsPrague:
jt = &pragueInstructionSet
- case evm.ChainRules().IsCancun:
+ case chainRules.IsCancun:
jt = &cancunInstructionSet
- case evm.ChainRules().IsNapoli:
+ case chainRules.IsNapoli:
jt = &napoliInstructionSet
- case evm.ChainRules().IsShanghai:
+ case chainRules.IsShanghai:
jt = &shanghaiInstructionSet
- case evm.ChainRules().IsLondon:
+ case chainRules.IsLondon:
jt = &londonInstructionSet
- case evm.ChainRules().IsBerlin:
+ case chainRules.IsBerlin:
jt = &berlinInstructionSet
- case evm.ChainRules().IsIstanbul:
+ case chainRules.IsIstanbul:
jt = &istanbulInstructionSet
- case evm.ChainRules().IsConstantinople:
+ case chainRules.IsConstantinople:
jt = &constantinopleInstructionSet
- case evm.ChainRules().IsByzantium:
+ case chainRules.IsByzantium:
jt = &byzantiumInstructionSet
- case evm.ChainRules().IsSpuriousDragon:
+ case chainRules.IsSpuriousDragon:
jt = &spuriousDragonInstructionSet
- case evm.ChainRules().IsTangerineWhistle:
+ case chainRules.IsTangerineWhistle:
jt = &tangerineWhistleInstructionSet
- case evm.ChainRules().IsHomestead:
+ case chainRules.IsHomestead:
jt = &homesteadInstructionSet
default:
jt = &frontierInstructionSet
@@ -287,13 +237,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
}
}
- return &EVMInterpreter{
- VM: &VM{
- evm: evm,
- cfg: cfg,
- },
- jt: jt,
- }
+ return jt
}
// Run loops and evaluates the contract's code with the given input data and returns
@@ -302,7 +246,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// 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, gas uint64, input []byte, readOnly bool) (_ []byte, _ uint64, err error) {
+func (evm *EVM) Run(contract Contract, gas uint64, input []byte, readOnly bool) (_ []byte, _ uint64, err error) {
// Don't bother with the execution if there's no code.
if len(contract.Code) == 0 {
return nil, gas, nil
@@ -310,7 +254,7 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
// 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
var (
op OpCode // current opcode
@@ -326,36 +270,37 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
callGas uint64
logged bool // deferred Tracer should ignore already logged steps
res []byte // result of the opcode execution function
- debug = in.cfg.Tracer != nil && (in.cfg.Tracer.OnOpcode != nil || in.cfg.Tracer.OnGasChange != nil || in.cfg.Tracer.OnFault != nil)
- trace = dbg.TraceInstructions && in.evm.intraBlockState.Trace()
+ tracer = evm.config.Tracer
+ debug = tracer != nil && (tracer.OnOpcode != nil || tracer.OnGasChange != nil || tracer.OnFault != nil)
+ trace = dbg.TraceInstructions && evm.intraBlockState.Trace()
blockNum uint64
txIndex, txIncarnation int
)
// Make sure the readOnly is only set if we aren't in readOnly yet.
// This makes also sure that the readOnly flag isn't removed for child calls.
- restoreReadonly := readOnly && !in.readOnly
+ restoreReadonly := readOnly && !evm.readOnly
if restoreReadonly {
- in.readOnly = true
+ evm.readOnly = true
}
// Increment the call depth which is restricted to 1024
- in.depth++
+ evm.depth++
defer func() {
// first: capture data/memory/state/depth/etc... then clenup them
if debug && err != nil {
- if !logged && in.cfg.Tracer.OnOpcode != nil {
- in.cfg.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.depth, VMErrorFromErr(err))
+ if !logged && tracer.OnOpcode != nil {
+ tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
}
- if logged && in.cfg.Tracer.OnFault != nil {
- in.cfg.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.depth, VMErrorFromErr(err))
+ if logged && tracer.OnFault != nil {
+ tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err))
}
}
// this function must execute _after_: the `CaptureState` needs the stacks before
callContext.put()
if restoreReadonly {
- in.readOnly = false
+ evm.readOnly = false
}
- in.depth--
+ evm.depth--
}()
// The Interpreter main run loop (contextual). This loop runs until either an
@@ -375,18 +320,18 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
for {
steps++
- if steps%5000 == 0 && in.evm.Cancelled() {
+ if steps%5000 == 0 && evm.Cancelled() {
break
}
if dbg.TraceDyanmicGas || debug || trace {
// Capture pre-execution values for tracing.
logged, pcCopy, gasCopy = false, pc, callContext.gas
- blockNum, txIndex, txIncarnation = in.evm.intraBlockState.BlockNumber(), in.evm.intraBlockState.TxIndex(), in.evm.intraBlockState.Incarnation()
+ blockNum, txIndex, txIncarnation = evm.intraBlockState.BlockNumber(), evm.intraBlockState.TxIndex(), evm.intraBlockState.Incarnation()
}
// Get the operation from the jump table and validate the stack to ensure there are
// enough stack items available to perform the operation.
op = contract.GetOp(pc)
- operation := in.jt[op]
+ operation := evm.jt[op]
cost = operation.constantGas // For tracing
// Validate stack
if sLen := callContext.Stack.len(); sLen < operation.numPop {
@@ -422,12 +367,12 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
// 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, callContext, callContext.gas, memorySize)
+ dynamicCost, err = operation.dynamicGas(evm, callContext, callContext.gas, memorySize)
if err != nil {
return nil, callContext.gas, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
cost += dynamicCost // for tracing
- callGas = operation.constantGas + dynamicCost - in.evm.CallGasTemp()
+ callGas = operation.constantGas + dynamicCost - evm.CallGasTemp()
if dbg.TraceDyanmicGas && dynamicCost > 0 {
fmt.Printf("%d (%d.%d) Dynamic Gas: %d (%s)\n", blockNum, txIndex, txIncarnation, traceGas(op, callGas, cost), op)
}
@@ -441,12 +386,12 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
}
// Do gas tracing before memory expansion
- if in.cfg.Tracer != nil {
- if in.cfg.Tracer.OnGasChange != nil {
- in.cfg.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
+ if tracer != nil {
+ if tracer.OnGasChange != nil {
+ tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
}
- if in.cfg.Tracer.OnOpcode != nil {
- in.cfg.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.depth, VMErrorFromErr(err))
+ if tracer.OnOpcode != nil {
+ tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
logged = true
}
}
@@ -469,7 +414,7 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
}
// execute the operation
- pc, res, err = operation.execute(pc, in, callContext)
+ pc, res, err = operation.execute(pc, evm, callContext)
if err != nil {
break
@@ -483,12 +428,3 @@ func (in *EVMInterpreter) Run(contract Contract, gas uint64, input []byte, readO
return res, callContext.gas, err
}
-
-// Depth returns the current call stack depth.
-func (in *EVMInterpreter) Depth() int { return in.depth }
-
-// Increments the current call stack's depth.
-func (in *EVMInterpreter) IncDepth() { in.depth++ }
-
-// Decrements the current call stack's depth
-func (in *EVMInterpreter) DecDepth() { in.depth-- }
diff --git a/execution/vm/jump_table.go b/execution/vm/jump_table.go
index 6b0902f8e60..12f44208131 100644
--- a/execution/vm/jump_table.go
+++ b/execution/vm/jump_table.go
@@ -26,7 +26,7 @@ import (
)
type (
- executionFunc func(pc uint64, interpreter *EVMInterpreter, callContext *CallContext) (uint64, []byte, error)
+ executionFunc func(pc uint64, evm *EVM, callContext *CallContext) (uint64, []byte, error)
gasFunc func(*EVM, *CallContext, uint64, 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(*CallContext) (size uint64, overflow bool)
diff --git a/execution/vm/mock_vm.go b/execution/vm/mock_vm.go
deleted file mode 100644
index 07146751c85..00000000000
--- a/execution/vm/mock_vm.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2024 The Erigon Authors
-// This file is part of Erigon.
-//
-// Erigon is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Erigon is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with Erigon. If not, see .
-
-package vm
-
-import (
- "fmt"
-
- "github.com/erigontech/erigon/execution/types/accounts"
- "github.com/holiman/uint256"
-)
-
-type readonlyGetSetter interface {
- setReadonly(outerReadonly bool) func()
- getReadonly() bool
-}
-
-type testVM struct {
- readonlyGetSetter
-
- recordedReadOnlies *[]*readOnlyState
- recordedIsEVMCalled *[]bool
-
- env *EVM
- isEVMSliceTest []bool
- readOnlySliceTest []bool
- currentIdx *int
-
- depth int
-}
-
-func (evm *testVM) Run(_ Contract, _ uint64, _ []byte, readOnly bool) (ret []byte, gas uint64, err error) {
- currentReadOnly := new(readOnlyState)
-
- currentReadOnly.outer = readOnly
- currentReadOnly.before = evm.getReadonly()
-
- currentIndex := *evm.currentIdx
-
- callback := evm.setReadonly(readOnly)
- defer func() {
- callback()
- currentReadOnly.after = evm.getReadonly()
- }()
-
- currentReadOnly.in = evm.getReadonly()
-
- (*evm.recordedReadOnlies)[currentIndex] = currentReadOnly
- (*evm.recordedIsEVMCalled)[currentIndex] = true
-
- *evm.currentIdx++
-
- if *evm.currentIdx < len(evm.readOnlySliceTest) {
- res, _, err := evm.env.interpreter.Run(*NewContract(
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- accounts.ZeroAddress,
- uint256.Int{},
- ), 0, nil, evm.readOnlySliceTest[*evm.currentIdx])
- return res, 0, err
- }
-
- return
-}
-
-func (evm *testVM) Depth() int { return evm.depth }
-
-func (evm *testVM) IncDepth() { evm.depth++ }
-func (evm *testVM) DecDepth() { evm.depth-- }
-
-type readOnlyState struct {
- outer bool
- before bool
- in bool
- after bool
-}
-
-func (r *readOnlyState) String() string {
- return fmt.Sprintf("READONLY Status: outer %t; before %t; in %t; after %t", r.outer, r.before, r.in, r.after)
-}
diff --git a/go.mod b/go.mod
index 956576c7c1c..8c635846388 100644
--- a/go.mod
+++ b/go.mod
@@ -127,7 +127,6 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
- pgregory.net/rapid v1.2.0
sigs.k8s.io/yaml v1.6.0
)
diff --git a/go.sum b/go.sum
index 725f236a3d2..8e534892169 100644
--- a/go.sum
+++ b/go.sum
@@ -1528,8 +1528,6 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
-pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
-pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=