From 53ef0712af0867cae8b1fb83d694b53597e1b2d3 Mon Sep 17 00:00:00 2001
From: Arran Schlosberg <519948+ARR4N@users.noreply.github.com>
Date: Wed, 25 Sep 2024 10:03:36 -0400
Subject: [PATCH] feat: override `EVM.Reset()` args (#36)
---
core/vm/contracts.libevm.go | 1 +
core/vm/evm.go | 3 +--
core/vm/evm.libevm_test.go | 54 ++++++++++++++++++++++++++++++-------
core/vm/hooks.libevm.go | 21 ++++++++++++++-
core/vm/stack.libevm.go | 1 +
5 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/core/vm/contracts.libevm.go b/core/vm/contracts.libevm.go
index 78f6df9192b3..a93120277036 100644
--- a/core/vm/contracts.libevm.go
+++ b/core/vm/contracts.libevm.go
@@ -13,6 +13,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
// .
+
package vm
import (
diff --git a/core/vm/evm.go b/core/vm/evm.go
index d61f19f3cdc1..48c1112f18ed 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -159,8 +159,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
// Reset resets the EVM with a new transaction context.Reset
// This is not threadsafe and should only be done very cautiously.
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {
- evm.TxContext = txCtx
- evm.StateDB = statedb
+ evm.TxContext, evm.StateDB = overrideEVMResetArgs(txCtx, statedb)
}
// Cancel cancels any running EVM operation. This may be called concurrently and
diff --git a/core/vm/evm.libevm_test.go b/core/vm/evm.libevm_test.go
index 069dbc288790..0a6f6f6209ab 100644
--- a/core/vm/evm.libevm_test.go
+++ b/core/vm/evm.libevm_test.go
@@ -24,15 +24,34 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-type chainIDOverrider struct {
- chainID int64
+type evmArgOverrider struct {
+ newEVMchainID int64
+
+ resetTxCtx TxContext
+ resetStateDB StateDB
}
-func (o chainIDOverrider) OverrideNewEVMArgs(args *NewEVMArgs) *NewEVMArgs {
- args.ChainConfig = ¶ms.ChainConfig{ChainID: big.NewInt(o.chainID)}
+func (o evmArgOverrider) OverrideNewEVMArgs(args *NewEVMArgs) *NewEVMArgs {
+ args.ChainConfig = ¶ms.ChainConfig{ChainID: big.NewInt(o.newEVMchainID)}
return args
}
+func (o evmArgOverrider) OverrideEVMResetArgs(*EVMResetArgs) *EVMResetArgs {
+ return &EVMResetArgs{
+ TxContext: o.resetTxCtx,
+ StateDB: o.resetStateDB,
+ }
+}
+
+func (o evmArgOverrider) register(t *testing.T) {
+ t.Helper()
+ libevmHooks = nil
+ RegisterHooks(o)
+ t.Cleanup(func() {
+ libevmHooks = nil
+ })
+}
+
func TestOverrideNewEVMArgs(t *testing.T) {
// The overrideNewEVMArgs function accepts and returns all arguments to
// NewEVM(), in order. Here we lock in our assumption of that order. If this
@@ -40,10 +59,27 @@ func TestOverrideNewEVMArgs(t *testing.T) {
var _ func(BlockContext, TxContext, StateDB, *params.ChainConfig, Config) *EVM = NewEVM
const chainID = 13579
- libevmHooks = nil
- RegisterHooks(chainIDOverrider{chainID: chainID})
- defer func() { libevmHooks = nil }()
+ hooks := evmArgOverrider{newEVMchainID: chainID}
+ hooks.register(t)
+
+ evm := NewEVM(BlockContext{}, TxContext{}, nil, nil, Config{})
+ got := evm.ChainConfig().ChainID
+ require.Equalf(t, big.NewInt(chainID), got, "%T.ChainConfig().ChainID set by NewEVM() hook", evm)
+}
+
+func TestOverrideEVMResetArgs(t *testing.T) {
+ // Equivalent to rationale for TestOverrideNewEVMArgs above.
+ var _ func(TxContext, StateDB) = (*EVM)(nil).Reset
+
+ const gasPrice = 1357924680
+ hooks := evmArgOverrider{
+ resetTxCtx: TxContext{
+ GasPrice: big.NewInt(gasPrice),
+ },
+ }
+ hooks.register(t)
- got := NewEVM(BlockContext{}, TxContext{}, nil, nil, Config{}).ChainConfig().ChainID
- require.Equal(t, big.NewInt(chainID), got)
+ evm := NewEVM(BlockContext{}, TxContext{}, nil, nil, Config{})
+ evm.Reset(TxContext{}, nil)
+ require.Equalf(t, big.NewInt(gasPrice), evm.GasPrice, "%T.GasPrice set by Reset() hook", evm)
}
diff --git a/core/vm/hooks.libevm.go b/core/vm/hooks.libevm.go
index 42b7f93a49e7..71362355b4c1 100644
--- a/core/vm/hooks.libevm.go
+++ b/core/vm/hooks.libevm.go
@@ -13,6 +13,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
// .
+
package vm
import "github.com/ethereum/go-ethereum/params"
@@ -29,11 +30,14 @@ func RegisterHooks(h Hooks) {
var libevmHooks Hooks
// Hooks are arbitrary configuration functions to modify default VM behaviour.
+// See [RegisterHooks].
type Hooks interface {
OverrideNewEVMArgs(*NewEVMArgs) *NewEVMArgs
+ OverrideEVMResetArgs(*EVMResetArgs) *EVMResetArgs
}
-// NewEVMArgs are the arguments received by [NewEVM], available for override.
+// NewEVMArgs are the arguments received by [NewEVM], available for override
+// via [Hooks].
type NewEVMArgs struct {
BlockContext BlockContext
TxContext TxContext
@@ -42,6 +46,13 @@ type NewEVMArgs struct {
Config Config
}
+// EVMResetArgs are the arguments received by [EVM.Reset], available for
+// override via [Hooks].
+type EVMResetArgs struct {
+ TxContext TxContext
+ StateDB StateDB
+}
+
func overrideNewEVMArgs(
blockCtx BlockContext,
txCtx TxContext,
@@ -55,3 +66,11 @@ func overrideNewEVMArgs(
args := libevmHooks.OverrideNewEVMArgs(&NewEVMArgs{blockCtx, txCtx, statedb, chainConfig, config})
return args.BlockContext, args.TxContext, args.StateDB, args.ChainConfig, args.Config
}
+
+func overrideEVMResetArgs(txCtx TxContext, statedb StateDB) (TxContext, StateDB) {
+ if libevmHooks == nil {
+ return txCtx, statedb
+ }
+ args := libevmHooks.OverrideEVMResetArgs(&EVMResetArgs{txCtx, statedb})
+ return args.TxContext, args.StateDB
+}
diff --git a/core/vm/stack.libevm.go b/core/vm/stack.libevm.go
index a022a62197e3..e4ad13440963 100644
--- a/core/vm/stack.libevm.go
+++ b/core/vm/stack.libevm.go
@@ -13,6 +13,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
// .
+
package vm
import "github.com/holiman/uint256"