From 0de47759c0071ac44bb373e5aa14c32b33c9ad9c Mon Sep 17 00:00:00 2001 From: thiolliere Date: Thu, 6 May 2021 17:31:47 +0200 Subject: [PATCH 1/9] implement max_values + storages info --- frame/support/procedural/src/lib.rs | 3 + .../src/pallet/expand/pallet_struct.rs | 42 ++- .../src/pallet/parse/pallet_struct.rs | 76 +++-- frame/support/procedural/src/storage/mod.rs | 13 + frame/support/procedural/src/storage/parse.rs | 35 +++ .../procedural/src/storage/storage_struct.rs | 98 +++++++ .../procedural/src/storage/storages_info.rs | 55 ++++ frame/support/src/lib.rs | 24 +- frame/support/src/storage/types/double_map.rs | 90 ++++-- frame/support/src/storage/types/map.rs | 79 ++++-- frame/support/src/storage/types/value.rs | 24 +- frame/support/src/traits.rs | 4 +- frame/support/src/traits/misc.rs | 15 + frame/support/src/traits/storage.rs | 34 +++ frame/support/test/tests/decl_storage.rs | 259 ++++++++++++++---- frame/support/test/tests/pallet.rs | 93 ++++++- frame/support/test/tests/pallet_instance.rs | 2 +- .../pallet_ui/duplicate_store_attr.stderr | 6 +- .../pallet_ui/storage_info_unsatisfied.rs | 27 ++ .../pallet_ui/storage_info_unsatisfied.stderr | 8 + 20 files changed, 864 insertions(+), 123 deletions(-) create mode 100644 frame/support/procedural/src/storage/storages_info.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 4cedf798821a9..49c953ee02b7f 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -155,6 +155,9 @@ use proc_macro::TokenStream; /// * \[optional\] `config(#field_name)`: `field_name` is optional if get is set. /// Will include the item in `GenesisConfig`. /// * \[optional\] `build(#closure)`: Closure called with storage overlays. +/// * \[optional\] `max_values(#expr)`: `expr` is an expression returning a `u32`. It is used to +/// implement `StoragesInfo`. Note this attribute is not available for storage value as the maximum +/// number of values is 1. /// * `#type`: Storage type. /// * \[optional\] `#default`: Value returned when none. /// diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 556c6515d4706..2bf62e9e3c8db 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::pallet::{Def, parse::helper::get_doc_literals}; +use crate::pallet::{Def, expand::merge_where_clauses, parse::helper::get_doc_literals}; /// * Add derive trait on Pallet /// * Implement GetPalletVersion on Pallet @@ -24,6 +24,7 @@ use crate::pallet::{Def, parse::helper::get_doc_literals}; /// * declare Module type alias for construct_runtime /// * replace the first field type of `struct Pallet` with `PhantomData` if it is `_` /// * implementation of `PalletInfoAccess` information +/// * implementation of `StoragesInfo` on Pallet pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { let frame_support = &def.frame_support; let frame_system = &def.frame_system; @@ -33,6 +34,10 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { let pallet_ident = &def.pallet_struct.pallet; let config_where_clause = &def.config.where_clause; + let mut storages_where_clauses = vec![&def.config.where_clause]; + storages_where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause)); + let storages_where_clauses = merge_where_clauses(&storages_where_clauses); + let pallet_item = { let pallet_module_items = &mut def.item.content.as_mut().expect("Checked by def").1; let item = &mut pallet_module_items[def.pallet_struct.index]; @@ -97,6 +102,39 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { ) }; + let storages_info = if let Some(storages_info_span) = def.pallet_struct.generate_storages_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!(storages_info_span => + impl<#type_impl_gen> #frame_support::traits::StoragesInfo + for #pallet_ident<#type_use_gen> + #storages_where_clauses + { + fn storages_info() + -> #frame_support::sp_std::vec::Vec<#frame_support::traits::StorageInfo> + { + #frame_support::sp_std::vec![ + #( + #(#storage_cfg_attrs)* + { + < + #storage_names<#type_use_gen> + as #frame_support::traits::StorageInfoTrait + >::storage_info() + }, + )* + ] + } + } + ) + } else { + Default::default() + }; + + quote::quote_spanned!(def.pallet_struct.attr_span => #module_error_metadata @@ -157,5 +195,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { implemented by the runtime") } } + + #storages_info ) } diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 6c2c90bd61a5f..3aeb70d201105 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -24,6 +24,7 @@ mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(Pallet); syn::custom_keyword!(generate_store); + syn::custom_keyword!(generate_storages_info); syn::custom_keyword!(Store); } @@ -39,12 +40,30 @@ pub struct PalletStructDef { pub store: Option<(syn::Visibility, keyword::Store)>, /// The span of the pallet::pallet attribute. pub attr_span: proc_macro2::Span, + /// Whether to specify the storages max encoded len when implementing `StoragesInfo`. + /// Contains the span of the attribute. + pub generate_storages_info: Option, } -/// Parse for `#[pallet::generate_store($vis trait Store)]` -pub struct PalletStructAttr { - vis: syn::Visibility, - keyword: keyword::Store, +/// Parse for one variant of: +/// * `#[pallet::generate_store($vis trait Store)]` +/// * `#[pallet::generate_storages_info]` +pub enum PalletStructAttr { + GenerateStore { + span: proc_macro2::Span, + vis: syn::Visibility, + keyword: keyword::Store, + }, + GenerateStoragesInfo(proc_macro2::Span), +} + +impl PalletStructAttr { + fn span(&self) -> proc_macro2::Span { + match self { + Self::GenerateStore { span, .. } => *span, + Self::GenerateStoragesInfo(span) => *span, + } + } } impl syn::parse::Parse for PalletStructAttr { @@ -54,14 +73,23 @@ impl syn::parse::Parse for PalletStructAttr { syn::bracketed!(content in input); content.parse::()?; content.parse::()?; - content.parse::()?; - - let generate_content; - syn::parenthesized!(generate_content in content); - let vis = generate_content.parse::()?; - generate_content.parse::()?; - let keyword = generate_content.parse::()?; - Ok(Self { vis, keyword }) + + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::generate_store) { + let span = content.parse::()?.span(); + + let generate_content; + syn::parenthesized!(generate_content in content); + let vis = generate_content.parse::()?; + generate_content.parse::()?; + let keyword = generate_content.parse::()?; + Ok(Self::GenerateStore { vis, keyword, span }) + } else if lookahead.peek(keyword::generate_storages_info) { + let span = content.parse::()?.span(); + Ok(Self::GenerateStoragesInfo(span)) + } else { + Err(lookahead.error()) + } } } @@ -78,12 +106,24 @@ impl PalletStructDef { return Err(syn::Error::new(item.span(), msg)); }; - let mut event_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; - if event_attrs.len() > 1 { - let msg = "Invalid pallet::pallet, multiple argument pallet::generate_store found"; - return Err(syn::Error::new(event_attrs[1].keyword.span(), msg)); + let mut store = None; + let mut generate_storages_info = None; + + let struct_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; + for attr in struct_attrs { + match attr { + PalletStructAttr::GenerateStore { vis, keyword, .. } if store.is_none() => { + store = Some((vis, keyword)); + }, + PalletStructAttr::GenerateStoragesInfo(span) if generate_storages_info.is_none() => { + generate_storages_info = Some(span); + }, + attr => { + let msg = "Unexpected duplicated attribute"; + return Err(syn::Error::new(attr.span(), msg)); + }, + } } - let store = event_attrs.pop().map(|attr| (attr.vis, attr.keyword)); let pallet = syn::parse2::(item.ident.to_token_stream())?; @@ -100,6 +140,6 @@ 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 }) + Ok(Self { index, instances, pallet, store, attr_span, generate_storages_info }) } } diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 2f9625d2c941e..556b7e92c5caa 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -18,6 +18,7 @@ //! `decl_storage` input definition and expansion. mod storage_struct; +mod storages_info; mod parse; mod store_trait; mod getters; @@ -35,6 +36,8 @@ use frame_support_procedural_tools::{ /// All information contained in input of decl_storage pub struct DeclStorageDef { + /// Whether to generate the storage info + generate_storage_info: bool, /// Name of the module used to import hidden imports. hidden_crate: Option, /// Visibility of store trait. @@ -69,6 +72,8 @@ impl syn::parse::Parse for DeclStorageDef { /// Extended version of `DeclStorageDef` with useful precomputed value. pub struct DeclStorageDefExt { + /// Whether to generate the storage info + generate_storage_info: bool, /// Name of the module used to import hidden imports. hidden_crate: Option, /// Visibility of store trait. @@ -144,6 +149,7 @@ impl From for DeclStorageDefExt { ); Self { + generate_storage_info: def.generate_storage_info, hidden_crate: def.hidden_crate, visibility: def.visibility, store_trait: def.store_trait, @@ -184,6 +190,8 @@ pub struct StorageLineDef { getter: Option, /// The name of the field to be used in genesis config if any. config: Option, + /// The given max values with `max_values` attribute, or a none if not specified. + max_values: Option, /// The build function of the storage if any. build: Option, /// Default value of genesis config field and also for storage when no value available. @@ -201,6 +209,8 @@ pub struct StorageLineDefExt { getter: Option, /// The name of the field to be used in genesis config if any. config: Option, + /// The given max values with `max_values` attribute, or a none if not specified. + max_values: Option, /// The build function of the storage if any. build: Option, /// Default value of genesis config field and also for storage when no value available. @@ -311,6 +321,7 @@ impl StorageLineDefExt { name: storage_def.name, getter: storage_def.getter, config: storage_def.config, + max_values: storage_def.max_values, build: storage_def.build, default_value: storage_def.default_value, storage_type: storage_def.storage_type, @@ -414,6 +425,7 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr let instance_trait = instance_trait::decl_and_impl(&scrate, &def_ext); let genesis_config = genesis_config::genesis_config_and_build_storage(&scrate, &def_ext); let storage_struct = storage_struct::decl_and_impl(&scrate, &def_ext); + let storages_info = storages_info::impl_storages_info(&scrate, &def_ext); quote!( use #scrate::{ @@ -432,5 +444,6 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr #instance_trait #genesis_config #storage_struct + #storages_info ).into() } diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 2ff7f1fbf38c9..523c7f2072383 100644 --- a/frame/support/procedural/src/storage/parse.rs +++ b/frame/support/procedural/src/storage/parse.rs @@ -21,10 +21,12 @@ use frame_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; use syn::{Ident, Token, spanned::Spanned}; mod keyword { + syn::custom_keyword!(generate_storage_info); syn::custom_keyword!(hiddencrate); syn::custom_keyword!(add_extra_genesis); syn::custom_keyword!(extra_genesis_skip_phantom_data_field); syn::custom_keyword!(config); + syn::custom_keyword!(max_values); syn::custom_keyword!(build); syn::custom_keyword!(get); syn::custom_keyword!(map); @@ -72,6 +74,7 @@ macro_rules! impl_parse_for_opt { /// Parsing usage only #[derive(Parse, ToTokens, Debug)] struct StorageDefinition { + pub generate_storage_info: Opt, pub hidden_crate: Opt, pub visibility: syn::Visibility, pub trait_token: Token![trait], @@ -96,6 +99,12 @@ struct StorageDefinition { pub extra_genesis: Opt, } +#[derive(Parse, ToTokens, Debug)] +struct GenerateStorageInfo { + pub keyword: keyword::generate_storage_info, +} +impl_parse_for_opt!(GenerateStorageInfo => keyword::generate_storage_info); + #[derive(Parse, ToTokens, Debug)] struct SpecificHiddenCrate { pub keyword: keyword::hiddencrate, @@ -159,6 +168,7 @@ struct DeclStorageLine { pub name: Ident, pub getter: Opt, pub config: Opt, + pub max_values: Opt, pub build: Opt, pub coldot_token: Token![:], pub storage_type: DeclStorageType, @@ -187,6 +197,14 @@ struct DeclStorageConfig { impl_parse_for_opt!(DeclStorageConfig => keyword::config); +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageMaxValues { + pub max_values_keyword: keyword::max_values, + pub expr: ext::Parens, +} + +impl_parse_for_opt!(DeclStorageMaxValues=> keyword::max_values); + #[derive(Parse, ToTokens, Debug)] struct DeclStorageBuild { pub build_keyword: keyword::build, @@ -419,6 +437,7 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result { + line.max_values.inner.map(|i| i.expr.content) + }, + DeclStorageType::Simple(_) => { + if let Some(max_values) = line.max_values.inner { + let msg = "unexpected max_values attribute for storage value."; + let span = max_values.max_values_keyword.span(); + return Err(syn::Error::new(span, msg)); + } else { + Some(syn::parse_quote!(1u32)) + } + }, + }; + let span = line.storage_type.span(); let no_hasher_error = || syn::Error::new( span, @@ -504,6 +538,7 @@ fn parse_storage_line_defs( name: line.name, getter, config, + max_values, build: line.build.inner.map(|o| o.expr.content), default_value: line.default_value.inner.map(|o| o.expr), storage_type, diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index 9c049789f9bd9..6145a6b38aa11 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -207,9 +207,107 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre } }; + let max_values = if let Some(max_values) = &line.max_values { + quote::quote!({ + let max_values: u32 = (|| #max_values)(); + Some(max_values) + }) + } else { + quote::quote!(None) + }; + + let storage_info_impl = if def.generate_storage_info { + match &line.storage_type { + StorageLineTypeDef::Simple(_) => { + quote!( + impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct + #optional_storage_where_clause + { + fn storage_info() -> #scrate::traits::StorageInfo { + use #scrate::sp_runtime::SaturatedConversion; + + let max_size = < + #value_type as #scrate::traits::MaxEncodedLen + >::max_encoded_len() + .saturated_into(); + #scrate::traits::StorageInfo { + prefix: < + #storage_struct as #scrate::#storage_generator_trait + >::storage_value_final_key(), + max_values: Some(1), + max_size: Some(max_size), + } + } + } + ) + }, + StorageLineTypeDef::Map(map) => { + let key = &map.key; + quote!( + impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct + #optional_storage_where_clause + { + fn storage_info() -> #scrate::traits::StorageInfo { + use #scrate::sp_runtime::SaturatedConversion; + let max_size = < + #value_type as #scrate::traits::MaxEncodedLen + >::max_encoded_len() + .saturating_add( + <#key as #scrate::traits::MaxEncodedLen>::max_encoded_len() + ) + .saturated_into(); + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: Some(max_size), + } + } + } + ) + }, + StorageLineTypeDef::DoubleMap(map) => { + let key1 = &map.key1; + let key2 = &map.key2; + quote!( + impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct + #optional_storage_where_clause + { + fn storage_info() -> #scrate::traits::StorageInfo { + use #scrate::sp_runtime::SaturatedConversion; + let max_size = < + #value_type as #scrate::traits::MaxEncodedLen + >::max_encoded_len() + .saturating_add( + <#key1 as #scrate::traits::MaxEncodedLen>::max_encoded_len() + ) + .saturating_add( + <#key2 as #scrate::traits::MaxEncodedLen>::max_encoded_len() + ) + .saturated_into(); + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: Some(max_size), + } + } + } + ) + } + } + } else { + Default::default() + }; + impls.extend(quote!( #struct_decl #struct_impl + #storage_info_impl )) } diff --git a/frame/support/procedural/src/storage/storages_info.rs b/frame/support/procedural/src/storage/storages_info.rs new file mode 100644 index 0000000000000..fe4d45cf89f88 --- /dev/null +++ b/frame/support/procedural/src/storage/storages_info.rs @@ -0,0 +1,55 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-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 trait `StoragesInfo` on module structure. + +use proc_macro2::TokenStream; +use quote::quote; +use super::DeclStorageDefExt; + +pub fn impl_storages_info(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { + if !def.generate_storage_info { + return Default::default() + } + + let mut entries = TokenStream::new(); + + for line in def.storage_lines.iter() { + let storage_struct = &line.storage_struct; + + let entry = quote!( + < + #storage_struct as #scrate::traits::StorageInfoTrait + >::storage_info(), + ); + entries.extend(entry); + } + + let module_struct = &def.module_struct; + let module_impl = &def.module_impl; + let where_clause = &def.where_clause; + + quote!( + impl#module_impl #scrate::traits::StoragesInfo for #module_struct #where_clause { + fn storages_info() -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { + #scrate::sp_std::vec![ + #entries + ] + } + } + ) +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 77163755ac56f..8d12c0cb64779 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1234,7 +1234,10 @@ pub mod pallet_prelude { EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, DebugNoBound, CloneNoBound, Twox256, Twox128, Blake2_256, Blake2_128, Identity, Twox64Concat, Blake2_128Concat, ensure, RuntimeDebug, storage, - traits::{Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess}, + traits::{ + Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, StoragesInfo, + ConstU32, GetDefault, + }, dispatch::{DispatchResultWithPostInfo, Parameter, DispatchError, DispatchResult}, weights::{DispatchClass, Pays, Weight}, storage::types::{StorageValue, StorageMap, StorageDoubleMap, ValueQuery, OptionQuery}, @@ -1343,6 +1346,17 @@ pub mod pallet_prelude { /// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using /// `::Foo`. /// +/// To generate the full storage info (used for PoV calculation) use the attribute +/// `#[pallet::set_storage_max_encoded_len]`, e.g.: +/// ```ignore +/// #[pallet::pallet] +/// #[pallet::set_storage_max_encoded_len] +/// pub struct Pallet(_); +/// ``` +/// +/// This require all storage to implement the trait [`traits::StorageMaxEncodedLen`], thus all keys +/// and value types must bound [`traits::MaxEncodedLen`]. +/// /// ### Macro expansion: /// /// The macro add this attribute to the struct definition: @@ -1367,7 +1381,13 @@ pub mod pallet_prelude { /// given by [`frame_support::traits::PalletInfo`]. /// (The implementation use the associated type `frame_system::Config::PalletInfo`). /// -/// If attribute generate_store then macro create the trait `Store` and implement it on `Pallet`. +/// It implements [`traits::StoragesInfo`] on `Pallet` which give information about all storages. +/// +/// If the attribute generate_store is set then the macro creates the trait `Store` and implements +/// it on `Pallet`. +/// +/// If the attribute set_storage_max_encoded_len is set then the macro call +/// [`traits::StorageMaxEncodedLen`] in the implementation of [`StoragesInfo`]. /// /// # Hooks: `#[pallet::hooks]` mandatory /// diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 184d96b3a54f9..20bebc6bb6075 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -21,13 +21,14 @@ use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ storage::{ - StorageAppend, StorageDecodeLength, + StorageAppend, StorageDecodeLength, StoragePrefixedMap, bounded_vec::{BoundedVec, BoundedVecValue}, types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, }, - traits::{GetDefault, StorageInstance, Get}, + traits::{GetDefault, StorageInstance, Get, MaxEncodedLen, StorageInfo}, }; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; +use sp_arithmetic::traits::SaturatedConversion; use sp_std::vec::Vec; /// A type that allow to store values for `(key1, key2)` couple. Similar to `StorageMap` but allow @@ -47,14 +48,24 @@ use sp_std::vec::Vec; /// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values /// in storage can be compromised. pub struct StorageDoubleMap< - Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind=OptionQuery, OnEmpty=GetDefault + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind=OptionQuery, + OnEmpty=GetDefault, + MaxValues=GetDefault, >( - core::marker::PhantomData<(Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty)> + core::marker::PhantomData< + (Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues) + > ); -impl +impl crate::storage::generator::StorageDoubleMap for - StorageDoubleMap + StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, @@ -63,7 +74,8 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + OnEmpty: Get + 'static, + MaxValues: Get>, { type Query = QueryKind::Query; type Hasher1 = Hasher1; @@ -82,9 +94,9 @@ where } } -impl - crate::storage::StoragePrefixedMap for - StorageDoubleMap +impl + StoragePrefixedMap for + StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, @@ -93,7 +105,8 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + OnEmpty: Get + 'static, + MaxValues: Get>, { fn module_prefix() -> &'static [u8] { >::module_prefix() @@ -103,7 +116,7 @@ where } } -impl +impl StorageDoubleMap< Prefix, Hasher1, @@ -113,6 +126,7 @@ impl, QueryKind, OnEmpty, + MaxValues, > where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, @@ -121,6 +135,7 @@ impl, OnEmpty>, OnEmpty: crate::traits::Get + 'static, + MaxValues: Get>, VecValue: BoundedVecValue, VecBound: Get, { @@ -147,8 +162,8 @@ impl - StorageDoubleMap +impl + StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, @@ -157,7 +172,8 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + OnEmpty: crate::traits::Get + 'static, + MaxValues: Get>, { /// Get the storage key used to fetch a value corresponding to a specific key. pub fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec @@ -376,8 +392,8 @@ where } } -impl - StorageDoubleMap +impl + StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher, @@ -386,7 +402,8 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + OnEmpty: crate::traits::Get + 'static, + MaxValues: Get>, { /// Enumerate all elements in the map with first key `k1` in no particular order. /// @@ -440,8 +457,10 @@ pub trait StorageDoubleMapMetadata { const HASHER2: frame_metadata::StorageHasher; } -impl StorageDoubleMapMetadata - for StorageDoubleMap where +impl + StorageDoubleMapMetadata for + StorageDoubleMap +where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, Hasher2: crate::hash::StorageHasher, @@ -449,7 +468,8 @@ impl StorageDou Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + OnEmpty: crate::traits::Get + 'static, + MaxValues: Get>, { const MODIFIER: StorageEntryModifier = QueryKind::METADATA; const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA; @@ -459,6 +479,34 @@ impl StorageDou DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); } +impl + crate::traits::StorageInfoTrait for + StorageDoubleMap +where + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec + MaxEncodedLen, + Key2: FullCodec + MaxEncodedLen, + Value: FullCodec + MaxEncodedLen, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, + MaxValues: Get>, +{ + fn storage_info() -> StorageInfo { + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: Some( + Key1::max_encoded_len() + .saturating_add(Key2::max_encoded_len()) + .saturating_add(Value::max_encoded_len()) + .saturated_into(), + ), + } + } +} + #[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 187323b4ad1ee..dbd7a54c2edb3 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -21,13 +21,14 @@ use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ storage::{ - StorageAppend, StorageDecodeLength, + StorageAppend, StorageDecodeLength, StoragePrefixedMap, bounded_vec::{BoundedVec, BoundedVecValue}, types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, }, - traits::{GetDefault, StorageInstance, Get}, + traits::{GetDefault, StorageInstance, Get, MaxEncodedLen, StorageInfo}, }; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; +use sp_arithmetic::traits::SaturatedConversion; use sp_std::prelude::*; /// A type that allow to store value for given key. Allowing to insert/remove/iterate on values. @@ -43,20 +44,23 @@ use sp_std::prelude::*; /// /// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as /// `blake2_128_concat` must be used. Otherwise, other values in storage can be compromised. -pub struct StorageMap( - core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)> +pub struct StorageMap< + Prefix, Hasher, Key, Value, QueryKind=OptionQuery, OnEmpty=GetDefault, MaxValues=GetDefault, +>( + core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues)> ); -impl +impl crate::storage::generator::StorageMap - for StorageMap + for StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, Key: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, + MaxValues: Get>, { type Query = QueryKind::Query; type Hasher = Hasher; @@ -74,15 +78,17 @@ where } } -impl crate::storage::StoragePrefixedMap for - StorageMap +impl + StoragePrefixedMap for + StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, Key: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, + MaxValues: Get>, { fn module_prefix() -> &'static [u8] { >::module_prefix() @@ -92,14 +98,15 @@ where } } -impl - StorageMap, QueryKind, OnEmpty> +impl + StorageMap, QueryKind, OnEmpty, MaxValues> where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, Key: FullCodec, QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, + MaxValues: Get>, VecValue: BoundedVecValue, VecBound: Get, { @@ -120,15 +127,16 @@ where } } -impl - StorageMap +impl + StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, Key: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, + MaxValues: Get>, { /// Get the storage key used to fetch a value corresponding to a specific key. pub fn hashed_key_for>(key: KeyArg) -> Vec { @@ -283,15 +291,16 @@ where } } -impl - StorageMap +impl + StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher, Key: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, + MaxValues: Get>, { /// Enumerate all elements in the map in no particular order. /// @@ -327,14 +336,15 @@ pub trait StorageMapMetadata { const HASHER: frame_metadata::StorageHasher; } -impl StorageMapMetadata - for StorageMap where +impl StorageMapMetadata + for StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, Key: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, + MaxValues: Get>, { const MODIFIER: StorageEntryModifier = QueryKind::METADATA; const HASHER: frame_metadata::StorageHasher = Hasher::METADATA; @@ -343,6 +353,31 @@ impl StorageMapMetadata DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); } +impl + crate::traits::StorageInfoTrait for + StorageMap +where + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec + MaxEncodedLen, + Value: FullCodec + MaxEncodedLen, + QueryKind: QueryKindTrait, + OnEmpty: Get + 'static, + MaxValues: Get>, +{ + fn storage_info() -> StorageInfo { + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: Some( + Key::max_encoded_len() + .saturating_add(Value::max_encoded_len()) + .saturated_into(), + ), + } + } +} + #[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 d536d76d76b8e..afb27c450fc6a 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -24,9 +24,10 @@ use crate::{ bounded_vec::{BoundedVec, BoundedVecValue}, types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, }, - traits::{GetDefault, StorageInstance, Get}, + traits::{GetDefault, StorageInstance, Get, MaxEncodedLen, StorageInfo}, }; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; +use sp_arithmetic::traits::SaturatedConversion; /// A type that allow to store a value. /// @@ -212,6 +213,27 @@ impl StorageValueMetadata DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); } +impl + crate::traits::StorageInfoTrait for + StorageValue +where + Prefix: StorageInstance, + Value: FullCodec + MaxEncodedLen, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static +{ + fn storage_info() -> StorageInfo { + StorageInfo { + prefix: Self::hashed_key(), + max_values: Some(1), + max_size: Some( + Value::max_encoded_len() + .saturated_into(), + ), + } + } +} + #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d15356c1e1b09..7e89917c5dbb9 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -50,7 +50,7 @@ mod misc; pub use misc::{ Len, Get, GetDefault, HandleLifetime, TryDrop, Time, UnixTime, IsType, IsSubType, ExecuteBlock, SameOrOther, OnNewAccount, OnKilledAccount, OffchainWorker, GetBacking, Backing, ExtrinsicCall, - EnsureInherentsAreFirst, + EnsureInherentsAreFirst, ConstU32, }; mod stored_map; @@ -73,7 +73,7 @@ pub use hooks::GenesisBuild; pub mod schedule; mod storage; -pub use storage::{Instance, StorageInstance}; +pub use storage::{Instance, StorageInstance, StoragesInfo, StorageInfo, StorageInfoTrait}; mod dispatch; pub use dispatch::{EnsureOrigin, OriginTrait, UnfilteredDispatchable}; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index d3010358dd883..7ec29522cbc75 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -53,6 +53,21 @@ impl Get for GetDefault { } } +/// Implement `Get` and `Get>` using the given const. +pub struct ConstU32; + +impl Get for ConstU32 { + fn get() -> u32 { + T + } +} + +impl Get> for ConstU32 { + fn get() -> Option { + Some(T) + } +} + /// A type for which some values make sense to be able to drop without further consideration. pub trait TryDrop: Sized { /// Drop an instance cleanly. Only works if its value represents "no-operation". diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index c42e1abf73ea3..205d20cd3c829 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -17,6 +17,8 @@ //! Traits for encoding data related to pallet's storage items. +use sp_std::prelude::*; + /// An instance of a pallet in the storage. /// /// It is required that these instances are unique, to support multiple instances per pallet in the same runtime! @@ -45,3 +47,35 @@ pub trait StorageInstance { /// Prefix given to a storage to isolate from other storages in the pallet. const STORAGE_PREFIX: &'static str; } + +/// Some info about a storage in a pallet. +#[derive(codec::Encode, codec::Decode, crate::RuntimeDebug, Eq, PartialEq, Clone)] +pub struct StorageInfo { + /// The prefix of the storage. All keys after the prefix are considered part of the storage + pub prefix: [u8; 32], + /// The maximum number of values in the storage, or none if no maximum specified. + pub max_values: Option, + /// The maximum size of key/values in the storage, or none if no maximum specified. + pub max_size: Option, +} + +/// A trait to give information about storages. +/// +/// It can be used to calculate PoV worst case size. +pub trait StoragesInfo { + fn storages_info() -> Vec; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl StoragesInfo for Tuple { + fn storages_info() -> Vec { + let mut res = vec![]; + for_tuples!( #( res.extend_from_slice(&Tuple::storages_info()); )* ); + res + } +} + +/// A trait for types which contains storage info. +pub trait StorageInfoTrait { + fn storage_info() -> StorageInfo; +} diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index a2690b1379db5..2e797731e14ff 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -27,9 +27,13 @@ mod tests { pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} } - pub trait Config: frame_support_test::Config {} + pub trait Config: frame_support_test::Config { + type Origin2: codec::Codec + codec::EncodeLike + Default + + frame_support::traits::MaxEncodedLen; + } frame_support::decl_storage! { + generate_storage_info trait Store for Module as TestStorage { // non-getters: pub / $default @@ -41,7 +45,7 @@ mod tests { // getters: pub / $default // we need at least one type which uses T, otherwise GenesisConfig will complain. - GETU32 get(fn u32_getter): T::Origin; + GETU32 get(fn u32_getter): T::Origin2; pub PUBGETU32 get(fn pub_u32_getter): u32; GETU32WITHCONFIG get(fn u32_getter_with_config) config(): u32; pub PUBGETU32WITHCONFIG get(fn pub_u32_getter_with_config) config(): u32; @@ -56,22 +60,26 @@ mod tests { GetOptU32WithBuilderNone get(fn opt_u32_with_builder_none) build(|_| None): Option; // map non-getters: pub / $default - MAPU32: map hasher(blake2_128_concat) u32 => Option; - pub PUBMAPU32: map hasher(blake2_128_concat) u32 => Option; - MAPU32MYDEF: map hasher(blake2_128_concat) u32 => Option; - pub PUBMAPU32MYDEF: map hasher(blake2_128_concat) u32 => Option; + MAPU32 max_values(3): map hasher(blake2_128_concat) u32 => Option<[u8; 4]>; + pub PUBMAPU32: map hasher(blake2_128_concat) u32 => Option<[u8; 4]>; // map getters: pub / $default - GETMAPU32 get(fn map_u32_getter): map hasher(blake2_128_concat) u32 => String; - pub PUBGETMAPU32 get(fn pub_map_u32_getter): map hasher(blake2_128_concat) u32 => String; + GETMAPU32 get(fn map_u32_getter): map hasher(blake2_128_concat) u32 => [u8; 4]; + pub PUBGETMAPU32 get(fn pub_map_u32_getter): map hasher(blake2_128_concat) u32 => [u8; 4]; GETMAPU32MYDEF get(fn map_u32_getter_mydef): - map hasher(blake2_128_concat) u32 => String = "map".into(); + map hasher(blake2_128_concat) u32 => [u8; 4] = *b"mapd"; pub PUBGETMAPU32MYDEF get(fn pub_map_u32_getter_mydef): - map hasher(blake2_128_concat) u32 => String = "pubmap".into(); + map hasher(blake2_128_concat) u32 => [u8; 4] = *b"pubm"; + + DOUBLEMAP max_values(3): double_map + hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => Option<[u8; 4]>; - COMPLEXTYPE1: ::std::vec::Vec; - COMPLEXTYPE2: (Vec)>>, u32); + DOUBLEMAP2: double_map + hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => Option<[u8; 4]>; + + COMPLEXTYPE1: (::std::option::Option,); + COMPLEXTYPE2: ([[(u16, Option<()>); 32]; 12], u32); COMPLEXTYPE3: [u32; 25]; } add_extra_genesis { @@ -88,7 +96,9 @@ mod tests { type DbWeight = (); } - impl Config for TraitImpl {} + impl Config for TraitImpl { + type Origin2 = u32; + } const EXPECTED_METADATA: StorageMetadata = StorageMetadata { prefix: DecodeDifferent::Encode("TestStorage"), @@ -133,7 +143,7 @@ mod tests { StorageEntryMetadata { name: DecodeDifferent::Encode("GETU32"), modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(DecodeDifferent::Encode("T::Origin")), + ty: StorageEntryType::Plain(DecodeDifferent::Encode("T::Origin2")), default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGETU32(PhantomData::)) ), @@ -244,7 +254,7 @@ mod tests { ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_128Concat, key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), + value: DecodeDifferent::Encode("[u8; 4]"), unused: false, }, default: DecodeDifferent::Encode( @@ -258,7 +268,7 @@ mod tests { ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_128Concat, key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), + value: DecodeDifferent::Encode("[u8; 4]"), unused: false, }, default: DecodeDifferent::Encode( @@ -267,93 +277,95 @@ mod tests { documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { - name: DecodeDifferent::Encode("MAPU32MYDEF"), - modifier: StorageEntryModifier::Optional, + name: DecodeDifferent::Encode("GETMAPU32"), + modifier: StorageEntryModifier::Default, ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_128Concat, key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), + value: DecodeDifferent::Encode("[u8; 4]"), unused: false, }, default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructMAPU32MYDEF(PhantomData::)) + DefaultByteGetter(&__GetByteStructGETMAPU32(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { - name: DecodeDifferent::Encode("PUBMAPU32MYDEF"), - modifier: StorageEntryModifier::Optional, + name: DecodeDifferent::Encode("PUBGETMAPU32"), + modifier: StorageEntryModifier::Default, ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_128Concat, key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), + value: DecodeDifferent::Encode("[u8; 4]"), unused: false, }, default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBMAPU32MYDEF(PhantomData::)) + DefaultByteGetter(&__GetByteStructPUBGETMAPU32(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { - name: DecodeDifferent::Encode("GETMAPU32"), + name: DecodeDifferent::Encode("GETMAPU32MYDEF"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_128Concat, key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), + value: DecodeDifferent::Encode("[u8; 4]"), unused: false, }, default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETMAPU32(PhantomData::)) + DefaultByteGetter(&__GetByteStructGETMAPU32MYDEF(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { - name: DecodeDifferent::Encode("PUBGETMAPU32"), + name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_128Concat, key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), + value: DecodeDifferent::Encode("[u8; 4]"), unused: false, }, default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETMAPU32(PhantomData::)) + DefaultByteGetter(&__GetByteStructPUBGETMAPU32MYDEF(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { - name: DecodeDifferent::Encode("GETMAPU32MYDEF"), - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + name: DecodeDifferent::Encode("DOUBLEMAP"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::DoubleMap { hasher: StorageHasher::Blake2_128Concat, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - unused: false, + key1: DecodeDifferent::Encode("u32"), + key2: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("[u8; 4]"), + key2_hasher: StorageHasher::Blake2_128Concat, }, default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETMAPU32MYDEF(PhantomData::)) + DefaultByteGetter(&__GetByteStructDOUBLEMAP(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { - name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"), - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + name: DecodeDifferent::Encode("DOUBLEMAP2"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::DoubleMap { hasher: StorageHasher::Blake2_128Concat, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - unused: false, + key1: DecodeDifferent::Encode("u32"), + key2: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("[u8; 4]"), + key2_hasher: StorageHasher::Blake2_128Concat, }, default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETMAPU32MYDEF(PhantomData::)) + DefaultByteGetter(&__GetByteStructDOUBLEMAP2(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("COMPLEXTYPE1"), modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(DecodeDifferent::Encode("::std::vec::Vec")), + ty: StorageEntryType::Plain(DecodeDifferent::Encode("(::std::option::Option,)")), default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructCOMPLEXTYPE1(PhantomData::)) ), @@ -362,7 +374,7 @@ mod tests { StorageEntryMetadata { name: DecodeDifferent::Encode("COMPLEXTYPE2"), modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(DecodeDifferent::Encode("(Vec)>>, u32)")), + ty: StorageEntryType::Plain(DecodeDifferent::Encode("([[(u16, Option<()>); 32]; 12], u32)")), default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructCOMPLEXTYPE2(PhantomData::)) ), @@ -381,6 +393,161 @@ mod tests { ), }; + #[test] + fn storages_info() { + use frame_support::{ + StorageHasher, + traits::{StoragesInfo, StorageInfo}, + pallet_prelude::*, + }; + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res + }; + pretty_assertions::assert_eq!( + >::storages_info(), + vec![ + StorageInfo { + prefix: prefix(b"TestStorage", b"U32"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBU32"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"U32MYDEF"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBU32MYDEF"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GETU32"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETU32"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GETU32WITHCONFIG"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETU32WITHCONFIG"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GETU32MYDEF"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETU32MYDEF"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GETU32WITHCONFIGMYDEF"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETU32WITHCONFIGMYDEF"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETU32WITHCONFIGMYDEFOPT"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GetU32WithBuilder"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GetOptU32WithBuilderSome"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GetOptU32WithBuilderNone"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"MAPU32"), + max_values: Some(3), + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBMAPU32"), + max_values: None, + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GETMAPU32"), + max_values: None, + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETMAPU32"), + max_values: None, + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"GETMAPU32MYDEF"), + max_values: None, + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"PUBGETMAPU32MYDEF"), + max_values: None, + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"DOUBLEMAP"), + max_values: Some(3), + max_size: Some(12), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"DOUBLEMAP2"), + max_values: None, + max_size: Some(12), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"COMPLEXTYPE1"), + max_values: Some(1), + max_size: Some(5), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"COMPLEXTYPE2"), + max_values: Some(1), + max_size: Some(1156), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"COMPLEXTYPE3"), + max_values: Some(1), + max_size: Some(100), + }, + ], + ); + } + #[test] fn store_metadata() { let metadata = Module::::storage_metadata(); diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 3bde38c78e2c1..c5612b267982e 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -19,6 +19,7 @@ use frame_support::{ weights::{DispatchInfo, DispatchClass, Pays, GetDispatchInfo}, traits::{ GetCallName, OnInitialize, OnFinalize, OnRuntimeUpgrade, GetPalletVersion, OnGenesis, + MaxEncodedLen, }, dispatch::{UnfilteredDispatchable, Parameter}, storage::unhashed, @@ -47,10 +48,10 @@ impl From for u64 { fn from(_t: SomeType6) -> Self { 0u64 } } pub struct SomeType7; impl From for u64 { fn from(_t: SomeType7) -> Self { 0u64 } } -pub trait SomeAssociation1 { type _1: Parameter; } +pub trait SomeAssociation1 { type _1: Parameter + MaxEncodedLen; } impl SomeAssociation1 for u64 { type _1 = u64; } -pub trait SomeAssociation2 { type _2: Parameter; } +pub trait SomeAssociation2 { type _2: Parameter + MaxEncodedLen; } impl SomeAssociation2 for u64 { type _2 = u64; } #[frame_support::pallet] @@ -100,6 +101,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::generate_storages_info] pub struct Pallet(_); #[pallet::hooks] @@ -209,13 +211,15 @@ pub mod pallet { StorageMap<_, Blake2_128Concat, u8, u16, ValueQuery, MyDefault>; #[pallet::storage] - pub type Map2 = StorageMap<_, Twox64Concat, u16, u32>; + pub type Map2 = StorageMap<_, Twox64Concat, u16, u32, OptionQuery, GetDefault, ConstU32<3>>; #[pallet::storage] pub type DoubleMap = StorageDoubleMap<_, Blake2_128Concat, u8, Twox64Concat, u16, u32>; #[pallet::storage] - pub type DoubleMap2 = StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; + pub type DoubleMap2 = StorageDoubleMap< + _, Twox64Concat, u16, Blake2_128Concat, u32, u64, OptionQuery, GetDefault, ConstU32<5>, + >; #[pallet::storage] #[pallet::getter(fn conditional_value)] @@ -225,7 +229,8 @@ pub mod pallet { #[cfg(feature = "conditional-storage")] #[pallet::storage] #[pallet::getter(fn conditional_map)] - pub type ConditionalMap = StorageMap<_, Twox64Concat, u16, u32>; + pub type ConditionalMap = + StorageMap<_, Twox64Concat, u16, u32, OptionQuery, GetDefault, ConstU32<12>>; #[cfg(feature = "conditional-storage")] #[pallet::storage] @@ -533,7 +538,7 @@ fn pallet_expand_deposit_event() { #[test] fn storage_expand() { use frame_support::pallet_prelude::*; - use frame_support::StoragePrefixedMap; + use frame_support::storage::StoragePrefixedMap; fn twox_64_concat(d: &[u8]) -> Vec { let mut v = twox_64(d).to_vec(); @@ -881,3 +886,79 @@ fn test_pallet_info_access() { assert_eq!(::index(), 1); assert_eq!(::index(), 2); } + +#[test] +fn test_storages_info() { + use frame_support::{ + StorageHasher, + traits::{StoragesInfo, StorageInfo}, + pallet_prelude::*, + }; + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res + }; + + assert_eq!( + Example::storages_info(), + vec![ + StorageInfo { + prefix: prefix(b"Example", b"ValueWhereClause"), + max_values: Some(1), + max_size: Some(8), + }, + StorageInfo { + prefix: prefix(b"Example", b"Value"), + max_values: Some(1), + max_size: Some(4), + }, + StorageInfo { + prefix: prefix(b"Example", b"Map"), + max_values: None, + max_size: Some(3), + }, + StorageInfo { + prefix: prefix(b"Example", b"Map2"), + max_values: Some(3), + max_size: Some(6), + }, + StorageInfo { + prefix: prefix(b"Example", b"DoubleMap"), + max_values: None, + max_size: Some(7), + }, + StorageInfo { + prefix: prefix(b"Example", b"DoubleMap2"), + max_values: Some(5), + max_size: Some(14), + }, + #[cfg(feature = "conditional-storage")] + { + StorageInfo { + prefix: prefix(b"Example", b"ConditionalValue"), + max_values: Some(1), + max_size: Some(4), + } + }, + #[cfg(feature = "conditional-storage")] + { + StorageInfo { + prefix: prefix(b"Example", b"ConditionalMap"), + max_values: Some(12), + max_size: Some(6), + } + }, + #[cfg(feature = "conditional-storage")] + { + StorageInfo { + prefix: prefix(b"Example", b"ConditionalDoubleMap"), + max_values: None, + max_size: Some(7), + } + }, + ], + ); +} diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index f0143b9c40d6c..ad88d3565aa5a 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -403,7 +403,7 @@ fn pallet_expand_deposit_event() { #[test] fn storage_expand() { use frame_support::pallet_prelude::*; - use frame_support::StoragePrefixedMap; + use frame_support::storage::StoragePrefixedMap; fn twox_64_concat(d: &[u8]) -> Vec { let mut v = twox_64(d).to_vec(); diff --git a/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr b/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr index eed6ad4494edc..232144b8deaca 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr +++ b/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr @@ -1,5 +1,5 @@ -error: Invalid pallet::pallet, multiple argument pallet::generate_store found - --> $DIR/duplicate_store_attr.rs:12:33 +error: Unexpected duplicated attribute + --> $DIR/duplicate_store_attr.rs:12:12 | 12 | #[pallet::generate_store(trait Store)] - | ^^^^^ + | ^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs new file mode 100644 index 0000000000000..22b3658329b97 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs @@ -0,0 +1,27 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::{Hooks, StorageValue}; + use frame_system::pallet_prelude::BlockNumberFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + #[pallet::generate_storages_info] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} + + #[derive(codec::Encode, codec::Decode)] + struct Bar; + + #[pallet::storage] + type Foo = StorageValue<_, Bar>; +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr new file mode 100644 index 0000000000000..a0ecd4f6555c9 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -0,0 +1,8 @@ +error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied + --> $DIR/storage_info_unsatisfied.rs:10:12 + | +10 | #[pallet::generate_storages_info] + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required by `storage_info` From 42c4f483496acf090724f7d61beec6be5a7e6c27 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Wed, 12 May 2021 13:25:03 +0200 Subject: [PATCH 2/9] some formatting + doc --- frame/support/procedural/src/lib.rs | 11 ++++++++++- .../procedural/src/pallet/expand/pallet_struct.rs | 1 - frame/support/procedural/src/storage/parse.rs | 1 - frame/support/src/storage/types/double_map.rs | 10 +++++----- frame/support/src/storage/types/map.rs | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 7f7584ac080e6..5146b8e78380e 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -237,11 +237,20 @@ use proc_macro::TokenStream; /// add_extra_genesis { /// config(phantom): std::marker::PhantomData, /// } -/// ... +/// ``` /// /// This adds a field to your `GenesisConfig` with the name `phantom` that you can initialize with /// `Default::default()`. /// +/// ## PoV information +/// +/// To implement the trait `StorageInfoTrait` for storages an additional attribute can be used +/// `generate_storage_info`: +/// ```nocompile +/// decl_storage! { generate_storage_info +/// trait Store for ... +/// } +/// ``` #[proc_macro] pub fn decl_storage(input: TokenStream) -> TokenStream { storage::decl_storage_impl(input) diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 2bf62e9e3c8db..cf0523a2899d5 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -134,7 +134,6 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { Default::default() }; - quote::quote_spanned!(def.pallet_struct.attr_span => #module_error_metadata diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 523c7f2072383..989496ad1c2ef 100644 --- a/frame/support/procedural/src/storage/parse.rs +++ b/frame/support/procedural/src/storage/parse.rs @@ -202,7 +202,6 @@ struct DeclStorageMaxValues { pub max_values_keyword: keyword::max_values, pub expr: ext::Parens, } - impl_parse_for_opt!(DeclStorageMaxValues=> keyword::max_values); #[derive(Parse, ToTokens, Debug)] diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index b95df9953ce2d..b88e6b8416c55 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -134,7 +134,7 @@ impl, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, MaxValues: Get>, VecValue: FullCodec, VecBound: Get, @@ -172,7 +172,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, MaxValues: Get>, { /// Get the storage key used to fetch a value corresponding to a specific key. @@ -402,7 +402,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, MaxValues: Get>, { /// Enumerate all elements in the map with first key `k1` in no particular order. @@ -468,7 +468,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, MaxValues: Get>, { const MODIFIER: StorageEntryModifier = QueryKind::METADATA; @@ -490,7 +490,7 @@ where Key2: FullCodec + MaxEncodedLen, Value: FullCodec + MaxEncodedLen, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, MaxValues: Get>, { fn storage_info() -> StorageInfo { diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index c44355e435c00..6e2e2221c4aae 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -105,7 +105,7 @@ where Hasher: crate::hash::StorageHasher, Key: FullCodec, QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: Get + 'static, MaxValues: Get>, VecValue: FullCodec, VecBound: Get, From ada719bc31e69ba51296116dd67ef91d11672332 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 14 May 2021 13:31:19 +0200 Subject: [PATCH 3/9] rename StoragesInfo -> PalletStorageInfo --- frame/support/procedural/src/lib.rs | 2 +- .../src/pallet/expand/pallet_struct.rs | 12 ++++----- .../src/pallet/parse/pallet_struct.rs | 26 +++++++++---------- frame/support/procedural/src/storage/mod.rs | 6 ++--- .../{storages_info.rs => storage_info.rs} | 8 +++--- frame/support/src/lib.rs | 6 ++--- frame/support/src/traits.rs | 2 +- frame/support/src/traits/storage.rs | 10 +++---- frame/support/test/tests/decl_storage.rs | 6 ++--- frame/support/test/tests/pallet.rs | 8 +++--- .../pallet_ui/storage_info_unsatisfied.rs | 2 +- .../pallet_ui/storage_info_unsatisfied.stderr | 6 ++--- .../storage_info_unsatisfied_nmap.rs | 2 +- .../storage_info_unsatisfied_nmap.stderr | 6 ++--- 14 files changed, 51 insertions(+), 51 deletions(-) rename frame/support/procedural/src/storage/{storages_info.rs => storage_info.rs} (81%) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 5146b8e78380e..27395d9660dc8 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -157,7 +157,7 @@ use proc_macro::TokenStream; /// Will include the item in `GenesisConfig`. /// * \[optional\] `build(#closure)`: Closure called with storage overlays. /// * \[optional\] `max_values(#expr)`: `expr` is an expression returning a `u32`. It is used to -/// implement `StoragesInfo`. Note this attribute is not available for storage value as the maximum +/// implement `PalletStorageInfo`. Note this attribute is not available for storage value as the maximum /// number of values is 1. /// * `#type`: Storage type. /// * \[optional\] `#default`: Value returned when none. diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index cf0523a2899d5..48cdd8cef59de 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -24,7 +24,7 @@ use crate::pallet::{Def, expand::merge_where_clauses, parse::helper::get_doc_lit /// * declare Module type alias for construct_runtime /// * replace the first field type of `struct Pallet` with `PhantomData` if it is `_` /// * implementation of `PalletInfoAccess` information -/// * implementation of `StoragesInfo` on Pallet +/// * implementation of `PalletStorageInfo` on Pallet pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { let frame_support = &def.frame_support; let frame_system = &def.frame_system; @@ -102,18 +102,18 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { ) }; - let storages_info = if let Some(storages_info_span) = def.pallet_struct.generate_storages_info { + 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!(storages_info_span => - impl<#type_impl_gen> #frame_support::traits::StoragesInfo + quote::quote_spanned!(storage_info_span => + impl<#type_impl_gen> #frame_support::traits::PalletStorageInfo for #pallet_ident<#type_use_gen> #storages_where_clauses { - fn storages_info() + fn storage_info() -> #frame_support::sp_std::vec::Vec<#frame_support::traits::StorageInfo> { #frame_support::sp_std::vec![ @@ -195,6 +195,6 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } } - #storages_info + #storage_info ) } diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 3aeb70d201105..b76b10437466f 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -24,7 +24,7 @@ mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(Pallet); syn::custom_keyword!(generate_store); - syn::custom_keyword!(generate_storages_info); + syn::custom_keyword!(generate_storage_info); syn::custom_keyword!(Store); } @@ -40,28 +40,28 @@ pub struct PalletStructDef { pub store: Option<(syn::Visibility, keyword::Store)>, /// The span of the pallet::pallet attribute. pub attr_span: proc_macro2::Span, - /// Whether to specify the storages max encoded len when implementing `StoragesInfo`. + /// Whether to specify the storages max encoded len when implementing `PalletStorageInfo`. /// Contains the span of the attribute. - pub generate_storages_info: Option, + pub generate_storage_info: Option, } /// Parse for one variant of: /// * `#[pallet::generate_store($vis trait Store)]` -/// * `#[pallet::generate_storages_info]` +/// * `#[pallet::generate_storage_info]` pub enum PalletStructAttr { GenerateStore { span: proc_macro2::Span, vis: syn::Visibility, keyword: keyword::Store, }, - GenerateStoragesInfo(proc_macro2::Span), + GeneratePalletStorageInfo(proc_macro2::Span), } impl PalletStructAttr { fn span(&self) -> proc_macro2::Span { match self { Self::GenerateStore { span, .. } => *span, - Self::GenerateStoragesInfo(span) => *span, + Self::GeneratePalletStorageInfo(span) => *span, } } } @@ -84,9 +84,9 @@ impl syn::parse::Parse for PalletStructAttr { generate_content.parse::()?; let keyword = generate_content.parse::()?; Ok(Self::GenerateStore { vis, keyword, span }) - } else if lookahead.peek(keyword::generate_storages_info) { - let span = content.parse::()?.span(); - Ok(Self::GenerateStoragesInfo(span)) + } else if lookahead.peek(keyword::generate_storage_info) { + let span = content.parse::()?.span(); + Ok(Self::GeneratePalletStorageInfo(span)) } else { Err(lookahead.error()) } @@ -107,7 +107,7 @@ impl PalletStructDef { }; let mut store = None; - let mut generate_storages_info = None; + let mut generate_storage_info = None; let struct_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; for attr in struct_attrs { @@ -115,8 +115,8 @@ impl PalletStructDef { PalletStructAttr::GenerateStore { vis, keyword, .. } if store.is_none() => { store = Some((vis, keyword)); }, - PalletStructAttr::GenerateStoragesInfo(span) if generate_storages_info.is_none() => { - generate_storages_info = Some(span); + PalletStructAttr::GeneratePalletStorageInfo(span) if generate_storage_info.is_none() => { + generate_storage_info = Some(span); }, attr => { let msg = "Unexpected duplicated attribute"; @@ -140,6 +140,6 @@ 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_storages_info }) + Ok(Self { index, instances, pallet, store, attr_span, generate_storage_info }) } } diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 1af0151f349cf..3a1915e43144d 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -18,7 +18,7 @@ //! `decl_storage` input definition and expansion. mod storage_struct; -mod storages_info; +mod storage_info; mod parse; mod store_trait; mod getters; @@ -480,7 +480,7 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr let instance_trait = instance_trait::decl_and_impl(&def_ext); let genesis_config = genesis_config::genesis_config_and_build_storage(&def_ext); let storage_struct = storage_struct::decl_and_impl(&def_ext); - let storages_info = storages_info::impl_storages_info(&def_ext); + let storage_info = storage_info::impl_storage_info(&def_ext); quote!( use #scrate::{ @@ -501,6 +501,6 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr #instance_trait #genesis_config #storage_struct - #storages_info + #storage_info ).into() } diff --git a/frame/support/procedural/src/storage/storages_info.rs b/frame/support/procedural/src/storage/storage_info.rs similarity index 81% rename from frame/support/procedural/src/storage/storages_info.rs rename to frame/support/procedural/src/storage/storage_info.rs index d6f79c5405ad5..2e59a96f146f2 100644 --- a/frame/support/procedural/src/storage/storages_info.rs +++ b/frame/support/procedural/src/storage/storage_info.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Implementation of trait `StoragesInfo` on module structure. +//! Implementation of trait `PalletStorageInfo` on module structure. use proc_macro2::TokenStream; use quote::quote; use super::DeclStorageDefExt; -pub fn impl_storages_info(def: &DeclStorageDefExt) -> TokenStream { +pub fn impl_storage_info(def: &DeclStorageDefExt) -> TokenStream { if !def.generate_storage_info { return Default::default() } @@ -46,8 +46,8 @@ pub fn impl_storages_info(def: &DeclStorageDefExt) -> TokenStream { let where_clause = &def.where_clause; quote!( - impl#module_impl #scrate::traits::StoragesInfo for #module_struct #where_clause { - fn storages_info() -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { + impl#module_impl #scrate::traits::PalletStorageInfo for #module_struct #where_clause { + fn storage_info() -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { #scrate::sp_std::vec![ #entries ] diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 0d6257ac6295c..72ff840bf8a10 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1235,7 +1235,7 @@ pub mod pallet_prelude { Twox128, Blake2_256, Blake2_128, Identity, Twox64Concat, Blake2_128Concat, ensure, RuntimeDebug, storage, traits::{ - Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, StoragesInfo, + Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, PalletStorageInfo, ConstU32, GetDefault, }, dispatch::{DispatchResultWithPostInfo, Parameter, DispatchError, DispatchResult}, @@ -1384,13 +1384,13 @@ pub mod pallet_prelude { /// given by [`frame_support::traits::PalletInfo`]. /// (The implementation use the associated type `frame_system::Config::PalletInfo`). /// -/// It implements [`traits::StoragesInfo`] on `Pallet` which give information about all storages. +/// It implements [`traits::PalletStorageInfo`] on `Pallet` which give information about all storages. /// /// If the attribute generate_store is set then the macro creates the trait `Store` and implements /// it on `Pallet`. /// /// If the attribute set_storage_max_encoded_len is set then the macro call -/// [`traits::StorageMaxEncodedLen`] in the implementation of [`StoragesInfo`]. +/// [`traits::StorageMaxEncodedLen`] in the implementation of [`PalletStorageInfo`]. /// /// # Hooks: `#[pallet::hooks]` mandatory /// diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index cfac84aea865e..5b0a80df0ed28 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -73,7 +73,7 @@ pub use hooks::GenesisBuild; pub mod schedule; mod storage; -pub use storage::{Instance, StorageInstance, StoragesInfo, StorageInfo, StorageInfoTrait}; +pub use storage::{Instance, StorageInstance, PalletStorageInfo, 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 205d20cd3c829..ab6fe96f1eeba 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -62,15 +62,15 @@ pub struct StorageInfo { /// A trait to give information about storages. /// /// It can be used to calculate PoV worst case size. -pub trait StoragesInfo { - fn storages_info() -> Vec; +pub trait PalletStorageInfo { + fn storage_info() -> Vec; } #[impl_trait_for_tuples::impl_for_tuples(30)] -impl StoragesInfo for Tuple { - fn storages_info() -> Vec { +impl PalletStorageInfo for Tuple { + fn storage_info() -> Vec { let mut res = vec![]; - for_tuples!( #( res.extend_from_slice(&Tuple::storages_info()); )* ); + for_tuples!( #( res.extend_from_slice(&Tuple::storage_info()); )* ); res } } diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index 2e797731e14ff..27813a76feec3 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -394,10 +394,10 @@ mod tests { }; #[test] - fn storages_info() { + fn storage_info() { use frame_support::{ StorageHasher, - traits::{StoragesInfo, StorageInfo}, + traits::{PalletStorageInfo, StorageInfo}, pallet_prelude::*, }; let prefix = |pallet_name, storage_name| { @@ -407,7 +407,7 @@ mod tests { res }; pretty_assertions::assert_eq!( - >::storages_info(), + >::storage_info(), vec![ StorageInfo { prefix: prefix(b"TestStorage", b"U32"), diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 4bb00d9f64087..114b975f8b502 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -101,7 +101,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - #[pallet::generate_storages_info] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::hooks] @@ -976,10 +976,10 @@ fn test_pallet_info_access() { } #[test] -fn test_storages_info() { +fn test_storage_info() { use frame_support::{ StorageHasher, - traits::{StoragesInfo, StorageInfo}, + traits::{PalletStorageInfo, StorageInfo}, pallet_prelude::*, }; @@ -991,7 +991,7 @@ fn test_storages_info() { }; assert_eq!( - Example::storages_info(), + Example::storage_info(), vec![ StorageInfo { prefix: prefix(b"Example", b"ValueWhereClause"), diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs index 22b3658329b97..569e59ef6ec27 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs @@ -7,7 +7,7 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_storages_info] + #[pallet::generate_storage_info] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index a0ecd4f6555c9..b263bdf52b2d5 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied --> $DIR/storage_info_unsatisfied.rs:10:12 | -10 | #[pallet::generate_storages_info] - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` +10 | #[pallet::generate_storage_info] + | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `storage_info` + = note: required by `frame_support::traits::StorageInfoTrait::storage_info` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs index 8afe3162c0c71..3d03099c3c4b6 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs @@ -7,7 +7,7 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_storages_info] + #[pallet::generate_storage_info] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 1079036f2aaa0..8ffa8eb1756a7 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -1,9 +1,9 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied --> $DIR/storage_info_unsatisfied_nmap.rs:10:12 | -10 | #[pallet::generate_storages_info] - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` +10 | #[pallet::generate_storage_info] + | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `types::key::KeyGeneratorMaxEncodedLen` for `NMapKey` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` - = note: required by `storage_info` + = note: required by `frame_support::traits::StorageInfoTrait::storage_info` From 341d3f578a4d5656ed0b7ae3348cc5baf7ab1f9d Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 14 May 2021 14:02:15 +0200 Subject: [PATCH 4/9] merge both StorageInfoTrait and PalletStorageInfo I think it is more future proof. In the future some storage could make use of multiple prefix. Like one to store how much value has been inserted, etc... --- frame/support/procedural/src/lib.rs | 2 +- .../src/pallet/expand/pallet_struct.rs | 29 +++--- .../src/pallet/parse/pallet_struct.rs | 10 +-- .../procedural/src/storage/storage_info.rs | 22 ++--- .../procedural/src/storage/storage_struct.rs | 90 +++++++++++-------- frame/support/src/lib.rs | 9 +- frame/support/src/storage/types/double_map.rs | 26 +++--- frame/support/src/storage/types/map.rs | 22 ++--- frame/support/src/storage/types/nmap.rs | 22 ++--- frame/support/src/storage/types/value.rs | 21 +++-- frame/support/src/traits.rs | 2 +- frame/support/src/traits/storage.rs | 13 +-- frame/support/test/tests/decl_storage.rs | 2 +- frame/support/test/tests/pallet.rs | 2 +- 14 files changed, 150 insertions(+), 122 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 27395d9660dc8..6b163ed5d79e3 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -157,7 +157,7 @@ use proc_macro::TokenStream; /// Will include the item in `GenesisConfig`. /// * \[optional\] `build(#closure)`: Closure called with storage overlays. /// * \[optional\] `max_values(#expr)`: `expr` is an expression returning a `u32`. It is used to -/// implement `PalletStorageInfo`. Note this attribute is not available for storage value as the maximum +/// implement `StorageInfoTrait`. Note this attribute is not available for storage value as the maximum /// number of values is 1. /// * `#type`: Storage type. /// * \[optional\] `#default`: Value returned when none. diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 48cdd8cef59de..b655227cfc10d 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -24,7 +24,7 @@ use crate::pallet::{Def, expand::merge_where_clauses, parse::helper::get_doc_lit /// * declare Module type alias for construct_runtime /// * replace the first field type of `struct Pallet` with `PhantomData` if it is `_` /// * implementation of `PalletInfoAccess` information -/// * implementation of `PalletStorageInfo` on Pallet +/// * implementation of `StorageInfoTrait` on Pallet pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { let frame_support = &def.frame_support; let frame_system = &def.frame_system; @@ -109,24 +109,27 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { .collect::>(); quote::quote_spanned!(storage_info_span => - impl<#type_impl_gen> #frame_support::traits::PalletStorageInfo + 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> { - #frame_support::sp_std::vec![ - #( - #(#storage_cfg_attrs)* - { - < - #storage_names<#type_use_gen> - as #frame_support::traits::StorageInfoTrait - >::storage_info() - }, - )* - ] + 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 } } ) diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index b76b10437466f..ba85da2d9e684 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -40,7 +40,7 @@ pub struct PalletStructDef { pub store: Option<(syn::Visibility, keyword::Store)>, /// The span of the pallet::pallet attribute. pub attr_span: proc_macro2::Span, - /// Whether to specify the storages max encoded len when implementing `PalletStorageInfo`. + /// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`. /// Contains the span of the attribute. pub generate_storage_info: Option, } @@ -54,14 +54,14 @@ pub enum PalletStructAttr { vis: syn::Visibility, keyword: keyword::Store, }, - GeneratePalletStorageInfo(proc_macro2::Span), + GenerateStorageInfoTrait(proc_macro2::Span), } impl PalletStructAttr { fn span(&self) -> proc_macro2::Span { match self { Self::GenerateStore { span, .. } => *span, - Self::GeneratePalletStorageInfo(span) => *span, + Self::GenerateStorageInfoTrait(span) => *span, } } } @@ -86,7 +86,7 @@ impl syn::parse::Parse for PalletStructAttr { Ok(Self::GenerateStore { vis, keyword, span }) } else if lookahead.peek(keyword::generate_storage_info) { let span = content.parse::()?.span(); - Ok(Self::GeneratePalletStorageInfo(span)) + Ok(Self::GenerateStorageInfoTrait(span)) } else { Err(lookahead.error()) } @@ -115,7 +115,7 @@ impl PalletStructDef { PalletStructAttr::GenerateStore { vis, keyword, .. } if store.is_none() => { store = Some((vis, keyword)); }, - PalletStructAttr::GeneratePalletStorageInfo(span) if generate_storage_info.is_none() => { + PalletStructAttr::GenerateStorageInfoTrait(span) if generate_storage_info.is_none() => { generate_storage_info = Some(span); }, attr => { diff --git a/frame/support/procedural/src/storage/storage_info.rs b/frame/support/procedural/src/storage/storage_info.rs index 2e59a96f146f2..ed07ccbfc71d6 100644 --- a/frame/support/procedural/src/storage/storage_info.rs +++ b/frame/support/procedural/src/storage/storage_info.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Implementation of trait `PalletStorageInfo` on module structure. +//! Implementation of trait `StorageInfoTrait` on module structure. use proc_macro2::TokenStream; use quote::quote; @@ -28,17 +28,17 @@ pub fn impl_storage_info(def: &DeclStorageDefExt) -> TokenStream { let scrate = &def.hidden_crate; - let mut entries = TokenStream::new(); + let mut res_append_storage = TokenStream::new(); for line in def.storage_lines.iter() { let storage_struct = &line.storage_struct; - let entry = quote!( - < + res_append_storage.extend(quote!( + let mut storage_info = < #storage_struct as #scrate::traits::StorageInfoTrait - >::storage_info(), - ); - entries.extend(entry); + >::storage_info(); + res.append(&mut storage_info); + )); } let module_struct = &def.module_struct; @@ -46,11 +46,11 @@ pub fn impl_storage_info(def: &DeclStorageDefExt) -> TokenStream { let where_clause = &def.where_clause; quote!( - impl#module_impl #scrate::traits::PalletStorageInfo for #module_struct #where_clause { + impl#module_impl #scrate::traits::StorageInfoTrait for #module_struct #where_clause { fn storage_info() -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { - #scrate::sp_std::vec![ - #entries - ] + let mut res = #scrate::sp_std::vec![]; + #res_append_storage + res } } ) diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index cec794913bcd3..cad92dc9ee44f 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -261,20 +261,25 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct #optional_storage_where_clause { - fn storage_info() -> #scrate::traits::StorageInfo { + fn storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { use #scrate::sp_runtime::SaturatedConversion; let max_size = < #value_type as #scrate::traits::MaxEncodedLen >::max_encoded_len() .saturated_into(); - #scrate::traits::StorageInfo { - prefix: < - #storage_struct as #scrate::#storage_generator_trait - >::storage_value_final_key(), - max_values: Some(1), - max_size: Some(max_size), - } + + #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: Some(max_size), + } + ] } } ) @@ -285,7 +290,9 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct #optional_storage_where_clause { - fn storage_info() -> #scrate::traits::StorageInfo { + fn storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { use #scrate::sp_runtime::SaturatedConversion; let max_size = < #value_type as #scrate::traits::MaxEncodedLen @@ -294,14 +301,17 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { <#key as #scrate::traits::MaxEncodedLen>::max_encoded_len() ) .saturated_into(); - #scrate::traits::StorageInfo { - prefix: < - #storage_struct - as #scrate::storage::StoragePrefixedMap<#value_type> - >::final_prefix(), - max_values: #max_values, - max_size: Some(max_size), - } + + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: Some(max_size), + } + ] } } ) @@ -313,7 +323,9 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct #optional_storage_where_clause { - fn storage_info() -> #scrate::traits::StorageInfo { + fn storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { use #scrate::sp_runtime::SaturatedConversion; let max_size = < #value_type as #scrate::traits::MaxEncodedLen @@ -325,14 +337,17 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { <#key2 as #scrate::traits::MaxEncodedLen>::max_encoded_len() ) .saturated_into(); - #scrate::traits::StorageInfo { - prefix: < - #storage_struct - as #scrate::storage::StoragePrefixedMap<#value_type> - >::final_prefix(), - max_values: #max_values, - max_size: Some(max_size), - } + + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: Some(max_size), + } + ] } } ) @@ -343,7 +358,9 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct #optional_storage_where_clause { - fn storage_info() -> #scrate::traits::StorageInfo { + fn storage_info() + -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> + { use #scrate::sp_runtime::SaturatedConversion; let max_size = < #value_type as #scrate::traits::MaxEncodedLen @@ -357,14 +374,17 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { ) )* .saturated_into(); - #scrate::traits::StorageInfo { - prefix: < - #storage_struct - as #scrate::storage::StoragePrefixedMap<#value_type> - >::final_prefix(), - max_values: #max_values, - max_size: Some(max_size), - } + + #scrate::sp_std::vec![ + #scrate::traits::StorageInfo { + prefix: < + #storage_struct + as #scrate::storage::StoragePrefixedMap<#value_type> + >::final_prefix(), + max_values: #max_values, + max_size: Some(max_size), + } + ] } } ) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 72ff840bf8a10..0f96cdd023195 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1235,7 +1235,7 @@ pub mod pallet_prelude { Twox128, Blake2_256, Blake2_128, Identity, Twox64Concat, Blake2_128Concat, ensure, RuntimeDebug, storage, traits::{ - Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, PalletStorageInfo, + Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, StorageInfoTrait, ConstU32, GetDefault, }, dispatch::{DispatchResultWithPostInfo, Parameter, DispatchError, DispatchResult}, @@ -1357,7 +1357,7 @@ pub mod pallet_prelude { /// pub struct Pallet(_); /// ``` /// -/// This require all storage to implement the trait [`traits::StorageMaxEncodedLen`], thus all keys +/// This require all storage to implement the trait [`traits::StorageInfoTrait`], thus all keys /// and value types must bound [`traits::MaxEncodedLen`]. /// /// ### Macro expansion: @@ -1384,13 +1384,14 @@ pub mod pallet_prelude { /// given by [`frame_support::traits::PalletInfo`]. /// (The implementation use the associated type `frame_system::Config::PalletInfo`). /// -/// It implements [`traits::PalletStorageInfo`] on `Pallet` which give information about all storages. +/// It implements [`traits::StorageInfoTrait`] on `Pallet` which give information about all storages. /// /// If the attribute generate_store is set then the macro creates the trait `Store` and implements /// it on `Pallet`. /// /// If the attribute set_storage_max_encoded_len is set then the macro call -/// [`traits::StorageMaxEncodedLen`] in the implementation of [`PalletStorageInfo`]. +/// [`traits::StorageInfoTrait`] for each storage in the implementation of +/// [`traits::StorageInfoTrait`] for the pallet. /// /// # Hooks: `#[pallet::hooks]` mandatory /// diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index b88e6b8416c55..22d1ed3f8207b 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -29,7 +29,7 @@ use crate::{ }; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_arithmetic::traits::SaturatedConversion; -use sp_std::vec::Vec; +use sp_std::prelude::*; /// A type that allow to store values for `(key1, key2)` couple. Similar to `StorageMap` but allow /// to iterate and remove value associated to first key. @@ -493,17 +493,19 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn storage_info() -> StorageInfo { - StorageInfo { - prefix: Self::final_prefix(), - max_values: MaxValues::get(), - max_size: Some( - Key1::max_encoded_len() - .saturating_add(Key2::max_encoded_len()) - .saturating_add(Value::max_encoded_len()) - .saturated_into(), - ), - } + fn storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: Some( + Key1::max_encoded_len() + .saturating_add(Key2::max_encoded_len()) + .saturating_add(Value::max_encoded_len()) + .saturated_into(), + ), + } + ] } } diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 6e2e2221c4aae..805737d7397d4 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -365,16 +365,18 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn storage_info() -> StorageInfo { - StorageInfo { - prefix: Self::final_prefix(), - max_values: MaxValues::get(), - max_size: Some( - Key::max_encoded_len() - .saturating_add(Value::max_encoded_len()) - .saturated_into(), - ), - } + fn storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: Some( + Key::max_encoded_len() + .saturating_add(Value::max_encoded_len()) + .saturated_into(), + ), + } + ] } } diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 900e2a578d93c..f018ccc38b4fe 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -395,16 +395,18 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn storage_info() -> StorageInfo { - StorageInfo { - prefix: Self::final_prefix(), - max_values: MaxValues::get(), - max_size: Some( - Key::key_max_encoded_len() - .saturating_add(Value::max_encoded_len()) - .saturated_into(), - ), - } + fn storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::final_prefix(), + max_values: MaxValues::get(), + max_size: Some( + Key::key_max_encoded_len() + .saturating_add(Value::max_encoded_len()) + .saturated_into(), + ), + } + ] } } diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index 0ece3b8713c5a..67d2e3741929e 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -28,6 +28,7 @@ use crate::{ }; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_arithmetic::traits::SaturatedConversion; +use sp_std::prelude::*; /// A type that allow to store a value. /// @@ -222,15 +223,17 @@ where QueryKind: QueryKindTrait, OnEmpty: crate::traits::Get + 'static { - fn storage_info() -> StorageInfo { - StorageInfo { - prefix: Self::hashed_key(), - max_values: Some(1), - max_size: Some( - Value::max_encoded_len() - .saturated_into(), - ), - } + fn storage_info() -> Vec { + vec![ + StorageInfo { + prefix: Self::hashed_key(), + max_values: Some(1), + max_size: Some( + Value::max_encoded_len() + .saturated_into(), + ), + } + ] } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 5b0a80df0ed28..295995b1bfebd 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -73,7 +73,7 @@ pub use hooks::GenesisBuild; pub mod schedule; mod storage; -pub use storage::{Instance, StorageInstance, PalletStorageInfo, StorageInfo, StorageInfoTrait}; +pub use storage::{Instance, 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 ab6fe96f1eeba..37957ceb67765 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -48,7 +48,7 @@ pub trait StorageInstance { const STORAGE_PREFIX: &'static str; } -/// Some info about a storage in a pallet. +/// Some info about an individual storage in a pallet. #[derive(codec::Encode, codec::Decode, crate::RuntimeDebug, Eq, PartialEq, Clone)] pub struct StorageInfo { /// The prefix of the storage. All keys after the prefix are considered part of the storage @@ -59,23 +59,18 @@ pub struct StorageInfo { pub max_size: Option, } -/// A trait to give information about storages. +/// A trait to give information about storage. /// /// It can be used to calculate PoV worst case size. -pub trait PalletStorageInfo { +pub trait StorageInfoTrait { fn storage_info() -> Vec; } #[impl_trait_for_tuples::impl_for_tuples(30)] -impl PalletStorageInfo for Tuple { +impl StorageInfoTrait for Tuple { fn storage_info() -> Vec { let mut res = vec![]; for_tuples!( #( res.extend_from_slice(&Tuple::storage_info()); )* ); res } } - -/// A trait for types which contains storage info. -pub trait StorageInfoTrait { - fn storage_info() -> StorageInfo; -} diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index 27813a76feec3..e7601f60c5444 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -397,7 +397,7 @@ mod tests { fn storage_info() { use frame_support::{ StorageHasher, - traits::{PalletStorageInfo, StorageInfo}, + traits::{StorageInfoTrait, StorageInfo}, pallet_prelude::*, }; let prefix = |pallet_name, storage_name| { diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 114b975f8b502..75ea1753c9ffa 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -979,7 +979,7 @@ fn test_pallet_info_access() { fn test_storage_info() { use frame_support::{ StorageHasher, - traits::{PalletStorageInfo, StorageInfo}, + traits::{StorageInfoTrait, StorageInfo}, pallet_prelude::*, }; From 5521953f8c3ae7168e30b52675b4b6648e99d93f Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Fri, 14 May 2021 14:09:54 +0200 Subject: [PATCH 5/9] Update frame/support/procedural/src/storage/parse.rs Co-authored-by: Peter Goodspeed-Niklaus --- frame/support/procedural/src/storage/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 164f0c1b11d29..ca97b7957c108 100644 --- a/frame/support/procedural/src/storage/parse.rs +++ b/frame/support/procedural/src/storage/parse.rs @@ -203,7 +203,7 @@ struct DeclStorageMaxValues { pub max_values_keyword: keyword::max_values, pub expr: ext::Parens, } -impl_parse_for_opt!(DeclStorageMaxValues=> keyword::max_values); +impl_parse_for_opt!(DeclStorageMaxValues => keyword::max_values); #[derive(Parse, ToTokens, Debug)] struct DeclStorageBuild { From 02b0cbb74d865315c8af731f4f98760ac2b32918 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Fri, 14 May 2021 14:10:19 +0200 Subject: [PATCH 6/9] Update frame/support/procedural/src/storage/storage_struct.rs Co-authored-by: Peter Goodspeed-Niklaus --- frame/support/procedural/src/storage/storage_struct.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index cad92dc9ee44f..23b6e3f311da4 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -391,7 +391,7 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { }, } } else { - Default::default() + TokenStream::default() }; impls.extend(quote!( From 999640b638d6255e6d7c70bd87ddec3407b862aa Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 14 May 2021 15:28:41 +0200 Subject: [PATCH 7/9] Fix max_size using hasher information hasher now expose `max_len` which allows to computes their maximum len. For hasher without concatenation, it is the size of the hash part, for hasher with concatenation, it is the size of the hash part + max encoded len of the key. --- .../procedural/src/storage/storage_struct.rs | 44 +++++++++------ frame/support/src/hash.rs | 36 ++++++++++++ frame/support/src/storage/types/double_map.rs | 4 +- frame/support/src/storage/types/key.rs | 4 +- frame/support/src/storage/types/map.rs | 2 +- frame/support/src/storage/types/mod.rs | 2 +- frame/support/test/tests/decl_storage.rs | 56 ++++++++++++++++--- frame/support/test/tests/pallet.rs | 18 +++--- 8 files changed, 124 insertions(+), 42 deletions(-) diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index 23b6e3f311da4..c1af0ee0701fb 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -294,12 +294,16 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { use #scrate::sp_runtime::SaturatedConversion; + use #scrate::StorageHasher; + + let key_max_size = < + Self as #scrate::storage::generator::StorageMap<_, _> + >::Hasher::max_len::<#key>(); + let max_size = < #value_type as #scrate::traits::MaxEncodedLen >::max_encoded_len() - .saturating_add( - <#key as #scrate::traits::MaxEncodedLen>::max_encoded_len() - ) + .saturating_add(key_max_size) .saturated_into(); #scrate::sp_std::vec![ @@ -327,15 +331,21 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { use #scrate::sp_runtime::SaturatedConversion; + use #scrate::StorageHasher; + + let key1_max_size = < + Self as #scrate::storage::generator::StorageDoubleMap<_, _, _> + >::Hasher1::max_len::<#key1>(); + + let key2_max_size = < + Self as #scrate::storage::generator::StorageDoubleMap<_, _, _> + >::Hasher2::max_len::<#key2>(); + let max_size = < #value_type as #scrate::traits::MaxEncodedLen >::max_encoded_len() - .saturating_add( - <#key1 as #scrate::traits::MaxEncodedLen>::max_encoded_len() - ) - .saturating_add( - <#key2 as #scrate::traits::MaxEncodedLen>::max_encoded_len() - ) + .saturating_add(key1_max_size) + .saturating_add(key2_max_size) .saturated_into(); #scrate::sp_std::vec![ @@ -353,7 +363,7 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { ) }, StorageLineTypeDef::NMap(map) => { - let keys = &map.keys; + let key = &map.to_keygen_struct(scrate); quote!( impl<#impl_trait> #scrate::traits::StorageInfoTrait for #storage_struct #optional_storage_where_clause @@ -362,17 +372,15 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { use #scrate::sp_runtime::SaturatedConversion; + + let key_max_size = < + #key as #scrate::storage::types::KeyGeneratorMaxEncodedLen + >::key_max_encoded_len(); + let max_size = < #value_type as #scrate::traits::MaxEncodedLen >::max_encoded_len() - #( - .saturating_add( - < - #keys - as #scrate::traits::MaxEncodedLen - >::max_encoded_len() - ) - )* + .saturating_add(key_max_size) .saturated_into(); #scrate::sp_std::vec![ diff --git a/frame/support/src/hash.rs b/frame/support/src/hash.rs index 22ccbeb6ceee3..db45801607e0d 100644 --- a/frame/support/src/hash.rs +++ b/frame/support/src/hash.rs @@ -20,6 +20,7 @@ use codec::Codec; use sp_std::prelude::Vec; use sp_io::hashing::{blake2_128, blake2_256, twox_64, twox_128, twox_256}; +use crate::traits::MaxEncodedLen; // This trait must be kept coherent with frame-support-procedural HasherKind usage pub trait Hashable: Sized { @@ -59,6 +60,9 @@ pub trait StorageHasher: 'static { const METADATA: frame_metadata::StorageHasher; type Output: AsRef<[u8]>; fn hash(x: &[u8]) -> Self::Output; + + /// The max length of the final hash, for the given key type. + fn max_len() -> usize; } /// Hasher to use to hash keys to insert to storage. @@ -79,6 +83,9 @@ impl StorageHasher for Identity { fn hash(x: &[u8]) -> Vec { x.to_vec() } + fn max_len() -> usize { + K::max_encoded_len() + } } impl ReversibleStorageHasher for Identity { fn reverse(x: &[u8]) -> &[u8] { @@ -98,6 +105,9 @@ impl StorageHasher for Twox64Concat { .cloned() .collect::>() } + fn max_len() -> usize { + K::max_encoded_len().saturating_add(8) + } } impl ReversibleStorageHasher for Twox64Concat { fn reverse(x: &[u8]) -> &[u8] { @@ -121,6 +131,9 @@ impl StorageHasher for Blake2_128Concat { .cloned() .collect::>() } + fn max_len() -> usize { + K::max_encoded_len().saturating_add(16) + } } impl ReversibleStorageHasher for Blake2_128Concat { fn reverse(x: &[u8]) -> &[u8] { @@ -140,6 +153,9 @@ impl StorageHasher for Blake2_128 { fn hash(x: &[u8]) -> [u8; 16] { blake2_128(x) } + fn max_len() -> usize { + 16 + } } /// Hash storage keys with blake2 256 @@ -150,6 +166,9 @@ impl StorageHasher for Blake2_256 { fn hash(x: &[u8]) -> [u8; 32] { blake2_256(x) } + fn max_len() -> usize { + 32 + } } /// Hash storage keys with twox 128 @@ -160,6 +179,9 @@ impl StorageHasher for Twox128 { fn hash(x: &[u8]) -> [u8; 16] { twox_128(x) } + fn max_len() -> usize { + 16 + } } /// Hash storage keys with twox 256 @@ -170,6 +192,9 @@ impl StorageHasher for Twox256 { fn hash(x: &[u8]) -> [u8; 32] { twox_256(x) } + fn max_len() -> usize { + 32 + } } #[cfg(test)] @@ -187,4 +212,15 @@ mod tests { let r = Blake2_128Concat::hash(b"foo"); assert_eq!(r.split_at(16), (&blake2_128(b"foo")[..], &b"foo"[..])) } + + #[test] + fn max_lengths() { + assert_eq!(Twox64Concat::hash(0u32).len() == Twox64Concat::max_len::); + assert_eq!(Twox128::hash(0u32).len() == Twox128::max_len::); + assert_eq!(Twox256::hash(0u32).len() == Twox256::max_len::); + assert_eq!(Blake2_128::hash(0u32).len() == Blake2_128::max_len::); + assert_eq!(Blake2_128Concat::hash(0u32).len() == Blake2_128Concat::max_len::); + assert_eq!(Blake2_256::hash(0u32).len() == Blake2_256::max_len::); + assert_eq!(Identity::hash(0u32).len() == Identity::max_len::); + } } diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 22d1ed3f8207b..8c23354817f4e 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -499,8 +499,8 @@ where prefix: Self::final_prefix(), max_values: MaxValues::get(), max_size: Some( - Key1::max_encoded_len() - .saturating_add(Key2::max_encoded_len()) + Hasher1::max_len::() + .saturating_add(Hasher2::max_len::()) .saturating_add(Value::max_encoded_len()) .saturated_into(), ), diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 78e80ee49268f..59f280bd2573e 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -53,7 +53,7 @@ pub trait KeyGenerator { ) -> Vec; } -/// TODO TODO: the max encoded len of the final key without the hash part (only the concat part) +/// The maximum length used by the key in storage. pub trait KeyGeneratorMaxEncodedLen: KeyGenerator { fn key_max_encoded_len() -> usize; } @@ -98,7 +98,7 @@ impl KeyGenerator for Key { impl KeyGeneratorMaxEncodedLen for Key { fn key_max_encoded_len() -> usize { - K::max_encoded_len() + H::max_len::() } } diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 805737d7397d4..ac2817c6887fd 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -371,7 +371,7 @@ where prefix: Self::final_prefix(), max_values: MaxValues::get(), max_size: Some( - Key::max_encoded_len() + Hasher::max_len::() .saturating_add(Value::max_encoded_len()) .saturated_into(), ), diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 5b7aa61d37693..f61065671315f 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -30,7 +30,7 @@ mod value; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; pub use key::{ EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, - ReversibleKeyGenerator, TupleToEncodedIter, + ReversibleKeyGenerator, TupleToEncodedIter, KeyGeneratorMaxEncodedLen, }; pub use map::{StorageMap, StorageMapMetadata}; pub use nmap::{StorageNMap, StorageNMapMetadata}; diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index e7601f60c5444..ef7b577ab6b8d 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -66,7 +66,6 @@ mod tests { // map getters: pub / $default GETMAPU32 get(fn map_u32_getter): map hasher(blake2_128_concat) u32 => [u8; 4]; pub PUBGETMAPU32 get(fn pub_map_u32_getter): map hasher(blake2_128_concat) u32 => [u8; 4]; - GETMAPU32MYDEF get(fn map_u32_getter_mydef): map hasher(blake2_128_concat) u32 => [u8; 4] = *b"mapd"; pub PUBGETMAPU32MYDEF get(fn pub_map_u32_getter_mydef): @@ -81,6 +80,9 @@ mod tests { COMPLEXTYPE1: (::std::option::Option,); COMPLEXTYPE2: ([[(u16, Option<()>); 32]; 12], u32); COMPLEXTYPE3: [u32; 25]; + + NMAP: nmap hasher(blake2_128_concat) u32, hasher(twox_64_concat) u16 => u8; + NMAP2: nmap hasher(blake2_128_concat) u32 => u8; } add_extra_genesis { build(|_| {}); @@ -389,6 +391,32 @@ mod tests { ), documentation: DecodeDifferent::Encode(&[]), }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("NMAP"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Encode(&["u32", "u16"]), + hashers: DecodeDifferent::Encode(&[StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat]), + value: DecodeDifferent::Encode("u8"), + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructNMAP(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("NMAP2"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Encode(&["u32"]), + hashers: DecodeDifferent::Encode(&[StorageHasher::Blake2_128Concat]), + value: DecodeDifferent::Encode("u8"), + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructNMAP(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, ] ), }; @@ -492,42 +520,42 @@ mod tests { StorageInfo { prefix: prefix(b"TestStorage", b"MAPU32"), max_values: Some(3), - max_size: Some(8), + max_size: Some(8 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"PUBMAPU32"), max_values: None, - max_size: Some(8), + max_size: Some(8 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"GETMAPU32"), max_values: None, - max_size: Some(8), + max_size: Some(8 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"PUBGETMAPU32"), max_values: None, - max_size: Some(8), + max_size: Some(8 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"GETMAPU32MYDEF"), max_values: None, - max_size: Some(8), + max_size: Some(8 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"PUBGETMAPU32MYDEF"), max_values: None, - max_size: Some(8), + max_size: Some(8 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"DOUBLEMAP"), max_values: Some(3), - max_size: Some(12), + max_size: Some(12 + 16 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"DOUBLEMAP2"), max_values: None, - max_size: Some(12), + max_size: Some(12 + 16 + 16), }, StorageInfo { prefix: prefix(b"TestStorage", b"COMPLEXTYPE1"), @@ -544,6 +572,16 @@ mod tests { max_values: Some(1), max_size: Some(100), }, + StorageInfo { + prefix: prefix(b"TestStorage", b"NMAP"), + max_values: None, + max_size: Some(16 + 4 + 8 + 2 + 1), + }, + StorageInfo { + prefix: prefix(b"TestStorage", b"NMAP2"), + max_values: None, + max_size: Some(16 + 4 + 1), + }, ], ); } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 75ea1753c9ffa..0a768c79e779c 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -1006,32 +1006,32 @@ fn test_storage_info() { StorageInfo { prefix: prefix(b"Example", b"Map"), max_values: None, - max_size: Some(3), + max_size: Some(3 + 16), }, StorageInfo { prefix: prefix(b"Example", b"Map2"), max_values: Some(3), - max_size: Some(6), + max_size: Some(6 + 8), }, StorageInfo { prefix: prefix(b"Example", b"DoubleMap"), max_values: None, - max_size: Some(7), + max_size: Some(7 + 16 + 8), }, StorageInfo { prefix: prefix(b"Example", b"DoubleMap2"), max_values: Some(5), - max_size: Some(14), + max_size: Some(14 + 8 + 16), }, StorageInfo { prefix: prefix(b"Example", b"NMap"), max_values: None, - max_size: Some(5), + max_size: Some(5 + 16), }, StorageInfo { prefix: prefix(b"Example", b"NMap2"), max_values: Some(11), - max_size: Some(14), + max_size: Some(14 + 8 + 16), }, #[cfg(feature = "conditional-storage")] { @@ -1046,7 +1046,7 @@ fn test_storage_info() { StorageInfo { prefix: prefix(b"Example", b"ConditionalMap"), max_values: Some(12), - max_size: Some(6), + max_size: Some(6 + 8), } }, #[cfg(feature = "conditional-storage")] @@ -1054,7 +1054,7 @@ fn test_storage_info() { StorageInfo { prefix: prefix(b"Example", b"ConditionalDoubleMap"), max_values: None, - max_size: Some(7), + max_size: Some(7 + 16 + 8), } }, #[cfg(feature = "conditional-storage")] @@ -1062,7 +1062,7 @@ fn test_storage_info() { StorageInfo { prefix: prefix(b"Example", b"ConditionalNMap"), max_values: None, - max_size: Some(7), + max_size: Some(7 + 16 + 8), } }, ], From a7909d7744d00bad38541c885c6ccd4cd1b250a7 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 14 May 2021 15:55:36 +0200 Subject: [PATCH 8/9] fix tests --- frame/support/src/hash.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frame/support/src/hash.rs b/frame/support/src/hash.rs index db45801607e0d..5c4bfb34f5f96 100644 --- a/frame/support/src/hash.rs +++ b/frame/support/src/hash.rs @@ -215,12 +215,14 @@ mod tests { #[test] fn max_lengths() { - assert_eq!(Twox64Concat::hash(0u32).len() == Twox64Concat::max_len::); - assert_eq!(Twox128::hash(0u32).len() == Twox128::max_len::); - assert_eq!(Twox256::hash(0u32).len() == Twox256::max_len::); - assert_eq!(Blake2_128::hash(0u32).len() == Blake2_128::max_len::); - assert_eq!(Blake2_128Concat::hash(0u32).len() == Blake2_128Concat::max_len::); - assert_eq!(Blake2_256::hash(0u32).len() == Blake2_256::max_len::); - assert_eq!(Identity::hash(0u32).len() == Identity::max_len::); + use codec::Encode; + let encoded_0u32 = &0u32.encode()[..]; + assert_eq!(Twox64Concat::hash(encoded_0u32).len(), Twox64Concat::max_len::()); + assert_eq!(Twox128::hash(encoded_0u32).len(), Twox128::max_len::()); + assert_eq!(Twox256::hash(encoded_0u32).len(), Twox256::max_len::()); + assert_eq!(Blake2_128::hash(encoded_0u32).len(), Blake2_128::max_len::()); + assert_eq!(Blake2_128Concat::hash(encoded_0u32).len(), Blake2_128Concat::max_len::()); + assert_eq!(Blake2_256::hash(encoded_0u32).len(), Blake2_256::max_len::()); + assert_eq!(Identity::hash(encoded_0u32).len(), Identity::max_len::()); } } From e5964c029d461c231fedf4fa6a01c07d88ee8f5c Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 14 May 2021 16:30:43 +0200 Subject: [PATCH 9/9] fix ui tests --- .../test/tests/pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index b263bdf52b2d5..ad415911bc933 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -5,4 +5,4 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `frame_support::traits::StorageInfoTrait::storage_info` + = note: required by `storage_info` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 8ffa8eb1756a7..545520124bfee 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,6 +4,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `types::key::KeyGeneratorMaxEncodedLen` for `NMapKey` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` - = note: required by `frame_support::traits::StorageInfoTrait::storage_info` + = note: required by `storage_info`