diff --git a/core/genesis_test.go b/core/genesis_test.go index 1b793c161a..820f6e5713 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -172,7 +172,7 @@ func TestStatefulPrecompilesConfigure(t *testing.T) { config := *params.TestChainConfig // Include the StatefulPrecompileConfigs here so that they will be configured in the genesis allowListAdminAddr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC") - config.AllowListConfig = precompile.AllowListConfig{ + config.AllowListConfig = &precompile.AllowListConfig{ BlockTimestamp: big.NewInt(0), AllowListAdmins: []common.Address{ allowListAdminAddr, diff --git a/core/test_blockchain.go b/core/test_blockchain.go index c6ef391a67..6946b3ddaa 100644 --- a/core/test_blockchain.go +++ b/core/test_blockchain.go @@ -1517,7 +1517,7 @@ func TestAllowList(t *testing.T, create func(db ethdb.Database, chainConfig *par // Ensure that key1 has some funds in the genesis block. genesisBalance := new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether)) config := *params.TestChainConfig - config.AllowListConfig = precompile.AllowListConfig{ + config.AllowListConfig = &precompile.AllowListConfig{ BlockTimestamp: big.NewInt(0), AllowListAdmins: []common.Address{ addr1, diff --git a/params/config.go b/params/config.go index a3daea96c5..f16c991186 100644 --- a/params/config.go +++ b/params/config.go @@ -31,6 +31,8 @@ import ( "errors" "fmt" "math/big" + "reflect" + "time" "github.com/ava-labs/subnet-evm/precompile" "github.com/ava-labs/subnet-evm/utils" @@ -100,7 +102,7 @@ var ( SubnetEVMTimestamp: big.NewInt(0), FeeConfig: DefaultFeeConfig, AllowFeeRecipients: false, - AllowListConfig: precompile.AllowListConfig{ + AllowListConfig: &precompile.AllowListConfig{ BlockTimestamp: big.NewInt(0), AllowListAdmins: []common.Address{ common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"), @@ -109,8 +111,8 @@ var ( }, } - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), DefaultFeeConfig, false, precompile.AllowListConfig{}} - TestPreSubnetEVMConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, DefaultFeeConfig, false, precompile.AllowListConfig{}} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), DefaultFeeConfig, false, nil} + TestPreSubnetEVMConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, DefaultFeeConfig, false, nil} ) // ChainConfig is the core config which determines the blockchain settings. @@ -141,7 +143,7 @@ type ChainConfig struct { FeeConfig *FeeConfig `json:"feeConfig,omitempty"` AllowFeeRecipients bool `json:"allowFeeRecipients,omitempty"` // Allows fees to be collected by block builders. - AllowListConfig precompile.AllowListConfig `json:"allowListConfig"` // Config for the allow list precompile + AllowListConfig *precompile.AllowListConfig `json:"allowListConfig,omitempty"` // Config for the allow list precompile } type FeeConfig struct { @@ -234,10 +236,13 @@ func (c *ChainConfig) IsSubnetEVM(blockTimestamp *big.Int) bool { // IsAllowList returns whether [blockTimestamp] is either equal to the AllowList fork block timestamp or greater. func (c *ChainConfig) IsAllowList(blockTimestamp *big.Int) bool { + if c.AllowListConfig == nil { + return false + } return utils.IsForked(c.AllowListConfig.Timestamp(), blockTimestamp) } -// IsIstanbul returns whether num is either equal to the Istanbul fork block or greater. +// GetFeeConfig returns the *FeeConfig if it exists. func (c *ChainConfig) GetFeeConfig() *FeeConfig { if c.FeeConfig == nil { return DefaultFeeConfig @@ -339,6 +344,21 @@ func (c *ChainConfig) CheckConfigForkOrder() error { return nil } +func isNil(a interface{}) bool { + return a == nil || reflect.ValueOf(a).IsNil() +} + +func matchNil(a, b interface{}) (match, ni bool) { + switch { + case isNil(a) && isNil(b): + return true, true + case !isNil(a) && !isNil(b): + return true, false + default: + return false, false + } +} + func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headHeight *big.Int, headTimestamp *big.Int) *ConfigCompatError { if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headHeight) { return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) @@ -374,12 +394,27 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headHeight *big.Int, if isForkIncompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, headHeight) { return newCompatError("Muir Glacier fork block", c.MuirGlacierBlock, newcfg.MuirGlacierBlock) } + + // Check subnet-evm specific activations if isForkIncompatible(c.SubnetEVMTimestamp, newcfg.SubnetEVMTimestamp, headTimestamp) { return newCompatError("SubnetEVM fork block timestamp", c.SubnetEVMTimestamp, newcfg.SubnetEVMTimestamp) } + currentTime := big.NewInt(time.Now().Unix()) + if match, ni := matchNil(c.AllowListConfig, newcfg.AllowListConfig); match && !ni { + if isForkIncompatible(c.AllowListConfig.Timestamp(), newcfg.AllowListConfig.Timestamp(), headTimestamp) { + return newCompatError("AllowList fork block timestamp", c.AllowListConfig.Timestamp(), newcfg.AllowListConfig.Timestamp()) + } + } else if !match { + return newCompatError("AllowList", currentTime, currentTime) + } - if isForkIncompatible(c.AllowListConfig.Timestamp(), newcfg.AllowListConfig.Timestamp(), headTimestamp) { - return newCompatError("AllowList fork block timestamp", c.AllowListConfig.Timestamp(), newcfg.AllowListConfig.Timestamp()) + // Check compatibility of misc, non-timed configs ([currentTime] returns on + // incompatibility to force error propagation) + if match, _ := matchNil(c.FeeConfig, newcfg.FeeConfig); !match { + return newCompatError("FeeConfig", currentTime, currentTime) + } + if c.AllowFeeRecipients != newcfg.AllowFeeRecipients { + return newCompatError("AllowFeeRecipients", currentTime, currentTime) } return nil @@ -483,8 +518,8 @@ func (c *ChainConfig) AvalancheRules(blockNum, blockTimestamp *big.Int) Rules { func (c *ChainConfig) enabledStatefulPrecompiles() []precompile.StatefulPrecompileConfig { statefulPrecompileConfigs := make([]precompile.StatefulPrecompileConfig, 0) - if c.AllowListConfig.Timestamp() != nil { - statefulPrecompileConfigs = append(statefulPrecompileConfigs, &c.AllowListConfig) + if c.AllowListConfig != nil { + statefulPrecompileConfigs = append(statefulPrecompileConfigs, c.AllowListConfig) } return statefulPrecompileConfigs diff --git a/precompile/allow_list.go b/precompile/allow_list.go index f710115b5d..5d1d7624b7 100644 --- a/precompile/allow_list.go +++ b/precompile/allow_list.go @@ -147,12 +147,6 @@ func writeAllowList(evm PrecompileAccessibleState, callerAddr common.Address, mo return nil, remainingGas, fmt.Errorf("caller %s cannot modify allow list", callerAddr) } - log.Info("allow list args", "address", modifyAddress, "status", role) - if err != nil { - log.Info("allow list reverted", "err", err) - return nil, remainingGas, fmt.Errorf("failed to unpack modify allow list input: %w", err) - } - SetAllowListRole(evm.GetStateDB(), modifyAddress, role) // Return an empty output and the remaining gas