Skip to content

Commit

Permalink
Merge branch 'libevm' into arr4n/precompile-env-evm-call
Browse files Browse the repository at this point in the history
  • Loading branch information
ARR4N committed Sep 26, 2024
2 parents 2abf1f2 + f1dba53 commit 5c1f285
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 16 deletions.
5 changes: 4 additions & 1 deletion core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ func init() {
}

// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
func ActivePrecompiles(rules params.Rules) (active []common.Address) {
defer func() {
active = rules.Hooks().ActivePrecompiles(append([]common.Address{}, active...))
}()
switch {
case rules.IsCancun:
return PrecompiledAddressesCancun
Expand Down
22 changes: 22 additions & 0 deletions core/vm/contracts.libevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,25 @@ func TestCanCreateContract(t *testing.T) {
})
}
}

func TestActivePrecompilesOverride(t *testing.T) {
newRules := func() params.Rules {
return new(params.ChainConfig).Rules(big.NewInt(0), false, 0)
}
defaultActive := vm.ActivePrecompiles(newRules())

rng := ethtest.NewPseudoRand(0xDecafC0ffeeBad)
precompiles := make([]common.Address, rng.Intn(10)+5)
for i := range precompiles {
precompiles[i] = rng.Address()
}
hooks := &hookstest.Stub{
ActivePrecompilesFn: func(active []common.Address) []common.Address {
assert.Equal(t, defaultActive, active, "ActivePrecompiles() hook receives default addresses")
return precompiles
},
}
hooks.Register(t)

require.Equal(t, precompiles, vm.ActivePrecompiles(newRules()), "vm.ActivePrecompiles() returns overridden addresses")
}
2 changes: 1 addition & 1 deletion core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +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, evm.StateDB = overrideEVMResetArgs(txCtx, statedb)
evm.TxContext, evm.StateDB = evm.overrideEVMResetArgs(txCtx, statedb)
}

// Cancel cancels any running EVM operation. This may be called concurrently and
Expand Down
30 changes: 19 additions & 11 deletions core/vm/evm.libevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"math/big"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ethereum/go-ethereum/params"
Expand All @@ -27,23 +28,25 @@ import (
type evmArgOverrider struct {
newEVMchainID int64

resetTxCtx TxContext
resetStateDB StateDB
gotResetChainID *big.Int
resetTxContextTo TxContext
resetStateDBTo StateDB
}

func (o evmArgOverrider) OverrideNewEVMArgs(args *NewEVMArgs) *NewEVMArgs {
func (o *evmArgOverrider) OverrideNewEVMArgs(args *NewEVMArgs) *NewEVMArgs {
args.ChainConfig = &params.ChainConfig{ChainID: big.NewInt(o.newEVMchainID)}
return args
}

func (o evmArgOverrider) OverrideEVMResetArgs(*EVMResetArgs) *EVMResetArgs {
func (o *evmArgOverrider) OverrideEVMResetArgs(r params.Rules, _ *EVMResetArgs) *EVMResetArgs {
o.gotResetChainID = r.ChainID
return &EVMResetArgs{
TxContext: o.resetTxCtx,
StateDB: o.resetStateDB,
TxContext: o.resetTxContextTo,
StateDB: o.resetStateDBTo,
}
}

func (o evmArgOverrider) register(t *testing.T) {
func (o *evmArgOverrider) register(t *testing.T) {
t.Helper()
libevmHooks = nil
RegisterHooks(o)
Expand Down Expand Up @@ -71,15 +74,20 @@ 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{
const (
chainID = 0xc0ffee
gasPrice = 1357924680
)
hooks := &evmArgOverrider{
newEVMchainID: chainID,
resetTxContextTo: TxContext{
GasPrice: big.NewInt(gasPrice),
},
}
hooks.register(t)

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)
assert.Equalf(t, big.NewInt(chainID), hooks.gotResetChainID, "%T.ChainID passed to Reset() hook", params.Rules{})
assert.Equalf(t, big.NewInt(gasPrice), evm.GasPrice, "%T.GasPrice set by Reset() hook", evm)
}
6 changes: 3 additions & 3 deletions core/vm/hooks.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var libevmHooks Hooks
// See [RegisterHooks].
type Hooks interface {
OverrideNewEVMArgs(*NewEVMArgs) *NewEVMArgs
OverrideEVMResetArgs(*EVMResetArgs) *EVMResetArgs
OverrideEVMResetArgs(params.Rules, *EVMResetArgs) *EVMResetArgs
}

// NewEVMArgs are the arguments received by [NewEVM], available for override
Expand Down Expand Up @@ -67,10 +67,10 @@ func overrideNewEVMArgs(
return args.BlockContext, args.TxContext, args.StateDB, args.ChainConfig, args.Config
}

func overrideEVMResetArgs(txCtx TxContext, statedb StateDB) (TxContext, StateDB) {
func (evm *EVM) overrideEVMResetArgs(txCtx TxContext, statedb StateDB) (TxContext, StateDB) {
if libevmHooks == nil {
return txCtx, statedb
}
args := libevmHooks.OverrideEVMResetArgs(&EVMResetArgs{txCtx, statedb})
args := libevmHooks.OverrideEVMResetArgs(evm.chainRules, &EVMResetArgs{txCtx, statedb})
return args.TxContext, args.StateDB
}
10 changes: 10 additions & 0 deletions libevm/hookstest/stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Stub struct {
CheckConfigCompatibleFn func(*params.ChainConfig, *big.Int, uint64) *params.ConfigCompatError
DescriptionSuffix string
PrecompileOverrides map[common.Address]libevm.PrecompiledContract
ActivePrecompilesFn func([]common.Address) []common.Address
CanExecuteTransactionFn func(common.Address, *common.Address, libevm.StateReader) error
CanCreateContractFn func(*libevm.AddressContext, uint64, libevm.StateReader) (uint64, error)
}
Expand All @@ -71,6 +72,15 @@ func (s Stub) PrecompileOverride(a common.Address) (libevm.PrecompiledContract,
return p, ok
}

// ActivePrecompiles proxies arguments to the s.ActivePrecompilesFn function if
// non-nil, otherwise it acts as a noop.
func (s Stub) ActivePrecompiles(active []common.Address) []common.Address {
if f := s.ActivePrecompilesFn; f != nil {
return f(active)
}
return active
}

// CheckConfigForkOrder proxies arguments to the s.CheckConfigForkOrderFn
// function if non-nil, otherwise it acts as a noop.
func (s Stub) CheckConfigForkOrder() error {
Expand Down
11 changes: 11 additions & 0 deletions params/hooks.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ type RulesHooks interface {
// [PrecompiledContract] is non-nil. If it returns `false` then the default
// precompile behaviour is honoured.
PrecompileOverride(common.Address) (_ libevm.PrecompiledContract, override bool)
// ActivePrecompiles receives the addresses that would usually be returned
// by a call to [vm.ActivePrecompiles] and MUST return the value to be
// returned by said function, which will be propagated. It MAY alter the
// received slice. The value it returns MUST be consistent with the
// behaviour of the PrecompileOverride hook.
ActivePrecompiles([]common.Address) []common.Address
}

// RulesAllowlistHooks are a subset of [RulesHooks] that gate actions, signalled
Expand Down Expand Up @@ -120,3 +126,8 @@ func (NOOPHooks) CanCreateContract(_ *libevm.AddressContext, gas uint64, _ libev
func (NOOPHooks) PrecompileOverride(common.Address) (libevm.PrecompiledContract, bool) {
return nil, false
}

// ActivePrecompiles echoes the active addresses unchanged.
func (NOOPHooks) ActivePrecompiles(active []common.Address) []common.Address {
return active
}

0 comments on commit 5c1f285

Please sign in to comment.