diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 5c8b336ee3bd6..bc3cea9aebc01 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -22,34 +22,38 @@ use frame_support::{ traits::OnRuntimeUpgrade, }; -/// Used for release versioning upto v12. -/// -/// Obsolete from v13. Keeping around to make encoding/decoding of old migration code easier. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -enum ObsoleteReleases { - V1_0_0Ancient, - V2_0_0, - V3_0_0, - V4_0_0, - V5_0_0, // blockable validators. - V6_0_0, // removal of all storage associated with offchain phragmen. - V7_0_0, // keep track of number of nominators / validators in map - V8_0_0, // populate `VoterList`. - V9_0_0, // inject validators into `VoterList` as well. - V10_0_0, // remove `EarliestUnappliedSlash`. - V11_0_0, // Move pallet storage prefix, e.g. BagsList -> VoterBagsList - V12_0_0, // remove `HistoryDepth`. -} +mod obsolete { + use super::*; + /// Used for release versioning upto v12. + /// + /// Obsolete from v13. Keeping around to make encoding/decoding of old migration code easier. + #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub(super) enum Releases { + V1_0_0Ancient, + V2_0_0, + V3_0_0, + V4_0_0, + V5_0_0, // blockable validators. + V6_0_0, // removal of all storage associated with offchain phragmen. + V7_0_0, // keep track of number of nominators / validators in map + V8_0_0, // populate `VoterList`. + V9_0_0, // inject validators into `VoterList` as well. + V10_0_0, // remove `EarliestUnappliedSlash`. + V11_0_0, // Move pallet storage prefix, e.g. BagsList -> VoterBagsList + V12_0_0, // remove `HistoryDepth`. + } -impl Default for ObsoleteReleases { - fn default() -> Self { - ObsoleteReleases::V12_0_0 + impl Default for Releases { + fn default() -> Self { + Releases::V12_0_0 + } } + + /// Alias to the old storage item used for release versioning. Obsolete since v13. + #[storage_alias] + pub(super) type StorageVersion = StorageValue, Releases, ValueQuery>; } -/// Alias to the old storage item used for release versioning. Obsolete since v13. -#[storage_alias] -type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; pub mod v13 { use super::*; @@ -59,7 +63,7 @@ pub mod v13 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( - StorageVersion::::get() == ObsoleteReleases::V12_0_0, + StorageVersion::::get() == obsolete::Releases::V12_0_0, "Required v12 before upgrading to v13" ); @@ -68,10 +72,10 @@ pub mod v13 { fn on_runtime_upgrade() -> Weight { let current = Pallet::::current_storage_version(); - let onchain = StorageVersion::::get(); + let onchain = obsolete::StorageVersion::::get(); - if current == 13 && onchain == ObsoleteReleases::V12_0_0 { - StorageVersion::::kill(); + if current == 13 && onchain == obsolete::Releases::V12_0_0 { + obsolete::StorageVersion::::kill(); current.put::>(); log!(info, "v13 applied successfully"); @@ -115,7 +119,7 @@ pub mod v12 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( - StorageVersion::::get() == ObsoleteReleases::V11_0_0, + StorageVersion::::get() == obsolete::Releases::V11_0_0, "Expected v11 before upgrading to v12" ); @@ -132,9 +136,9 @@ pub mod v12 { } fn on_runtime_upgrade() -> frame_support::weights::Weight { - if StorageVersion::::get() == ObsoleteReleases::V11_0_0 { + if obsolete::StorageVersion::::get() == obsolete::Releases::V11_0_0 { HistoryDepth::::kill(); - StorageVersion::::put(ObsoleteReleases::V12_0_0); + obsolete::StorageVersion::::put(obsolete::Releases::V12_0_0); log!(info, "v12 applied successfully"); T::DbWeight::get().reads_writes(1, 2) @@ -147,7 +151,7 @@ pub mod v12 { #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), &'static str> { frame_support::ensure!( - StorageVersion::::get() == ObsoleteReleases::V12_0_0, + obsolete::StorageVersion::::get() == obsolete::Releases::V12_0_0, "v12 not applied" ); Ok(()) @@ -171,7 +175,7 @@ pub mod v11 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( - StorageVersion::::get() == ObsoleteReleases::V10_0_0, + obsolete::StorageVersion::::get() == obsolete::Releases::V10_0_0, "must upgrade linearly" ); let old_pallet_prefix = twox_128(N::get().as_bytes()); @@ -196,9 +200,9 @@ pub mod v11 { let old_pallet_name = N::get(); let new_pallet_name =

::name(); - if StorageVersion::::get() == ObsoleteReleases::V10_0_0 { + if obsolete::StorageVersion::::get() == obsolete::Releases::V10_0_0 { // bump version anyway, even if we don't need to move the prefix - StorageVersion::::put(ObsoleteReleases::V11_0_0); + obsolete::StorageVersion::::put(obsolete::Releases::V11_0_0); if new_pallet_name == old_pallet_name { log!( warn, @@ -218,7 +222,7 @@ pub mod v11 { #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), &'static str> { frame_support::ensure!( - StorageVersion::::get() == ObsoleteReleases::V11_0_0, + obsolete::StorageVersion::::get() == obsolete::Releases::V11_0_0, "wrong version after the upgrade" ); @@ -263,7 +267,7 @@ pub mod v10 { pub struct MigrateToV10(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV10 { fn on_runtime_upgrade() -> frame_support::weights::Weight { - if StorageVersion::::get() == ObsoleteReleases::V9_0_0 { + if obsolete::StorageVersion::::get() == obsolete::Releases::V9_0_0 { let pending_slashes = as Store>::UnappliedSlashes::iter().take(512); for (era, slashes) in pending_slashes { for slash in slashes { @@ -275,7 +279,7 @@ pub mod v10 { } EarliestUnappliedSlash::::kill(); - StorageVersion::::put(ObsoleteReleases::V10_0_0); + obsolete::StorageVersion::::put(obsolete::Releases::V10_0_0); log!(info, "MigrateToV10 executed successfully"); T::DbWeight::get().reads_writes(1, 1) @@ -287,217 +291,228 @@ pub mod v10 { } } -// These migrations have been commented out as they are no longer compatible with the current -// codebase. -// -// pub mod v9 { -// use super::*; -// #[cfg(feature = "try-runtime")] -// use frame_support::codec::{Decode, Encode}; -// #[cfg(feature = "try-runtime")] -// use sp_std::vec::Vec; -// -// /// Migration implementation that injects all validators into sorted list. -// /// -// /// This is only useful for chains that started their `VoterList` just based on nominators. -// pub struct InjectValidatorsIntoVoterList(sp_std::marker::PhantomData); -// impl OnRuntimeUpgrade for InjectValidatorsIntoVoterList { -// fn on_runtime_upgrade() -> Weight { -// if StorageVersion::::get() == ObsoleteReleases::V8_0_0 { -// let prev_count = T::VoterList::count(); -// let weight_of_cached = Pallet::::weight_of_fn(); -// for (v, _) in Validators::::iter() { -// let weight = weight_of_cached(&v); -// let _ = T::VoterList::on_insert(v.clone(), weight).map_err(|err| { -// log!(warn, "failed to insert {:?} into VoterList: {:?}", v, err) -// }); -// } -// -// log!( -// info, -// "injected a total of {} new voters, prev count: {} next count: {}, updating to version 9", -// Validators::::count(), -// prev_count, -// T::VoterList::count(), -// ); -// -// StorageVersion::::put(ObsoleteReleases::V9_0_0); -// T::BlockWeights::get().max_block -// } else { -// log!( -// warn, -// "InjectValidatorsIntoVoterList being executed on the wrong storage \ -// version, expected ObsoleteReleases::V8_0_0" -// ); -// T::DbWeight::get().reads(1) -// } -// } -// -// #[cfg(feature = "try-runtime")] -// fn pre_upgrade() -> Result, &'static str> { -// frame_support::ensure!( -// StorageVersion::::get() == ObsoleteReleases::V8_0_0, -// "must upgrade linearly" -// ); -// -// let prev_count = T::VoterList::count(); -// Ok(prev_count.encode()) -// } -// -// #[cfg(feature = "try-runtime")] -// fn post_upgrade(prev_count: Vec) -> Result<(), &'static str> { -// let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( -// "the state parameter should be something that was generated by pre_upgrade", -// ); -// let post_count = T::VoterList::count(); -// let validators = Validators::::count(); -// assert!(post_count == prev_count + validators); -// -// frame_support::ensure!( -// StorageVersion::::get() == ObsoleteReleases::V9_0_0, -// "must upgrade " -// ); -// Ok(()) -// } -// } -// } -// -// pub mod v8 { -// use super::*; -// use crate::{Config, Nominators, Pallet, Weight}; -// use frame_election_provider_support::SortedListProvider; -// use frame_support::traits::Get; -// -// #[cfg(feature = "try-runtime")] -// pub fn pre_migrate() -> Result<(), &'static str> { -// frame_support::ensure!( -// StorageVersion::::get() == ObsoleteReleases::V7_0_0, -// "must upgrade linearly" -// ); -// -// crate::log!(info, "👜 staking bags-list migration passes PRE migrate checks ✅",); -// Ok(()) -// } -// -// /// Migration to sorted `VoterList`. -// pub fn migrate() -> Weight { -// if StorageVersion::::get() == ObsoleteReleases::V7_0_0 { -// crate::log!(info, "migrating staking to ObsoleteReleases::V8_0_0"); -// -// let migrated = T::VoterList::unsafe_regenerate( -// Nominators::::iter().map(|(id, _)| id), -// Pallet::::weight_of_fn(), -// ); -// debug_assert_eq!(T::VoterList::try_state(), Ok(())); -// -// StorageVersion::::put(ObsoleteReleases::V8_0_0); -// crate::log!( -// info, -// "👜 completed staking migration to ObsoleteReleases::V8_0_0 with {} voters migrated", -// migrated, -// ); -// -// T::BlockWeights::get().max_block -// } else { -// T::DbWeight::get().reads(1) -// } -// } -// -// #[cfg(feature = "try-runtime")] -// pub fn post_migrate() -> Result<(), &'static str> { -// T::VoterList::try_state().map_err(|_| "VoterList is not in a sane state.")?; -// crate::log!(info, "👜 staking bags-list migration passes POST migrate checks ✅",); -// Ok(()) -// } -// } -// -// pub mod v7 { -// use super::*; -// use frame_support::storage_alias; -// -// #[storage_alias] -// type CounterForValidators = StorageValue, u32>; -// #[storage_alias] -// type CounterForNominators = StorageValue, u32>; -// -// pub fn pre_migrate() -> Result<(), &'static str> { -// assert!( -// CounterForValidators::::get().unwrap().is_zero(), -// "CounterForValidators already set." -// ); -// assert!( -// CounterForNominators::::get().unwrap().is_zero(), -// "CounterForNominators already set." -// ); -// assert!(Validators::::count().is_zero(), "Validators already set."); -// assert!(Nominators::::count().is_zero(), "Nominators already set."); -// assert!(StorageVersion::::get() == ObsoleteReleases::V6_0_0); -// Ok(()) -// } -// -// pub fn migrate() -> Weight { -// log!(info, "Migrating staking to ObsoleteReleases::V7_0_0"); -// let validator_count = Validators::::iter().count() as u32; -// let nominator_count = Nominators::::iter().count() as u32; -// -// CounterForValidators::::put(validator_count); -// CounterForNominators::::put(nominator_count); -// -// StorageVersion::::put(ObsoleteReleases::V7_0_0); -// log!(info, "Completed staking migration to ObsoleteReleases::V7_0_0"); -// -// T::DbWeight::get().reads_writes(validator_count.saturating_add(nominator_count).into(), 2) -// } -// } -// -// pub mod v6 { -// use super::*; -// use frame_support::{storage_alias, traits::Get, weights::Weight}; -// -// // NOTE: value type doesn't matter, we just set it to () here. -// #[storage_alias] -// type SnapshotValidators = StorageValue, ()>; -// #[storage_alias] -// type SnapshotNominators = StorageValue, ()>; -// #[storage_alias] -// type QueuedElected = StorageValue, ()>; -// #[storage_alias] -// type QueuedScore = StorageValue, ()>; -// #[storage_alias] -// type EraElectionStatus = StorageValue, ()>; -// #[storage_alias] -// type IsCurrentSessionFinal = StorageValue, ()>; -// -// /// check to execute prior to migration. -// pub fn pre_migrate() -> Result<(), &'static str> { -// // these may or may not exist. -// log!(info, "SnapshotValidators.exits()? {:?}", SnapshotValidators::::exists()); -// log!(info, "SnapshotNominators.exits()? {:?}", SnapshotNominators::::exists()); -// log!(info, "QueuedElected.exits()? {:?}", QueuedElected::::exists()); -// log!(info, "QueuedScore.exits()? {:?}", QueuedScore::::exists()); -// // these must exist. -// assert!( -// IsCurrentSessionFinal::::exists(), -// "IsCurrentSessionFinal storage item not found!" -// ); -// assert!(EraElectionStatus::::exists(), "EraElectionStatus storage item not found!"); -// Ok(()) -// } -// -// /// Migrate storage to v6. -// pub fn migrate() -> Weight { -// log!(info, "Migrating staking to ObsoleteReleases::V6_0_0"); -// -// SnapshotValidators::::kill(); -// SnapshotNominators::::kill(); -// QueuedElected::::kill(); -// QueuedScore::::kill(); -// EraElectionStatus::::kill(); -// IsCurrentSessionFinal::::kill(); -// -// StorageVersion::::put(ObsoleteReleases::V6_0_0); -// -// log!(info, "Done."); -// T::DbWeight::get().writes(6 + 1) -// } -// } +pub mod v9 { + use super::*; + #[cfg(feature = "try-runtime")] + use frame_support::codec::{Decode, Encode}; + #[cfg(feature = "try-runtime")] + use sp_std::vec::Vec; + use frame_election_provider_support::{SortedListProvider, ReadOnlySortedListProvider}; + + pub trait MigrationConfig { + type Config: Config; + type VoterList: frame_election_provider_support::SortedListProvider< + ::AccountId, + Score = u64 + >; + } + + /// Migration implementation that injects all validators into sorted list. + /// + /// This is only useful for chains that started their `VoterList` just based on nominators. + pub struct InjectValidatorsIntoVoterList(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for InjectValidatorsIntoVoterList { + fn on_runtime_upgrade() -> Weight { + if obsolete::StorageVersion::::get() == obsolete::Releases::V8_0_0 { + let prev_count = T::VoterList::count(); + let weight_of_cached = Pallet::::weight_of_fn(); + for (v, _) in Validators::::iter() { + let weight = weight_of_cached(&v); + let _ = T::VoterList::on_insert(v.clone(), weight).map_err(|err| { + frame_support::log::warn!("failed to insert {:?} into VoterList: {:?}", v, err) + }); + } + + frame_support::log::info!( + "injected a total of {} new voters, prev count: {} next count: {}, updating to version 9", + Validators::::count(), + prev_count, + T::VoterList::count(), + ); + + obsolete::StorageVersion::::put(obsolete::Releases::V9_0_0); + ::BlockWeights::get().max_block + } else { + frame_support::log::warn!( + "InjectValidatorsIntoVoterList being executed on the wrong storage \ + version, expected obsolete::Releases::V8_0_0" + ); + ::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + obsolete::StorageVersion::::get() == obsolete::Releases::V8_0_0, + "must upgrade linearly" + ); + + let prev_count = T::VoterList::count(); + Ok(prev_count.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev_count: Vec) -> Result<(), &'static str> { + let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); + let post_count = T::VoterList::count(); + let validators = Validators::::count(); + assert!(post_count == prev_count + validators); + + frame_support::ensure!( + obsolete::StorageVersion::::get() == obsolete::Releases::V9_0_0, + "must upgrade " + ); + Ok(()) + } + } +} + +pub mod v8 { + use super::*; + use crate::{Config, Nominators, Pallet, Weight}; + use frame_election_provider_support::{SortedListProvider, ReadOnlySortedListProvider}; + use frame_support::traits::Get; + + pub trait MigrationConfig { + type Config: Config; + type VoterList: frame_election_provider_support::SortedListProvider< + ::AccountId, + Score = u64 + >; + } + + #[cfg(feature = "try-runtime")] + pub fn pre_migrate() -> Result<(), &'static str> { + frame_support::ensure!( + obsolete::StorageVersion::::get() == obsolete::Releases::V7_0_0, + "must upgrade linearly" + ); + + crate::log!(info, "👜 staking bags-list migration passes PRE migrate checks ✅",); + Ok(()) + } + + /// Migration to sorted `VoterList`. + pub fn migrate() -> Weight { + if obsolete::StorageVersion::::get() == obsolete::Releases::V7_0_0 { + frame_support::log::info!("migrating staking to obsolete::Releases::V8_0_0"); + + let migrated = T::VoterList::unsafe_regenerate( + Nominators::::iter().map(|(id, _)| id), + Pallet::::weight_of_fn(), + ); + debug_assert_eq!(T::VoterList::try_state(), Ok(())); + + obsolete::StorageVersion::::put(obsolete::Releases::V8_0_0); + frame_support::log::info!( + "👜 completed staking migration to obsolete::Releases::V8_0_0 with {} voters migrated", + migrated, + ); + + ::BlockWeights::get().max_block + } else { + ::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + pub fn post_migrate() -> Result<(), &'static str> { + T::VoterList::try_state().map_err(|_| "VoterList is not in a sane state.")?; + crate::log!(info, "👜 staking bags-list migration passes POST migrate checks ✅",); + Ok(()) + } +} + +pub mod v7 { + use super::*; + use frame_support::storage_alias; + + #[storage_alias] + type CounterForValidators = StorageValue, u32>; + #[storage_alias] + type CounterForNominators = StorageValue, u32>; + + pub fn pre_migrate() -> Result<(), &'static str> { + assert!( + CounterForValidators::::get().unwrap().is_zero(), + "CounterForValidators already set." + ); + assert!( + CounterForNominators::::get().unwrap().is_zero(), + "CounterForNominators already set." + ); + assert!(Validators::::count().is_zero(), "Validators already set."); + assert!(Nominators::::count().is_zero(), "Nominators already set."); + assert!(obsolete::StorageVersion::::get() == obsolete::Releases::V6_0_0); + Ok(()) + } + + pub fn migrate() -> Weight { + log!(info, "Migrating staking to obsolete::Releases::V7_0_0"); + let validator_count = Validators::::iter().count() as u32; + let nominator_count = Nominators::::iter().count() as u32; + + CounterForValidators::::put(validator_count); + CounterForNominators::::put(nominator_count); + + obsolete::StorageVersion::::put(obsolete::Releases::V7_0_0); + log!(info, "Completed staking migration to obsolete::Releases::V7_0_0"); + + T::DbWeight::get().reads_writes(validator_count.saturating_add(nominator_count).into(), 2) + } +} + +pub mod v6 { + use super::*; + use frame_support::{storage_alias, traits::Get, weights::Weight}; + + // NOTE: value type doesn't matter, we just set it to () here. + #[storage_alias] + type SnapshotValidators = StorageValue, ()>; + #[storage_alias] + type SnapshotNominators = StorageValue, ()>; + #[storage_alias] + type QueuedElected = StorageValue, ()>; + #[storage_alias] + type QueuedScore = StorageValue, ()>; + #[storage_alias] + type EraElectionStatus = StorageValue, ()>; + #[storage_alias] + type IsCurrentSessionFinal = StorageValue, ()>; + + /// check to execute prior to migration. + pub fn pre_migrate() -> Result<(), &'static str> { + // these may or may not exist. + log!(info, "SnapshotValidators.exits()? {:?}", SnapshotValidators::::exists()); + log!(info, "SnapshotNominators.exits()? {:?}", SnapshotNominators::::exists()); + log!(info, "QueuedElected.exits()? {:?}", QueuedElected::::exists()); + log!(info, "QueuedScore.exits()? {:?}", QueuedScore::::exists()); + // these must exist. + assert!( + IsCurrentSessionFinal::::exists(), + "IsCurrentSessionFinal storage item not found!" + ); + assert!(EraElectionStatus::::exists(), "EraElectionStatus storage item not found!"); + Ok(()) + } + + /// Migrate storage to v6. + pub fn migrate() -> Weight { + log!(info, "Migrating staking to obsolete::Releases::V6_0_0"); + + SnapshotValidators::::kill(); + SnapshotNominators::::kill(); + QueuedElected::::kill(); + QueuedScore::::kill(); + EraElectionStatus::::kill(); + IsCurrentSessionFinal::::kill(); + + obsolete::StorageVersion::::put(obsolete::Releases::V6_0_0); + + log!(info, "Done."); + T::DbWeight::get().writes(6 + 1) + } +}