mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 15:47:58 +00:00
Improve handling of unset StorageVersion (#13417)
* Improve handling of unset `StorageVersion` When a user is forgetting to set the storage version in a pallet and calls `current_storage_version` to compare it against the `on_chain_storage_version` it will now fail to compile the code. Before the pallet macro just returned `StorageVersion::default()` for `current_storage_version` leading to potential issues with migrations. Besides that it also checks in `post_upgrade` that the pallet storage version was upgraded and thus, no migration was missed. * Use correct `Cargo.lock` * Fixes * Fix test * Update frame/support/test/tests/pallet.rs * Ensure we don't set a storage version when the pallet is missing the attribute * Fix merge conflict * Update frame/support/procedural/src/pallet/expand/hooks.rs Co-authored-by: Roman Useinov <roman.useinov@gmail.com> * Update frame/support/procedural/src/pallet/expand/hooks.rs Co-authored-by: Roman Useinov <roman.useinov@gmail.com> * Fix compilation * Do not run everything with `try-runtime` * Fix test * Apply suggestions from code review Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix `no-metadata-docs` --------- Co-authored-by: Roman Useinov <roman.useinov@gmail.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: parity-processbot <>
This commit is contained in:
@@ -2500,7 +2500,9 @@ macro_rules! decl_module {
|
||||
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 {
|
||||
type CurrentStorageVersion = $crate::traits::StorageVersion;
|
||||
|
||||
fn current_storage_version() -> Self::CurrentStorageVersion {
|
||||
$( $storage_version )*
|
||||
}
|
||||
|
||||
@@ -2508,6 +2510,16 @@ macro_rules! decl_module {
|
||||
$crate::traits::StorageVersion::get::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `OnGenesis` for `Module`
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::OnGenesis
|
||||
for $module<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn on_genesis() {
|
||||
let storage_version = <Self as $crate::traits::GetStorageVersion>::current_storage_version();
|
||||
storage_version.put::<Self>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation for `GetStorageVersion` when no storage version is passed.
|
||||
@@ -2519,7 +2531,9 @@ macro_rules! decl_module {
|
||||
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 {
|
||||
type CurrentStorageVersion = $crate::traits::NoStorageVersionSet;
|
||||
|
||||
fn current_storage_version() -> Self::CurrentStorageVersion {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
@@ -2527,6 +2541,16 @@ macro_rules! decl_module {
|
||||
$crate::traits::StorageVersion::get::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `OnGenesis` for `Module`
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::OnGenesis
|
||||
for $module<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
|
||||
{
|
||||
fn on_genesis() {
|
||||
let storage_version = $crate::traits::StorageVersion::default();
|
||||
storage_version.put::<Self>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The main macro expansion that actually renders the module code.
|
||||
@@ -2814,16 +2838,6 @@ macro_rules! decl_module {
|
||||
}
|
||||
}
|
||||
|
||||
// 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() {
|
||||
let storage_version = <Self as $crate::traits::GetStorageVersion>::current_storage_version();
|
||||
storage_version.put::<Self>();
|
||||
}
|
||||
}
|
||||
|
||||
// manual implementation of clone/eq/partialeq because using derive erroneously requires
|
||||
// clone/eq/partialeq from T.
|
||||
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::Clone
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use crate::storage::unhashed::contains_prefixed_key;
|
||||
use crate::{
|
||||
traits::{GetStorageVersion, PalletInfoAccess},
|
||||
traits::{GetStorageVersion, NoStorageVersionSet, PalletInfoAccess, StorageVersion},
|
||||
weights::{RuntimeDbWeight, Weight},
|
||||
};
|
||||
use impl_trait_for_tuples::impl_for_tuples;
|
||||
@@ -28,12 +28,38 @@ use sp_std::marker::PhantomData;
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
/// Can store the current pallet version in storage.
|
||||
pub trait StoreCurrentStorageVersion<T: GetStorageVersion + PalletInfoAccess> {
|
||||
/// Write the current storage version to the storage.
|
||||
fn store_current_storage_version();
|
||||
}
|
||||
|
||||
impl<T: GetStorageVersion<CurrentStorageVersion = StorageVersion> + PalletInfoAccess>
|
||||
StoreCurrentStorageVersion<T> for StorageVersion
|
||||
{
|
||||
fn store_current_storage_version() {
|
||||
let version = <T as GetStorageVersion>::current_storage_version();
|
||||
version.put::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: GetStorageVersion<CurrentStorageVersion = NoStorageVersionSet> + PalletInfoAccess>
|
||||
StoreCurrentStorageVersion<T> for NoStorageVersionSet
|
||||
{
|
||||
fn store_current_storage_version() {
|
||||
StorageVersion::default().put::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
impl<T: GetStorageVersion + PalletInfoAccess> PalletVersionToStorageVersionHelper for T
|
||||
where
|
||||
T::CurrentStorageVersion: StoreCurrentStorageVersion<T>,
|
||||
{
|
||||
fn migrate(db_weight: &RuntimeDbWeight) -> Weight {
|
||||
const PALLET_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__PALLET_VERSION__:";
|
||||
|
||||
@@ -43,8 +69,8 @@ impl<T: GetStorageVersion + PalletInfoAccess> PalletVersionToStorageVersionHelpe
|
||||
|
||||
sp_io::storage::clear(&pallet_version_key(<T as PalletInfoAccess>::name()));
|
||||
|
||||
let version = <T as GetStorageVersion>::current_storage_version();
|
||||
version.put::<T>();
|
||||
<T::CurrentStorageVersion as StoreCurrentStorageVersion<T>>::store_current_storage_version(
|
||||
);
|
||||
|
||||
db_weight.writes(2)
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ pub use randomness::Randomness;
|
||||
mod metadata;
|
||||
pub use metadata::{
|
||||
CallMetadata, CrateVersion, GetCallIndex, GetCallMetadata, GetCallName, GetStorageVersion,
|
||||
PalletInfo, PalletInfoAccess, PalletInfoData, PalletsInfoAccess, StorageVersion,
|
||||
STORAGE_VERSION_STORAGE_KEY_POSTFIX,
|
||||
NoStorageVersionSet, PalletInfo, PalletInfoAccess, PalletInfoData, PalletsInfoAccess,
|
||||
StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX,
|
||||
};
|
||||
|
||||
mod hooks;
|
||||
|
||||
@@ -232,6 +232,16 @@ impl PartialOrd<u16> for StorageVersion {
|
||||
}
|
||||
}
|
||||
|
||||
/// Special marker struct if no storage version is set for a pallet.
|
||||
///
|
||||
/// If you (the reader) end up here, it probably means that you tried to compare
|
||||
/// [`GetStorageVersion::on_chain_storage_version`] against
|
||||
/// [`GetStorageVersion::current_storage_version`]. This basically means that the
|
||||
/// [`storage_version`](crate::pallet_macros::storage_version) is missing in the pallet where the
|
||||
/// mentioned functions are being called.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct NoStorageVersionSet;
|
||||
|
||||
/// 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
|
||||
@@ -244,8 +254,18 @@ impl PartialOrd<u16> for StorageVersion {
|
||||
///
|
||||
/// It is required to update the on-chain storage version manually when a migration was applied.
|
||||
pub trait GetStorageVersion {
|
||||
/// This will be filled out by the [`pallet`](crate::pallet) macro.
|
||||
///
|
||||
/// If the [`storage_version`](crate::pallet_macros::storage_version) attribute isn't given
|
||||
/// this is set to [`NoStorageVersionSet`] to inform the user that the attribute is missing.
|
||||
/// This should prevent that the user forgets to set a storage version when required. However,
|
||||
/// this will only work when the user actually tries to call [`Self::current_storage_version`]
|
||||
/// to compare it against the [`Self::on_chain_storage_version`]. If the attribute is given,
|
||||
/// this will be set to [`StorageVersion`].
|
||||
type CurrentStorageVersion;
|
||||
|
||||
/// Returns the current storage version as supported by the pallet.
|
||||
fn current_storage_version() -> StorageVersion;
|
||||
fn current_storage_version() -> Self::CurrentStorageVersion;
|
||||
/// Returns the on-chain storage version of the pallet as stored in the storage.
|
||||
fn on_chain_storage_version() -> StorageVersion;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user