Skip to content

Commit 564a74c

Browse files
Ross Bulatggwpezgpestana
authored andcommitted
Reward pool migration fix (paritytech#13715)
* reward pool migration fix * comment * remove generic * rm max * foramtting * Add note to V4 migration Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Add more asserts to the V5 migration Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Make compile Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Update frame/nomination-pools/src/migration.rs Co-authored-by: Gonçalo Pestana <[email protected]> * Make V4 migration re-usable Otherwise it wont chain together with the V5. Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Add MigrateV3ToV5 wrapper Signed-off-by: Oliver Tale-Yazdi <[email protected]> --------- Signed-off-by: Oliver Tale-Yazdi <[email protected]> Co-authored-by: Oliver Tale-Yazdi <[email protected]> Co-authored-by: Gonçalo Pestana <[email protected]>
1 parent cfc3475 commit 564a74c

File tree

2 files changed

+161
-3
lines changed

2 files changed

+161
-3
lines changed

frame/nomination-pools/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ pub mod pallet {
14961496
use sp_runtime::Perbill;
14971497

14981498
/// The current storage version.
1499-
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
1499+
const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
15001500

15011501
#[pallet::pallet]
15021502
#[pallet::storage_version(STORAGE_VERSION)]

frame/nomination-pools/src/migration.rs

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)