@@ -149,18 +149,38 @@ func (c *ChainConfig) verifyPrecompileUpgrades() error {
149149 return nil
150150}
151151
152- // GetActivePrecompileConfig returns the most recent precompile config corresponding to [address].
152+ // verifyStateUpgrades checks [c.StateUpgrades] is well formed:
153+ // - the specified blockTimestamps must monotonically increase
154+ func (c * ChainConfig ) verifyStateUpgrades () error {
155+ var previousUpgradeTimestamp * big.Int
156+ for i , upgrade := range c .StateUpgrades {
157+ upgradeTimestamp := upgrade .BlockTimestamp
158+ // Verify the upgrade's timestamp is greater than 0 (to avoid confusion with genesis).
159+ if upgradeTimestamp .Cmp (common .Big0 ) <= 0 {
160+ return fmt .Errorf ("StateUpgrade[%d]: config block timestamp (%v) must be greater than 0" , i , upgradeTimestamp )
161+ }
162+
163+ // Verify specified timestamps are strictly monotonically increasing.
164+ if previousUpgradeTimestamp != nil && upgradeTimestamp .Cmp (previousUpgradeTimestamp ) <= 0 {
165+ return fmt .Errorf ("StateUpgrade[%d]: config block timestamp (%v) <= previous timestamp (%v)" , i , upgradeTimestamp , previousUpgradeTimestamp )
166+ }
167+ previousUpgradeTimestamp = upgradeTimestamp
168+ }
169+ return nil
170+ }
171+
172+ // getActivePrecompileConfig returns the most recent precompile config corresponding to [address].
153173// If none have occurred, returns nil.
154- func (c * ChainConfig ) GetActivePrecompileConfig (address common.Address , blockTimestamp * big.Int ) precompileconfig.Config {
174+ func (c * ChainConfig ) getActivePrecompileConfig (address common.Address , blockTimestamp * big.Int ) precompileconfig.Config {
155175 configs := c .GetActivatingPrecompileConfigs (address , nil , blockTimestamp , c .PrecompileUpgrades )
156176 if len (configs ) == 0 {
157177 return nil
158178 }
159179 return configs [len (configs )- 1 ] // return the most recent config
160180}
161181
162- // GetActivatingPrecompileConfigs returns all upgrades configured to activate during the state transition from a block with timestamp [from]
163- // to a block with timestamp [to].
182+ // GetActivatingPrecompileConfigs returns all precompile upgrades configured to activate during the
183+ // state transition from a block with timestamp [from] to a block with timestamp [to].
164184func (c * ChainConfig ) GetActivatingPrecompileConfigs (address common.Address , from * big.Int , to * big.Int , upgrades []PrecompileUpgrade ) []precompileconfig.Config {
165185 // Get key from address.
166186 module , ok := modules .GetPrecompileModuleByAddress (address )
@@ -188,6 +208,18 @@ func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, fro
188208 return configs
189209}
190210
211+ // GetActivatingStateUpgrades returns all state upgrades configured to activate during the
212+ // state transition from a block with timestamp [from] to a block with timestamp [to].
213+ func (c * ChainConfig ) GetActivatingStateUpgrades (from * big.Int , to * big.Int , upgrades []StateUpgrade ) []StateUpgrade {
214+ activating := make ([]StateUpgrade , 0 )
215+ for _ , upgrade := range upgrades {
216+ if utils .IsForkTransition (upgrade .BlockTimestamp , from , to ) {
217+ activating = append (activating , upgrade )
218+ }
219+ }
220+ return activating
221+ }
222+
191223// CheckPrecompilesCompatible checks if [precompileUpgrades] are compatible with [c] at [headTimestamp].
192224// Returns a ConfigCompatError if upgrades already activated at [headTimestamp] are missing from
193225// [precompileUpgrades]. Upgrades not already activated may be modified or absent from [precompileUpgrades].
@@ -246,11 +278,49 @@ func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompi
246278 return nil
247279}
248280
281+ // CheckStateUpgradesCompatible checks if [stateUpgrades] are compatible with [c] at [headTimestamp].
282+ func (c * ChainConfig ) CheckStateUpgradesCompatible (stateUpgrades []StateUpgrade , lastTimestamp * big.Int ) * ConfigCompatError {
283+ // All active upgrades (from nil to [lastTimestamp]) must match.
284+ activeUpgrades := c .GetActivatingStateUpgrades (nil , lastTimestamp , c .StateUpgrades )
285+ newUpgrades := c .GetActivatingStateUpgrades (nil , lastTimestamp , stateUpgrades )
286+
287+ // Check activated upgrades are still present.
288+ for i , upgrade := range activeUpgrades {
289+ if len (newUpgrades ) <= i {
290+ // missing upgrade
291+ return newCompatError (
292+ fmt .Sprintf ("missing StateUpgrade[%d]" , i ),
293+ upgrade .BlockTimestamp ,
294+ nil ,
295+ )
296+ }
297+ // All upgrades that have activated must be identical.
298+ if ! upgrade .Equal (& newUpgrades [i ]) {
299+ return newCompatError (
300+ fmt .Sprintf ("StateUpgrade[%d]" , i ),
301+ upgrade .BlockTimestamp ,
302+ newUpgrades [i ].BlockTimestamp ,
303+ )
304+ }
305+ }
306+ // then, make sure newUpgrades does not have additional upgrades
307+ // that are already activated. (cannot perform retroactive upgrade)
308+ if len (newUpgrades ) > len (activeUpgrades ) {
309+ return newCompatError (
310+ fmt .Sprintf ("cannot retroactively enable StateUpgrade[%d]" , len (activeUpgrades )),
311+ nil ,
312+ newUpgrades [len (activeUpgrades )].BlockTimestamp , // this indexes to the first element in newUpgrades after the end of activeUpgrades
313+ )
314+ }
315+
316+ return nil
317+ }
318+
249319// EnabledStatefulPrecompiles returns current stateful precompile configs that are enabled at [blockTimestamp].
250320func (c * ChainConfig ) EnabledStatefulPrecompiles (blockTimestamp * big.Int ) Precompiles {
251321 statefulPrecompileConfigs := make (Precompiles )
252322 for _ , module := range modules .RegisteredModules () {
253- if config := c .GetActivePrecompileConfig (module .Address , blockTimestamp ); config != nil && ! config .IsDisabled () {
323+ if config := c .getActivePrecompileConfig (module .Address , blockTimestamp ); config != nil && ! config .IsDisabled () {
254324 statefulPrecompileConfigs [module .ConfigKey ] = config
255325 }
256326 }
0 commit comments