@@ -478,9 +478,22 @@ pub mod v4 {
478478 }
479479 }
480480
481+ /// Migrates from `v3` directly to `v5` to avoid the broken `v4` migration.
482+ #[ allow( deprecated) ]
483+ pub type MigrateV3ToV5 < T , U > = ( v4:: MigrateToV4 < T , U > , v5:: MigrateToV5 < T > ) ;
484+
485+ /// # Warning
486+ ///
487+ /// To avoid mangled storage please use `MigrateV3ToV5` instead.
488+ /// See: github.com/paritytech/substrate/pull/13715
489+ ///
481490 /// This migration adds a `commission` field to every `BondedPoolInner`, if
482491 /// any.
492+ #[ deprecated(
493+ note = "To avoid mangled storage please use `MigrateV3ToV5` instead. See: github.com/paritytech/substrate/pull/13715"
494+ ) ]
483495 pub struct MigrateToV4 < T , U > ( sp_std:: marker:: PhantomData < ( T , U ) > ) ;
496+ #[ allow( deprecated) ]
484497 impl < T : Config , U : Get < Perbill > > OnRuntimeUpgrade for MigrateToV4 < T , U > {
485498 fn on_runtime_upgrade ( ) -> Weight {
486499 let current = Pallet :: < T > :: current_storage_version ( ) ;
@@ -493,7 +506,8 @@ pub mod v4 {
493506 onchain
494507 ) ;
495508
496- if current == 4 && onchain == 3 {
509+ if onchain == 3 {
510+ log ! ( warn, "Please run MigrateToV5 immediately after this migration. See github.com/paritytech/substrate/pull/13715" ) ;
497511 let initial_global_max_commission = U :: get ( ) ;
498512 GlobalMaxCommission :: < T > :: set ( Some ( initial_global_max_commission) ) ;
499513 log ! (
@@ -508,7 +522,7 @@ pub mod v4 {
508522 Some ( old_value. migrate_to_v4 ( ) )
509523 } ) ;
510524
511- current . put :: < Pallet < T > > ( ) ;
525+ StorageVersion :: new ( 4 ) . put :: < Pallet < T > > ( ) ;
512526 log ! ( info, "Upgraded {} pools, storage to version {:?}" , translated, current) ;
513527
514528 // reads: translated + onchain version.
@@ -548,3 +562,147 @@ pub mod v4 {
548562 }
549563 }
550564}
565+
566+ pub mod v5 {
567+ use super :: * ;
568+
569+ #[ derive( Decode ) ]
570+ pub struct OldRewardPool < T : Config > {
571+ last_recorded_reward_counter : T :: RewardCounter ,
572+ last_recorded_total_payouts : BalanceOf < T > ,
573+ total_rewards_claimed : BalanceOf < T > ,
574+ }
575+
576+ impl < T : Config > OldRewardPool < T > {
577+ fn migrate_to_v5 ( self ) -> RewardPool < T > {
578+ RewardPool {
579+ last_recorded_reward_counter : self . last_recorded_reward_counter ,
580+ last_recorded_total_payouts : self . last_recorded_total_payouts ,
581+ total_rewards_claimed : self . total_rewards_claimed ,
582+ total_commission_pending : Zero :: zero ( ) ,
583+ total_commission_claimed : Zero :: zero ( ) ,
584+ }
585+ }
586+ }
587+
588+ /// This migration adds `total_commission_pending` and `total_commission_claimed` field to every
589+ /// `RewardPool`, if any.
590+ pub struct MigrateToV5 < T > ( sp_std:: marker:: PhantomData < T > ) ;
591+ impl < T : Config > OnRuntimeUpgrade for MigrateToV5 < T > {
592+ fn on_runtime_upgrade ( ) -> Weight {
593+ let current = Pallet :: < T > :: current_storage_version ( ) ;
594+ let onchain = Pallet :: < T > :: on_chain_storage_version ( ) ;
595+
596+ log ! (
597+ info,
598+ "Running migration with current storage version {:?} / onchain {:?}" ,
599+ current,
600+ onchain
601+ ) ;
602+
603+ if current == 5 && onchain == 4 {
604+ let mut translated = 0u64 ;
605+ RewardPools :: < T > :: translate :: < OldRewardPool < T > , _ > ( |_id, old_value| {
606+ translated. saturating_inc ( ) ;
607+ Some ( old_value. migrate_to_v5 ( ) )
608+ } ) ;
609+
610+ current. put :: < Pallet < T > > ( ) ;
611+ log ! ( info, "Upgraded {} pools, storage to version {:?}" , translated, current) ;
612+
613+ // reads: translated + onchain version.
614+ // writes: translated + current.put.
615+ T :: DbWeight :: get ( ) . reads_writes ( translated + 1 , translated + 1 )
616+ } else {
617+ log ! ( info, "Migration did not execute. This probably should be removed" ) ;
618+ T :: DbWeight :: get ( ) . reads ( 1 )
619+ }
620+ }
621+
622+ #[ cfg( feature = "try-runtime" ) ]
623+ fn pre_upgrade ( ) -> Result < Vec < u8 > , & ' static str > {
624+ ensure ! (
625+ Pallet :: <T >:: current_storage_version( ) > Pallet :: <T >:: on_chain_storage_version( ) ,
626+ "the on_chain version is equal or more than the current one"
627+ ) ;
628+
629+ let rpool_keys = RewardPools :: < T > :: iter_keys ( ) . count ( ) ;
630+ let rpool_values = RewardPools :: < T > :: iter_values ( ) . count ( ) ;
631+ if rpool_keys != rpool_values {
632+ log ! ( info, "🔥 There are {} undecodable RewardPools in storage. This migration will try to correct them. keys: {}, values: {}" , rpool_keys. saturating_sub( rpool_values) , rpool_keys, rpool_values) ;
633+ }
634+
635+ ensure ! (
636+ PoolMembers :: <T >:: iter_keys( ) . count( ) == PoolMembers :: <T >:: iter_values( ) . count( ) ,
637+ "There are undecodable PoolMembers in storage. This migration will not fix that."
638+ ) ;
639+ ensure ! (
640+ BondedPools :: <T >:: iter_keys( ) . count( ) == BondedPools :: <T >:: iter_values( ) . count( ) ,
641+ "There are undecodable BondedPools in storage. This migration will not fix that."
642+ ) ;
643+ ensure ! (
644+ SubPoolsStorage :: <T >:: iter_keys( ) . count( ) ==
645+ SubPoolsStorage :: <T >:: iter_values( ) . count( ) ,
646+ "There are undecodable SubPools in storage. This migration will not fix that."
647+ ) ;
648+ ensure ! (
649+ Metadata :: <T >:: iter_keys( ) . count( ) == Metadata :: <T >:: iter_values( ) . count( ) ,
650+ "There are undecodable Metadata in storage. This migration will not fix that."
651+ ) ;
652+
653+ Ok ( ( rpool_values as u64 ) . encode ( ) )
654+ }
655+
656+ #[ cfg( feature = "try-runtime" ) ]
657+ fn post_upgrade ( data : Vec < u8 > ) -> Result < ( ) , & ' static str > {
658+ let old_rpool_values: u64 = Decode :: decode ( & mut & data[ ..] ) . unwrap ( ) ;
659+ let rpool_keys = RewardPools :: < T > :: iter_keys ( ) . count ( ) as u64 ;
660+ let rpool_values = RewardPools :: < T > :: iter_values ( ) . count ( ) as u64 ;
661+ ensure ! (
662+ rpool_keys == rpool_values,
663+ "There are STILL undecodable RewardPools - migration failed"
664+ ) ;
665+
666+ if old_rpool_values != rpool_values {
667+ log ! (
668+ info,
669+ "🎉 Fixed {} undecodable RewardPools." ,
670+ rpool_values. saturating_sub( old_rpool_values)
671+ ) ;
672+ }
673+
674+ // ensure all RewardPools items now contain `total_commission_pending` and
675+ // `total_commission_claimed` field.
676+ ensure ! (
677+ RewardPools :: <T >:: iter( ) . all( |( _, reward_pool) | reward_pool
678+ . total_commission_pending
679+ . is_zero( ) && reward_pool
680+ . total_commission_claimed
681+ . is_zero( ) ) ,
682+ "a commission value has been incorrectly set"
683+ ) ;
684+ ensure ! ( Pallet :: <T >:: on_chain_storage_version( ) == 5 , "wrong storage version" ) ;
685+
686+ // These should not have been touched - just in case.
687+ ensure ! (
688+ PoolMembers :: <T >:: iter_keys( ) . count( ) == PoolMembers :: <T >:: iter_values( ) . count( ) ,
689+ "There are undecodable PoolMembers in storage."
690+ ) ;
691+ ensure ! (
692+ BondedPools :: <T >:: iter_keys( ) . count( ) == BondedPools :: <T >:: iter_values( ) . count( ) ,
693+ "There are undecodable BondedPools in storage."
694+ ) ;
695+ ensure ! (
696+ SubPoolsStorage :: <T >:: iter_keys( ) . count( ) ==
697+ SubPoolsStorage :: <T >:: iter_values( ) . count( ) ,
698+ "There are undecodable SubPools in storage."
699+ ) ;
700+ ensure ! (
701+ Metadata :: <T >:: iter_keys( ) . count( ) == Metadata :: <T >:: iter_values( ) . count( ) ,
702+ "There are undecodable Metadata in storage."
703+ ) ;
704+
705+ Ok ( ( ) )
706+ }
707+ }
708+ }
0 commit comments