From f1dba53688e39e13f85c4d2e3284c64413c8ccd3 Mon Sep 17 00:00:00 2001 From: Arran Schlosberg <519948+ARR4N@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:36:07 +0100 Subject: [PATCH] feat: `params.RulesHooks.ActivePrecompiles` override (#39) --- core/vm/contracts.go | 5 ++++- core/vm/contracts.libevm_test.go | 22 ++++++++++++++++++++++ libevm/hookstest/stub.go | 10 ++++++++++ params/hooks.libevm.go | 11 +++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 00df55eee6b8..cc7c56d0e4fc 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -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 diff --git a/core/vm/contracts.libevm_test.go b/core/vm/contracts.libevm_test.go index d40513f89c48..b28174b38230 100644 --- a/core/vm/contracts.libevm_test.go +++ b/core/vm/contracts.libevm_test.go @@ -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") +} diff --git a/libevm/hookstest/stub.go b/libevm/hookstest/stub.go index 78fec96f0e75..53df887f8288 100644 --- a/libevm/hookstest/stub.go +++ b/libevm/hookstest/stub.go @@ -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) } @@ -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 { diff --git a/params/hooks.libevm.go b/params/hooks.libevm.go index 57e40d4f31a9..23e4e27490bf 100644 --- a/params/hooks.libevm.go +++ b/params/hooks.libevm.go @@ -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 @@ -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 +}