github.com/MetalBlockchain/subnet-evm@v0.4.9/params/precompile_config.go (about)

     1  // (c) 2022 Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package params
     5  
     6  import (
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/MetalBlockchain/subnet-evm/precompile"
    11  	"github.com/MetalBlockchain/subnet-evm/utils"
    12  	"github.com/ethereum/go-ethereum/log"
    13  )
    14  
    15  // precompileKey is a helper type used to reference each of the
    16  // possible stateful precompile types that can be activated
    17  // as a network upgrade.
    18  type precompileKey int
    19  
    20  const (
    21  	contractDeployerAllowListKey precompileKey = iota + 1
    22  	contractNativeMinterKey
    23  	txAllowListKey
    24  	feeManagerKey
    25  	rewardManagerKey
    26  	// ADD YOUR PRECOMPILE HERE
    27  	// {yourPrecompile}Key
    28  )
    29  
    30  // TODO: Move this to the interface or PrecompileConfig struct
    31  func (k precompileKey) String() string {
    32  	switch k {
    33  	case contractDeployerAllowListKey:
    34  		return "contractDeployerAllowList"
    35  	case contractNativeMinterKey:
    36  		return "contractNativeMinter"
    37  	case txAllowListKey:
    38  		return "txAllowList"
    39  	case feeManagerKey:
    40  		return "feeManager"
    41  	case rewardManagerKey:
    42  		return "rewardManager"
    43  		// ADD YOUR PRECOMPILE HERE
    44  		/*
    45  			case {yourPrecompile}Key:
    46  				return "{yourPrecompile}"
    47  		*/
    48  	}
    49  	return "unknown"
    50  }
    51  
    52  // ADD YOUR PRECOMPILE HERE
    53  var precompileKeys = []precompileKey{contractDeployerAllowListKey, contractNativeMinterKey, txAllowListKey, feeManagerKey, rewardManagerKey /* {yourPrecompile}Key */}
    54  
    55  // PrecompileUpgrade is a helper struct embedded in UpgradeConfig, representing
    56  // each of the possible stateful precompile types that can be activated
    57  // as a network upgrade.
    58  type PrecompileUpgrade struct {
    59  	ContractDeployerAllowListConfig *precompile.ContractDeployerAllowListConfig `json:"contractDeployerAllowListConfig,omitempty"` // Config for the contract deployer allow list precompile
    60  	ContractNativeMinterConfig      *precompile.ContractNativeMinterConfig      `json:"contractNativeMinterConfig,omitempty"`      // Config for the native minter precompile
    61  	TxAllowListConfig               *precompile.TxAllowListConfig               `json:"txAllowListConfig,omitempty"`               // Config for the tx allow list precompile
    62  	FeeManagerConfig                *precompile.FeeConfigManagerConfig          `json:"feeManagerConfig,omitempty"`                // Config for the fee manager precompile
    63  	RewardManagerConfig             *precompile.RewardManagerConfig             `json:"rewardManagerConfig,omitempty"`             // Config for the reward manager precompile
    64  	// ADD YOUR PRECOMPILE HERE
    65  	// {YourPrecompile}Config  *precompile.{YourPrecompile}Config `json:"{yourPrecompile}Config,omitempty"`
    66  }
    67  
    68  func (p *PrecompileUpgrade) getByKey(key precompileKey) (precompile.StatefulPrecompileConfig, bool) {
    69  	switch key {
    70  	case contractDeployerAllowListKey:
    71  		return p.ContractDeployerAllowListConfig, p.ContractDeployerAllowListConfig != nil
    72  	case contractNativeMinterKey:
    73  		return p.ContractNativeMinterConfig, p.ContractNativeMinterConfig != nil
    74  	case txAllowListKey:
    75  		return p.TxAllowListConfig, p.TxAllowListConfig != nil
    76  	case feeManagerKey:
    77  		return p.FeeManagerConfig, p.FeeManagerConfig != nil
    78  	case rewardManagerKey:
    79  		return p.RewardManagerConfig, p.RewardManagerConfig != nil
    80  	// ADD YOUR PRECOMPILE HERE
    81  	/*
    82  		case {yourPrecompile}Key:
    83  		return p.{YourPrecompile}Config , p.{YourPrecompile}Config  != nil
    84  	*/
    85  	default:
    86  		panic(fmt.Sprintf("unknown upgrade key: %v", key))
    87  	}
    88  }
    89  
    90  // verifyPrecompileUpgrades checks [c.PrecompileUpgrades] is well formed:
    91  // - [upgrades] must specify exactly one key per PrecompileUpgrade
    92  // - the specified blockTimestamps must monotonically increase
    93  // - the specified blockTimestamps must be compatible with those
    94  //   specified in the chainConfig by genesis.
    95  // - check a precompile is disabled before it is re-enabled
    96  func (c *ChainConfig) verifyPrecompileUpgrades() error {
    97  	var lastBlockTimestamp *big.Int
    98  	for i, upgrade := range c.PrecompileUpgrades {
    99  		hasKey := false // used to verify if there is only one key per Upgrade
   100  
   101  		for _, key := range precompileKeys {
   102  			config, ok := upgrade.getByKey(key)
   103  			if !ok {
   104  				continue
   105  			}
   106  			if hasKey {
   107  				return fmt.Errorf("PrecompileUpgrades[%d] has more than one key set", i)
   108  			}
   109  			configTimestamp := config.Timestamp()
   110  			if configTimestamp == nil {
   111  				return fmt.Errorf("PrecompileUpgrades[%d] cannot have a nil timestamp", i)
   112  			}
   113  			// Verify specified timestamps are monotonically increasing across all precompile keys.
   114  			// Note: It is OK for multiple configs of different keys to specify the same timestamp.
   115  			if lastBlockTimestamp != nil && configTimestamp.Cmp(lastBlockTimestamp) < 0 {
   116  				return fmt.Errorf("PrecompileUpgrades[%d] config timestamp (%v) < previous timestamp (%v)", i, configTimestamp, lastBlockTimestamp)
   117  			}
   118  			lastBlockTimestamp = configTimestamp
   119  			hasKey = true
   120  		}
   121  		if !hasKey {
   122  			return fmt.Errorf("empty precompile upgrade at index %d", i)
   123  		}
   124  	}
   125  
   126  	for _, key := range precompileKeys {
   127  		var (
   128  			lastUpgraded *big.Int
   129  			disabled     bool
   130  		)
   131  		// check the genesis chain config for any enabled upgrade
   132  		if config, ok := c.PrecompileUpgrade.getByKey(key); ok && config.Timestamp() != nil {
   133  			if err := config.Verify(); err != nil {
   134  				return err
   135  			}
   136  			disabled = false
   137  			lastUpgraded = config.Timestamp()
   138  		} else {
   139  			disabled = true
   140  		}
   141  		// next range over upgrades to verify correct use of disabled and blockTimestamps.
   142  		for i, upgrade := range c.PrecompileUpgrades {
   143  			config, ok := upgrade.getByKey(key)
   144  			// Skip the upgrade if it's not relevant to [key].
   145  			if !ok {
   146  				continue
   147  			}
   148  
   149  			if disabled == config.IsDisabled() {
   150  				return fmt.Errorf("PrecompileUpgrades[%d] disable should be [%v]", i, !disabled)
   151  			}
   152  			if lastUpgraded != nil && (config.Timestamp().Cmp(lastUpgraded) <= 0) {
   153  				return fmt.Errorf("PrecompileUpgrades[%d] config timestamp (%v) <= previous timestamp (%v)", i, config.Timestamp(), lastUpgraded)
   154  			}
   155  
   156  			if err := config.Verify(); err != nil {
   157  				return err
   158  			}
   159  
   160  			disabled = config.IsDisabled()
   161  			lastUpgraded = config.Timestamp()
   162  		}
   163  	}
   164  
   165  	return nil
   166  }
   167  
   168  // getActivePrecompileConfig returns the most recent precompile config corresponding to [key].
   169  // If none have occurred, returns nil.
   170  func (c *ChainConfig) getActivePrecompileConfig(blockTimestamp *big.Int, key precompileKey, upgrades []PrecompileUpgrade) precompile.StatefulPrecompileConfig {
   171  	configs := c.getActivatingPrecompileConfigs(nil, blockTimestamp, key, upgrades)
   172  	if len(configs) == 0 {
   173  		return nil
   174  	}
   175  	return configs[len(configs)-1] // return the most recent config
   176  }
   177  
   178  // getActivatingPrecompileConfigs returns all forks configured to activate during the state transition from a block with timestamp [from]
   179  // to a block with timestamp [to].
   180  func (c *ChainConfig) getActivatingPrecompileConfigs(from *big.Int, to *big.Int, key precompileKey, upgrades []PrecompileUpgrade) []precompile.StatefulPrecompileConfig {
   181  	configs := make([]precompile.StatefulPrecompileConfig, 0)
   182  	// First check the embedded [upgrade] for precompiles configured
   183  	// in the genesis chain config.
   184  	if config, ok := c.PrecompileUpgrade.getByKey(key); ok {
   185  		if utils.IsForkTransition(config.Timestamp(), from, to) {
   186  			configs = append(configs, config)
   187  		}
   188  	}
   189  	// Loop over all upgrades checking for the requested precompile config.
   190  	for _, upgrade := range upgrades {
   191  		if config, ok := upgrade.getByKey(key); ok {
   192  			// Check if the precompile activates in the specified range.
   193  			if utils.IsForkTransition(config.Timestamp(), from, to) {
   194  				configs = append(configs, config)
   195  			}
   196  		}
   197  	}
   198  	return configs
   199  }
   200  
   201  // GetContractDeployerAllowListConfig returns the latest forked ContractDeployerAllowListConfig
   202  // specified by [c] or nil if it was never enabled.
   203  func (c *ChainConfig) GetContractDeployerAllowListConfig(blockTimestamp *big.Int) *precompile.ContractDeployerAllowListConfig {
   204  	if val := c.getActivePrecompileConfig(blockTimestamp, contractDeployerAllowListKey, c.PrecompileUpgrades); val != nil {
   205  		return val.(*precompile.ContractDeployerAllowListConfig)
   206  	}
   207  	return nil
   208  }
   209  
   210  // GetContractNativeMinterConfig returns the latest forked ContractNativeMinterConfig
   211  // specified by [c] or nil if it was never enabled.
   212  func (c *ChainConfig) GetContractNativeMinterConfig(blockTimestamp *big.Int) *precompile.ContractNativeMinterConfig {
   213  	if val := c.getActivePrecompileConfig(blockTimestamp, contractNativeMinterKey, c.PrecompileUpgrades); val != nil {
   214  		return val.(*precompile.ContractNativeMinterConfig)
   215  	}
   216  	return nil
   217  }
   218  
   219  // GetTxAllowListConfig returns the latest forked TxAllowListConfig
   220  // specified by [c] or nil if it was never enabled.
   221  func (c *ChainConfig) GetTxAllowListConfig(blockTimestamp *big.Int) *precompile.TxAllowListConfig {
   222  	if val := c.getActivePrecompileConfig(blockTimestamp, txAllowListKey, c.PrecompileUpgrades); val != nil {
   223  		return val.(*precompile.TxAllowListConfig)
   224  	}
   225  	return nil
   226  }
   227  
   228  // GetFeeConfigManagerConfig returns the latest forked FeeManagerConfig
   229  // specified by [c] or nil if it was never enabled.
   230  func (c *ChainConfig) GetFeeConfigManagerConfig(blockTimestamp *big.Int) *precompile.FeeConfigManagerConfig {
   231  	if val := c.getActivePrecompileConfig(blockTimestamp, feeManagerKey, c.PrecompileUpgrades); val != nil {
   232  		return val.(*precompile.FeeConfigManagerConfig)
   233  	}
   234  	return nil
   235  }
   236  
   237  // GetRewardManagerConfig returns the latest forked RewardManagerConfig
   238  // specified by [c] or nil if it was never enabled.
   239  func (c *ChainConfig) GetRewardManagerConfig(blockTimestamp *big.Int) *precompile.RewardManagerConfig {
   240  	if val := c.getActivePrecompileConfig(blockTimestamp, rewardManagerKey, c.PrecompileUpgrades); val != nil {
   241  		return val.(*precompile.RewardManagerConfig)
   242  	}
   243  	return nil
   244  }
   245  
   246  /* ADD YOUR PRECOMPILE HERE
   247  func (c *ChainConfig) Get{YourPrecompile}Config(blockTimestamp *big.Int) *precompile.{YourPrecompile}Config {
   248  	if val := c.getActivePrecompileConfig(blockTimestamp, {yourPrecompile}Key, c.PrecompileUpgrades); val != nil {
   249  		return val.(*precompile.{YourPrecompile}Config)
   250  	}
   251  	return nil
   252  }
   253  */
   254  
   255  func (c *ChainConfig) GetActivePrecompiles(blockTimestamp *big.Int) PrecompileUpgrade {
   256  	pu := PrecompileUpgrade{}
   257  	if config := c.GetContractDeployerAllowListConfig(blockTimestamp); config != nil && !config.Disable {
   258  		pu.ContractDeployerAllowListConfig = config
   259  	}
   260  	if config := c.GetContractNativeMinterConfig(blockTimestamp); config != nil && !config.Disable {
   261  		pu.ContractNativeMinterConfig = config
   262  	}
   263  	if config := c.GetTxAllowListConfig(blockTimestamp); config != nil && !config.Disable {
   264  		pu.TxAllowListConfig = config
   265  	}
   266  	if config := c.GetFeeConfigManagerConfig(blockTimestamp); config != nil && !config.Disable {
   267  		pu.FeeManagerConfig = config
   268  	}
   269  	if config := c.GetRewardManagerConfig(blockTimestamp); config != nil && !config.Disable {
   270  		pu.RewardManagerConfig = config
   271  	}
   272  	// ADD YOUR PRECOMPILE HERE
   273  	// if config := c.{YourPrecompile}Config(blockTimestamp); config != nil && !config.Disable {
   274  	// 	pu.{YourPrecompile}Config = config
   275  	// }
   276  
   277  	return pu
   278  }
   279  
   280  // CheckPrecompilesCompatible checks if [precompileUpgrades] are compatible with [c] at [headTimestamp].
   281  // Returns a ConfigCompatError if upgrades already forked at [headTimestamp] are missing from
   282  // [precompileUpgrades]. Upgrades not already forked may be modified or absent from [precompileUpgrades].
   283  // Returns nil if [precompileUpgrades] is compatible with [c].
   284  // Assumes given timestamp is the last accepted block timestamp.
   285  // This ensures that as long as the node has not accepted a block with a different rule set it will allow a new upgrade to be applied as long as it activates after the last accepted block.
   286  func (c *ChainConfig) CheckPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, lastTimestamp *big.Int) *ConfigCompatError {
   287  	for _, key := range precompileKeys {
   288  		if err := c.checkPrecompileCompatible(key, precompileUpgrades, lastTimestamp); err != nil {
   289  			return err
   290  		}
   291  	}
   292  
   293  	return nil
   294  }
   295  
   296  // checkPrecompileCompatible verifies that the precompile specified by [key] is compatible between [c] and [precompileUpgrades] at [headTimestamp].
   297  // Returns an error if upgrades already forked at [headTimestamp] are missing from [precompileUpgrades].
   298  // Upgrades that have already gone into effect cannot be modified or absent from [precompileUpgrades].
   299  func (c *ChainConfig) checkPrecompileCompatible(key precompileKey, precompileUpgrades []PrecompileUpgrade, lastTimestamp *big.Int) *ConfigCompatError {
   300  	// all active upgrades must match
   301  	activeUpgrades := c.getActivatingPrecompileConfigs(nil, lastTimestamp, key, c.PrecompileUpgrades)
   302  	newUpgrades := c.getActivatingPrecompileConfigs(nil, lastTimestamp, key, precompileUpgrades)
   303  
   304  	// first, check existing upgrades are there
   305  	for i, upgrade := range activeUpgrades {
   306  		if len(newUpgrades) <= i {
   307  			// missing upgrade
   308  			return newCompatError(
   309  				fmt.Sprintf("missing PrecompileUpgrade[%d]", i),
   310  				upgrade.Timestamp(),
   311  				nil,
   312  			)
   313  		}
   314  		// All upgrades that have forked must be identical.
   315  		if !upgrade.Equal(newUpgrades[i]) {
   316  			return newCompatError(
   317  				fmt.Sprintf("PrecompileUpgrade[%d]", i),
   318  				upgrade.Timestamp(),
   319  				newUpgrades[i].Timestamp(),
   320  			)
   321  		}
   322  	}
   323  	// then, make sure newUpgrades does not have additional upgrades
   324  	// that are already activated. (cannot perform retroactive upgrade)
   325  	if len(newUpgrades) > len(activeUpgrades) {
   326  		return newCompatError(
   327  			fmt.Sprintf("cannot retroactively enable PrecompileUpgrade[%d]", len(activeUpgrades)),
   328  			nil,
   329  			newUpgrades[len(activeUpgrades)].Timestamp(), // this indexes to the first element in newUpgrades after the end of activeUpgrades
   330  		)
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  // EnabledStatefulPrecompiles returns a slice of stateful precompile configs that
   337  // have been activated through an upgrade.
   338  func (c *ChainConfig) EnabledStatefulPrecompiles(blockTimestamp *big.Int) []precompile.StatefulPrecompileConfig {
   339  	statefulPrecompileConfigs := make([]precompile.StatefulPrecompileConfig, 0)
   340  	for _, key := range precompileKeys {
   341  		if config := c.getActivePrecompileConfig(blockTimestamp, key, c.PrecompileUpgrades); config != nil {
   342  			statefulPrecompileConfigs = append(statefulPrecompileConfigs, config)
   343  		}
   344  	}
   345  
   346  	return statefulPrecompileConfigs
   347  }
   348  
   349  // CheckConfigurePrecompiles checks if any of the precompiles specified by the chain config are enabled or disabled by the block
   350  // transition from [parentTimestamp] to the timestamp set in [blockContext]. If this is the case, it calls [Configure]
   351  // or [Deconfigure] to apply the necessary state transitions for the upgrade.
   352  // This function is called:
   353  // - within genesis setup to configure the starting state for precompiles enabled at genesis,
   354  // - during block processing to update the state before processing the given block.
   355  func (c *ChainConfig) CheckConfigurePrecompiles(parentTimestamp *big.Int, blockContext precompile.BlockContext, statedb precompile.StateDB) {
   356  	blockTimestamp := blockContext.Timestamp()
   357  	for _, key := range precompileKeys { // Note: configure precompiles in a deterministic order.
   358  		for _, config := range c.getActivatingPrecompileConfigs(parentTimestamp, blockTimestamp, key, c.PrecompileUpgrades) {
   359  			// If this transition activates the upgrade, configure the stateful precompile.
   360  			// (or deconfigure it if it is being disabled.)
   361  			if config.IsDisabled() {
   362  				log.Info("Disabling precompile", "name", key)
   363  				statedb.Suicide(config.Address())
   364  				// Calling Finalise here effectively commits Suicide call and wipes the contract state.
   365  				// This enables re-configuration of the same contract state in the same block.
   366  				// Without an immediate Finalise call after the Suicide, a reconfigured precompiled state can be wiped out
   367  				// since Suicide will be committed after the reconfiguration.
   368  				statedb.Finalise(true)
   369  			} else {
   370  				log.Info("Activating new precompile", "name", key, "config", config)
   371  				precompile.Configure(c, blockContext, config, statedb)
   372  			}
   373  		}
   374  	}
   375  }