diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index b655227cfc10d..3be9d60492e9d 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -102,41 +102,59 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { ) }; - let storage_info = if let Some(storage_info_span) = def.pallet_struct.generate_storage_info { - let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); - let storage_cfg_attrs = &def.storages.iter() - .map(|storage| &storage.cfg_attrs) - .collect::>(); - - quote::quote_spanned!(storage_info_span => - impl<#type_impl_gen> #frame_support::traits::StorageInfoTrait - for #pallet_ident<#type_use_gen> - #storages_where_clauses - { - fn storage_info() - -> #frame_support::sp_std::vec::Vec<#frame_support::traits::StorageInfo> - { - let mut res = #frame_support::sp_std::vec![]; - - #( - #(#storage_cfg_attrs)* - { - let mut storage_info = < - #storage_names<#type_use_gen> - as #frame_support::traits::StorageInfoTrait - >::storage_info(); - res.append(&mut storage_info); - } - )* - - res - } - } + // Depending on the flag `generate_storage_info` we use partial or full storage info from + // storage. + let ( + storage_info_span, + storage_info_trait, + storage_info_method, + ) = if let Some(span) = def.pallet_struct.generate_storage_info { + ( + span, + quote::quote_spanned!(span => StorageInfoTrait), + quote::quote_spanned!(span => storage_info), ) } else { - Default::default() + let span = def.pallet_struct.attr_span; + ( + span, + quote::quote_spanned!(span => PartialStorageInfoTrait), + quote::quote_spanned!(span => partial_storage_info), + ) }; + let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); + let storage_cfg_attrs = &def.storages.iter() + .map(|storage| &storage.cfg_attrs) + .collect::>(); + + let storage_info = quote::quote_spanned!(storage_info_span => + impl<#type_impl_gen> #frame_support::traits::StorageInfoTrait + for #pallet_ident<#type_use_gen> + #storages_where_clauses + { + fn storage_info() + -> #frame_support::sp_std::vec::Vec<#frame_support::traits::StorageInfo> + { + #[allow(unused_mut)] + let mut res = #frame_support::sp_std::vec![]; + + #( + #(#storage_cfg_attrs)* + { + let mut storage_info = < + #storage_names<#type_use_gen> + as #frame_support::traits::#storage_info_trait + >::#storage_info_method(); + res.append(&mut storage_info); + } + )* + + res + } + } + ); + quote::quote_spanned!(def.pallet_struct.attr_span => #module_error_metadata diff --git a/frame/support/procedural/src/storage/storage_info.rs b/frame/support/procedural/src/storage/storage_info.rs index ed07ccbfc71d6..947f4c2bb9f64 100644 --- a/frame/support/procedural/src/storage/storage_info.rs +++ b/frame/support/procedural/src/storage/storage_info.rs @@ -33,10 +33,16 @@ pub fn impl_storage_info(def: &DeclStorageDefExt) -> TokenStream { for line in def.storage_lines.iter() { let storage_struct = &line.storage_struct; + let (trait_, method) = if def.generate_storage_info { + (quote!(#scrate::traits::StorageInfoTrait), quote!(storage_info)) + } else { + (quote!(#scrate::traits::PartialStorageInfoTrait), quote!(partial_storage_info)) + }; + res_append_storage.extend(quote!( let mut storage_info = < - #storage_struct as #scrate::traits::StorageInfoTrait - >::storage_info(); + #storage_struct as #trait_ + >::#method(); res.append(&mut storage_info); )); } diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index c1af0ee0701fb..a713f5dff0033 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -399,7 +399,101 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { }, } } else { - TokenStream::default() + // Implement `__partial_storage_info` which doesn't require MaxEncodedLen on keys and + // values. + match &line.storage_type { + StorageLineTypeDef::Simple(_) => { + quote!( + impl<#impl_trait> #scrate::traits::PartialStorageInfoTrait + for #storage_struct + #optional_storage_where_clause + { + fn partial_storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct as #scrate::#storage_generator_trait + >::storage_value_final_key(), + max_values: Some(1), + max_size: None, + } + ] + } + } + ) + }, + StorageLineTypeDef::Map(_) => { + quote!( + impl<#impl_trait> #scrate::traits::PartialStorageInfoTrait + for #storage_struct + #optional_storage_where_clause + { + fn partial_storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: None, + } + ] + } + } + ) + }, + StorageLineTypeDef::DoubleMap(_) => { + quote!( + impl<#impl_trait> #scrate::traits::PartialStorageInfoTrait + for #storage_struct + #optional_storage_where_clause + { + fn partial_storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: None, + } + ] + } + } + ) + }, + StorageLineTypeDef::NMap(_) => { + quote!( + impl<#impl_trait> #scrate::traits::PartialStorageInfoTrait + for #storage_struct + #optional_storage_where_clause + { + fn partial_storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: None, + } + ] + } + } + ) + }, + } }; impls.extend(quote!( diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 638485360c589..466f92dc2d1b7 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1430,6 +1430,8 @@ pub mod pallet_prelude { /// If the attribute set_storage_max_encoded_len is set then the macro call /// [`traits::StorageInfoTrait`] for each storage in the implementation of /// [`traits::StorageInfoTrait`] for the pallet. +/// Otherwise it implements [`traits::StorageInfoTrait`] for the pallet using the +/// [`traits::PartialStorageInfoTrait`] implementation of storages. /// /// # Hooks: `#[pallet::hooks]` optional /// diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 6f03e9b8b2dd0..4126b2c53a329 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -483,6 +483,32 @@ where } } +/// It doesn't require to implement `MaxEncodedLen` and give no information for `max_size`. +impl + crate::traits::PartialStorageInfoTrait for + StorageDoubleMap +where + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn partial_storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: None + } + ] + } +} + #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index db3a5e73c9cb1..ea72aa529160c 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -368,6 +368,30 @@ where } } +/// It doesn't require to implement `MaxEncodedLen` and give no information for `max_size`. +impl + crate::traits::PartialStorageInfoTrait for + StorageMap +where + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn partial_storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: None, + } + ] + } +} + #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index fd1ca47b32c95..57f21e0199056 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -410,6 +410,28 @@ where } } +/// It doesn't require to implement `MaxEncodedLen` and give no information for `max_size`. +impl + crate::traits::PartialStorageInfoTrait for + StorageNMap +where + Prefix: StorageInstance, + Key: super::key::KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn partial_storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: None, + } + ] + } +} #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index 5b37066fc3942..44a0fd8dc7425 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -228,6 +228,27 @@ where } } +/// It doesn't require to implement `MaxEncodedLen` and give no information for `max_size`. +impl + crate::traits::PartialStorageInfoTrait for + StorageValue +where + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static +{ + fn partial_storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::hashed_key(), + max_values: Some(1), + max_size: None, + } + ] + } +} + #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 96e1cece55065..4eb630c6d9d79 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -74,7 +74,7 @@ pub use hooks::GenesisBuild; pub mod schedule; mod storage; -pub use storage::{Instance, StorageInstance, StorageInfo, StorageInfoTrait}; +pub use storage::{Instance, PartialStorageInfoTrait, StorageInstance, StorageInfo, StorageInfoTrait}; mod dispatch; pub use dispatch::{EnsureOrigin, OriginTrait, UnfilteredDispatchable}; diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index 37957ceb67765..c1f97694df7cb 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -74,3 +74,11 @@ impl StorageInfoTrait for Tuple { res } } + +/// Similar to [`StorageInfoTrait`], a trait to give partial information about storage. +/// +/// This is useful when a type can give some partial information with its generic parameter doesn't +/// implement some bounds. +pub trait PartialStorageInfoTrait { + fn partial_storage_info() -> Vec; +} diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 4f1e66a868947..589fca0dcd756 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -397,6 +397,9 @@ pub mod pallet2 { { } + #[pallet::storage] + pub type SomeValue = StorageValue<_, Vec>; + #[pallet::event] pub enum Event { /// Something @@ -1247,4 +1250,15 @@ fn test_storage_info() { }, ], ); + + assert_eq!( + Example2::storage_info(), + vec![ + StorageInfo { + prefix: prefix(b"Example2", b"SomeValue"), + max_values: Some(1), + max_size: None, + }, + ], + ); } diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index e2802b5e545f7..aff86e333457c 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -31,3 +31,37 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageValueMetadata` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` = note: required by `frame_support::storage::types::StorageValueMetadata::NAME` + +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `partial_storage_info` + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `partial_storage_info` + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `pallet::_::_parity_scale_codec::Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `partial_storage_info` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index e54a8c227eea2..2f4876554aa54 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -31,3 +31,37 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageValueMetadata` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` = note: required by `frame_support::storage::types::StorageValueMetadata::NAME` + +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `partial_storage_info` + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `partial_storage_info` + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `pallet::_::_parity_scale_codec::Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `partial_storage_info`