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:
Bastian Köcher
2021-07-27 23:21:27 +02:00
committed by GitHub
parent 988c399983
commit 4fe55f0bcb
24 changed files with 550 additions and 657 deletions
+179 -53
View File
@@ -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>();
}
}
+16 -17
View File
@@ -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.
///
+73
View File
@@ -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)
}
+2 -2
View File
@@ -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));
}
}
+81 -63
View File
@@ -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));
}
}