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:
Bastian Köcher
2023-05-04 21:18:53 +02:00
committed by GitHub
parent 0e55bace37
commit e2547f5064
17 changed files with 368 additions and 72 deletions
@@ -82,6 +82,57 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
proc_macro2::TokenStream::new()
};
// If a storage version is set, we should ensure that the storage version on chain matches the
// current storage version. This assumes that `Executive` is running custom migrations before
// the pallets are called.
let post_storage_version_check = if def.pallet_struct.storage_version.is_some() {
quote::quote! {
let on_chain_version = <Self as #frame_support::traits::GetStorageVersion>::on_chain_storage_version();
let current_version = <Self as #frame_support::traits::GetStorageVersion>::current_storage_version();
if on_chain_version != current_version {
let pallet_name = <
<T as #frame_system::Config>::PalletInfo
as
#frame_support::traits::PalletInfo
>::name::<Self>().unwrap_or("<unknown pallet name>");
#frame_support::log::error!(
target: #frame_support::LOG_TARGET,
"{}: On chain storage version {:?} doesn't match current storage version {:?}.",
pallet_name,
on_chain_version,
current_version,
);
return Err("On chain and current storage version do not match. Missing runtime upgrade?");
}
}
} else {
quote::quote! {
let on_chain_version = <Self as #frame_support::traits::GetStorageVersion>::on_chain_storage_version();
if on_chain_version != #frame_support::traits::StorageVersion::new(0) {
let pallet_name = <
<T as #frame_system::Config>::PalletInfo
as
#frame_support::traits::PalletInfo
>::name::<Self>().unwrap_or("<unknown pallet name>");
#frame_support::log::error!(
target: #frame_support::LOG_TARGET,
"{}: On chain storage version {:?} is set to non zero,\
while the pallet is missing the `#[pallet::storage_version(VERSION)]` attribute.",
pallet_name,
on_chain_version,
);
return Err("On chain storage version set, while the pallet doesn't \
have the `#[pallet::storage_version(VERSION)]` attribute.");
}
}
};
quote::quote_spanned!(span =>
#hooks_impl
@@ -170,6 +221,8 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: #frame_support::sp_std::vec::Vec<u8>) -> Result<(), &'static str> {
#post_storage_version_check
<
Self
as
@@ -160,11 +160,15 @@ 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() }
};
let (storage_version, current_storage_version_ty) =
if let Some(v) = def.pallet_struct.storage_version.as_ref() {
(quote::quote! { #v }, quote::quote! { #frame_support::traits::StorageVersion })
} else {
(
quote::quote! { core::default::Default::default() },
quote::quote! { #frame_support::traits::NoStorageVersionSet },
)
};
let whitelisted_storage_idents: Vec<syn::Ident> = def
.storages
@@ -199,7 +203,9 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn current_storage_version() -> #frame_support::traits::StorageVersion {
type CurrentStorageVersion = #current_storage_version_ty;
fn current_storage_version() -> Self::CurrentStorageVersion {
#storage_version
}
@@ -214,7 +220,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
#config_where_clause
{
fn on_genesis() {
let storage_version = #storage_version;
let storage_version: #frame_support::traits::StorageVersion = #storage_version;
storage_version.put::<Self>();
}
}