mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 14:11:09 +00:00
Move PalletVersion away from the crate version (#9165)
* Move `PalletVersion` away from the crate version Before this pr, `PalletVersion` was referring to the crate version that hosted the pallet. This pr introduces a custom `package.metadata.frame` section in the `Cargo.toml` that can contain a `pallet-version` key value pair. While the value is expected to be a valid u16. If this key/value pair isn't given, the version is set to 1. It also changes the `PalletVersion` declaration. We now only have one `u16` that represents the version. Not a major/minor/patch version. As the old `PalletVersion` was starting with the `u16` major, decoding the old values will work. * Overhaul the entire implementation - Drop PalletVersion - Introduce StorageVersion - StorageVersion needs to be set in the crate and set for the macros - Added migration * Fix migrations * Review feedback * Remove unneeded dep * remove pub consts * Brings back logging and implements `GetStorageVersion` * Return weight from migration * Fmt and remove unused import * Update frame/support/src/dispatch.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Update frame/support/src/traits/metadata.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -111,7 +111,7 @@ use crate::{
|
||||
};
|
||||
use frame_support::{
|
||||
dispatch::Dispatchable,
|
||||
traits::{Currency, Filter, Get, OnUnbalanced, Randomness, Time},
|
||||
traits::{Currency, Filter, Get, OnUnbalanced, Randomness, StorageVersion, Time},
|
||||
weights::{GetDispatchInfo, PostDispatchInfo, Weight, WithPostDispatchInfo},
|
||||
};
|
||||
use frame_system::Pallet as System;
|
||||
@@ -134,6 +134,9 @@ type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
|
||||
<T as frame_system::Config>::AccountId,
|
||||
>>::NegativeImbalance;
|
||||
|
||||
/// The current storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
@@ -273,6 +276,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
#[pallet::hooks]
|
||||
|
||||
@@ -18,22 +18,17 @@
|
||||
use crate::{Config, Pallet, Weight};
|
||||
use frame_support::{
|
||||
storage::migration,
|
||||
traits::{Get, GetPalletVersion, PalletInfoAccess, PalletVersion},
|
||||
traits::{Get, PalletInfoAccess, StorageVersion},
|
||||
};
|
||||
|
||||
pub fn migrate<T: Config>() -> Weight {
|
||||
let mut weight: Weight = 0;
|
||||
|
||||
match <Pallet<T>>::storage_version() {
|
||||
Some(version) if version == PalletVersion::new(3, 0, 0) => {
|
||||
weight = weight.saturating_add(T::DbWeight::get().writes(1));
|
||||
migration::remove_storage_prefix(
|
||||
<Pallet<T>>::name().as_bytes(),
|
||||
b"CurrentSchedule",
|
||||
b"",
|
||||
);
|
||||
},
|
||||
_ => (),
|
||||
if StorageVersion::get::<Pallet<T>>() == 3 {
|
||||
weight = weight.saturating_add(T::DbWeight::get().writes(1));
|
||||
migration::remove_storage_prefix(<Pallet<T>>::name().as_bytes(), b"CurrentSchedule", b"");
|
||||
|
||||
StorageVersion::new(4).put::<Pallet<T>>();
|
||||
}
|
||||
|
||||
weight
|
||||
|
||||
@@ -104,7 +104,7 @@ use frame_support::{
|
||||
traits::{
|
||||
ChangeMembers, Contains, ContainsLengthBound, Currency, CurrencyToVote, Get,
|
||||
InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, ReservableCurrency,
|
||||
SortedMembers, WithdrawReasons,
|
||||
SortedMembers, StorageVersion, WithdrawReasons,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
@@ -122,6 +122,9 @@ pub use weights::WeightInfo;
|
||||
/// All migrations.
|
||||
pub mod migrations;
|
||||
|
||||
/// The current storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
/// The maximum votes allowed per voter.
|
||||
pub const MAXIMUM_VOTE: usize = 16;
|
||||
|
||||
@@ -239,6 +242,7 @@ pub mod pallet {
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
#[pallet::hooks]
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
use codec::{Decode, Encode, FullCodec};
|
||||
use frame_support::{
|
||||
traits::{GetPalletVersion, PalletVersion},
|
||||
traits::{PalletInfoAccess, StorageVersion},
|
||||
weights::Weight,
|
||||
RuntimeDebug, Twox64Concat,
|
||||
};
|
||||
@@ -41,8 +41,8 @@ struct Voter<AccountId, Balance> {
|
||||
|
||||
/// Trait to implement to give information about types used for migration
|
||||
pub trait V2ToV3 {
|
||||
/// elections-phragmen module, used to check storage version.
|
||||
type Module: GetPalletVersion;
|
||||
/// The elections-phragmen pallet.
|
||||
type Pallet: 'static + PalletInfoAccess;
|
||||
|
||||
/// System config account id
|
||||
type AccountId: 'static + FullCodec;
|
||||
@@ -67,7 +67,7 @@ frame_support::generate_storage_alias!(
|
||||
>
|
||||
);
|
||||
|
||||
/// Apply all of the migrations from 2_0_0 to 3_0_0.
|
||||
/// Apply all of the migrations from 2 to 3.
|
||||
///
|
||||
/// ### Warning
|
||||
///
|
||||
@@ -77,28 +77,29 @@ frame_support::generate_storage_alias!(
|
||||
/// Be aware that this migration is intended to be used only for the mentioned versions. Use
|
||||
/// with care and run at your own risk.
|
||||
pub fn apply<T: V2ToV3>(old_voter_bond: T::Balance, old_candidacy_bond: T::Balance) -> Weight {
|
||||
let maybe_storage_version = <T::Module as GetPalletVersion>::storage_version();
|
||||
let storage_version = StorageVersion::get::<T::Pallet>();
|
||||
log::info!(
|
||||
target: "runtime::elections-phragmen",
|
||||
"Running migration for elections-phragmen with storage version {:?}",
|
||||
maybe_storage_version,
|
||||
storage_version,
|
||||
);
|
||||
match maybe_storage_version {
|
||||
Some(storage_version) if storage_version <= PalletVersion::new(2, 0, 0) => {
|
||||
migrate_voters_to_recorded_deposit::<T>(old_voter_bond);
|
||||
migrate_candidates_to_recorded_deposit::<T>(old_candidacy_bond);
|
||||
migrate_runners_up_to_recorded_deposit::<T>(old_candidacy_bond);
|
||||
migrate_members_to_recorded_deposit::<T>(old_candidacy_bond);
|
||||
Weight::max_value()
|
||||
},
|
||||
_ => {
|
||||
log::warn!(
|
||||
target: "runtime::elections-phragmen",
|
||||
"Attempted to apply migration to V3 but failed because storage version is {:?}",
|
||||
maybe_storage_version,
|
||||
);
|
||||
0
|
||||
},
|
||||
|
||||
if storage_version <= 2 {
|
||||
migrate_voters_to_recorded_deposit::<T>(old_voter_bond);
|
||||
migrate_candidates_to_recorded_deposit::<T>(old_candidacy_bond);
|
||||
migrate_runners_up_to_recorded_deposit::<T>(old_candidacy_bond);
|
||||
migrate_members_to_recorded_deposit::<T>(old_candidacy_bond);
|
||||
|
||||
StorageVersion::new(3).put::<T::Pallet>();
|
||||
|
||||
Weight::max_value()
|
||||
} else {
|
||||
log::warn!(
|
||||
target: "runtime::elections-phragmen",
|
||||
"Attempted to apply migration to V3 but failed because storage version is {:?}",
|
||||
storage_version,
|
||||
);
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//! Migrations to version [`4.0.0`], as denoted by the changelog.
|
||||
|
||||
use frame_support::{
|
||||
traits::{Get, GetPalletVersion, PalletVersion},
|
||||
traits::{Get, StorageVersion},
|
||||
weights::Weight,
|
||||
};
|
||||
|
||||
@@ -32,9 +32,7 @@ pub const OLD_PREFIX: &[u8] = b"PhragmenElection";
|
||||
/// `<Runtime as frame_system::Config>::PalletInfo::name::<ElectionsPhragmenPallet>`.
|
||||
///
|
||||
/// The old storage prefix, `PhragmenElection` is hardcoded in the migration code.
|
||||
pub fn migrate<T: frame_system::Config, P: GetPalletVersion, N: AsRef<str>>(
|
||||
new_pallet_name: N,
|
||||
) -> Weight {
|
||||
pub fn migrate<T: crate::Config, N: AsRef<str>>(new_pallet_name: N) -> Weight {
|
||||
if new_pallet_name.as_ref().as_bytes() == OLD_PREFIX {
|
||||
log::info!(
|
||||
target: "runtime::elections-phragmen",
|
||||
@@ -42,30 +40,30 @@ pub fn migrate<T: frame_system::Config, P: GetPalletVersion, N: AsRef<str>>(
|
||||
);
|
||||
return 0
|
||||
}
|
||||
let maybe_storage_version = <P as GetPalletVersion>::storage_version();
|
||||
let storage_version = StorageVersion::get::<crate::Pallet<T>>();
|
||||
log::info!(
|
||||
target: "runtime::elections-phragmen",
|
||||
"Running migration to v4 for elections-phragmen with storage version {:?}",
|
||||
maybe_storage_version,
|
||||
storage_version,
|
||||
);
|
||||
|
||||
match maybe_storage_version {
|
||||
Some(storage_version) if storage_version <= PalletVersion::new(3, 0, 0) => {
|
||||
log::info!("new prefix: {}", new_pallet_name.as_ref());
|
||||
frame_support::storage::migration::move_pallet(
|
||||
OLD_PREFIX,
|
||||
new_pallet_name.as_ref().as_bytes(),
|
||||
);
|
||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||
},
|
||||
_ => {
|
||||
log::warn!(
|
||||
target: "runtime::elections-phragmen",
|
||||
"Attempted to apply migration to v4 but failed because storage version is {:?}",
|
||||
maybe_storage_version,
|
||||
);
|
||||
0
|
||||
},
|
||||
if storage_version <= 3 {
|
||||
log::info!("new prefix: {}", new_pallet_name.as_ref());
|
||||
frame_support::storage::migration::move_pallet(
|
||||
OLD_PREFIX,
|
||||
new_pallet_name.as_ref().as_bytes(),
|
||||
);
|
||||
|
||||
StorageVersion::new(4).put::<crate::Pallet<T>>();
|
||||
|
||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||
} else {
|
||||
log::warn!(
|
||||
target: "runtime::elections-phragmen",
|
||||
"Attempted to apply migration to v4 but failed because storage version is {:?}",
|
||||
storage_version,
|
||||
);
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +71,7 @@ pub fn migrate<T: frame_system::Config, P: GetPalletVersion, N: AsRef<str>>(
|
||||
/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing.
|
||||
///
|
||||
/// Panics if anything goes wrong.
|
||||
pub fn pre_migration<P: GetPalletVersion, N: AsRef<str>>(new: N) {
|
||||
pub fn pre_migration<T: crate::Config, N: AsRef<str>>(new: N) {
|
||||
let new = new.as_ref();
|
||||
log::info!("pre-migration elections-phragmen test with new = {}", new);
|
||||
|
||||
@@ -94,15 +92,15 @@ pub fn pre_migration<P: GetPalletVersion, N: AsRef<str>>(new: N) {
|
||||
sp_core::hexdisplay::HexDisplay::from(&sp_io::storage::next_key(new.as_bytes()).unwrap())
|
||||
);
|
||||
// ensure storage version is 3.
|
||||
assert!(<P as GetPalletVersion>::storage_version().unwrap().major == 3);
|
||||
assert_eq!(StorageVersion::get::<crate::Pallet<T>>(), 3);
|
||||
}
|
||||
|
||||
/// 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_migration<P: GetPalletVersion>() {
|
||||
pub fn post_migration<T: crate::Config>() {
|
||||
log::info!("post-migration elections-phragmen");
|
||||
// ensure we've been updated to v4 by the automatic write of crate version -> storage version.
|
||||
assert!(<P as GetPalletVersion>::storage_version().unwrap().major == 4);
|
||||
assert_eq!(StorageVersion::get::<crate::Pallet<T>>(), 4);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ use fg_primitives::{
|
||||
use frame_support::{
|
||||
dispatch::DispatchResultWithPostInfo,
|
||||
storage,
|
||||
traits::{KeyOwnerProofSystem, OneSessionHandler},
|
||||
traits::{KeyOwnerProofSystem, OneSessionHandler, StorageVersion},
|
||||
weights::{Pays, Weight},
|
||||
};
|
||||
use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult, KeyTypeId};
|
||||
@@ -67,6 +67,9 @@ pub use equivocation::{
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
/// The current storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
@@ -75,6 +78,7 @@ pub mod pallet {
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// Version 3.1.
|
||||
pub mod v3_1;
|
||||
/// Version 4.
|
||||
pub mod v4;
|
||||
|
||||
+20
-29
@@ -16,7 +16,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use frame_support::{
|
||||
traits::{Get, GetPalletVersion, PalletVersion},
|
||||
traits::{Get, StorageVersion},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_io::hashing::twox_128;
|
||||
@@ -31,9 +31,7 @@ pub const OLD_PREFIX: &[u8] = b"GrandpaFinality";
|
||||
/// `<Runtime as frame_system::Config>::PalletInfo::name::<GrandpaPallet>`.
|
||||
///
|
||||
/// The old storage prefix, `GrandpaFinality` is hardcoded in the migration code.
|
||||
pub fn migrate<T: frame_system::Config, P: GetPalletVersion, N: AsRef<str>>(
|
||||
new_pallet_name: N,
|
||||
) -> Weight {
|
||||
pub fn migrate<T: crate::Config, N: AsRef<str>>(new_pallet_name: N) -> Weight {
|
||||
if new_pallet_name.as_ref().as_bytes() == OLD_PREFIX {
|
||||
log::info!(
|
||||
target: "runtime::afg",
|
||||
@@ -41,30 +39,25 @@ pub fn migrate<T: frame_system::Config, P: GetPalletVersion, N: AsRef<str>>(
|
||||
);
|
||||
return 0
|
||||
}
|
||||
let maybe_storage_version = <P as GetPalletVersion>::storage_version();
|
||||
let storage_version = StorageVersion::get::<crate::Pallet<T>>();
|
||||
log::info!(
|
||||
target: "runtime::afg",
|
||||
"Running migration to v3.1 for grandpa with storage version {:?}",
|
||||
maybe_storage_version,
|
||||
storage_version,
|
||||
);
|
||||
|
||||
match maybe_storage_version {
|
||||
Some(storage_version) if storage_version <= PalletVersion::new(3, 0, 0) => {
|
||||
log::info!("new prefix: {}", new_pallet_name.as_ref());
|
||||
frame_support::storage::migration::move_pallet(
|
||||
OLD_PREFIX,
|
||||
new_pallet_name.as_ref().as_bytes(),
|
||||
);
|
||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||
},
|
||||
_ => {
|
||||
log::warn!(
|
||||
target: "runtime::afg",
|
||||
"Attempted to apply migration to v3.1 but cancelled because storage version is {:?}",
|
||||
maybe_storage_version,
|
||||
);
|
||||
0
|
||||
},
|
||||
if storage_version <= 3 {
|
||||
log::info!("new prefix: {}", new_pallet_name.as_ref());
|
||||
frame_support::storage::migration::move_pallet(
|
||||
OLD_PREFIX,
|
||||
new_pallet_name.as_ref().as_bytes(),
|
||||
);
|
||||
|
||||
StorageVersion::new(4).put::<crate::Pallet<T>>();
|
||||
|
||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +65,7 @@ pub fn migrate<T: frame_system::Config, P: GetPalletVersion, N: AsRef<str>>(
|
||||
/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing.
|
||||
///
|
||||
/// Panics if anything goes wrong.
|
||||
pub fn pre_migration<T: frame_system::Config, P: GetPalletVersion + 'static, N: AsRef<str>>(
|
||||
new: N,
|
||||
) {
|
||||
pub fn pre_migration<T: crate::Config, N: AsRef<str>>(new: N) {
|
||||
let new = new.as_ref();
|
||||
log::info!("pre-migration grandpa test with new = {}", new);
|
||||
|
||||
@@ -83,7 +74,7 @@ pub fn pre_migration<T: frame_system::Config, P: GetPalletVersion + 'static, N:
|
||||
assert!(next_key.starts_with(&twox_128(OLD_PREFIX)));
|
||||
|
||||
// The pallet version is already stored using the pallet name
|
||||
let storage_key = PalletVersion::storage_key::<T::PalletInfo, P>().unwrap();
|
||||
let storage_key = StorageVersion::storage_key::<crate::Pallet<T>>();
|
||||
|
||||
// ensure nothing is stored in the new prefix.
|
||||
assert!(
|
||||
@@ -103,14 +94,14 @@ pub fn pre_migration<T: frame_system::Config, P: GetPalletVersion + 'static, N:
|
||||
),
|
||||
);
|
||||
// ensure storage version is 3.
|
||||
assert!(<P as GetPalletVersion>::storage_version().unwrap().major == 3);
|
||||
assert_eq!(StorageVersion::get::<crate::Pallet<T>>(), 3);
|
||||
}
|
||||
|
||||
/// 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_migration<P: GetPalletVersion>() {
|
||||
pub fn post_migration() {
|
||||
log::info!("post-migration grandpa");
|
||||
|
||||
// Assert that nothing remains at the old prefix
|
||||
@@ -81,7 +81,7 @@ mod test {
|
||||
// when
|
||||
assert_eq!(
|
||||
Offences::on_runtime_upgrade(),
|
||||
<T as frame_system::Config>::DbWeight::get().reads_writes(1, 2),
|
||||
<T as frame_system::Config>::DbWeight::get().reads_writes(1, 1),
|
||||
);
|
||||
|
||||
// then
|
||||
|
||||
@@ -26,7 +26,6 @@ mod default_no_bound;
|
||||
mod dummy_part_checker;
|
||||
mod key_prefix;
|
||||
mod pallet;
|
||||
mod pallet_version;
|
||||
mod partial_eq_no_bound;
|
||||
mod storage;
|
||||
mod transactional;
|
||||
@@ -461,13 +460,6 @@ pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStre
|
||||
.unwrap_or_else(|e| e.to_compile_error().into())
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn crate_to_pallet_version(input: TokenStream) -> TokenStream {
|
||||
pallet_version::crate_to_pallet_version(input)
|
||||
.unwrap_or_else(|e| e.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
||||
/// The number of module instances supported by the runtime, starting at index 1,
|
||||
/// and up to `NUMBER_OF_INSTANCE`.
|
||||
pub(crate) const NUMBER_OF_INSTANCE: u8 = 16;
|
||||
|
||||
@@ -40,9 +40,11 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
quote::quote! {
|
||||
#frame_support::log::info!(
|
||||
target: #frame_support::LOG_TARGET,
|
||||
"⚠️ {} declares internal migrations (which *might* execute), setting storage version to {:?}",
|
||||
"⚠️ {} declares internal migrations (which *might* execute). \
|
||||
On-chain `{:?}` vs current storage version `{:?}`",
|
||||
pallet_name,
|
||||
new_storage_version,
|
||||
<Self as #frame_support::traits::GetStorageVersion>::on_chain_storage_version(),
|
||||
<Self as #frame_support::traits::GetStorageVersion>::current_storage_version(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -50,9 +52,8 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
quote::quote! {
|
||||
#frame_support::log::info!(
|
||||
target: #frame_support::LOG_TARGET,
|
||||
"✅ no migration for {}, setting storage version to {:?}",
|
||||
"✅ no migration for {}",
|
||||
pallet_name,
|
||||
new_storage_version,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -131,7 +132,6 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
);
|
||||
|
||||
// log info about the upgrade.
|
||||
let new_storage_version = #frame_support::crate_to_pallet_version!();
|
||||
let pallet_name = <
|
||||
<T as #frame_system::Config>::PalletInfo
|
||||
as
|
||||
@@ -139,19 +139,11 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
>::name::<Self>().unwrap_or("<unknown pallet name>");
|
||||
#log_runtime_upgrade
|
||||
|
||||
let result = <
|
||||
<
|
||||
Self as #frame_support::traits::Hooks<
|
||||
<T as #frame_system::Config>::BlockNumber
|
||||
>
|
||||
>::on_runtime_upgrade();
|
||||
|
||||
new_storage_version.put_into_storage::<<T as #frame_system::Config>::PalletInfo, Self>();
|
||||
|
||||
let additional_write = <
|
||||
<T as #frame_system::Config>::DbWeight as #frame_support::traits::Get<_>
|
||||
>::get().writes(1);
|
||||
|
||||
result.saturating_add(additional_write)
|
||||
>::on_runtime_upgrade()
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
use crate::pallet::{expand::merge_where_clauses, parse::helper::get_doc_literals, Def};
|
||||
|
||||
/// * Add derive trait on Pallet
|
||||
/// * Implement GetPalletVersion on Pallet
|
||||
/// * Implement GetStorageVersion on Pallet
|
||||
/// * Implement OnGenesis on Pallet
|
||||
/// * Implement ModuleErrorMetadata on Pallet
|
||||
/// * declare Module type alias for construct_runtime
|
||||
@@ -151,6 +151,12 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
}
|
||||
);
|
||||
|
||||
let storage_version = if let Some(v) = def.pallet_struct.storage_version.as_ref() {
|
||||
quote::quote! { #v }
|
||||
} else {
|
||||
quote::quote! { #frame_support::traits::StorageVersion::default() }
|
||||
};
|
||||
|
||||
quote::quote_spanned!(def.pallet_struct.attr_span =>
|
||||
#module_error_metadata
|
||||
|
||||
@@ -161,21 +167,17 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
#[allow(dead_code)]
|
||||
pub type Module<#type_decl_gen> = #pallet_ident<#type_use_gen>;
|
||||
|
||||
// Implement `GetPalletVersion` for `Pallet`
|
||||
impl<#type_impl_gen> #frame_support::traits::GetPalletVersion
|
||||
// Implement `GetStorageVersion` for `Pallet`
|
||||
impl<#type_impl_gen> #frame_support::traits::GetStorageVersion
|
||||
for #pallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn current_version() -> #frame_support::traits::PalletVersion {
|
||||
#frame_support::crate_to_pallet_version!()
|
||||
fn current_storage_version() -> #frame_support::traits::StorageVersion {
|
||||
#storage_version
|
||||
}
|
||||
|
||||
fn storage_version() -> Option<#frame_support::traits::PalletVersion> {
|
||||
let key = #frame_support::traits::PalletVersion::storage_key::<
|
||||
<T as #frame_system::Config>::PalletInfo, Self
|
||||
>().expect("Every active pallet has a name in the runtime; qed");
|
||||
|
||||
#frame_support::storage::unhashed::get(&key)
|
||||
fn on_chain_storage_version() -> #frame_support::traits::StorageVersion {
|
||||
#frame_support::traits::StorageVersion::get::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +187,8 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
#config_where_clause
|
||||
{
|
||||
fn on_genesis() {
|
||||
#frame_support::crate_to_pallet_version!()
|
||||
.put_into_storage::<<T as #frame_system::Config>::PalletInfo, Self>();
|
||||
let storage_version = #storage_version;
|
||||
storage_version.put::<Self>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ mod keyword {
|
||||
syn::custom_keyword!(Pallet);
|
||||
syn::custom_keyword!(generate_store);
|
||||
syn::custom_keyword!(generate_storage_info);
|
||||
syn::custom_keyword!(storage_version);
|
||||
syn::custom_keyword!(Store);
|
||||
}
|
||||
|
||||
@@ -43,14 +44,18 @@ pub struct PalletStructDef {
|
||||
/// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`.
|
||||
/// Contains the span of the attribute.
|
||||
pub generate_storage_info: Option<proc_macro2::Span>,
|
||||
/// The current storage version of the pallet.
|
||||
pub storage_version: Option<syn::Path>,
|
||||
}
|
||||
|
||||
/// Parse for one variant of:
|
||||
/// * `#[pallet::generate_store($vis trait Store)]`
|
||||
/// * `#[pallet::generate_storage_info]`
|
||||
/// * `#[pallet::storage_version(STORAGE_VERSION)]`
|
||||
pub enum PalletStructAttr {
|
||||
GenerateStore { span: proc_macro2::Span, vis: syn::Visibility, keyword: keyword::Store },
|
||||
GenerateStorageInfoTrait(proc_macro2::Span),
|
||||
StorageVersion { storage_version: syn::Path, span: proc_macro2::Span },
|
||||
}
|
||||
|
||||
impl PalletStructAttr {
|
||||
@@ -58,6 +63,7 @@ impl PalletStructAttr {
|
||||
match self {
|
||||
Self::GenerateStore { span, .. } => *span,
|
||||
Self::GenerateStorageInfoTrait(span) => *span,
|
||||
Self::StorageVersion { span, .. } => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,6 +89,14 @@ impl syn::parse::Parse for PalletStructAttr {
|
||||
} else if lookahead.peek(keyword::generate_storage_info) {
|
||||
let span = content.parse::<keyword::generate_storage_info>()?.span();
|
||||
Ok(Self::GenerateStorageInfoTrait(span))
|
||||
} else if lookahead.peek(keyword::storage_version) {
|
||||
let span = content.parse::<keyword::storage_version>()?.span();
|
||||
|
||||
let version_content;
|
||||
syn::parenthesized!(version_content in content);
|
||||
let storage_version = version_content.parse::<syn::Path>()?;
|
||||
|
||||
Ok(Self::StorageVersion { storage_version, span })
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
@@ -104,6 +118,7 @@ impl PalletStructDef {
|
||||
|
||||
let mut store = None;
|
||||
let mut generate_storage_info = None;
|
||||
let mut storage_version_found = None;
|
||||
|
||||
let struct_attrs: Vec<PalletStructAttr> = helper::take_item_pallet_attrs(&mut item.attrs)?;
|
||||
for attr in struct_attrs {
|
||||
@@ -116,6 +131,11 @@ impl PalletStructDef {
|
||||
{
|
||||
generate_storage_info = Some(span);
|
||||
}
|
||||
PalletStructAttr::StorageVersion { storage_version, .. }
|
||||
if storage_version_found.is_none() =>
|
||||
{
|
||||
storage_version_found = Some(storage_version);
|
||||
}
|
||||
attr => {
|
||||
let msg = "Unexpected duplicated attribute";
|
||||
return Err(syn::Error::new(attr.span(), msg))
|
||||
@@ -138,6 +158,14 @@ impl PalletStructDef {
|
||||
let mut instances = vec![];
|
||||
instances.push(helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?);
|
||||
|
||||
Ok(Self { index, instances, pallet, store, attr_span, generate_storage_info })
|
||||
Ok(Self {
|
||||
index,
|
||||
instances,
|
||||
pallet,
|
||||
store,
|
||||
attr_span,
|
||||
generate_storage_info,
|
||||
storage_version: storage_version_found,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-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.
|
||||
|
||||
//! Implementation of macros related to pallet versioning.
|
||||
|
||||
use frame_support_procedural_tools::generate_crate_access_2018;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use std::{env, str::FromStr};
|
||||
use syn::{Error, Result};
|
||||
|
||||
/// Get the version from the given version environment variable.
|
||||
///
|
||||
/// The version is parsed into the requested destination type.
|
||||
fn get_version<T: FromStr>(version_env: &str) -> std::result::Result<T, ()> {
|
||||
let version = env::var(version_env)
|
||||
.unwrap_or_else(|_| panic!("`{}` is always set by cargo; qed", version_env));
|
||||
|
||||
T::from_str(&version).map_err(drop)
|
||||
}
|
||||
|
||||
/// Create an error that will be shown by rustc at the call site of the macro.
|
||||
fn create_error(message: &str) -> Error {
|
||||
Error::new(Span::call_site(), message)
|
||||
}
|
||||
|
||||
/// Implementation of the `crate_to_pallet_version!` macro.
|
||||
pub fn crate_to_pallet_version(input: proc_macro::TokenStream) -> Result<TokenStream> {
|
||||
if !input.is_empty() {
|
||||
return Err(create_error("No arguments expected!"))
|
||||
}
|
||||
|
||||
let major_version = get_version::<u16>("CARGO_PKG_VERSION_MAJOR")
|
||||
.map_err(|_| create_error("Major version needs to fit into `u16`"))?;
|
||||
|
||||
let minor_version = get_version::<u8>("CARGO_PKG_VERSION_MINOR")
|
||||
.map_err(|_| create_error("Minor version needs to fit into `u8`"))?;
|
||||
|
||||
let patch_version = get_version::<u8>("CARGO_PKG_VERSION_PATCH")
|
||||
.map_err(|_| create_error("Patch version needs to fit into `u8`"))?;
|
||||
|
||||
let crate_ = generate_crate_access_2018("frame-support")?;
|
||||
|
||||
Ok(quote::quote! {
|
||||
#crate_::traits::PalletVersion {
|
||||
major: #major_version,
|
||||
minor: #minor_version,
|
||||
patch: #patch_version,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -26,7 +26,7 @@ pub use crate::{
|
||||
result,
|
||||
},
|
||||
traits::{
|
||||
CallMetadata, GetCallMetadata, GetCallName, GetPalletVersion, UnfilteredDispatchable,
|
||||
CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable,
|
||||
},
|
||||
weights::{
|
||||
ClassifyDispatch, DispatchInfo, GetDispatchInfo, PaysFee, PostDispatchInfo,
|
||||
@@ -352,6 +352,7 @@ macro_rules! decl_module {
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
[]
|
||||
$($t)*
|
||||
);
|
||||
@@ -388,6 +389,7 @@ macro_rules! decl_module {
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
[]
|
||||
$($t)*
|
||||
);
|
||||
@@ -408,6 +410,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$vis:vis fn deposit_event() = default;
|
||||
@@ -426,7 +429,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -445,6 +449,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$vis:vis fn deposit_event
|
||||
@@ -471,6 +476,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$vis:vis fn deposit_event() = default;
|
||||
@@ -493,6 +499,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_finalize( $( $param_name:ident : $param:ty ),* $(,)? ) { $( $impl:tt )* }
|
||||
@@ -513,7 +520,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -533,6 +541,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
#[weight = $weight:expr]
|
||||
@@ -561,6 +570,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
#[weight = $weight:expr]
|
||||
@@ -585,6 +595,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_idle($param_name1:ident : $param1:ty, $param_name2:ident: $param2:ty $(,)? ) -> $return:ty { $( $impl:tt )* }
|
||||
@@ -605,7 +616,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -626,6 +638,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$(#[weight = $weight:expr])?
|
||||
@@ -652,6 +665,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_runtime_upgrade( $( $param_name:ident : $param:ty ),* $(,)? ) { $( $impl:tt )* }
|
||||
@@ -678,6 +692,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
#[weight = $weight:expr]
|
||||
@@ -706,6 +721,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_runtime_upgrade( $( $param_name:ident : $param:ty ),* $(,)? ) -> $return:ty { $( $impl:tt )* }
|
||||
@@ -726,7 +742,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -748,6 +765,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_runtime_upgrade( $( $param_name:ident : $param:ty ),* $(,)? ) -> $return:ty { $( $impl:tt )* }
|
||||
@@ -772,6 +790,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{}
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn integrity_test() { $( $impl:tt )* }
|
||||
@@ -794,6 +813,7 @@ macro_rules! decl_module {
|
||||
$(#[doc = $doc_attr])*
|
||||
fn integrity_test() { $( $impl)* }
|
||||
}
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -815,6 +835,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )+ }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn integrity_test() { $( $impl:tt )* }
|
||||
@@ -839,6 +860,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_initialize( $( $param_name:ident : $param:ty ),* $(,)? ) { $( $impl:tt )* }
|
||||
@@ -865,6 +887,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
#[weight = $weight:expr]
|
||||
@@ -893,6 +916,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_initialize( $( $param_name:ident : $param:ty ),* $(,)? ) -> $return:ty { $( $impl:tt )* }
|
||||
@@ -913,7 +937,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -935,6 +960,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn on_initialize( $( $param_name:ident : $param:ty ),* $(,)? ) -> $return:ty { $( $impl:tt )* }
|
||||
@@ -959,6 +985,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn offchain_worker( $( $param_name:ident : $param:ty ),* $(,)? ) { $( $impl:tt )* }
|
||||
@@ -979,7 +1006,8 @@ macro_rules! decl_module {
|
||||
{ fn offchain_worker( $( $param_name : $param ),* ) { $( $impl )* } }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -1001,6 +1029,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
fn offchain_worker( $( $param_name:ident : $param:ty ),* $(,)? ) -> $return:ty { $( $impl:tt )* }
|
||||
@@ -1026,6 +1055,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$( #[doc = $doc_attr:tt] )*
|
||||
const $name:ident: $ty:ty = $value:expr;
|
||||
@@ -1051,7 +1081,8 @@ macro_rules! decl_module {
|
||||
$name: $ty = $value;
|
||||
}
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -1075,6 +1106,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
type Error = $error_type:ty;
|
||||
@@ -1095,7 +1127,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $error_type }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
@@ -1118,6 +1151,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $($t:tt)* ]
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
@@ -1136,12 +1170,59 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ &'static str }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[ $($t)* ]
|
||||
$($rest)*
|
||||
);
|
||||
};
|
||||
|
||||
// Parse storage version
|
||||
(@normalize
|
||||
$(#[$attr:meta])*
|
||||
pub struct $mod_type:ident<
|
||||
$trait_instance:ident:
|
||||
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
|
||||
>
|
||||
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
|
||||
{ $( $other_where_bounds:tt )* }
|
||||
{ $( $deposit_event:tt )* }
|
||||
{ $( $on_initialize:tt )* }
|
||||
{ $( $on_runtime_upgrade:tt )* }
|
||||
{ $( $on_idle:tt )* }
|
||||
{ $( $on_finalize:tt )* }
|
||||
{ $( $offchain:tt )* }
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
type StorageVersion = $storage_version:path;
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
$crate::decl_module!(@normalize
|
||||
$(#[$attr])*
|
||||
pub struct $mod_type<
|
||||
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
|
||||
>
|
||||
for enum $call_type where origin: $origin_type, system = $system
|
||||
{ $( $other_where_bounds )* }
|
||||
{ $( $deposit_event )* }
|
||||
{ $( $on_initialize )* }
|
||||
{ $( $on_runtime_upgrade )* }
|
||||
{ $( $on_idle )* }
|
||||
{ $( $on_finalize )* }
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $storage_version }
|
||||
[ $( $dispatchables )* ]
|
||||
$($rest)*
|
||||
);
|
||||
};
|
||||
|
||||
// This puts the function statement into the [], decreasing `$rest` and moving toward finishing the parse.
|
||||
(@normalize
|
||||
$(#[$attr:meta])*
|
||||
@@ -1160,6 +1241,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $error_type:ty }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
#[weight = $weight:expr]
|
||||
@@ -1184,7 +1266,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $error_type }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
[
|
||||
$( $dispatchables )*
|
||||
$(#[doc = $doc_attr])*
|
||||
@@ -1216,6 +1299,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$(#[$fn_attr:meta])*
|
||||
@@ -1245,6 +1329,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$(#[weight = $weight:expr])?
|
||||
@@ -1274,6 +1359,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$(#[weight = $weight:expr])?
|
||||
@@ -1303,6 +1389,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
$(#[doc = $doc_attr:tt])*
|
||||
$(#[weight = $weight:expr])?
|
||||
@@ -1333,6 +1420,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $( $error_type:tt )* }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
[ $( $dispatchables:tt )* ]
|
||||
) => {
|
||||
$crate::decl_module!(@imp
|
||||
@@ -1350,7 +1438,8 @@ macro_rules! decl_module {
|
||||
{ $( $offchain )* }
|
||||
{ $( $constants )* }
|
||||
{ $( $error_type )* }
|
||||
{ $( $integrity_test)* }
|
||||
{ $( $integrity_test )* }
|
||||
{ $( $storage_version )* }
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1451,25 +1540,17 @@ macro_rules! decl_module {
|
||||
as
|
||||
$system::Config
|
||||
>::PalletInfo as $crate::traits::PalletInfo>::name::<Self>().unwrap_or("<unknown pallet name>");
|
||||
let new_storage_version = $crate::crate_to_pallet_version!();
|
||||
|
||||
$crate::log::info!(
|
||||
target: $crate::LOG_TARGET,
|
||||
"⚠️ {} declares internal migrations (which *might* execute), setting storage version to {:?}",
|
||||
"⚠️ {} declares internal migrations (which *might* execute). \
|
||||
On-chain `{:?}` vs current storage version `{:?}`",
|
||||
pallet_name,
|
||||
new_storage_version,
|
||||
<Self as $crate::traits::GetStorageVersion>::on_chain_storage_version(),
|
||||
<Self as $crate::traits::GetStorageVersion>::current_storage_version(),
|
||||
);
|
||||
|
||||
let result: $return = (|| { $( $impl )* })();
|
||||
|
||||
new_storage_version
|
||||
.put_into_storage::<<$trait_instance as $system::Config>::PalletInfo, Self>();
|
||||
|
||||
let additional_write = <
|
||||
<$trait_instance as $system::Config>::DbWeight as $crate::traits::Get<_>
|
||||
>::get().writes(1);
|
||||
|
||||
result.saturating_add(additional_write)
|
||||
(|| { $( $impl )* })()
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
@@ -1500,19 +1581,14 @@ macro_rules! decl_module {
|
||||
as
|
||||
$system::Config
|
||||
>::PalletInfo as $crate::traits::PalletInfo>::name::<Self>().unwrap_or("<unknown pallet name>");
|
||||
let new_storage_version = $crate::crate_to_pallet_version!();
|
||||
|
||||
$crate::log::info!(
|
||||
target: $crate::LOG_TARGET,
|
||||
"✅ no migration for {}, setting storage version to {:?}",
|
||||
"✅ no migration for {}",
|
||||
pallet_name,
|
||||
new_storage_version,
|
||||
);
|
||||
|
||||
new_storage_version
|
||||
.put_into_storage::<<$trait_instance as $system::Config>::PalletInfo, Self>();
|
||||
|
||||
<<$trait_instance as $system::Config>::DbWeight as $crate::traits::Get<_>>::get().writes(1)
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
@@ -1823,6 +1899,45 @@ macro_rules! decl_module {
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation for `GetStorageVersion`.
|
||||
(@impl_get_storage_version
|
||||
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
|
||||
{ $( $other_where_bounds:tt )* }
|
||||
$( $storage_version:tt )+
|
||||
) => {
|
||||
// Implement `GetStorageVersion` for `Pallet`
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::GetStorageVersion
|
||||
for $module<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn current_storage_version() -> $crate::traits::StorageVersion {
|
||||
$( $storage_version )*
|
||||
}
|
||||
|
||||
fn on_chain_storage_version() -> $crate::traits::StorageVersion {
|
||||
$crate::traits::StorageVersion::get::<Self>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation for `GetStorageVersion` when no storage version is passed.
|
||||
(@impl_get_storage_version
|
||||
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
|
||||
{ $( $other_where_bounds:tt )* }
|
||||
) => {
|
||||
// Implement `GetStorageVersion` for `Pallet`
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::GetStorageVersion
|
||||
for $module<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn current_storage_version() -> $crate::traits::StorageVersion {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn on_chain_storage_version() -> $crate::traits::StorageVersion {
|
||||
$crate::traits::StorageVersion::get::<Self>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The main macro expansion that actually renders the module code.
|
||||
|
||||
(@imp
|
||||
@@ -1852,6 +1967,7 @@ macro_rules! decl_module {
|
||||
{ $( $constants:tt )* }
|
||||
{ $error_type:ty }
|
||||
{ $( $integrity_test:tt )* }
|
||||
{ $( $storage_version:tt )* }
|
||||
) => {
|
||||
$crate::__check_reserved_fn_name! { $( $fn_name )* }
|
||||
|
||||
@@ -1908,6 +2024,7 @@ macro_rules! decl_module {
|
||||
{ $( $other_where_bounds )* }
|
||||
$( $offchain )*
|
||||
}
|
||||
|
||||
$crate::decl_module! {
|
||||
@impl_deposit_event
|
||||
$mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?>;
|
||||
@@ -1964,6 +2081,13 @@ macro_rules! decl_module {
|
||||
)*
|
||||
}
|
||||
|
||||
$crate::decl_module! {
|
||||
@impl_get_storage_version
|
||||
$mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?>;
|
||||
{ $( $other_where_bounds )* }
|
||||
$( $storage_version )*
|
||||
}
|
||||
|
||||
// Implement weight calculation function for Call
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::GetDispatchInfo
|
||||
for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
@@ -1997,6 +2121,27 @@ macro_rules! decl_module {
|
||||
}
|
||||
}
|
||||
|
||||
// Implement PalletInfoAccess for the module.
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::PalletInfoAccess
|
||||
for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn index() -> usize {
|
||||
<
|
||||
<$trait_instance as $system::Config>::PalletInfo as $crate::traits::PalletInfo
|
||||
>::index::<Self>()
|
||||
.expect("Pallet is part of the runtime because pallet `Config` trait is \
|
||||
implemented by the runtime")
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
<
|
||||
<$trait_instance as $system::Config>::PalletInfo as $crate::traits::PalletInfo
|
||||
>::name::<Self>()
|
||||
.expect("Pallet is part of the runtime because pallet `Config` trait is \
|
||||
implemented by the runtime")
|
||||
}
|
||||
}
|
||||
|
||||
// Implement GetCallName for the Call.
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::GetCallName
|
||||
for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
@@ -2023,32 +2168,13 @@ macro_rules! decl_module {
|
||||
}
|
||||
}
|
||||
|
||||
// Bring `GetPalletVersion` into scope to make it easily usable.
|
||||
pub use $crate::traits::GetPalletVersion as _;
|
||||
// Implement `GetPalletVersion` for `Module`
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::GetPalletVersion
|
||||
for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn current_version() -> $crate::traits::PalletVersion {
|
||||
$crate::crate_to_pallet_version!()
|
||||
}
|
||||
|
||||
fn storage_version() -> Option<$crate::traits::PalletVersion> {
|
||||
let key = $crate::traits::PalletVersion::storage_key::<
|
||||
<$trait_instance as $system::Config>::PalletInfo, Self
|
||||
>().expect("Every active pallet has a name in the runtime; qed");
|
||||
|
||||
$crate::storage::unhashed::get(&key)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `OnGenesis` for `Module`
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::OnGenesis
|
||||
for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn on_genesis() {
|
||||
$crate::crate_to_pallet_version!()
|
||||
.put_into_storage::<<$trait_instance as $system::Config>::PalletInfo, Self>();
|
||||
let storage_version = <Self as $crate::traits::GetStorageVersion>::current_storage_version();
|
||||
storage_version.put::<Self>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ pub mod inherent;
|
||||
#[macro_use]
|
||||
pub mod error;
|
||||
pub mod instances;
|
||||
pub mod migrations;
|
||||
pub mod traits;
|
||||
pub mod weights;
|
||||
|
||||
@@ -667,21 +668,6 @@ pub use frame_support_procedural::DefaultNoBound;
|
||||
/// ```
|
||||
pub use frame_support_procedural::require_transactional;
|
||||
|
||||
/// Convert the current crate version into a [`PalletVersion`](crate::traits::PalletVersion).
|
||||
///
|
||||
/// It uses the `CARGO_PKG_VERSION_MAJOR`, `CARGO_PKG_VERSION_MINOR` and
|
||||
/// `CARGO_PKG_VERSION_PATCH` environment variables to fetch the crate version.
|
||||
/// This means that the [`PalletVersion`](crate::traits::PalletVersion)
|
||||
/// object will correspond to the version of the crate the macro is called in!
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use frame_support::{traits::PalletVersion, crate_to_pallet_version};
|
||||
/// const Version: PalletVersion = crate_to_pallet_version!();
|
||||
/// ```
|
||||
pub use frame_support_procedural::crate_to_pallet_version;
|
||||
|
||||
/// Return Err of the expression: `return Err($expression);`.
|
||||
///
|
||||
/// Used as `fail!(expression)`.
|
||||
@@ -1301,7 +1287,7 @@ pub mod pallet_prelude {
|
||||
},
|
||||
},
|
||||
traits::{
|
||||
ConstU32, EnsureOrigin, Get, GetDefault, GetPalletVersion, Hooks, IsType,
|
||||
ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType,
|
||||
PalletInfoAccess, StorageInfoTrait,
|
||||
},
|
||||
weights::{DispatchClass, Pays, Weight},
|
||||
@@ -1422,6 +1408,19 @@ pub mod pallet_prelude {
|
||||
/// This require all storage to implement the trait [`traits::StorageInfoTrait`], thus all keys
|
||||
/// and value types must bound [`pallet_prelude::MaxEncodedLen`].
|
||||
///
|
||||
/// As the macro implements [`traits::GetStorageVersion`], the current storage version needs to be
|
||||
/// communicated to the macro. This can be done by using the `storage_version` attribute:
|
||||
///
|
||||
/// ```ignore
|
||||
/// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
|
||||
///
|
||||
/// #[pallet::pallet]
|
||||
/// #[pallet::storage_version(STORAGE_VERSION)]
|
||||
/// pub struct Pallet<T>(_);
|
||||
/// ```
|
||||
///
|
||||
/// If not present, the current storage version is set to the default value.
|
||||
///
|
||||
/// ### Macro expansion:
|
||||
///
|
||||
/// The macro add this attribute to the struct definition:
|
||||
@@ -1436,7 +1435,7 @@ pub mod pallet_prelude {
|
||||
/// and replace the type `_` by `PhantomData<T>`.
|
||||
///
|
||||
/// It implements on pallet:
|
||||
/// * [`traits::GetPalletVersion`]
|
||||
/// * [`traits::GetStorageVersion`]
|
||||
/// * [`traits::OnGenesis`]: contains some logic to write pallet version into storage.
|
||||
/// * `ModuleErrorMetadata`: using error declared or no metadata.
|
||||
///
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 crate::{
|
||||
traits::{GetStorageVersion, PalletInfoAccess},
|
||||
weights::{RuntimeDbWeight, Weight},
|
||||
};
|
||||
|
||||
/// Trait used by [`migrate_from_pallet_version_to_storage_version`] to do the actual migration.
|
||||
pub trait PalletVersionToStorageVersionHelper {
|
||||
fn migrate(db_weight: &RuntimeDbWeight) -> Weight;
|
||||
}
|
||||
|
||||
impl<T: GetStorageVersion + PalletInfoAccess> PalletVersionToStorageVersionHelper for T {
|
||||
fn migrate(db_weight: &RuntimeDbWeight) -> Weight {
|
||||
const PALLET_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__PALLET_VERSION__:";
|
||||
|
||||
fn pallet_version_key(name: &str) -> [u8; 32] {
|
||||
let pallet_name = sp_io::hashing::twox_128(name.as_bytes());
|
||||
let postfix = sp_io::hashing::twox_128(PALLET_VERSION_STORAGE_KEY_POSTFIX);
|
||||
|
||||
let mut final_key = [0u8; 32];
|
||||
final_key[..16].copy_from_slice(&pallet_name);
|
||||
final_key[16..].copy_from_slice(&postfix);
|
||||
|
||||
final_key
|
||||
}
|
||||
|
||||
sp_io::storage::clear(&pallet_version_key(<T as PalletInfoAccess>::name()));
|
||||
|
||||
let version = <T as GetStorageVersion>::current_storage_version();
|
||||
version.put::<T>();
|
||||
|
||||
db_weight.writes(2)
|
||||
}
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl PalletVersionToStorageVersionHelper for T {
|
||||
fn migrate(db_weight: &RuntimeDbWeight) -> Weight {
|
||||
let mut weight: Weight = 0;
|
||||
|
||||
for_tuples!( #( weight = weight.saturating_add(T::migrate(db_weight)); )* );
|
||||
|
||||
weight
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrate from the `PalletVersion` struct to the new
|
||||
/// [`StorageVersion`](crate::traits::StorageVersion) struct.
|
||||
///
|
||||
/// This will remove all `PalletVersion's` from the state and insert the current storage version.
|
||||
pub fn migrate_from_pallet_version_to_storage_version<
|
||||
AllPallets: PalletVersionToStorageVersionHelper,
|
||||
>(
|
||||
db_weight: &RuntimeDbWeight,
|
||||
) -> Weight {
|
||||
AllPallets::migrate(db_weight)
|
||||
}
|
||||
@@ -63,8 +63,8 @@ pub use randomness::Randomness;
|
||||
|
||||
mod metadata;
|
||||
pub use metadata::{
|
||||
CallMetadata, GetCallMetadata, GetCallName, GetPalletVersion, PalletInfo, PalletInfoAccess,
|
||||
PalletVersion, PALLET_VERSION_STORAGE_KEY_POSTFIX,
|
||||
CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo, PalletInfoAccess,
|
||||
StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX,
|
||||
};
|
||||
|
||||
mod hooks;
|
||||
|
||||
@@ -323,7 +323,6 @@ pub trait OnTimestampSet<Moment> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::traits::metadata::PalletVersion;
|
||||
|
||||
#[test]
|
||||
fn on_initialize_and_on_runtime_upgrade_weight_merge_works() {
|
||||
@@ -342,18 +341,4 @@ mod tests {
|
||||
assert_eq!(<(Test, Test)>::on_initialize(0), 20);
|
||||
assert_eq!(<(Test, Test)>::on_runtime_upgrade(), 40);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_pallet_version_ordering() {
|
||||
let version = PalletVersion::new(1, 0, 0);
|
||||
assert!(version > PalletVersion::new(0, 1, 2));
|
||||
assert!(version == PalletVersion::new(1, 0, 0));
|
||||
assert!(version < PalletVersion::new(1, 0, 1));
|
||||
assert!(version < PalletVersion::new(1, 1, 0));
|
||||
|
||||
let version = PalletVersion::new(2, 50, 50);
|
||||
assert!(version < PalletVersion::new(2, 50, 51));
|
||||
assert!(version > PalletVersion::new(2, 49, 51));
|
||||
assert!(version < PalletVersion::new(3, 49, 51));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,52 +68,42 @@ pub trait GetCallMetadata {
|
||||
fn get_call_metadata(&self) -> CallMetadata;
|
||||
}
|
||||
|
||||
/// The storage key postfix that is used to store the [`PalletVersion`] per pallet.
|
||||
/// The storage key postfix that is used to store the [`StorageVersion`] per pallet.
|
||||
///
|
||||
/// The full storage key is built by using:
|
||||
/// Twox128([`PalletInfo::name`]) ++ Twox128([`PALLET_VERSION_STORAGE_KEY_POSTFIX`])
|
||||
pub const PALLET_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__PALLET_VERSION__:";
|
||||
/// Twox128([`PalletInfo::name`]) ++ Twox128([`STORAGE_VERSION_STORAGE_KEY_POSTFIX`])
|
||||
pub const STORAGE_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__STORAGE_VERSION__:";
|
||||
|
||||
/// The version of a pallet.
|
||||
/// The storage version of a pallet.
|
||||
///
|
||||
/// Each pallet version is stored in the state under a fixed key. See
|
||||
/// [`PALLET_VERSION_STORAGE_KEY_POSTFIX`] for how this key is built.
|
||||
#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy)]
|
||||
pub struct PalletVersion {
|
||||
/// The major version of the pallet.
|
||||
pub major: u16,
|
||||
/// The minor version of the pallet.
|
||||
pub minor: u8,
|
||||
/// The patch version of the pallet.
|
||||
pub patch: u8,
|
||||
}
|
||||
/// Each storage version of a pallet is stored in the state under a fixed key. See
|
||||
/// [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] for how this key is built.
|
||||
#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, PartialOrd, Default)]
|
||||
pub struct StorageVersion(u16);
|
||||
|
||||
impl PalletVersion {
|
||||
impl StorageVersion {
|
||||
/// Creates a new instance of `Self`.
|
||||
pub fn new(major: u16, minor: u8, patch: u8) -> Self {
|
||||
Self { major, minor, patch }
|
||||
pub const fn new(version: u16) -> Self {
|
||||
Self(version)
|
||||
}
|
||||
|
||||
/// Returns the storage key for a pallet version.
|
||||
/// Returns the storage key for a storage version.
|
||||
///
|
||||
/// See [`PALLET_VERSION_STORAGE_KEY_POSTFIX`] on how this key is built.
|
||||
///
|
||||
/// Returns `None` if the given `PI` returned a `None` as name for the given
|
||||
/// `Pallet`.
|
||||
pub fn storage_key<PI: PalletInfo, Pallet: 'static>() -> Option<[u8; 32]> {
|
||||
let pallet_name = PI::name::<Pallet>()?;
|
||||
/// See [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] on how this key is built.
|
||||
pub fn storage_key<P: PalletInfoAccess>() -> [u8; 32] {
|
||||
let pallet_name = P::name();
|
||||
|
||||
let pallet_name = sp_io::hashing::twox_128(pallet_name.as_bytes());
|
||||
let postfix = sp_io::hashing::twox_128(PALLET_VERSION_STORAGE_KEY_POSTFIX);
|
||||
let postfix = sp_io::hashing::twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX);
|
||||
|
||||
let mut final_key = [0u8; 32];
|
||||
final_key[..16].copy_from_slice(&pallet_name);
|
||||
final_key[16..].copy_from_slice(&postfix);
|
||||
|
||||
Some(final_key)
|
||||
final_key
|
||||
}
|
||||
|
||||
/// Put this pallet version into the storage.
|
||||
/// Put this storage version for the given pallet into the storage.
|
||||
///
|
||||
/// It will use the storage key that is associated with the given `Pallet`.
|
||||
///
|
||||
@@ -125,47 +115,75 @@ impl PalletVersion {
|
||||
///
|
||||
/// It will also panic if this function isn't executed in an externalities
|
||||
/// provided environment.
|
||||
pub fn put_into_storage<PI: PalletInfo, Pallet: 'static>(&self) {
|
||||
let key = Self::storage_key::<PI, Pallet>()
|
||||
.expect("Every active pallet has a name in the runtime; qed");
|
||||
pub fn put<P: PalletInfoAccess>(&self) {
|
||||
let key = Self::storage_key::<P>();
|
||||
|
||||
crate::storage::unhashed::put(&key, self);
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_std::cmp::PartialOrd for PalletVersion {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<sp_std::cmp::Ordering> {
|
||||
let res = self
|
||||
.major
|
||||
.cmp(&other.major)
|
||||
.then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch)));
|
||||
/// Get the storage version of the given pallet from the storage.
|
||||
///
|
||||
/// It will use the storage key that is associated with the given `Pallet`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic iff `Pallet` can not be found by `PalletInfo`.
|
||||
/// In a runtime that is put together using
|
||||
/// [`construct_runtime!`](crate::construct_runtime) this should never happen.
|
||||
///
|
||||
/// It will also panic if this function isn't executed in an externalities
|
||||
/// provided environment.
|
||||
pub fn get<P: PalletInfoAccess>() -> Self {
|
||||
let key = Self::storage_key::<P>();
|
||||
|
||||
Some(res)
|
||||
crate::storage::unhashed::get_or_default(&key)
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides version information about a pallet.
|
||||
///
|
||||
/// This trait provides two functions for returning the version of a
|
||||
/// pallet. There is a state where both functions can return distinct versions.
|
||||
/// See [`GetPalletVersion::storage_version`] for more information about this.
|
||||
pub trait GetPalletVersion {
|
||||
/// Returns the current version of the pallet.
|
||||
fn current_version() -> PalletVersion;
|
||||
|
||||
/// Returns the version of the pallet that is stored in storage.
|
||||
///
|
||||
/// Most of the time this will return the exact same version as
|
||||
/// [`GetPalletVersion::current_version`]. Only when being in
|
||||
/// a state after a runtime upgrade happened and the pallet did
|
||||
/// not yet updated its version in storage, this will return a
|
||||
/// different(the previous, seen from the time of calling) version.
|
||||
///
|
||||
/// See [`PalletVersion`] for more information.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If there was no previous version of the pallet stored in the state,
|
||||
/// this function returns `None`.
|
||||
fn storage_version() -> Option<PalletVersion>;
|
||||
impl PartialEq<u16> for StorageVersion {
|
||||
fn eq(&self, other: &u16) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<u16> for StorageVersion {
|
||||
fn partial_cmp(&self, other: &u16) -> Option<sp_std::cmp::Ordering> {
|
||||
Some(self.0.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides information about the storage version of a pallet.
|
||||
///
|
||||
/// It differentiates between current and on-chain storage version. Both should be only out of sync
|
||||
/// when a new runtime upgrade was applied and the runtime migrations did not yet executed.
|
||||
/// Otherwise it means that the pallet works with an unsupported storage version and unforeseen
|
||||
/// stuff can happen.
|
||||
///
|
||||
/// The current storage version is the version of the pallet as supported at runtime. The active
|
||||
/// storage version is the version of the pallet in the storage.
|
||||
///
|
||||
/// It is required to update the on-chain storage version manually when a migration was applied.
|
||||
pub trait GetStorageVersion {
|
||||
/// Returns the current storage version as supported by the pallet.
|
||||
fn current_storage_version() -> StorageVersion;
|
||||
/// Returns the on-chain storage version of the pallet as stored in the storage.
|
||||
fn on_chain_storage_version() -> StorageVersion;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_storage_version_ordering() {
|
||||
let version = StorageVersion::new(1);
|
||||
assert!(version == StorageVersion::new(1));
|
||||
assert!(version < StorageVersion::new(2));
|
||||
assert!(version < StorageVersion::new(3));
|
||||
|
||||
let version = StorageVersion::new(2);
|
||||
assert!(version < StorageVersion::new(3));
|
||||
assert!(version > StorageVersion::new(1));
|
||||
assert!(version < StorageVersion::new(5));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
#![warn(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod pallet_version;
|
||||
|
||||
/// The configuration trait
|
||||
pub trait Config: 'static {
|
||||
/// The runtime origin type.
|
||||
|
||||
@@ -19,9 +19,10 @@ use frame_support::{
|
||||
dispatch::{Parameter, UnfilteredDispatchable},
|
||||
storage::unhashed,
|
||||
traits::{
|
||||
GetCallName, GetPalletVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade,
|
||||
GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade,
|
||||
PalletInfoAccess, StorageVersion,
|
||||
},
|
||||
weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays},
|
||||
weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight},
|
||||
};
|
||||
use sp_io::{
|
||||
hashing::{blake2_128, twox_128, twox_64},
|
||||
@@ -96,13 +97,15 @@ impl SomeAssociation2 for u64 {
|
||||
pub mod pallet {
|
||||
use super::{
|
||||
SomeAssociation1, SomeAssociation2, SomeType1, SomeType2, SomeType3, SomeType4, SomeType5,
|
||||
SomeType6, SomeType7,
|
||||
SomeType6, SomeType7, StorageVersion,
|
||||
};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
type BalanceOf<T> = <T as Config>::Balance;
|
||||
|
||||
pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(10);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config
|
||||
where
|
||||
@@ -146,6 +149,7 @@ pub mod pallet {
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(crate) trait Store)]
|
||||
#[pallet::generate_storage_info]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::hooks]
|
||||
@@ -896,12 +900,7 @@ fn pallet_hooks_expand() {
|
||||
assert_eq!(AllPallets::on_initialize(1), 10);
|
||||
AllPallets::on_finalize(1);
|
||||
|
||||
assert_eq!(pallet::Pallet::<Runtime>::storage_version(), None);
|
||||
assert_eq!(AllPallets::on_runtime_upgrade(), 30);
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime>::storage_version(),
|
||||
Some(pallet::Pallet::<Runtime>::current_version()),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
frame_system::Pallet::<Runtime>::events()[0].event,
|
||||
@@ -921,15 +920,60 @@ fn pallet_hooks_expand() {
|
||||
#[test]
|
||||
fn pallet_on_genesis() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
assert_eq!(pallet::Pallet::<Runtime>::storage_version(), None);
|
||||
assert_eq!(pallet::Pallet::<Runtime>::on_chain_storage_version(), StorageVersion::new(0));
|
||||
pallet::Pallet::<Runtime>::on_genesis();
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime>::storage_version(),
|
||||
Some(pallet::Pallet::<Runtime>::current_version()),
|
||||
pallet::Pallet::<Runtime>::current_storage_version(),
|
||||
pallet::Pallet::<Runtime>::on_chain_storage_version(),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn migrate_from_pallet_version_to_storage_version() {
|
||||
const PALLET_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__PALLET_VERSION__:";
|
||||
|
||||
fn pallet_version_key(name: &str) -> [u8; 32] {
|
||||
let pallet_name = sp_io::hashing::twox_128(name.as_bytes());
|
||||
let postfix = sp_io::hashing::twox_128(PALLET_VERSION_STORAGE_KEY_POSTFIX);
|
||||
|
||||
let mut final_key = [0u8; 32];
|
||||
final_key[..16].copy_from_slice(&pallet_name);
|
||||
final_key[16..].copy_from_slice(&postfix);
|
||||
|
||||
final_key
|
||||
}
|
||||
|
||||
TestExternalities::default().execute_with(|| {
|
||||
// Insert some fake pallet versions
|
||||
sp_io::storage::set(&pallet_version_key(Example::name()), &[1, 2, 3]);
|
||||
sp_io::storage::set(&pallet_version_key(Example2::name()), &[1, 2, 3]);
|
||||
sp_io::storage::set(&pallet_version_key(System::name()), &[1, 2, 3]);
|
||||
|
||||
// Check that everyone currently is at version 0
|
||||
assert_eq!(Example::on_chain_storage_version(), StorageVersion::new(0));
|
||||
assert_eq!(Example2::on_chain_storage_version(), StorageVersion::new(0));
|
||||
assert_eq!(System::on_chain_storage_version(), StorageVersion::new(0));
|
||||
|
||||
let db_weight = RuntimeDbWeight { read: 0, write: 5 };
|
||||
let weight = frame_support::migrations::migrate_from_pallet_version_to_storage_version::<
|
||||
AllPalletsWithSystem,
|
||||
>(&db_weight);
|
||||
|
||||
// 3 pallets, 2 writes and every write costs 5 weight.
|
||||
assert_eq!(3 * 2 * 5, weight);
|
||||
|
||||
// All pallet versions should be removed
|
||||
assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none());
|
||||
assert!(sp_io::storage::get(&pallet_version_key(Example2::name())).is_none());
|
||||
assert!(sp_io::storage::get(&pallet_version_key(System::name())).is_none());
|
||||
|
||||
assert_eq!(Example::on_chain_storage_version(), pallet::STORAGE_VERSION);
|
||||
assert_eq!(Example2::on_chain_storage_version(), StorageVersion::new(0));
|
||||
assert_eq!(System::on_chain_storage_version(), StorageVersion::new(0));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata() {
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
use frame_support::{
|
||||
dispatch::UnfilteredDispatchable,
|
||||
storage::unhashed,
|
||||
traits::{
|
||||
GetCallName, GetPalletVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade,
|
||||
},
|
||||
traits::{GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade},
|
||||
weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays},
|
||||
};
|
||||
use sp_io::{
|
||||
@@ -505,17 +503,7 @@ fn pallet_hooks_expand() {
|
||||
assert_eq!(AllPallets::on_initialize(1), 21);
|
||||
AllPallets::on_finalize(1);
|
||||
|
||||
assert_eq!(pallet::Pallet::<Runtime>::storage_version(), None);
|
||||
assert_eq!(pallet::Pallet::<Runtime, pallet::Instance1>::storage_version(), None);
|
||||
assert_eq!(AllPallets::on_runtime_upgrade(), 61);
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime>::storage_version(),
|
||||
Some(pallet::Pallet::<Runtime>::current_version()),
|
||||
);
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime, pallet::Instance1>::storage_version(),
|
||||
Some(pallet::Pallet::<Runtime, pallet::Instance1>::current_version()),
|
||||
);
|
||||
|
||||
// The order is indeed reversed due to https://github.com/paritytech/substrate/issues/6280
|
||||
assert_eq!(
|
||||
@@ -548,19 +536,9 @@ fn pallet_hooks_expand() {
|
||||
#[test]
|
||||
fn pallet_on_genesis() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
assert_eq!(pallet::Pallet::<Runtime>::storage_version(), None);
|
||||
pallet::Pallet::<Runtime>::on_genesis();
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime>::storage_version(),
|
||||
Some(pallet::Pallet::<Runtime>::current_version()),
|
||||
);
|
||||
|
||||
assert_eq!(pallet::Pallet::<Runtime, pallet::Instance1>::storage_version(), None);
|
||||
pallet::Pallet::<Runtime, pallet::Instance1>::on_genesis();
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime, pallet::Instance1>::storage_version(),
|
||||
Some(pallet::Pallet::<Runtime, pallet::Instance1>::current_version()),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-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.
|
||||
|
||||
//! Tests related to the pallet version.
|
||||
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
crate_to_pallet_version,
|
||||
traits::{
|
||||
GetPalletVersion, OnRuntimeUpgrade, PalletVersion, PALLET_VERSION_STORAGE_KEY_POSTFIX,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_core::{sr25519, H256};
|
||||
use sp_runtime::{
|
||||
generic,
|
||||
traits::{BlakeTwo256, Verify},
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
/// A version that we will check for in the tests
|
||||
const SOME_TEST_VERSION: PalletVersion = PalletVersion { major: 3000, minor: 30, patch: 13 };
|
||||
|
||||
/// Checks that `on_runtime_upgrade` sets the latest pallet version when being called without
|
||||
/// being provided by the user.
|
||||
mod module1 {
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
frame_support::decl_module! {
|
||||
pub struct Module<T: Config> for enum Call where
|
||||
origin: <T as frame_system::Config>::Origin,
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that `on_runtime_upgrade` sets the latest pallet version when being called and also
|
||||
/// being provided by the user.
|
||||
mod module2 {
|
||||
use super::*;
|
||||
|
||||
pub trait Config<I = DefaultInstance>: frame_system::Config {}
|
||||
|
||||
frame_support::decl_module! {
|
||||
pub struct Module<T: Config<I>, I: Instance=DefaultInstance> for enum Call where
|
||||
origin: <T as frame_system::Config>::Origin,
|
||||
{
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
assert_eq!(crate_to_pallet_version!(), Self::current_version());
|
||||
|
||||
let version_key = PalletVersion::storage_key::<T::PalletInfo, Self>().unwrap();
|
||||
let version_value = sp_io::storage::get(&version_key);
|
||||
|
||||
if version_value.is_some() {
|
||||
assert_eq!(SOME_TEST_VERSION, Self::storage_version().unwrap());
|
||||
} else {
|
||||
// As the storage version does not exist yet, it should be `None`.
|
||||
assert!(Self::storage_version().is_none());
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame_support::decl_storage! {
|
||||
trait Store for Module<T: Config<I>, I: Instance=DefaultInstance> as Module2 {}
|
||||
}
|
||||
}
|
||||
|
||||
#[frame_support::pallet]
|
||||
mod pallet3 {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
}
|
||||
|
||||
#[frame_support::pallet]
|
||||
mod pallet4 {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config<I: 'static = ()>: frame_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {}
|
||||
}
|
||||
|
||||
impl module1::Config for Runtime {}
|
||||
impl module2::Config for Runtime {}
|
||||
impl module2::Config<module2::Instance1> for Runtime {}
|
||||
impl module2::Config<module2::Instance2> for Runtime {}
|
||||
|
||||
impl pallet3::Config for Runtime {}
|
||||
impl pallet4::Config for Runtime {}
|
||||
impl pallet4::Config<pallet4::Instance1> for Runtime {}
|
||||
impl pallet4::Config<pallet4::Instance2> for Runtime {}
|
||||
|
||||
pub type Signature = sr25519::Signature;
|
||||
pub type AccountId = <Signature as Verify>::Signer;
|
||||
pub type BlockNumber = u64;
|
||||
pub type Index = u64;
|
||||
|
||||
frame_support::parameter_types!(
|
||||
pub const BlockHashCount: u32 = 250;
|
||||
);
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = BlockNumber;
|
||||
type Call = Call;
|
||||
type Hash = H256;
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = Event;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = ();
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
}
|
||||
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Event<T>},
|
||||
Module1: module1::{Pallet, Call},
|
||||
Module2: module2::{Pallet, Call},
|
||||
Module2_1: module2::<Instance1>::{Pallet, Call},
|
||||
Module2_2: module2::<Instance2>::{Pallet, Call},
|
||||
Pallet3: pallet3::{Pallet, Call},
|
||||
Pallet4: pallet4::{Pallet, Call},
|
||||
Pallet4_1: pallet4::<Instance1>::{Pallet, Call},
|
||||
Pallet4_2: pallet4::<Instance2>::{Pallet, Call},
|
||||
}
|
||||
);
|
||||
|
||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||
|
||||
/// Returns the storage key for `PalletVersion` for the given `pallet`.
|
||||
fn get_pallet_version_storage_key_for_pallet(pallet: &str) -> [u8; 32] {
|
||||
let pallet_name = sp_io::hashing::twox_128(pallet.as_bytes());
|
||||
let postfix = sp_io::hashing::twox_128(PALLET_VERSION_STORAGE_KEY_POSTFIX);
|
||||
|
||||
let mut final_key = [0u8; 32];
|
||||
final_key[..16].copy_from_slice(&pallet_name);
|
||||
final_key[16..].copy_from_slice(&postfix);
|
||||
|
||||
final_key
|
||||
}
|
||||
|
||||
/// Checks the version of the given `pallet`.
|
||||
///
|
||||
/// It is expected that the pallet version can be found in the storage and equals the
|
||||
/// current crate version.
|
||||
fn check_pallet_version(pallet: &str) {
|
||||
let key = get_pallet_version_storage_key_for_pallet(pallet);
|
||||
let value = sp_io::storage::get(&key).expect("Pallet version exists");
|
||||
let version =
|
||||
PalletVersion::decode(&mut &value[..]).expect("Pallet version is encoded correctly");
|
||||
|
||||
assert_eq!(crate_to_pallet_version!(), version);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_runtime_upgrade_sets_the_pallet_versions_in_storage() {
|
||||
sp_io::TestExternalities::new_empty().execute_with(|| {
|
||||
AllPallets::on_runtime_upgrade();
|
||||
|
||||
check_pallet_version("Module1");
|
||||
check_pallet_version("Module2");
|
||||
check_pallet_version("Module2_1");
|
||||
check_pallet_version("Module2_2");
|
||||
check_pallet_version("Pallet3");
|
||||
check_pallet_version("Pallet4");
|
||||
check_pallet_version("Pallet4_1");
|
||||
check_pallet_version("Pallet4_2");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_runtime_upgrade_overwrites_old_version() {
|
||||
sp_io::TestExternalities::new_empty().execute_with(|| {
|
||||
let key = get_pallet_version_storage_key_for_pallet("Module2");
|
||||
sp_io::storage::set(&key, &SOME_TEST_VERSION.encode());
|
||||
|
||||
AllPallets::on_runtime_upgrade();
|
||||
|
||||
check_pallet_version("Module1");
|
||||
check_pallet_version("Module2");
|
||||
check_pallet_version("Module2_1");
|
||||
check_pallet_version("Module2_2");
|
||||
check_pallet_version("Pallet3");
|
||||
check_pallet_version("Pallet4");
|
||||
check_pallet_version("Pallet4_1");
|
||||
check_pallet_version("Pallet4_2");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_init_puts_pallet_version_into_storage() {
|
||||
let storage = GenesisConfig::default().build_storage().expect("Builds genesis storage");
|
||||
|
||||
sp_io::TestExternalities::new(storage).execute_with(|| {
|
||||
check_pallet_version("Module1");
|
||||
check_pallet_version("Module2");
|
||||
check_pallet_version("Module2_1");
|
||||
check_pallet_version("Module2_2");
|
||||
check_pallet_version("Pallet3");
|
||||
check_pallet_version("Pallet4");
|
||||
check_pallet_version("Pallet4_1");
|
||||
check_pallet_version("Pallet4_2");
|
||||
|
||||
let system_version = System::storage_version().expect("System version should be set");
|
||||
assert_eq!(System::current_version(), system_version);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user