From 03b294641efbf754d507ab362f3614d70e347fbf Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 7 Sep 2021 20:17:26 +0800 Subject: [PATCH] Migrate `pallet-membership` to the new pallet attribute macro (#9080) * Migrate pallet-membership to new pallet attribute macro Signed-off-by: koushiro * Add migrations Signed-off-by: koushiro * more general Signed-off-by: koushiro * fix event metadata Signed-off-by: koushiro * some nits Signed-off-by: koushiro * fix some nits Signed-off-by: koushiro * apply suggestion Signed-off-by: koushiro * some nits Signed-off-by: koushiro * Fix Signed-off-by: koushiro * Remove useless Signed-off-by: koushiro * Fix migration Signed-off-by: koushiro * Fix format Signed-off-by: koushiro * Fix Signed-off-by: koushiro * Fix migration now we need to store the new version manually. * Fix migration and Add migration test Signed-off-by: koushiro * Fix Signed-off-by: koushiro * Fix format Signed-off-by: koushiro * Use new_test_ext Signed-off-by: koushiro Co-authored-by: thiolliere --- substrate/frame/membership/Cargo.toml | 14 +- substrate/frame/membership/src/lib.rs | 307 +++++++++++------- .../frame/membership/src/migrations/mod.rs | 19 ++ .../frame/membership/src/migrations/v4.rs | 154 +++++++++ 4 files changed, 362 insertions(+), 132 deletions(-) create mode 100644 substrate/frame/membership/src/migrations/mod.rs create mode 100644 substrate/frame/membership/src/migrations/v4.rs diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 3200d986fe..8136b818ea 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -15,25 +15,25 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4.0", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } + +sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-benchmarking = { version = "4.0.0-dev", optional = true, default-features = false, path = "../benchmarking" } - -[dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } - [features] default = ["std"] std = [ "codec/std", "log/std", - "sp-std/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", + "sp-std/std", "frame-support/std", "frame-system/std", "frame-benchmarking/std", diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index a9bc59a361..b66dc51b3b 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -23,84 +23,118 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - traits::{ChangeMembers, Contains, EnsureOrigin, Get, InitializeMembers, SortedMembers}, +use frame_support::traits::{ + ChangeMembers, Contains, Get, InitializeMembers, SortedMembers, StorageVersion, }; -use frame_system::ensure_signed; use sp_std::prelude::*; +pub mod migrations; pub mod weights; + +pub use pallet::*; pub use weights::WeightInfo; -pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From> + Into<::Event>; +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; - /// Required origin for adding a member (though can always be Root). - type AddOrigin: EnsureOrigin; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); - /// Required origin for removing a member (though can always be Root). - type RemoveOrigin: EnsureOrigin; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(PhantomData<(T, I)>); - /// Required origin for adding and removing a member in a single action. - type SwapOrigin: EnsureOrigin; + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; - /// Required origin for resetting membership. - type ResetOrigin: EnsureOrigin; + /// Required origin for adding a member (though can always be Root). + type AddOrigin: EnsureOrigin; - /// Required origin for setting or resetting the prime member. - type PrimeOrigin: EnsureOrigin; + /// Required origin for removing a member (though can always be Root). + type RemoveOrigin: EnsureOrigin; - /// The receiver of the signal for when the membership has been initialized. This happens pre- - /// genesis and will usually be the same as `MembershipChanged`. If you need to do something - /// different on initialization, then you can change this accordingly. - type MembershipInitialized: InitializeMembers; + /// Required origin for adding and removing a member in a single action. + type SwapOrigin: EnsureOrigin; - /// The receiver of the signal for when the membership has changed. - type MembershipChanged: ChangeMembers; + /// Required origin for resetting membership. + type ResetOrigin: EnsureOrigin; - /// The maximum number of members that this membership can have. - /// - /// This is used for benchmarking. Re-run the benchmarks if this changes. - /// - /// This is not enforced in the code; the membership size can exceed this limit. - type MaxMembers: Get; + /// Required origin for setting or resetting the prime member. + type PrimeOrigin: EnsureOrigin; - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; -} + /// The receiver of the signal for when the membership has been initialized. This happens + /// pre-genesis and will usually be the same as `MembershipChanged`. If you need to do + /// something different on initialization, then you can change this accordingly. + type MembershipInitialized: InitializeMembers; -decl_storage! { - trait Store for Module, I: Instance=DefaultInstance> as Membership { - /// The current membership, stored as an ordered Vec. - Members get(fn members): Vec; + /// The receiver of the signal for when the membership has changed. + type MembershipChanged: ChangeMembers; - /// The current prime member, if one exists. - Prime get(fn prime): Option; + /// The maximum number of members that this membership can have. + /// + /// This is used for benchmarking. Re-run the benchmarks if this changes. + /// + /// This is not enforced in the code; the membership size can exceed this limit. + type MaxMembers: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } - add_extra_genesis { - config(members): Vec; - config(phantom): sp_std::marker::PhantomData; - build(|config: &Self| { - let mut members = config.members.clone(); + /// The current membership, stored as an ordered Vec. + #[pallet::storage] + #[pallet::getter(fn members)] + pub type Members, I: 'static = ()> = + StorageValue<_, Vec, ValueQuery>; + + /// The current prime member, if one exists. + #[pallet::storage] + #[pallet::getter(fn prime)] + pub type Prime, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + pub members: Vec, + pub phantom: PhantomData, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { members: Vec::new(), phantom: Default::default() } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { use sp_std::collections::btree_set::BTreeSet; - let members_set: BTreeSet<_> = config.members.iter().collect(); - assert!(members_set.len() == config.members.len(), "Members cannot contain duplicate accounts."); + let members_set: BTreeSet<_> = self.members.iter().collect(); + assert_eq!( + members_set.len(), + self.members.len(), + "Members cannot contain duplicate accounts." + ); + let mut members = self.members.clone(); members.sort(); T::MembershipInitialized::initialize_members(&members); >::put(members); - }) + } } -} -decl_event!( - pub enum Event where - ::AccountId, - >::Event, - { + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[pallet::metadata( + PhantomData<(T::AccountId, >::Event)> = "sp_std::marker::PhantomData<(AccountId, Event)>", + )] + pub enum Event, I: 'static = ()> { /// The given member was added; see the transaction for who. MemberAdded, /// The given member was removed; see the transaction for who. @@ -112,34 +146,28 @@ decl_event!( /// One of the members' keys changed. KeyChanged, /// Phantom member, never used. - Dummy(sp_std::marker::PhantomData<(AccountId, Event)>), + Dummy(PhantomData<(T::AccountId, >::Event)>), } -); -decl_error! { - /// Error for the nicks module. - pub enum Error for Module, I: Instance> { + /// Old name generated by `decl_event`. + #[deprecated(note = "use `Event` instead")] + pub type RawEvent = Event; + + #[pallet::error] + pub enum Error { /// Already a member. AlreadyMember, /// Not a member. NotMember, } -} - -decl_module! { - pub struct Module, I: Instance=DefaultInstance> - for enum Call - where origin: T::Origin - { - type Error = Error; - - fn deposit_event() = default; + #[pallet::call] + impl, I: 'static> Pallet { /// Add a member `who` to the set. /// /// May only be called from `T::AddOrigin`. - #[weight = 50_000_000] - pub fn add_member(origin, who: T::AccountId) { + #[pallet::weight(50_000_000)] + pub fn add_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { T::AddOrigin::ensure_origin(origin)?; let mut members = >::get(); @@ -151,14 +179,15 @@ decl_module! { T::MembershipChanged::change_members_sorted(&[who], &[], &members[..]); - Self::deposit_event(RawEvent::MemberAdded); + Self::deposit_event(Event::MemberAdded); + Ok(()) } /// Remove a member `who` from the set. /// /// May only be called from `T::RemoveOrigin`. - #[weight = 50_000_000] - pub fn remove_member(origin, who: T::AccountId) { + #[pallet::weight(50_000_000)] + pub fn remove_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { T::RemoveOrigin::ensure_origin(origin)?; let mut members = >::get(); @@ -171,7 +200,8 @@ decl_module! { T::MembershipChanged::change_members_sorted(&[], &[who], &members[..]); Self::rejig_prime(&members); - Self::deposit_event(RawEvent::MemberRemoved); + Self::deposit_event(Event::MemberRemoved); + Ok(()) } /// Swap out one member `remove` for another `add`. @@ -179,11 +209,17 @@ decl_module! { /// May only be called from `T::SwapOrigin`. /// /// Prime membership is *not* passed from `remove` to `add`, if extant. - #[weight = 50_000_000] - pub fn swap_member(origin, remove: T::AccountId, add: T::AccountId) { + #[pallet::weight(50_000_000)] + pub fn swap_member( + origin: OriginFor, + remove: T::AccountId, + add: T::AccountId, + ) -> DispatchResult { T::SwapOrigin::ensure_origin(origin)?; - if remove == add { return Ok(()) } + if remove == add { + return Ok(()) + } let mut members = >::get(); let location = members.binary_search(&remove).ok().ok_or(Error::::NotMember)?; @@ -194,22 +230,19 @@ decl_module! { Self::maybe_warn_max_members(&members); >::put(&members); - T::MembershipChanged::change_members_sorted( - &[add], - &[remove], - &members[..], - ); + T::MembershipChanged::change_members_sorted(&[add], &[remove], &members[..]); Self::rejig_prime(&members); - Self::deposit_event(RawEvent::MembersSwapped); + Self::deposit_event(Event::MembersSwapped); + Ok(()) } /// Change the membership to a new set, disregarding the existing membership. Be nice and /// pass `members` pre-sorted. /// /// May only be called from `T::ResetOrigin`. - #[weight = 50_000_000] - pub fn reset_members(origin, members: Vec) { + #[pallet::weight(50_000_000)] + pub fn reset_members(origin: OriginFor, members: Vec) -> DispatchResult { T::ResetOrigin::ensure_origin(origin)?; let mut members = members; @@ -221,7 +254,8 @@ decl_module! { *m = members; }); - Self::deposit_event(RawEvent::MembersReset); + Self::deposit_event(Event::MembersReset); + Ok(()) } /// Swap out the sending member for some other key `new`. @@ -229,13 +263,14 @@ decl_module! { /// May only be called from `Signed` origin of a current member. /// /// Prime membership is passed from the origin account to `new`, if extant. - #[weight = 50_000_000] - pub fn change_key(origin, new: T::AccountId) { + #[pallet::weight(50_000_000)] + pub fn change_key(origin: OriginFor, new: T::AccountId) -> DispatchResult { let remove = ensure_signed(origin)?; if remove != new { let mut members = >::get(); - let location = members.binary_search(&remove).ok().ok_or(Error::::NotMember)?; + let location = + members.binary_search(&remove).ok().ok_or(Error::::NotMember)?; let _ = members.binary_search(&new).err().ok_or(Error::::AlreadyMember)?; members[location] = new.clone(); members.sort(); @@ -255,33 +290,36 @@ decl_module! { } } - Self::deposit_event(RawEvent::KeyChanged); + Self::deposit_event(Event::KeyChanged); + Ok(()) } /// Set the prime member. Must be a current member. /// /// May only be called from `T::PrimeOrigin`. - #[weight = 50_000_000] - pub fn set_prime(origin, who: T::AccountId) { + #[pallet::weight(50_000_000)] + pub fn set_prime(origin: OriginFor, who: T::AccountId) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; Self::members().binary_search(&who).ok().ok_or(Error::::NotMember)?; Prime::::put(&who); T::MembershipChanged::set_prime(Some(who)); + Ok(()) } /// Remove the prime member if it exists. /// /// May only be called from `T::PrimeOrigin`. - #[weight = 50_000_000] - pub fn clear_prime(origin) { + #[pallet::weight(50_000_000)] + pub fn clear_prime(origin: OriginFor) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; Prime::::kill(); T::MembershipChanged::set_prime(None); + Ok(()) } } } -impl, I: Instance> Module { +impl, I: 'static> Pallet { fn rejig_prime(members: &[T::AccountId]) { if let Some(prime) = Prime::::get() { match members.binary_search(&prime) { @@ -303,13 +341,13 @@ impl, I: Instance> Module { } } -impl, I: Instance> Contains for Module { +impl, I: 'static> Contains for Pallet { fn contains(t: &T::AccountId) -> bool { Self::members().binary_search(t).is_ok() } } -impl, I: Instance> SortedMembers for Module { +impl, I: 'static> SortedMembers for Pallet { fn sorted_members() -> Vec { Self::members() } @@ -321,26 +359,28 @@ impl, I: Instance> SortedMembers for Module { #[cfg(feature = "runtime-benchmarks")] mod benchmark { - use super::{Module as Membership, *}; - use frame_benchmarking::{account, benchmarks_instance, impl_benchmark_test_suite, whitelist}; + use super::{Pallet as Membership, *}; + use frame_benchmarking::{ + account, benchmarks_instance_pallet, impl_benchmark_test_suite, whitelist, + }; use frame_support::{assert_ok, traits::EnsureOrigin}; use frame_system::RawOrigin; const SEED: u32 = 0; - fn set_members, I: Instance>(members: Vec, prime: Option) { + fn set_members, I: 'static>(members: Vec, prime: Option) { let reset_origin = T::ResetOrigin::successful_origin(); let prime_origin = T::PrimeOrigin::successful_origin(); - assert_ok!(>::reset_members(reset_origin, members.clone())); + assert_ok!(>::reset_members(reset_origin, members.clone())); if let Some(prime) = prime.map(|i| members[i].clone()) { - assert_ok!(>::set_prime(prime_origin, prime)); + assert_ok!(>::set_prime(prime_origin, prime)); } else { - assert_ok!(>::clear_prime(prime_origin)); + assert_ok!(>::clear_prime(prime_origin)); } } - benchmarks_instance! { + benchmarks_instance_pallet! { add_member { let m in 1 .. T::MaxMembers::get(); @@ -348,10 +388,10 @@ mod benchmark { set_members::(members.clone(), None); let new_member = account::("add", m, SEED); }: { - assert_ok!(>::add_member(T::AddOrigin::successful_origin(), new_member.clone())); + assert_ok!(>::add_member(T::AddOrigin::successful_origin(), new_member.clone())); } verify { - assert!(>::get().contains(&new_member)); + assert!(>::get().contains(&new_member)); #[cfg(test)] crate::tests::clean(); } @@ -365,11 +405,11 @@ mod benchmark { let to_remove = members.first().cloned().unwrap(); }: { - assert_ok!(>::remove_member(T::RemoveOrigin::successful_origin(), to_remove.clone())); + assert_ok!(>::remove_member(T::RemoveOrigin::successful_origin(), to_remove.clone())); } verify { - assert!(!>::get().contains(&to_remove)); + assert!(!>::get().contains(&to_remove)); // prime is rejigged - assert!(>::get().is_some() && T::MembershipChanged::get_prime().is_some()); + assert!(>::get().is_some() && T::MembershipChanged::get_prime().is_some()); #[cfg(test)] crate::tests::clean(); } @@ -382,16 +422,16 @@ mod benchmark { let add = account::("member", m, SEED); let remove = members.first().cloned().unwrap(); }: { - assert_ok!(>::swap_member( + assert_ok!(>::swap_member( T::SwapOrigin::successful_origin(), remove.clone(), add.clone(), )); } verify { - assert!(!>::get().contains(&remove)); - assert!(>::get().contains(&add)); + assert!(!>::get().contains(&remove)); + assert!(>::get().contains(&add)); // prime is rejigged - assert!(>::get().is_some() && T::MembershipChanged::get_prime().is_some()); + assert!(>::get().is_some() && T::MembershipChanged::get_prime().is_some()); #[cfg(test)] crate::tests::clean(); } @@ -403,12 +443,12 @@ mod benchmark { set_members::(members.clone(), Some(members.len() - 1)); let mut new_members = (m..2*m).map(|i| account("member", i, SEED)).collect::>(); }: { - assert_ok!(>::reset_members(T::ResetOrigin::successful_origin(), new_members.clone())); + assert_ok!(>::reset_members(T::ResetOrigin::successful_origin(), new_members.clone())); } verify { new_members.sort(); - assert_eq!(>::get(), new_members); + assert_eq!(>::get(), new_members); // prime is rejigged - assert!(>::get().is_some() && T::MembershipChanged::get_prime().is_some()); + assert!(>::get().is_some() && T::MembershipChanged::get_prime().is_some()); #[cfg(test)] crate::tests::clean(); } @@ -423,12 +463,12 @@ mod benchmark { let add = account::("member", m, SEED); whitelist!(prime); }: { - assert_ok!(>::change_key(RawOrigin::Signed(prime.clone()).into(), add.clone())); + assert_ok!(>::change_key(RawOrigin::Signed(prime.clone()).into(), add.clone())); } verify { - assert!(!>::get().contains(&prime)); - assert!(>::get().contains(&add)); + assert!(!>::get().contains(&prime)); + assert!(>::get().contains(&add)); // prime is rejigged - assert_eq!(>::get().unwrap(), add); + assert_eq!(>::get().unwrap(), add); #[cfg(test)] crate::tests::clean(); } @@ -438,9 +478,9 @@ mod benchmark { let prime = members.last().cloned().unwrap(); set_members::(members, None); }: { - assert_ok!(>::set_prime(T::PrimeOrigin::successful_origin(), prime)); + assert_ok!(>::set_prime(T::PrimeOrigin::successful_origin(), prime)); } verify { - assert!(>::get().is_some()); + assert!(>::get().is_some()); assert!(::get_prime().is_some()); #[cfg(test)] crate::tests::clean(); } @@ -451,9 +491,9 @@ mod benchmark { let prime = members.last().cloned().unwrap(); set_members::(members, None); }: { - assert_ok!(>::clear_prime(T::PrimeOrigin::successful_origin())); + assert_ok!(>::clear_prime(T::PrimeOrigin::successful_origin())); } verify { - assert!(>::get().is_none()); + assert!(>::get().is_none()); assert!(::get_prime().is_none()); #[cfg(test)] crate::tests::clean(); } @@ -467,14 +507,17 @@ mod tests { use super::*; use crate as pallet_membership; - use frame_support::{assert_noop, assert_ok, ord_parameter_types, parameter_types}; - use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BadOrigin, BlakeTwo256, IdentityLookup}, }; + use frame_support::{ + assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::GenesisBuild, + }; + use frame_system::EnsureSignedBy; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -745,4 +788,18 @@ mod tests { .build_storage() .unwrap(); } + + #[test] + fn migration_v4() { + new_test_ext().execute_with(|| { + use frame_support::traits::PalletInfo; + let old_pallet_name = + ::PalletInfo::name::().unwrap(); + let new_pallet_name = "NewMembership"; + + crate::migrations::v4::pre_migrate::(old_pallet_name, new_pallet_name); + crate::migrations::v4::migrate::(old_pallet_name, new_pallet_name); + crate::migrations::v4::post_migrate::(old_pallet_name, new_pallet_name); + }); + } } diff --git a/substrate/frame/membership/src/migrations/mod.rs b/substrate/frame/membership/src/migrations/mod.rs new file mode 100644 index 0000000000..26d07a0cd5 --- /dev/null +++ b/substrate/frame/membership/src/migrations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Version 4. +pub mod v4; diff --git a/substrate/frame/membership/src/migrations/v4.rs b/substrate/frame/membership/src/migrations/v4.rs new file mode 100644 index 0000000000..9f4b15e468 --- /dev/null +++ b/substrate/frame/membership/src/migrations/v4.rs @@ -0,0 +1,154 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sp_core::hexdisplay::HexDisplay; +use sp_io::{hashing::twox_128, storage}; + +use frame_support::{ + traits::{ + Get, GetStorageVersion, PalletInfoAccess, StorageVersion, + STORAGE_VERSION_STORAGE_KEY_POSTFIX, + }, + weights::Weight, +}; + +/// Migrate the entire storage of this pallet to a new prefix. +/// +/// This new prefix must be the same as the one set in construct_runtime. For safety, use +/// `PalletInfo` to get it, as: +/// `::PalletInfo::name::`. +/// +/// The migration will look into the storage version in order not to trigger a migration on an up +/// to date storage. Thus the on chain storage version must be less than 4 in order to trigger the +/// migration. +pub fn migrate>( + old_pallet_name: N, + new_pallet_name: N, +) -> Weight { + let old_pallet_name = old_pallet_name.as_ref(); + let new_pallet_name = new_pallet_name.as_ref(); + + if new_pallet_name == old_pallet_name { + log::info!( + target: "runtime::membership", + "New pallet name is equal to the old prefix. No migration needs to be done.", + ); + return 0 + } + + let on_chain_storage_version =

::on_chain_storage_version(); + log::info!( + target: "runtime::membership", + "Running migration to v4 for membership with storage version {:?}", + on_chain_storage_version, + ); + + if on_chain_storage_version < 4 { + frame_support::storage::migration::move_pallet( + old_pallet_name.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", old_pallet_name, new_pallet_name); + + StorageVersion::new(4).put::

(); + ::BlockWeights::get().max_block + } else { + log::warn!( + target: "runtime::membership", + "Attempted to apply migration to v4 but failed because storage version is {:?}", + on_chain_storage_version, + ); + 0 + } +} + +/// Some checks prior to migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn pre_migrate>(old_pallet_name: N, new_pallet_name: N) { + let old_pallet_name = old_pallet_name.as_ref(); + let new_pallet_name = new_pallet_name.as_ref(); + log_migration("pre-migration", old_pallet_name, new_pallet_name); + + let old_pallet_prefix = twox_128(old_pallet_name.as_bytes()); + assert!(storage::next_key(&old_pallet_prefix) + .map_or(true, |next_key| next_key.starts_with(&old_pallet_prefix))); + + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + let storage_version_key = + [&new_pallet_prefix, &twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX)[..]].concat(); + // ensure nothing is stored in the new prefix. + assert!( + storage::next_key(&new_pallet_prefix).map_or( + // either nothing is there + true, + // or we ensure that it has no common prefix with twox_128(new), + // or isn't the storage version that is already stored using the pallet name + |next_key| { + !next_key.starts_with(&new_pallet_prefix) || next_key == storage_version_key + }, + ), + "unexpected next_key({}) = {:?}", + new_pallet_name, + HexDisplay::from(&storage::next_key(&new_pallet_prefix).unwrap()), + ); + assert!(

::on_chain_storage_version() < 4); +} + +/// Some checks for after migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn post_migrate>(old_pallet_name: N, new_pallet_name: N) { + let old_pallet_name = old_pallet_name.as_ref(); + let new_pallet_name = new_pallet_name.as_ref(); + log_migration("post-migration", old_pallet_name, new_pallet_name); + + let old_pallet_prefix = twox_128(old_pallet_name.as_bytes()); + #[cfg(test)] + { + let storage_version_key = + [&old_pallet_prefix, &twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX)[..]].concat(); + assert!(storage::next_key(&old_pallet_prefix) + .map_or(true, |next_key| !next_key.starts_with(&old_pallet_prefix) || + next_key == storage_version_key)); + } + #[cfg(not(test))] + { + // Assert that nothing remains at the old prefix + assert!(storage::next_key(&old_pallet_prefix) + .map_or(true, |next_key| !next_key.starts_with(&old_pallet_prefix))); + } + + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + // Assert that the storages have been moved to the new prefix + assert!(storage::next_key(&new_pallet_prefix) + .map_or(true, |next_key| next_key.starts_with(&new_pallet_prefix))); + + assert_eq!(

::on_chain_storage_version(), 4); +} + +fn log_migration(stage: &str, old_pallet_name: &str, new_pallet_name: &str) { + log::info!( + target: "runtime::membership", + "{}, prefix: '{}' ==> '{}'", + stage, + old_pallet_name, + new_pallet_name, + ); +}