@@ -149,18 +149,38 @@ func (c *ChainConfig) verifyPrecompileUpgrades() error {
149
149
return nil
150
150
}
151
151
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].
153
173
// 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 {
155
175
configs := c .GetActivatingPrecompileConfigs (address , nil , blockTimestamp , c .PrecompileUpgrades )
156
176
if len (configs ) == 0 {
157
177
return nil
158
178
}
159
179
return configs [len (configs )- 1 ] // return the most recent config
160
180
}
161
181
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].
164
184
func (c * ChainConfig ) GetActivatingPrecompileConfigs (address common.Address , from * big.Int , to * big.Int , upgrades []PrecompileUpgrade ) []precompileconfig.Config {
165
185
// Get key from address.
166
186
module , ok := modules .GetPrecompileModuleByAddress (address )
@@ -188,6 +208,18 @@ func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, fro
188
208
return configs
189
209
}
190
210
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
+
191
223
// CheckPrecompilesCompatible checks if [precompileUpgrades] are compatible with [c] at [headTimestamp].
192
224
// Returns a ConfigCompatError if upgrades already activated at [headTimestamp] are missing from
193
225
// [precompileUpgrades]. Upgrades not already activated may be modified or absent from [precompileUpgrades].
@@ -246,11 +278,49 @@ func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompi
246
278
return nil
247
279
}
248
280
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
+
249
319
// EnabledStatefulPrecompiles returns current stateful precompile configs that are enabled at [blockTimestamp].
250
320
func (c * ChainConfig ) EnabledStatefulPrecompiles (blockTimestamp * big.Int ) Precompiles {
251
321
statefulPrecompileConfigs := make (Precompiles )
252
322
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 () {
254
324
statefulPrecompileConfigs [module .ConfigKey ] = config
255
325
}
256
326
}
0 commit comments