@@ -35,6 +35,8 @@ import (
3535 "github.com/ava-labs/subnet-evm/core/types"
3636 "github.com/ava-labs/subnet-evm/core/vm"
3737 "github.com/ava-labs/subnet-evm/params"
38+ "github.com/ava-labs/subnet-evm/precompile/contract"
39+ "github.com/ava-labs/subnet-evm/precompile/modules"
3840 "github.com/ethereum/go-ethereum/common"
3941 "github.com/ethereum/go-ethereum/crypto"
4042 "github.com/ethereum/go-ethereum/log"
@@ -79,7 +81,7 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state
7981 )
8082
8183 // Configure any stateful precompiles that should go into effect during this block.
82- err := p .config . ConfigurePrecompiles ( new (big.Int ).SetUint64 (parent .Time ), block , statedb )
84+ err := ApplyPrecompileActivations ( p .config , new (big.Int ).SetUint64 (parent .Time ), block , statedb )
8385 if err != nil {
8486 log .Error ("failed to configure precompiles processing block" , "hash" , block .Hash (), "number" , block .NumberU64 (), "timestamp" , block .Time (), "err" , err )
8587 return nil , nil , 0 , err
@@ -168,3 +170,50 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
168170 vmenv := vm .NewEVM (blockContext , vm.TxContext {}, statedb , config , cfg )
169171 return applyTransaction (msg , config , author , gp , statedb , header .Number , header .Hash (), tx , usedGas , vmenv )
170172}
173+
174+ // ApplyPrecompileActivations checks if any of the precompiles specified by the chain config are enabled or disabled by the block
175+ // transition from [parentTimestamp] to the timestamp set in [blockContext]. If this is the case, it calls [Configure]
176+ // to apply the necessary state transitions for the upgrade.
177+ // This function is called:
178+ // - within genesis setup to configure the starting state for precompiles enabled at genesis,
179+ // - during block processing to update the state before processing the given block.
180+ // - during block producing to apply the precompile upgrades before producing the block.
181+ func ApplyPrecompileActivations (c * params.ChainConfig , parentTimestamp * big.Int , blockContext contract.BlockContext , statedb * state.StateDB ) error {
182+ blockTimestamp := blockContext .Timestamp ()
183+ // Note: RegisteredModules returns precompiles sorted by module addresses.
184+ // This is important because we want to configure precompiles in the same order
185+ // so that the state is deterministic.
186+ for _ , module := range modules .RegisteredModules () {
187+ key := module .ConfigKey
188+ for _ , activatingConfig := range c .GetActivatingPrecompileConfigs (module .Address , parentTimestamp , blockTimestamp , c .PrecompileUpgrades ) {
189+ // If this transition activates the upgrade, configure the stateful precompile.
190+ // (or deconfigure it if it is being disabled.)
191+ if activatingConfig .IsDisabled () {
192+ log .Info ("Disabling precompile" , "name" , key )
193+ statedb .Suicide (module .Address )
194+ // Calling Finalise here effectively commits Suicide call and wipes the contract state.
195+ // This enables re-configuration of the same contract state in the same block.
196+ // Without an immediate Finalise call after the Suicide, a reconfigured precompiled state can be wiped out
197+ // since Suicide will be committed after the reconfiguration.
198+ statedb .Finalise (true )
199+ } else {
200+ module , ok := modules .GetPrecompileModule (key )
201+ if ! ok {
202+ return fmt .Errorf ("could not find module for activating precompile, name: %s" , key )
203+ }
204+ log .Info ("Activating new precompile" , "name" , key , "config" , activatingConfig )
205+ // Set the nonce of the precompile's address (as is done when a contract is created) to ensure
206+ // that it is marked as non-empty and will not be cleaned up when the statedb is finalized.
207+ statedb .SetNonce (module .Address , 1 )
208+ // Set the code of the precompile's address to a non-zero length byte slice to ensure that the precompile
209+ // can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure
210+ // that it does not attempt to invoke a non-existent contract.
211+ statedb .SetCode (module .Address , []byte {0x1 })
212+ if err := module .Configure (c , activatingConfig , statedb , blockContext ); err != nil {
213+ return fmt .Errorf ("could not configure precompile, name: %s, reason: %w" , key , err )
214+ }
215+ }
216+ }
217+ }
218+ return nil
219+ }
0 commit comments