Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Use #[pallet::storage_version] for pallet staking #12728

Merged
merged 15 commits into from
Jan 3, 2023
Merged
2 changes: 1 addition & 1 deletion frame/election-provider-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ pub trait ElectionProviderBase {
if desired_targets <= Self::MaxWinners::get() {
Ok(desired_targets)
} else {
Err("desired_targets should not be greater than MaxWinners")
Err("desired_targets should never be greater than MaxWinners")
},
Err(e) => Err(e),
}
Expand Down
25 changes: 0 additions & 25 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,31 +881,6 @@ impl Default for Forcing {
}
}

// A value placed in storage that represents the current version of the Staking storage. This value
// is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic.
// This should match directly with the semantic versions of the Rust crate.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
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 Releases {
fn default() -> Self {
Releases::V11_0_0
}
}

/// A `Convert` implementation that finds the stash of the given controller account,
/// if any.
pub struct StashOf<T>(sp_std::marker::PhantomData<T>);
Expand Down
136 changes: 108 additions & 28 deletions frame/staking/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,85 @@

use super::*;
use frame_election_provider_support::SortedListProvider;
use frame_support::traits::OnRuntimeUpgrade;
use frame_support::{
dispatch::GetStorageVersion, pallet_prelude::ValueQuery, storage_alias,
traits::OnRuntimeUpgrade,
};

/// Outdated since v12. Useful 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`.
}

impl Default for ObsoleteReleases {
fn default() -> Self {
ObsoleteReleases::V12_0_0
}
}

/// Alias to the old storage item for keeping versions. Outdated since v12.
#[storage_alias]
type StorageVersion<T: Config> = StorageValue<Pallet<T>, ObsoleteReleases, ValueQuery>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be scoped in v13?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its used in all migrations prior to v13. May be we should get rid of old migrations (unless you see a reason to keep them) and keep it scoped only in v13?


pub mod v13 {
use super::*;

pub struct MigrateToV13<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV13<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V12_0_0,
"Required v12 before upgrading to v13"
);

Ok(Default::default())
}

fn on_runtime_upgrade() -> Weight {
let current = Pallet::<T>::current_storage_version();
let onchain = StorageVersion::<T>::get();

if current == 13 && onchain == ObsoleteReleases::V12_0_0 {
StorageVersion::<T>::kill();
current.put::<Pallet<T>>();

log!(info, "v13 applied successfully");
T::DbWeight::get().reads_writes(1, 2)
} else {
log!(warn, "Skipping v13, should be removed");
melekes marked this conversation as resolved.
Show resolved Hide resolved
T::DbWeight::get().reads(1)
}
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
frame_support::ensure!(
Pallet::<T>::on_chain_storage_version() == 13,
"v13 not applied"
);

frame_support::ensure!(
!StorageVersion::<T>::exists(),
"Storage version not migrated correctly"
);

Ok(())
}
}
}

pub mod v12 {
use super::*;
Expand All @@ -36,7 +114,7 @@ pub mod v12 {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == Releases::V11_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V11_0_0,
"Expected v11 before upgrading to v12"
);

Expand All @@ -53,9 +131,9 @@ pub mod v12 {
}

fn on_runtime_upgrade() -> frame_support::weights::Weight {
if StorageVersion::<T>::get() == Releases::V11_0_0 {
if StorageVersion::<T>::get() == ObsoleteReleases::V11_0_0 {
HistoryDepth::<T>::kill();
StorageVersion::<T>::put(Releases::V12_0_0);
StorageVersion::<T>::put(ObsoleteReleases::V12_0_0);

log!(info, "v12 applied successfully");
T::DbWeight::get().reads_writes(1, 2)
Expand All @@ -68,7 +146,7 @@ pub mod v12 {
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V12_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V12_0_0,
"v12 not applied"
);
Ok(())
Expand All @@ -92,7 +170,7 @@ pub mod v11 {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V10_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V10_0_0,
"must upgrade linearly"
);
let old_pallet_prefix = twox_128(N::get().as_bytes());
Expand All @@ -117,9 +195,9 @@ pub mod v11 {
let old_pallet_name = N::get();
let new_pallet_name = <P as PalletInfoAccess>::name();

if StorageVersion::<T>::get() == Releases::V10_0_0 {
if StorageVersion::<T>::get() == ObsoleteReleases::V10_0_0 {
// bump version anyway, even if we don't need to move the prefix
StorageVersion::<T>::put(Releases::V11_0_0);
StorageVersion::<T>::put(ObsoleteReleases::V11_0_0);
if new_pallet_name == old_pallet_name {
log!(
warn,
Expand All @@ -139,7 +217,7 @@ pub mod v11 {
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V11_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V11_0_0,
"wrong version after the upgrade"
);

Expand Down Expand Up @@ -184,7 +262,7 @@ pub mod v10 {
pub struct MigrateToV10<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV10<T> {
fn on_runtime_upgrade() -> frame_support::weights::Weight {
if StorageVersion::<T>::get() == Releases::V9_0_0 {
if StorageVersion::<T>::get() == ObsoleteReleases::V9_0_0 {
let pending_slashes = <Pallet<T> as Store>::UnappliedSlashes::iter().take(512);
for (era, slashes) in pending_slashes {
for slash in slashes {
Expand All @@ -196,7 +274,7 @@ pub mod v10 {
}

EarliestUnappliedSlash::<T>::kill();
StorageVersion::<T>::put(Releases::V10_0_0);
StorageVersion::<T>::put(ObsoleteReleases::V10_0_0);

log!(info, "MigrateToV10 executed successfully");
T::DbWeight::get().reads_writes(1, 1)
Expand All @@ -221,7 +299,7 @@ pub mod v9 {
pub struct InjectValidatorsIntoVoterList<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for InjectValidatorsIntoVoterList<T> {
fn on_runtime_upgrade() -> Weight {
if StorageVersion::<T>::get() == Releases::V8_0_0 {
if StorageVersion::<T>::get() == ObsoleteReleases::V8_0_0 {
let prev_count = T::VoterList::count();
let weight_of_cached = Pallet::<T>::weight_of_fn();
for (v, _) in Validators::<T>::iter() {
Expand All @@ -239,13 +317,13 @@ pub mod v9 {
T::VoterList::count(),
);

StorageVersion::<T>::put(crate::Releases::V9_0_0);
StorageVersion::<T>::put(ObsoleteReleases::V9_0_0);
T::BlockWeights::get().max_block
} else {
log!(
warn,
"InjectValidatorsIntoVoterList being executed on the wrong storage \
version, expected Releases::V8_0_0"
version, expected OldReleases::V8_0_0"
Ank4n marked this conversation as resolved.
Show resolved Hide resolved
);
T::DbWeight::get().reads(1)
}
Expand All @@ -254,7 +332,7 @@ pub mod v9 {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V8_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V8_0_0,
"must upgrade linearly"
);

Expand All @@ -272,7 +350,7 @@ pub mod v9 {
assert!(post_count == prev_count + validators);

frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V9_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V9_0_0,
"must upgrade "
);
Ok(())
Expand All @@ -281,14 +359,15 @@ pub mod v9 {
}

pub mod v8 {
use crate::{Config, Nominators, Pallet, StorageVersion, Weight};
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<T: Config>() -> Result<(), &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V7_0_0,
StorageVersion::<T>::get() == ObsoleteReleases::V7_0_0,
"must upgrade linearly"
);

Expand All @@ -298,19 +377,19 @@ pub mod v8 {

/// Migration to sorted `VoterList`.
pub fn migrate<T: Config>() -> Weight {
if StorageVersion::<T>::get() == crate::Releases::V7_0_0 {
crate::log!(info, "migrating staking to Releases::V8_0_0");
if StorageVersion::<T>::get() == ObsoleteReleases::V7_0_0 {
crate::log!(info, "migrating staking to OldReleases::V8_0_0");

let migrated = T::VoterList::unsafe_regenerate(
Nominators::<T>::iter().map(|(id, _)| id),
Pallet::<T>::weight_of_fn(),
);
debug_assert_eq!(T::VoterList::try_state(), Ok(()));

StorageVersion::<T>::put(crate::Releases::V8_0_0);
StorageVersion::<T>::put(ObsoleteReleases::V8_0_0);
crate::log!(
info,
"👜 completed staking migration to Releases::V8_0_0 with {} voters migrated",
"👜 completed staking migration to OldReleases::V8_0_0 with {} voters migrated",
migrated,
);

Expand Down Expand Up @@ -348,20 +427,20 @@ pub mod v7 {
);
assert!(Validators::<T>::count().is_zero(), "Validators already set.");
assert!(Nominators::<T>::count().is_zero(), "Nominators already set.");
assert!(StorageVersion::<T>::get() == Releases::V6_0_0);
assert!(StorageVersion::<T>::get() == ObsoleteReleases::V6_0_0);
Ok(())
}

pub fn migrate<T: Config>() -> Weight {
log!(info, "Migrating staking to Releases::V7_0_0");
log!(info, "Migrating staking to OldReleases::V7_0_0");
let validator_count = Validators::<T>::iter().count() as u32;
let nominator_count = Nominators::<T>::iter().count() as u32;

CounterForValidators::<T>::put(validator_count);
CounterForNominators::<T>::put(nominator_count);

StorageVersion::<T>::put(Releases::V7_0_0);
log!(info, "Completed staking migration to Releases::V7_0_0");
StorageVersion::<T>::put(ObsoleteReleases::V7_0_0);
log!(info, "Completed staking migration to OldReleases::V7_0_0");

T::DbWeight::get().reads_writes(validator_count.saturating_add(nominator_count).into(), 2)
}
Expand Down Expand Up @@ -403,7 +482,7 @@ pub mod v6 {

/// Migrate storage to v6.
pub fn migrate<T: Config>() -> Weight {
log!(info, "Migrating staking to Releases::V6_0_0");
log!(info, "Migrating staking to OldReleases::V6_0_0");

SnapshotValidators::<T>::kill();
SnapshotNominators::<T>::kill();
Expand All @@ -412,7 +491,8 @@ pub mod v6 {
EraElectionStatus::<T>::kill();
IsCurrentSessionFinal::<T>::kill();

StorageVersion::<T>::put(Releases::V6_0_0);
StorageVersion::<T>::put(ObsoleteReleases::V6_0_0);

log!(info, "Done.");
T::DbWeight::get().writes(6 + 1)
}
Expand Down
14 changes: 5 additions & 9 deletions frame/staking/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub use impls::*;
use crate::{
slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout,
EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf,
Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
ValidatorPrefs,
};

Expand All @@ -60,8 +60,12 @@ pub mod pallet {

use super::*;

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(13);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically we could have started from 0 as well, but whatever :P

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically yes :). But may be still nice to convey this is the 13th migration. 😉


#[pallet::pallet]
#[pallet::generate_store(pub(crate) trait Store)]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);

/// Possible operations on the configuration values of this pallet.
Expand Down Expand Up @@ -552,13 +556,6 @@ pub mod pallet {
#[pallet::getter(fn offending_validators)]
pub type OffendingValidators<T: Config> = StorageValue<_, Vec<(u32, bool)>, ValueQuery>;

/// True if network has been upgraded to this version.
/// Storage version of the pallet.
///
/// This is set to v7.0.0 for new networks.
#[pallet::storage]
pub(crate) type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;

/// The threshold for when users can start calling `chill_other` for other validators /
/// nominators. The threshold is compared to the actual number of validators / nominators
/// (`CountFor*`) in the system compared to the configured max (`Max*Count`).
Expand Down Expand Up @@ -609,7 +606,6 @@ pub mod pallet {
ForceEra::<T>::put(self.force_era);
CanceledSlashPayout::<T>::put(self.canceled_payout);
SlashRewardFraction::<T>::put(self.slash_reward_fraction);
StorageVersion::<T>::put(Releases::V7_0_0);
MinNominatorBond::<T>::put(self.min_nominator_bond);
MinValidatorBond::<T>::put(self.min_validator_bond);
if let Some(x) = self.max_validator_count {
Expand Down