github.com/MetalBlockchain/subnet-evm@v0.6.3/params/state_upgrade.go (about) 1 // (c) 2023 Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package params 5 6 import ( 7 "fmt" 8 "reflect" 9 10 "github.com/MetalBlockchain/subnet-evm/utils" 11 "github.com/ethereum/go-ethereum/common" 12 "github.com/ethereum/go-ethereum/common/hexutil" 13 "github.com/ethereum/go-ethereum/common/math" 14 ) 15 16 // StateUpgrade describes the modifications to be made to the state during 17 // a state upgrade. 18 type StateUpgrade struct { 19 BlockTimestamp *uint64 `json:"blockTimestamp,omitempty"` 20 21 // map from account address to the modification to be made to the account. 22 StateUpgradeAccounts map[common.Address]StateUpgradeAccount `json:"accounts"` 23 } 24 25 // StateUpgradeAccount describes the modifications to be made to an account during 26 // a state upgrade. 27 type StateUpgradeAccount struct { 28 Code hexutil.Bytes `json:"code,omitempty"` 29 Storage map[common.Hash]common.Hash `json:"storage,omitempty"` 30 BalanceChange *math.HexOrDecimal256 `json:"balanceChange,omitempty"` 31 } 32 33 func (s *StateUpgrade) Equal(other *StateUpgrade) bool { 34 return reflect.DeepEqual(s, other) 35 } 36 37 // verifyStateUpgrades checks [c.StateUpgrades] is well formed: 38 // - the specified blockTimestamps must monotonically increase 39 func (c *ChainConfig) verifyStateUpgrades() error { 40 var previousUpgradeTimestamp *uint64 41 for i, upgrade := range c.StateUpgrades { 42 upgradeTimestamp := upgrade.BlockTimestamp 43 if upgradeTimestamp == nil { 44 return fmt.Errorf("StateUpgrade[%d]: config block timestamp cannot be nil ", i) 45 } 46 // Verify the upgrade's timestamp is equal 0 (to avoid confusion with genesis). 47 if *upgradeTimestamp == 0 { 48 return fmt.Errorf("StateUpgrade[%d]: config block timestamp (%v) must be greater than 0", i, *upgradeTimestamp) 49 } 50 51 // Verify specified timestamps are strictly monotonically increasing. 52 if previousUpgradeTimestamp != nil && *upgradeTimestamp <= *previousUpgradeTimestamp { 53 return fmt.Errorf("StateUpgrade[%d]: config block timestamp (%v) <= previous timestamp (%v)", i, *upgradeTimestamp, *previousUpgradeTimestamp) 54 } 55 previousUpgradeTimestamp = upgradeTimestamp 56 } 57 return nil 58 } 59 60 // GetActivatingStateUpgrades returns all state upgrades configured to activate during the 61 // state transition from a block with timestamp [from] to a block with timestamp [to]. 62 func (c *ChainConfig) GetActivatingStateUpgrades(from *uint64, to uint64, upgrades []StateUpgrade) []StateUpgrade { 63 activating := make([]StateUpgrade, 0) 64 for _, upgrade := range upgrades { 65 if utils.IsForkTransition(upgrade.BlockTimestamp, from, to) { 66 activating = append(activating, upgrade) 67 } 68 } 69 return activating 70 } 71 72 // CheckStateUpgradesCompatible checks if [stateUpgrades] are compatible with [c] at [headTimestamp]. 73 func (c *ChainConfig) CheckStateUpgradesCompatible(stateUpgrades []StateUpgrade, lastTimestamp uint64) *ConfigCompatError { 74 // All active upgrades (from nil to [lastTimestamp]) must match. 75 activeUpgrades := c.GetActivatingStateUpgrades(nil, lastTimestamp, c.StateUpgrades) 76 newUpgrades := c.GetActivatingStateUpgrades(nil, lastTimestamp, stateUpgrades) 77 78 // Check activated upgrades are still present. 79 for i, upgrade := range activeUpgrades { 80 if len(newUpgrades) <= i { 81 // missing upgrade 82 return newTimestampCompatError( 83 fmt.Sprintf("missing StateUpgrade[%d]", i), 84 upgrade.BlockTimestamp, 85 nil, 86 ) 87 } 88 // All upgrades that have activated must be identical. 89 if !upgrade.Equal(&newUpgrades[i]) { 90 return newTimestampCompatError( 91 fmt.Sprintf("StateUpgrade[%d]", i), 92 upgrade.BlockTimestamp, 93 newUpgrades[i].BlockTimestamp, 94 ) 95 } 96 } 97 // then, make sure newUpgrades does not have additional upgrades 98 // that are already activated. (cannot perform retroactive upgrade) 99 if len(newUpgrades) > len(activeUpgrades) { 100 return newTimestampCompatError( 101 fmt.Sprintf("cannot retroactively enable StateUpgrade[%d]", len(activeUpgrades)), 102 nil, 103 newUpgrades[len(activeUpgrades)].BlockTimestamp, // this indexes to the first element in newUpgrades after the end of activeUpgrades 104 ) 105 } 106 107 return nil 108 }