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 }