@@ -58,6 +58,7 @@ use sp_runtime::{
5858} ;
5959
6060pub mod bls12_381;
61+ pub mod migrations;
6162pub mod types;
6263pub mod utils;
6364pub mod verifier;
@@ -91,6 +92,8 @@ pub const QUICKNET_CHAIN_HASH: &str =
9192const CHAIN_HASH : & str = QUICKNET_CHAIN_HASH ;
9293
9394pub const MAX_PULSES_TO_FETCH : u64 = 50 ;
95+ pub const MAX_KEPT_PULSES : u64 = 216_000 ; // 1 week
96+ pub const MAX_REMOVED_PULSES : u64 = 100 ;
9497
9598/// Defines application identifier for crypto keys of this module.
9699///
@@ -212,12 +215,24 @@ pub mod pallet {
212215 }
213216 }
214217
218+ /// Define a maximum length for the migration key
219+ type MigrationKeyMaxLen = ConstU32 < 128 > ;
220+
221+ /// Storage for migration run status
222+ #[ pallet:: storage]
223+ pub type HasMigrationRun < T : Config > =
224+ StorageMap < _ , Identity , BoundedVec < u8 , MigrationKeyMaxLen > , bool , ValueQuery > ;
225+
215226 /// map round number to pulse
216227 #[ pallet:: storage]
217228 pub type Pulses < T : Config > = StorageMap < _ , Blake2_128Concat , RoundNumber , Pulse , OptionQuery > ;
218229
219230 #[ pallet:: storage]
220- pub ( super ) type LastStoredRound < T : Config > = StorageValue < _ , RoundNumber , ValueQuery > ;
231+ pub type LastStoredRound < T : Config > = StorageValue < _ , RoundNumber , ValueQuery > ;
232+
233+ /// oldest stored round
234+ #[ pallet:: storage]
235+ pub type OldestStoredRound < T : Config > = StorageValue < _ , RoundNumber , ValueQuery > ;
221236
222237 /// Defines the block when next unsigned transaction will be accepted.
223238 ///
@@ -261,6 +276,13 @@ pub mod pallet {
261276 log:: debug!( "Drand: Failed to fetch pulse from drand. {e:?}" ) ;
262277 }
263278 }
279+ fn on_runtime_upgrade ( ) -> frame_support:: weights:: Weight {
280+ let mut weight = frame_support:: weights:: Weight :: from_parts ( 0 , 0 ) ;
281+
282+ weight = weight. saturating_add ( migrations:: migrate_set_oldest_round :: < T > ( ) ) ;
283+
284+ weight
285+ }
264286 }
265287
266288 #[ pallet:: validate_unsigned]
@@ -308,8 +330,8 @@ pub mod pallet {
308330 /// Verify and write a pulse from the beacon into the runtime
309331 #[ pallet:: call_index( 0 ) ]
310332 #[ pallet:: weight( Weight :: from_parts( 5_708_000_000 , 0 )
311- . saturating_add( T :: DbWeight :: get( ) . reads( 2_u64 ) )
312- . saturating_add( T :: DbWeight :: get( ) . writes( 3_u64 ) ) ) ]
333+ . saturating_add( T :: DbWeight :: get( ) . reads( 3_u64 ) )
334+ . saturating_add( T :: DbWeight :: get( ) . writes( 4_u64 ) ) ) ]
313335 pub fn write_pulse (
314336 origin : OriginFor < T > ,
315337 pulses_payload : PulsesPayload < T :: Public , BlockNumberFor < T > > ,
@@ -321,6 +343,10 @@ pub mod pallet {
321343 let mut last_stored_round = LastStoredRound :: < T > :: get ( ) ;
322344 let mut new_rounds = Vec :: new ( ) ;
323345
346+ let oldest_stored_round = OldestStoredRound :: < T > :: get ( ) ;
347+ let is_first_storage = last_stored_round == 0 && oldest_stored_round == 0 ;
348+ let mut first_new_round: Option < RoundNumber > = None ;
349+
324350 for pulse in & pulses_payload. pulses {
325351 let is_verified = T :: Verifier :: verify ( config. clone ( ) , pulse. clone ( ) )
326352 . map_err ( |_| Error :: < T > :: PulseVerificationError ) ?;
@@ -339,12 +365,25 @@ pub mod pallet {
339365
340366 // Collect the new round
341367 new_rounds. push ( pulse. round ) ;
368+
369+ // Set the first new round if this is the initial storage
370+ if is_first_storage && first_new_round. is_none ( ) {
371+ first_new_round = Some ( pulse. round ) ;
372+ }
342373 }
343374 }
344375
345376 // Update LastStoredRound storage
346377 LastStoredRound :: < T > :: put ( last_stored_round) ;
347378
379+ // Set OldestStoredRound if this was the first storage
380+ if let Some ( first_round) = first_new_round {
381+ OldestStoredRound :: < T > :: put ( first_round) ;
382+ }
383+
384+ // Prune old pulses
385+ Self :: prune_old_pulses ( last_stored_round) ;
386+
348387 // Update the next unsigned block number
349388 let current_block = frame_system:: Pallet :: < T > :: block_number ( ) ;
350389 <NextUnsignedAt < T > >:: put ( current_block) ;
@@ -628,6 +667,24 @@ impl<T: Config> Pallet<T> {
628667 . propagate ( true )
629668 . build ( )
630669 }
670+
671+ fn prune_old_pulses ( last_stored_round : RoundNumber ) {
672+ let mut oldest = OldestStoredRound :: < T > :: get ( ) ;
673+ if oldest == 0 {
674+ return ;
675+ }
676+
677+ let mut removed: u64 = 0 ;
678+ while last_stored_round. saturating_sub ( oldest) . saturating_add ( 1 ) > MAX_KEPT_PULSES
679+ && removed < MAX_REMOVED_PULSES
680+ {
681+ Pulses :: < T > :: remove ( oldest) ;
682+ oldest = oldest. saturating_add ( 1 ) ;
683+ removed = removed. saturating_add ( 1 ) ;
684+ }
685+
686+ OldestStoredRound :: < T > :: put ( oldest) ;
687+ }
631688}
632689
633690/// construct a message (e.g. signed by drand)
0 commit comments