From 7544664936145bb71883462dc2eef7284b0cbd98 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Tue, 26 Sep 2023 00:04:54 +0200 Subject: [PATCH 01/24] Move macro docs from procedural to pallet_macros --- substrate/frame/support/procedural/src/lib.rs | 82 ++----- substrate/frame/support/src/lib.rs | 219 +++++++++++++++++- 2 files changed, 235 insertions(+), 66 deletions(-) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 466ceca42961..e60591b26960 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -972,21 +972,20 @@ pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by `Get` -/// from [`pallet::config`](`macro@config`) into metadata, e.g.: -/// -/// ```ignore -/// #[pallet::config] -/// pub trait Config: frame_system::Config { -/// #[pallet::constant] -/// type Foo: Get; -/// } -/// ``` +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::constant`. #[proc_macro_attribute] pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::constant_name`. +#[proc_macro_attribute] +pub fn constant_name(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// To bypass the `frame_system::Config` supertrait check, use the attribute /// `pallet::disable_frame_system_supertrait_check`, e.g.: /// @@ -1092,6 +1091,13 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::call`. +#[proc_macro_attribute] +pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, /// which explicitly defines the codec index for the dispatchable function in the `Call` enum. /// @@ -1261,60 +1267,8 @@ pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime -/// storage and also set its metadata. This attribute can be used multiple times. -/// -/// Item should be defined as: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; -/// ``` -/// -/// or with unnamed generic: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<_, $some_generics, ...>; -/// ``` -/// -/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be -/// one of `StorageValue`, `StorageMap` or `StorageDoubleMap`. The generic arguments of the -/// storage type can be given in two manners: named and unnamed. For named generic arguments, -/// the name for each argument should match the name defined for it on the storage struct: -/// * `StorageValue` expects `Value` and optionally `QueryKind` and `OnEmpty`, -/// * `StorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, -/// * `CountedStorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, -/// * `StorageDoubleMap` expects `Hasher1`, `Key1`, `Hasher2`, `Key2`, `Value` and optionally -/// `QueryKind` and `OnEmpty`. -/// -/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the -/// macro and other generic must declared as a normal generic type declaration. -/// -/// The `Prefix` generic written by the macro is generated using -/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names -/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: -/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. -/// -/// For the `CountedStorageMap` variant, the `Prefix` also implements -/// `CountedStorageMapInstance`. It also associates a `CounterPrefix`, which is implemented the -/// same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. if runtime names -/// the pallet "MyExample" then the storage `type Foo = CountedStorageaMap<...>` will store -/// its counter at the prefix: `Twox128(b"MyExample") ++ Twox128(b"CounterForFoo")`. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::storage] -/// pub(super) type MyStorage = StorageMap; -/// ``` -/// -/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ -/// Twox128(b"OtherName")`. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::storage`. #[proc_macro_attribute] pub fn storage(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 8c4b3de49b5d..c462fa5f6039 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2186,10 +2186,10 @@ pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the pallet:: macros pub mod pallet_macros { pub use frame_support_procedural::{ - call_index, compact, composite_enum, config, constant, + call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section, inherent, no_default, no_default_bounds, - origin, pallet_section, storage, storage_prefix, storage_version, type_value, unbounded, + origin, pallet_section, storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; @@ -2262,6 +2262,221 @@ pub mod pallet_macros { /// } /// ``` pub use frame_support_procedural::genesis_build; + + /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by `Get` + /// from [`pallet::config`](`macro@config`) into metadata. + /// + /// ## Example: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// use frame_support::pallet_prelude::*; + /// + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// + /// #[pallet::config] + /// pub trait Config: frame_system::Config { + /// /// This is like a normal `Get` trait, but it will be added into metadata. + /// #[pallet::constant] + /// type Foo: Get; + /// } + /// } + /// ``` + pub use frame_support_procedural::constant; + + // TODO: Add documentation + pub use frame_support_procedural::constant_name; + + /// Declares an implementation block to be the callable portion of a pallet. In other words, + /// each function in the implementation block of this section is an extrinsic that can be called + /// externally. + /// + /// Other than the `fn` attached to `Pallet`, this block will also generate an `enum Call` + /// which encapsulates the different functions, alongside their arguments, except for `origin`. + /// [`sp_runtime::traits::Dispatchable`] is then implemented for `enum Call`. + /// + /// ## Example: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// use frame_support::pallet_prelude::*; + /// + /// #[pallet::config] + /// pub trait Config: frame_system::Config { } + /// + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::call] + /// impl Pallet { + /// fn do_stuff(_origin: OriginFor, arg: u32) { + /// unimplemented!() + /// } + /// } + /// } + /// ``` + /// + /// TODO: Once we have default pallet config, it would also be easy to create types in the example + /// that implement `Config`. + pub use frame_support_procedural::call; + + /// Declares a type alias as a storage item. Storage items are pointers to data stored on-chain (the + /// *blockchain state*), under a specific key. The exact key is dependent on the type of the + /// storage. + /// + /// > Hypothetically, one can directly manipulate the state via [`sp_io::storage`](sp_io::storage). However, this is + /// > an advance usage and is not recommended. + /// + /// ## Storage Types + /// + /// The following storage types are supported by the FRAME macros. + /// + /// * [`StorageValue`](frame_support::storage::types::StorageValue) + /// * [`StorageMap`](frame_support::storage::types::StorageMap) + /// * [`CountedStorageMap`](frame_support::storage::types::CountedStorageMap) + /// * [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) + /// * [`StorageNMap`](frame_support::storage::types::StorageNMap) + /// * [`CountedStorageNMap`](frame_support::storage::types::CountedStorageNMap) + /// + /// The FRAME macros always generate a type alias for one of these types, as indicated by the syntax, + /// for example: `type Foo = StorageValue<..>`. For specific information about each storage type, refer to + /// the documentation of the respective type. + /// + /// ### Example: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// #[pallet::storage] + /// type Foo = StorageValue<_, u32>; + /// + /// #[pallet::storage] + /// type Bar = StorageMap<_, Blake2_128Concat, u32, u32>; + /// + /// #[pallet::storage] + /// type Baz = CountedStorageMap<_, Blake2_128Concat, u32, u32>; + /// } + /// ``` + /// + /// ## Related Macros + /// + /// The following macros can be used in conjunction with the storage macro: + /// + /// * [`macro@getter`]: Creates a custom getter function. + /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. + /// * [`macro@unbounded`]: Declares the storage item as unbounded. + /// + /// ## Common Details to All Storage Types. + /// + /// The following details are relevant to all of the aforementioned storage types. + /// + /// ### Syntax + /// + /// Two general syntaxes are supported, as demonstrated below: + /// + /// 1. Named generics, e.g., `type Foo = StorageValue`. + /// 2. Unnamed generics, e.g., `type Foo = StorageValue<_, u32>`. + /// + /// In both instances, declaring `` is mandatory. While it can optionally + /// be written as ``, in the generated code, it is always ``. + /// + /// #### Example: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// /// Unnamed syntax, without bounding `T`. + /// #[pallet::storage] + /// pub type Foo = StorageValue<_, u32>; + /// + /// /// Unnamed syntax, with bounding `T`. + /// #[pallet::storage] + /// pub type Bar = StorageValue<_, u32>; + /// + /// /// Named syntax. + /// #[pallet::storage] + /// pub type Baz = StorageMap<_, Hasher = Blake2_128Concat, Key = u32, Value = u32>; + /// } + /// ``` + /// + /// ### Query Type + /// + /// Every storage type mentioned above has a generic type called `QueryKind` that determines its "query" type. + /// This refers to the kind of value returned when querying the storage, for instance, through a `::get()` method. + /// + /// There are three types of queries: + /// + /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. It returns `Some(V)` if the value is present, or + /// `None` if it isn't, where `V` is the value type. + /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself if present; otherwise, it returns + /// `Default::default()`. This behavior can be adjusted with the `OnEmpty` generic parameter, which defaults to `OnEmpty = GetDefault`. + /// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result`, where `V` is the value type, and `E` is the pallet error type defined by the [`#[pallet::error]`](frame_support::pallet_macros::error) attribute. + /// + /// ### Appending + /// + /// All storage items — such as `StorageValue`, `StorageMap`, and their variants—offer an `::append()` method + /// optimized for collections. Using this method avoids the inefficiency of decoding and re-encoding + /// entire collections when adding items. For instance, consider the storage declaration + /// `type MyVal = StorageValue<_, Vec, ValueQuery>`. With `MyVal` storing a large list of bytes, + /// `::append()` lets you directly add bytes to the end in storage without processing the full list. + /// Depending on the storage type, additional key specifications may be needed. + /// + /// ### Optimized Length Decoding + /// + /// All storage items — such as `StorageValue`, `StorageMap`, and their counterparts — + /// incorporate the `::decode_len()` method. This method allows for efficient retrieval + /// of a collection's length without the necessity of decoding the entire dataset. + /// + /// ### Hashers + /// + /// For all storage types, except `StorageValue`, a set of hashers needs to be specified. The choice + /// of hashers is crucial, especially in production chains. The purpose of + /// storage hashers in maps is to ensure the keys of a map are uniformly distributed. An + /// unbalanced map/trie can lead to inefficient performance. + /// + /// In general, hashers are categorized as either cryptographically secure or not. The former is slower than the + /// latter. `Blake2` and `Twox` serve as examples of each, respectively. + /// + /// As a rule of thumb: + /// + /// 1. If the map keys are not controlled by end users, or are cryptographically secure by + /// definition (e.g., `AccountId`), then the use of cryptographically secure hashers is NOT required. + /// 2. If the map keys are controllable by the end users, cryptographically secure hashers should + /// be used. + /// + /// For more information, look at the types that implement + /// [`frame_support::StorageHasher`](frame_support::StorageHasher). + /// + /// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to the + /// implementors section of [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher). + /// + /// ### Prefixes + /// + /// Internally, every storage type generates a "prefix". This prefix serves as the initial segment of + /// the key utilized to store values in the on-chain state (i.e., the final key used in + /// [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule applies: + /// + /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(storage_prefix)`, where + /// > `pallet_prefix` is the name assigned to the pallet instance in + /// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and `storage_prefix` is the name of the `type` aliased to + /// > a particular storage type, such as `Foo` in `type Foo = StorageValue<..>`. + /// + /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is required. + /// For map types, the prefix is extended with one or more keys defined by the map. + pub use frame_support_procedural::storage; } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] From 3b1bcc70cecd863c6032cdd5d6e3a139e2564a26 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Tue, 26 Sep 2023 13:23:31 +0200 Subject: [PATCH 02/24] Added Storage types docs, altered RA hint --- substrate/frame/support/procedural/src/lib.rs | 12 +++++ .../support/src/storage/types/counted_map.rs | 31 +++++++++++- .../support/src/storage/types/counted_nmap.rs | 34 +++++++++++++- .../support/src/storage/types/double_map.rs | 47 ++++++++++++++----- .../frame/support/src/storage/types/map.rs | 36 ++++++++++---- .../frame/support/src/storage/types/nmap.rs | 47 +++++++++++++------ .../frame/support/src/storage/types/value.rs | 26 ++++++++-- 7 files changed, 187 insertions(+), 46 deletions(-) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index e60591b26960..2fddfbac1634 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -972,6 +972,9 @@ pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::constant`. #[proc_macro_attribute] @@ -979,6 +982,9 @@ pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::constant_name`. #[proc_macro_attribute] @@ -1091,6 +1097,9 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::call`. #[proc_macro_attribute] @@ -1267,6 +1276,9 @@ pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::storage`. #[proc_macro_attribute] diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 5b750a74098b..fdba0c893a5a 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -35,8 +35,8 @@ use sp_metadata_ir::StorageEntryMetadataIR; use sp_runtime::traits::Saturating; use sp_std::prelude::*; -/// A wrapper around a `StorageMap` and a `StorageValue` to keep track of how many items -/// are in a map, without needing to iterate all the values. +/// A wrapper around a [`StorageMap`] and a [`StorageValue`] (with the value being `u32`) to keep +/// track of how many items are in a map, without needing to iterate all the values. /// /// This storage item has additional storage read and write overhead when manipulating values /// compared to a regular storage map. @@ -47,6 +47,33 @@ use sp_std::prelude::*; /// /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Example +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink counted storage map, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = CountedStorageMap< +/// Hasher = Blake2_128Concat, +/// Key = u32, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } +/// ``` pub struct CountedStorageMap< Prefix, Hasher, diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 54f8e57cf242..c08a2f4f5c17 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -33,8 +33,8 @@ use sp_metadata_ir::StorageEntryMetadataIR; use sp_runtime::traits::Saturating; use sp_std::prelude::*; -/// A wrapper around a `StorageNMap` and a `StorageValue` to keep track of how many items -/// are in a map, without needing to iterate over all of the values. +/// A wrapper around a [`StorageNMap`] and a [`StorageValue`] (with the value being `u32`) to keep +/// track of how many items are in a map, without needing to iterate all the values. /// /// This storage item has some additional storage read and write overhead when manipulating values /// compared to a regular storage map. @@ -45,6 +45,36 @@ use sp_std::prelude::*; /// /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Example +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink storage map, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = CountedStorageNMap< +/// Key = ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// Value = u64, +/// QueryKind = ValueQuery, +/// >; +/// } +/// ``` pub struct CountedStorageNMap< Prefix, Key, diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index e78792184103..5c8455c97dc0 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -31,22 +31,43 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; 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. +/// A type representing a *double map* in storage. This structure associates a pair of keys +/// with a value of a specified type stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key1)) -/// ++ Hasher2(encode(key2)) -/// ``` +/// A double map with keys `k1` and `k2` can be likened to a [`StorageMap`](frame_support::storage::types::StorageMap) with a key of type `(k1, k2)`. +/// However, a double map offers functions specific to each key, enabling partial iteration +/// and deletion based on one key alone. +/// +/// Additionally, a double map is an alias for [`StorageNMap`](frame_support::storage::types::StorageNMap) using two keys. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. /// -/// # Warning +/// # Example /// -/// If the key1s (or key2s) are not trusted (e.g. can be set by a user), a cryptographic `hasher` -/// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values -/// in storage can be compromised. +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink storage map, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageDoubleMap< +/// Hasher1 = Blake2_128Concat, +/// Key1 = u8, +/// Hasher2 = Twox64Concat, +/// Key2 = u16, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } +/// ``` pub struct StorageDoubleMap< Prefix, Hasher1, diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index 816b90162f64..47372cb53a07 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -31,19 +31,35 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type that allow to store value for given key. Allowing to insert/remove/iterate on values. +/// A type representing a *map* in storage. A *storage map* is a mapping of keys to values of a given +/// type stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key)) -/// ``` +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. /// -/// # Warning +/// # Example /// -/// 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. +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink storage map, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageMap< +/// Hasher = Blake2_128Concat, +/// Key = u32, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; +/// } +/// ``` pub struct StorageMap< Prefix, Hasher, diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index e9a4b12dd43a..ffb28472c79e 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -33,24 +33,41 @@ use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_runtime::SaturatedConversion; use sp_std::prelude::*; -/// A type that allow to store values for an arbitrary number of keys in the form of -/// `(Key, Key, ..., Key)`. +/// A type representing an *NMap* in storage. This structure associates an arbitrary number of +/// keys with a value of a specified type stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key1)) -/// ++ Hasher2(encode(key2)) -/// ++ ... -/// ++ HasherN(encode(keyN)) -/// ``` +/// For example, [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) is a special case of +/// an *NMap* with N = 2. +/// +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. /// -/// # Warning +/// # Example /// -/// 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 for the key hashers. Otherwise, other values -/// in storage can be compromised. +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink storage map, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageNMap< +/// Key = ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// Value = u64, +/// QueryKind = ValueQuery, +/// >; +/// } +/// ``` pub struct StorageNMap< Prefix, Key, diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 3c7f24715ac9..2648dc79d22a 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -30,11 +30,29 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type that allow to store a value. +/// A type representing a *value* in storage. A *storage value* is a single value of a given type +/// stored on-chain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) ++ Twox128(Prefix::STORAGE_PREFIX) +/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// [`crate::pallet_macros::storage`]. +/// +/// # Example +/// +/// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink storage value, with all possible additional attributes. +/// #[pallet::storage] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] +/// pub type Foo = StorageValue<_, u32, ValueQuery>; +/// } /// ``` pub struct StorageValue( core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>, From 53649ea86e294545f223844be5cddf2a1f352eb4 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 27 Sep 2023 12:03:38 +0200 Subject: [PATCH 03/24] Tidy up RA hint for genesis macros --- substrate/frame/support/procedural/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 2fddfbac1634..4f07be33a7e0 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1383,6 +1383,9 @@ pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::genesis_config`. #[proc_macro_attribute] @@ -1390,6 +1393,9 @@ pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::genesis_build`. #[proc_macro_attribute] From b9f3b65b95a560eed70e9da8b0c663888f9fee2d Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 27 Sep 2023 12:08:11 +0200 Subject: [PATCH 04/24] Unify storage item naming in examples --- substrate/frame/support/src/storage/types/counted_map.rs | 2 +- substrate/frame/support/src/storage/types/counted_nmap.rs | 2 +- substrate/frame/support/src/storage/types/double_map.rs | 2 +- substrate/frame/support/src/storage/types/map.rs | 2 +- substrate/frame/support/src/storage/types/nmap.rs | 2 +- substrate/frame/support/src/storage/types/value.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index fdba0c893a5a..2938d2b5be82 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -61,7 +61,7 @@ use sp_std::prelude::*; /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); -/// /// A kitchen-sink counted storage map, with all possible additional attributes. +/// /// A kitchen-sink CountedStorageMap, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index c08a2f4f5c17..17c9793c6d8a 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -59,7 +59,7 @@ use sp_std::prelude::*; /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); -/// /// A kitchen-sink storage map, with all possible additional attributes. +/// /// A kitchen-sink CountedStorageNMap, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 5c8455c97dc0..386b98a1a875 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -53,7 +53,7 @@ use sp_std::prelude::*; /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); -/// /// A kitchen-sink storage map, with all possible additional attributes. +/// /// A kitchen-sink StorageDoubleMap, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index 47372cb53a07..dcfd3f24f80c 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -47,7 +47,7 @@ use sp_std::prelude::*; /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); -/// /// A kitchen-sink storage map, with all possible additional attributes. +/// /// A kitchen-sink StorageMap, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index ffb28472c79e..013ff940f8c4 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -52,7 +52,7 @@ use sp_std::prelude::*; /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); -/// /// A kitchen-sink storage map, with all possible additional attributes. +/// /// A kitchen-sink StorageNMap, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 2648dc79d22a..b61bf890386a 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -46,7 +46,7 @@ use sp_std::prelude::*; /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); -/// /// A kitchen-sink storage value, with all possible additional attributes. +/// /// A kitchen-sink StorageValue, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] From 9fce277d10a0b745389509bd6e0d44e605bf155c Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 27 Sep 2023 12:35:06 +0200 Subject: [PATCH 05/24] Fixed missing links, fmt --- substrate/frame/support/src/lib.rs | 115 ++++++++++++++++------------- 1 file changed, 64 insertions(+), 51 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index c462fa5f6039..e56816c94c44 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2263,8 +2263,9 @@ pub mod pallet_macros { /// ``` pub use frame_support_procedural::genesis_build; - /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by `Get` - /// from [`pallet::config`](`macro@config`) into metadata. + /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by + /// [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) into + /// metadata. /// /// ## Example: /// @@ -2293,8 +2294,8 @@ pub mod pallet_macros { /// each function in the implementation block of this section is an extrinsic that can be called /// externally. /// - /// Other than the `fn` attached to `Pallet`, this block will also generate an `enum Call` - /// which encapsulates the different functions, alongside their arguments, except for `origin`. + /// Other than the `fn` attached to `Pallet`, this block will also generate an `enum Call` which + /// encapsulates the different functions, alongside their arguments, except for `origin`. /// [`sp_runtime::traits::Dispatchable`] is then implemented for `enum Call`. /// /// ## Example: @@ -2319,16 +2320,17 @@ pub mod pallet_macros { /// } /// ``` /// - /// TODO: Once we have default pallet config, it would also be easy to create types in the example - /// that implement `Config`. + /// TODO: Once we have default pallet config, it would also be easy to create types in the + /// example that implement `Config`. pub use frame_support_procedural::call; - /// Declares a type alias as a storage item. Storage items are pointers to data stored on-chain (the - /// *blockchain state*), under a specific key. The exact key is dependent on the type of the - /// storage. + /// Declares a type alias as a storage item. Storage items are pointers to data stored on-chain + /// (the *blockchain state*), under a specific key. The exact key is dependent on the type of + /// the storage. /// - /// > Hypothetically, one can directly manipulate the state via [`sp_io::storage`](sp_io::storage). However, this is - /// > an advance usage and is not recommended. + /// > Hypothetically, one can directly manipulate the state via + /// > [`sp_io::storage`](sp_io::storage). However, this is an advance usage and is not + /// > recommended. /// /// ## Storage Types /// @@ -2341,9 +2343,9 @@ pub mod pallet_macros { /// * [`StorageNMap`](frame_support::storage::types::StorageNMap) /// * [`CountedStorageNMap`](frame_support::storage::types::CountedStorageNMap) /// - /// The FRAME macros always generate a type alias for one of these types, as indicated by the syntax, - /// for example: `type Foo = StorageValue<..>`. For specific information about each storage type, refer to - /// the documentation of the respective type. + /// The FRAME macros always generate a type alias for one of these types, as indicated by the + /// syntax, for example: `type Foo = StorageValue<..>`. For specific information about each + /// storage type, refer to the documentation of the respective type. /// /// ### Example: /// @@ -2374,7 +2376,7 @@ pub mod pallet_macros { /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. /// * [`macro@unbounded`]: Declares the storage item as unbounded. /// - /// ## Common Details to All Storage Types. + /// ## Common Details to All Storage Types /// /// The following details are relevant to all of the aforementioned storage types. /// @@ -2385,8 +2387,8 @@ pub mod pallet_macros { /// 1. Named generics, e.g., `type Foo = StorageValue`. /// 2. Unnamed generics, e.g., `type Foo = StorageValue<_, u32>`. /// - /// In both instances, declaring `` is mandatory. While it can optionally - /// be written as ``, in the generated code, it is always ``. + /// In both instances, declaring `` is mandatory. While it can optionally be written as ``, in the generated code, it is always ``. /// /// #### Example: /// @@ -2414,68 +2416,79 @@ pub mod pallet_macros { /// /// ### Query Type /// - /// Every storage type mentioned above has a generic type called `QueryKind` that determines its "query" type. - /// This refers to the kind of value returned when querying the storage, for instance, through a `::get()` method. + /// Every storage type mentioned above has a generic type called `QueryKind` that determines its + /// "query" type. This refers to the kind of value returned when querying the storage, for + /// instance, through a `::get()` method. /// /// There are three types of queries: /// - /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. It returns `Some(V)` if the value is present, or - /// `None` if it isn't, where `V` is the value type. - /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself if present; otherwise, it returns - /// `Default::default()`. This behavior can be adjusted with the `OnEmpty` generic parameter, which defaults to `OnEmpty = GetDefault`. - /// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result`, where `V` is the value type, and `E` is the pallet error type defined by the [`#[pallet::error]`](frame_support::pallet_macros::error) attribute. + /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. It + /// returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is the value + /// type. + /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself if + /// present; otherwise, it returns `Default::default()`. This behavior can be adjusted with the + /// `OnEmpty` generic parameter, which defaults to `OnEmpty = GetDefault`. + /// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result`, + /// where `V` is the value type, and `E` is the pallet error type defined by the + /// [`#[pallet::error]`](frame_support::pallet_macros::error) attribute. /// /// ### Appending /// - /// All storage items — such as `StorageValue`, `StorageMap`, and their variants—offer an `::append()` method - /// optimized for collections. Using this method avoids the inefficiency of decoding and re-encoding - /// entire collections when adding items. For instance, consider the storage declaration - /// `type MyVal = StorageValue<_, Vec, ValueQuery>`. With `MyVal` storing a large list of bytes, - /// `::append()` lets you directly add bytes to the end in storage without processing the full list. - /// Depending on the storage type, additional key specifications may be needed. + /// All storage items — such as [`StorageValue`](frame_support::storage::types::StorageValue), + /// [`StorageMap`](frame_support::storage::types::StorageMap), and their variants—offer an + /// `::append()` method optimized for collections. Using this method avoids the inefficiency of + /// decoding and re-encoding entire collections when adding items. For instance, consider the + /// storage declaration `type MyVal = StorageValue<_, Vec, ValueQuery>`. With `MyVal` + /// storing a large list of bytes, `::append()` lets you directly add bytes to the end in + /// storage without processing the full list. Depending on the storage type, additional key + /// specifications may be needed. /// /// ### Optimized Length Decoding /// - /// All storage items — such as `StorageValue`, `StorageMap`, and their counterparts — - /// incorporate the `::decode_len()` method. This method allows for efficient retrieval - /// of a collection's length without the necessity of decoding the entire dataset. + /// All storage items — such as [`StorageValue`](frame_support::storage::types::StorageValue), + /// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts — + /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of a + /// collection's length without the necessity of decoding the entire dataset. /// /// ### Hashers /// - /// For all storage types, except `StorageValue`, a set of hashers needs to be specified. The choice - /// of hashers is crucial, especially in production chains. The purpose of - /// storage hashers in maps is to ensure the keys of a map are uniformly distributed. An - /// unbalanced map/trie can lead to inefficient performance. + /// For all storage types, except [`StorageValue`](frame_support::storage::types::StorageValue), + /// a set of hashers needs to be specified. The choice of hashers is crucial, especially in + /// production chains. The purpose of storage hashers in maps is to ensure the keys of a map are + /// uniformly distributed. An unbalanced map/trie can lead to inefficient performance. /// - /// In general, hashers are categorized as either cryptographically secure or not. The former is slower than the - /// latter. `Blake2` and `Twox` serve as examples of each, respectively. + /// In general, hashers are categorized as either cryptographically secure or not. The former is + /// slower than the latter. `Blake2` and `Twox` serve as examples of each, respectively. /// /// As a rule of thumb: /// /// 1. If the map keys are not controlled by end users, or are cryptographically secure by - /// definition (e.g., `AccountId`), then the use of cryptographically secure hashers is NOT required. - /// 2. If the map keys are controllable by the end users, cryptographically secure hashers should - /// be used. + /// definition (e.g., `AccountId`), then the use of cryptographically secure hashers is NOT + /// required. + /// 2. If the map keys are controllable by the end users, cryptographically secure hashers + /// should be used. /// /// For more information, look at the types that implement /// [`frame_support::StorageHasher`](frame_support::StorageHasher). /// /// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to the - /// implementors section of [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher). + /// implementors section of + /// [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher). /// /// ### Prefixes /// - /// Internally, every storage type generates a "prefix". This prefix serves as the initial segment of - /// the key utilized to store values in the on-chain state (i.e., the final key used in - /// [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule applies: + /// Internally, every storage type generates a "prefix". This prefix serves as the initial + /// segment of the key utilized to store values in the on-chain state (i.e., the final key used + /// in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule applies: /// /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(storage_prefix)`, where - /// > `pallet_prefix` is the name assigned to the pallet instance in - /// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and `storage_prefix` is the name of the `type` aliased to - /// > a particular storage type, such as `Foo` in `type Foo = StorageValue<..>`. + /// > `pallet_prefix` is the name assigned to the pallet instance in + /// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and + /// > `storage_prefix` is the name of the `type` aliased to a particular storage type, such as + /// > `Foo` in `type Foo = StorageValue<..>`. /// - /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is required. - /// For map types, the prefix is extended with one or more keys defined by the map. + /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is + /// required. For map types, the prefix is extended with one or more keys defined by the map. pub use frame_support_procedural::storage; } From ad9df39ff809e8c2e41a721d0127b5676428940e Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 27 Sep 2023 14:11:35 +0200 Subject: [PATCH 06/24] Fixed pallet::call example --- substrate/frame/support/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index e56816c94c44..26633c24d9e7 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2313,7 +2313,7 @@ pub mod pallet_macros { /// /// #[pallet::call] /// impl Pallet { - /// fn do_stuff(_origin: OriginFor, arg: u32) { + /// pub fn do_stuff(_origin: OriginFor, arg: u32) -> DispatchResult { /// unimplemented!() /// } /// } @@ -2410,7 +2410,7 @@ pub mod pallet_macros { /// /// /// Named syntax. /// #[pallet::storage] - /// pub type Baz = StorageMap<_, Hasher = Blake2_128Concat, Key = u32, Value = u32>; + /// pub type Baz = StorageMap; /// } /// ``` /// From d91c8a79f6cb8665e9ac23b58e0bdc065dc1bdb6 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 27 Sep 2023 17:04:57 +0200 Subject: [PATCH 07/24] Added simple count example for CountedStorageMap --- .../support/src/storage/types/counted_map.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 2938d2b5be82..712ec9c1261a 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -52,7 +52,7 @@ use sp_std::prelude::*; /// [`crate::pallet_macros::storage`]. /// /// # Example -/// +/// /// ``` /// #[frame_support::pallet] /// mod pallet { @@ -74,6 +74,11 @@ use sp_std::prelude::*; /// >; /// } /// ``` +/// +/// The total number of items currently stored in the map can be retrieved with the +/// [`count()`](#method.count) method. +/// +#[doc = docify::embed!("src/storage/types/counted_map.rs", test_simple_count_works)] pub struct CountedStorageMap< Prefix, Hasher, @@ -1200,4 +1205,15 @@ mod test { ] ); } + + #[docify::export] + #[test] + fn test_simple_count_works() { + type A = CountedStorageMap; + TestExternalities::default().execute_with(|| { + A::insert(1, 1); + A::insert(2, 2); + assert_eq!(A::count(), 2); + }); + } } From c4824bba8c3f5558c4e70f056712d67eab06383f Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 27 Sep 2023 17:10:42 +0200 Subject: [PATCH 08/24] fmt --- .../support/src/storage/types/counted_map.rs | 2 +- .../support/src/storage/types/counted_nmap.rs | 2 +- .../support/src/storage/types/double_map.rs | 16 +++++++++------- substrate/frame/support/src/storage/types/map.rs | 6 +++--- .../frame/support/src/storage/types/nmap.rs | 10 +++++----- .../frame/support/src/storage/types/value.rs | 2 +- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 712ec9c1261a..3c21e787519a 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -48,7 +48,7 @@ use sp_std::prelude::*; /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. /// -/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Example diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 17c9793c6d8a..9e6dfdadef8c 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -46,7 +46,7 @@ use sp_std::prelude::*; /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. /// -/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Example diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 386b98a1a875..17c3bd635ce6 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -31,16 +31,18 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type representing a *double map* in storage. This structure associates a pair of keys -/// with a value of a specified type stored on-chain. +/// A type representing a *double map* in storage. This structure associates a pair of keys with a +/// value of a specified type stored on-chain. /// -/// A double map with keys `k1` and `k2` can be likened to a [`StorageMap`](frame_support::storage::types::StorageMap) with a key of type `(k1, k2)`. -/// However, a double map offers functions specific to each key, enabling partial iteration -/// and deletion based on one key alone. +/// A double map with keys `k1` and `k2` can be likened to a +/// [`StorageMap`](frame_support::storage::types::StorageMap) with a key of type `(k1, k2)`. +/// However, a double map offers functions specific to each key, enabling partial iteration and +/// deletion based on one key alone. /// -/// Additionally, a double map is an alias for [`StorageNMap`](frame_support::storage::types::StorageNMap) using two keys. +/// Additionally, a double map is an alias for +/// [`StorageNMap`](frame_support::storage::types::StorageNMap) using two keys. /// -/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Example diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index dcfd3f24f80c..8fdfade2bf0d 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -31,10 +31,10 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_std::prelude::*; -/// A type representing a *map* in storage. A *storage map* is a mapping of keys to values of a given -/// type stored on-chain. +/// A type representing a *map* in storage. A *storage map* is a mapping of keys to values of a +/// given type stored on-chain. /// -/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Example diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index 013ff940f8c4..0e0cc4904f8c 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -33,13 +33,13 @@ use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}; use sp_runtime::SaturatedConversion; use sp_std::prelude::*; -/// A type representing an *NMap* in storage. This structure associates an arbitrary number of -/// keys with a value of a specified type stored on-chain. +/// A type representing an *NMap* in storage. This structure associates an arbitrary number of keys +/// with a value of a specified type stored on-chain. /// -/// For example, [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) is a special case of -/// an *NMap* with N = 2. +/// For example, [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) is a special +/// case of an *NMap* with N = 2. /// -/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Example diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index b61bf890386a..555de5b94a12 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -33,7 +33,7 @@ use sp_std::prelude::*; /// A type representing a *value* in storage. A *storage value* is a single value of a given type /// stored on-chain. /// -/// For general information regarding the `#[pallet::storage]` attribute, refer to +/// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Example From 9f812c7fb2dc4500188e8dbbc2053026a8190023 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Thu, 28 Sep 2023 11:53:26 +0200 Subject: [PATCH 09/24] Added ValueQuery Draft --- .../frame/support/src/storage/types/mod.rs | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index c7f2557099b3..602c7d86df04 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -113,7 +113,19 @@ where } } -/// Implement QueryKindTrait with query being `Value` +/// Implement [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with query being `Value` +/// +/// ## Example +/// +/// The `ValueQuery` implementation exposes two generic type parameters: `Value` and `OnEmpty`. By +/// default, all FRAME storage items set `OnEmpty` to +/// [`GetDefault`](frame_support::traits::GetDefault). This returns `Default::default()` for `Value` +/// types implementing [`Default`](core::default::Default) when the queried value is absent. +/// However, the behavior for missing values can be altered with a custom `OnEmpty` implementation. +#[doc = docify::embed!("src/storage/types/mod.rs", custom_onempty_implementation)] +/// Using `OnEmpty = ADefault` causes storage items to return `42` when values are absent. For an +/// overview of FRAME storage items and their use, refer to [crate::pallet_macros::storage]. +#[doc = docify::embed!("src/storage/types/mod.rs", test_valuequery_with_custom_onempty)] pub struct ValueQuery; impl QueryKindTrait for ValueQuery where @@ -140,3 +152,40 @@ pub trait StorageEntryMetadataBuilder { /// Build into `entries` the storage metadata entries of a storage given some `docs`. fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); } + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + storage::types::ValueQuery, + traits::{Get, StorageInstance}, + }; + use sp_io::TestExternalities; + + // A custom `OnEmpty` implementation returning 42 consistently + struct ADefault; + #[docify::export(custom_onempty_implementation)] + impl Get for ADefault { + fn get() -> u32 { + 42 + } + } + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + #[docify::export] + #[test] + pub fn test_valuequery_with_custom_onempty() { + type A = StorageValue; + TestExternalities::default().execute_with(|| { + // Unset StorageValue should default to 42 + assert_eq!(A::get(), 42); + }); + } +} \ No newline at end of file From e2d36b94e90f40d90e3cda637d041c41c540c67b Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Thu, 28 Sep 2023 13:44:05 +0200 Subject: [PATCH 10/24] Small changes to QueryKindTraits --- .../frame/support/src/storage/types/mod.rs | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index 602c7d86df04..b0364703f7df 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -44,12 +44,12 @@ pub use value::StorageValue; /// Trait implementing how the storage optional value is converted into the queried type. /// /// It is implemented by: -/// * `OptionQuery` which converts an optional value to an optional value, used when querying +/// * [`OptionQuery`] which converts an optional value to an optional value, used when querying /// storage returns an optional value. -/// * `ResultQuery` which converts an optional value to a result value, used when querying storage +/// * [`ResultQuery`] which converts an optional value to a result value, used when querying storage /// returns a result value. -/// * `ValueQuery` which converts an optional value to a value, used when querying storage returns a -/// value. +/// * [`ValueQuery`] which converts an optional value to a value, used when querying storage returns +/// a value. pub trait QueryKindTrait { /// Metadata for the storage kind. const METADATA: StorageEntryModifierIR; @@ -65,11 +65,11 @@ pub trait QueryKindTrait { fn from_query_to_optional_value(v: Self::Query) -> Option; } -/// Implement QueryKindTrait with query being `Option` +/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` +/// type being `Option`. /// -/// NOTE: it doesn't support a generic `OnEmpty`. This means only `None` can be -/// returned when no value is found. To use another `OnEmpty` implementation, `ValueQuery` can be -/// used instead. +/// NOTE: it doesn't support a generic `OnEmpty`. This means only `None` can be returned when no +/// value is found. To use another `OnEmpty` implementation, `ValueQuery` can be used instead. pub struct OptionQuery; impl QueryKindTrait for OptionQuery where @@ -89,7 +89,8 @@ where } } -/// Implement QueryKindTrait with query being `Result` +/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` +/// type being `Result`. pub struct ResultQuery(sp_std::marker::PhantomData); impl QueryKindTrait for ResultQuery where @@ -113,7 +114,8 @@ where } } -/// Implement [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with query being `Value` +/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` +/// type being `Value`. /// /// ## Example /// @@ -123,8 +125,9 @@ where /// types implementing [`Default`](core::default::Default) when the queried value is absent. /// However, the behavior for missing values can be altered with a custom `OnEmpty` implementation. #[doc = docify::embed!("src/storage/types/mod.rs", custom_onempty_implementation)] -/// Using `OnEmpty = ADefault` causes storage items to return `42` when values are absent. For an -/// overview of FRAME storage items and their use, refer to [crate::pallet_macros::storage]. +/// Using `OnEmpty = ADefault` causes storage items to return `42` when values are absent. This is +/// demonstrated in the following example with a [`StorageValue`]. For an overview of FRAME storage +/// items and their use, refer to [crate::pallet_macros::storage]. #[doc = docify::embed!("src/storage/types/mod.rs", test_valuequery_with_custom_onempty)] pub struct ValueQuery; impl QueryKindTrait for ValueQuery From 5cd7a8a9cacc3fdaecad855d8f45a0c374e0176f Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Thu, 28 Sep 2023 14:35:48 +0200 Subject: [PATCH 11/24] Small corrections --- substrate/frame/support/src/storage/types/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index b0364703f7df..0fede90831f3 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -114,13 +114,13 @@ where } } -/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` -/// type being `Value`. +/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` type +/// being `Value`. /// /// ## Example /// -/// The `ValueQuery` implementation exposes two generic type parameters: `Value` and `OnEmpty`. By -/// default, all FRAME storage items set `OnEmpty` to +/// The `ValueQuery` implementation accommodates two generic type parameters defined by +/// [`QueryKindTrait`]: `Value` and `OnEmpty`. By default, all FRAME storage items set `OnEmpty` to /// [`GetDefault`](frame_support::traits::GetDefault). This returns `Default::default()` for `Value` /// types implementing [`Default`](core::default::Default) when the queried value is absent. /// However, the behavior for missing values can be altered with a custom `OnEmpty` implementation. From a1ccd97b14d1309277581752157c686f5b8cea70 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Thu, 28 Sep 2023 14:54:20 +0200 Subject: [PATCH 12/24] Added clarification on OnEmpty use with ValueQuery --- substrate/frame/support/src/storage/types/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index 0fede90831f3..b5183051c8d3 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -125,9 +125,10 @@ where /// types implementing [`Default`](core::default::Default) when the queried value is absent. /// However, the behavior for missing values can be altered with a custom `OnEmpty` implementation. #[doc = docify::embed!("src/storage/types/mod.rs", custom_onempty_implementation)] -/// Using `OnEmpty = ADefault` causes storage items to return `42` when values are absent. This is -/// demonstrated in the following example with a [`StorageValue`]. For an overview of FRAME storage -/// items and their use, refer to [crate::pallet_macros::storage]. +/// Using `QueryKind = ValueQuery` in conjunction with `OnEmpty = ADefault` causes storage items to +/// return `42` when values are absent. This is demonstrated in the following example with a +/// [`StorageValue`]. For an overview of FRAME storage items and their use, refer to +/// [crate::pallet_macros::storage]. #[doc = docify::embed!("src/storage/types/mod.rs", test_valuequery_with_custom_onempty)] pub struct ValueQuery; impl QueryKindTrait for ValueQuery From 23c996e111a8249d4fd7d7ac8f028b6f27912141 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Mon, 16 Oct 2023 15:00:45 +0200 Subject: [PATCH 13/24] Add examples for append, decode_len, some general restructuring --- substrate/frame/support/src/lib.rs | 83 ++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 9 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 26633c24d9e7..df5dfbcaaa60 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2358,13 +2358,13 @@ pub mod pallet_macros { /// # #[pallet::pallet] /// # pub struct Pallet(_); /// #[pallet::storage] - /// type Foo = StorageValue<_, u32>; + /// type FooValue = StorageValue<_, u32>; /// /// #[pallet::storage] - /// type Bar = StorageMap<_, Blake2_128Concat, u32, u32>; + /// type BarMap = StorageMap<_, Blake2_128Concat, u32, u32>; /// /// #[pallet::storage] - /// type Baz = CountedStorageMap<_, Blake2_128Concat, u32, u32>; + /// type BazCountedMap = CountedStorageMap<_, Blake2_128Concat, u32, u32>; /// } /// ``` /// @@ -2376,7 +2376,7 @@ pub mod pallet_macros { /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. /// * [`macro@unbounded`]: Declares the storage item as unbounded. /// - /// ## Common Details to All Storage Types + /// ## Storage Type Usage /// /// The following details are relevant to all of the aforementioned storage types. /// @@ -2384,8 +2384,8 @@ pub mod pallet_macros { /// /// Two general syntaxes are supported, as demonstrated below: /// - /// 1. Named generics, e.g., `type Foo = StorageValue`. - /// 2. Unnamed generics, e.g., `type Foo = StorageValue<_, u32>`. + /// 1. Named type parameters, e.g., `type Foo = StorageValue`. + /// 2. Positional type parameters, e.g., `type Foo = StorageValue<_, u32>`. /// /// In both instances, declaring `` is mandatory. While it can optionally be written as ``, in the generated code, it is always ``. @@ -2432,7 +2432,7 @@ pub mod pallet_macros { /// where `V` is the value type, and `E` is the pallet error type defined by the /// [`#[pallet::error]`](frame_support::pallet_macros::error) attribute. /// - /// ### Appending + /// ### Optimized Appending /// /// All storage items — such as [`StorageValue`](frame_support::storage::types::StorageValue), /// [`StorageMap`](frame_support::storage::types::StorageMap), and their variants—offer an @@ -2442,14 +2442,17 @@ pub mod pallet_macros { /// storing a large list of bytes, `::append()` lets you directly add bytes to the end in /// storage without processing the full list. Depending on the storage type, additional key /// specifications may be needed. - /// + #[doc = docify::embed!("src/lib.rs", test_storage_value_append)] + /// Similarly, there also exists a `::try_append()` method, which can be used when handling + /// types where an append operation might fail, such as a [`BoundedVec`](frame_support::BoundedVec). + #[doc = docify::embed!("src/lib.rs", test_storage_value_try_append)] /// ### Optimized Length Decoding /// /// All storage items — such as [`StorageValue`](frame_support::storage::types::StorageValue), /// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts — /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of a /// collection's length without the necessity of decoding the entire dataset. - /// + #[doc = docify::embed!("src/lib.rs", test_storage_value_decode_len)] /// ### Hashers /// /// For all storage types, except [`StorageValue`](frame_support::storage::types::StorageValue), @@ -2490,6 +2493,68 @@ pub mod pallet_macros { /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is /// required. For map types, the prefix is extended with one or more keys defined by the map. pub use frame_support_procedural::storage; + + #[cfg(test)] + mod test { + // use super::*; + use crate::{ + BoundedVec, + storage::types::{StorageValue, ValueQuery}, + traits::{ConstU32, StorageInstance}, + }; + use sp_io::TestExternalities; + // use sp_runtime::traits::Bounded; + // use sp_runtime::bounded_vec; + + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + #[docify::export] + #[test] + pub fn test_storage_value_try_append() { + type MyVal = StorageValue>, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(BoundedVec::try_from(vec![42,43]).unwrap()); + assert_eq!(MyVal::get(), vec![42,43]); + // Try to append a single u32 to BoundedVec stored in `MyVal` + assert_ok!(MyVal::try_append(40)); + assert_eq!(MyVal::get(), vec![42,43,40]); + }); + } + + #[docify::export] + #[test] + pub fn test_storage_value_append() { + type MyVal = StorageValue, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(vec![42,43]); + assert_eq!(MyVal::get(), vec![42,43]); + // Append a single u32 to Vec stored in `MyVal` + MyVal::append(40); + assert_eq!(MyVal::get(), vec![42,43,40]); + }); + } + + #[docify::export] + #[test] + pub fn test_storage_value_decode_len() { + type MyVal = StorageValue>, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(BoundedVec::try_from(vec![42,43]).unwrap()); + assert_eq!(MyVal::decode_len().unwrap(), 2); + }); + } + + } } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] From ebdcc933892a67f8f3d29edf2db6b07a624e7f6e Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Mon, 16 Oct 2023 15:05:49 +0200 Subject: [PATCH 14/24] Move related macros to EOF for now --- substrate/frame/support/src/lib.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index df5dfbcaaa60..54a483fcc9bb 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2367,15 +2367,6 @@ pub mod pallet_macros { /// type BazCountedMap = CountedStorageMap<_, Blake2_128Concat, u32, u32>; /// } /// ``` - /// - /// ## Related Macros - /// - /// The following macros can be used in conjunction with the storage macro: - /// - /// * [`macro@getter`]: Creates a custom getter function. - /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. - /// * [`macro@unbounded`]: Declares the storage item as unbounded. - /// /// ## Storage Type Usage /// /// The following details are relevant to all of the aforementioned storage types. @@ -2492,8 +2483,16 @@ pub mod pallet_macros { /// /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is /// required. For map types, the prefix is extended with one or more keys defined by the map. + /// + /// ## Related Macros + /// + /// The following macros can be used in conjunction with the storage macro: + /// + /// * [`macro@getter`]: Creates a custom getter function. + /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. + /// * [`macro@unbounded`]: Declares the storage item as unbounded. pub use frame_support_procedural::storage; - + #[cfg(test)] mod test { // use super::*; From ee4d9d8bddf67e325c3ebda6ee4b4427617c7e03 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Mon, 16 Oct 2023 15:28:40 +0200 Subject: [PATCH 15/24] fmt --- substrate/frame/support/procedural/src/lib.rs | 18 +-- substrate/frame/support/src/lib.rs | 151 +++++++++--------- .../support/src/storage/types/counted_map.rs | 5 +- .../frame/support/src/storage/types/mod.rs | 12 +- .../frame/support/src/storage/types/value.rs | 4 +- 5 files changed, 98 insertions(+), 92 deletions(-) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 4f07be33a7e0..666116a3db77 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -972,7 +972,7 @@ pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// +/// /// --- /// /// **Rust-Analyzer users**: See the documentation of the Rust item in @@ -982,7 +982,7 @@ pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// +/// /// --- /// /// **Rust-Analyzer users**: See the documentation of the Rust item in @@ -1097,7 +1097,7 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// +/// /// --- /// /// **Rust-Analyzer users**: See the documentation of the Rust item in @@ -1276,9 +1276,9 @@ pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// +/// /// --- -/// +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::storage`. #[proc_macro_attribute] @@ -1383,9 +1383,9 @@ pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// +/// /// --- -/// +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::genesis_config`. #[proc_macro_attribute] @@ -1393,9 +1393,9 @@ pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// +/// /// --- -/// +/// /// **Rust-Analyzer users**: See the documentation of the Rust item in /// `frame_support::pallet_macros::genesis_build`. #[proc_macro_attribute] diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 54a483fcc9bb..70bb61f01edf 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2186,11 +2186,10 @@ pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the pallet:: macros pub mod pallet_macros { pub use frame_support_procedural::{ - call_index, compact, composite_enum, config, - disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit, - generate_store, getter, hooks, import_section, inherent, no_default, no_default_bounds, - origin, pallet_section, storage_prefix, storage_version, type_value, unbounded, - validate_unsigned, weight, whitelist_storage, + call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error, + event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section, + inherent, no_default, no_default_bounds, origin, pallet_section, storage_prefix, + storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; /// Allows you to define the genesis configuration for the pallet. @@ -2263,9 +2262,9 @@ pub mod pallet_macros { /// ``` pub use frame_support_procedural::genesis_build; - /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by - /// [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) into - /// metadata. + /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded + /// by [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) + /// into metadata. /// /// ## Example: /// @@ -2290,13 +2289,13 @@ pub mod pallet_macros { // TODO: Add documentation pub use frame_support_procedural::constant_name; - /// Declares an implementation block to be the callable portion of a pallet. In other words, - /// each function in the implementation block of this section is an extrinsic that can be called - /// externally. + /// Declares an implementation block to be the callable portion of a pallet. In other + /// words, each function in the implementation block of this section is an extrinsic that + /// can be called externally. /// - /// Other than the `fn` attached to `Pallet`, this block will also generate an `enum Call` which - /// encapsulates the different functions, alongside their arguments, except for `origin`. - /// [`sp_runtime::traits::Dispatchable`] is then implemented for `enum Call`. + /// Other than the `fn` attached to `Pallet`, this block will also generate an `enum Call` + /// which encapsulates the different functions, alongside their arguments, except for + /// `origin`. [`sp_runtime::traits::Dispatchable`] is then implemented for `enum Call`. /// /// ## Example: /// @@ -2324,16 +2323,16 @@ pub mod pallet_macros { /// example that implement `Config`. pub use frame_support_procedural::call; - /// Declares a type alias as a storage item. Storage items are pointers to data stored on-chain - /// (the *blockchain state*), under a specific key. The exact key is dependent on the type of - /// the storage. - /// + /// Declares a type alias as a storage item. Storage items are pointers to data stored + /// on-chain (the *blockchain state*), under a specific key. The exact key is dependent on + /// the type of the storage. + /// /// > Hypothetically, one can directly manipulate the state via /// > [`sp_io::storage`](sp_io::storage). However, this is an advance usage and is not /// > recommended. - /// + /// /// ## Storage Types - /// + /// /// The following storage types are supported by the FRAME macros. /// /// * [`StorageValue`](frame_support::storage::types::StorageValue) @@ -2343,12 +2342,12 @@ pub mod pallet_macros { /// * [`StorageNMap`](frame_support::storage::types::StorageNMap) /// * [`CountedStorageNMap`](frame_support::storage::types::CountedStorageNMap) /// - /// The FRAME macros always generate a type alias for one of these types, as indicated by the - /// syntax, for example: `type Foo = StorageValue<..>`. For specific information about each - /// storage type, refer to the documentation of the respective type. + /// The FRAME macros always generate a type alias for one of these types, as indicated by + /// the syntax, for example: `type Foo = StorageValue<..>`. For specific information about + /// each storage type, refer to the documentation of the respective type. /// /// ### Example: - /// + /// /// ``` /// #[frame_support::pallet] /// mod pallet { @@ -2378,11 +2377,11 @@ pub mod pallet_macros { /// 1. Named type parameters, e.g., `type Foo = StorageValue`. /// 2. Positional type parameters, e.g., `type Foo = StorageValue<_, u32>`. /// - /// In both instances, declaring `` is mandatory. While it can optionally be written as ``, in the generated code, it is always ``. + /// In both instances, declaring `` is mandatory. While it can optionally be written as + /// ``, in the generated code, it is always ``. /// /// #### Example: - /// + /// /// ``` /// #[frame_support::pallet] /// mod pallet { @@ -2407,52 +2406,58 @@ pub mod pallet_macros { /// /// ### Query Type /// - /// Every storage type mentioned above has a generic type called `QueryKind` that determines its + /// Every storage type mentioned above has a generic type called + /// [`QueryKind`](frame_support::storage::types::QueryKindTrait) that determines its /// "query" type. This refers to the kind of value returned when querying the storage, for - /// instance, through a `::get()` method. + /// instance, through a `::get()` method. /// /// There are three types of queries: /// - /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. It - /// returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is the value - /// type. - /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself if - /// present; otherwise, it returns `Default::default()`. This behavior can be adjusted with the - /// `OnEmpty` generic parameter, which defaults to `OnEmpty = GetDefault`. + /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. + /// It returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is the + /// value type. + /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself + /// if present; otherwise, it returns `Default::default()`. This behavior can be adjusted + /// with the `OnEmpty` generic parameter, which defaults to `OnEmpty = GetDefault`. /// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result`, /// where `V` is the value type, and `E` is the pallet error type defined by the /// [`#[pallet::error]`](frame_support::pallet_macros::error) attribute. /// /// ### Optimized Appending /// - /// All storage items — such as [`StorageValue`](frame_support::storage::types::StorageValue), + /// All storage items — such as + /// [`StorageValue`](frame_support::storage::types::StorageValue), /// [`StorageMap`](frame_support::storage::types::StorageMap), and their variants—offer an - /// `::append()` method optimized for collections. Using this method avoids the inefficiency of - /// decoding and re-encoding entire collections when adding items. For instance, consider the - /// storage declaration `type MyVal = StorageValue<_, Vec, ValueQuery>`. With `MyVal` - /// storing a large list of bytes, `::append()` lets you directly add bytes to the end in - /// storage without processing the full list. Depending on the storage type, additional key - /// specifications may be needed. + /// `::append()` method optimized for collections. Using this method avoids the + /// inefficiency of decoding and re-encoding entire collections when adding items. For + /// instance, consider the storage declaration `type MyVal = StorageValue<_, Vec, + /// ValueQuery>`. With `MyVal` storing a large list of bytes, `::append()` lets you + /// directly add bytes to the end in storage without processing the full list. Depending on + /// the storage type, additional key specifications may be needed. #[doc = docify::embed!("src/lib.rs", test_storage_value_append)] /// Similarly, there also exists a `::try_append()` method, which can be used when handling - /// types where an append operation might fail, such as a [`BoundedVec`](frame_support::BoundedVec). + /// types where an append operation might fail, such as a + /// [`BoundedVec`](frame_support::BoundedVec). #[doc = docify::embed!("src/lib.rs", test_storage_value_try_append)] /// ### Optimized Length Decoding /// - /// All storage items — such as [`StorageValue`](frame_support::storage::types::StorageValue), + /// All storage items — such as + /// [`StorageValue`](frame_support::storage::types::StorageValue), /// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts — - /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of a - /// collection's length without the necessity of decoding the entire dataset. + /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of + /// a collection's length without the necessity of decoding the entire dataset. #[doc = docify::embed!("src/lib.rs", test_storage_value_decode_len)] /// ### Hashers /// - /// For all storage types, except [`StorageValue`](frame_support::storage::types::StorageValue), - /// a set of hashers needs to be specified. The choice of hashers is crucial, especially in - /// production chains. The purpose of storage hashers in maps is to ensure the keys of a map are + /// For all storage types, except + /// [`StorageValue`](frame_support::storage::types::StorageValue), a set of hashers needs + /// to be specified. The choice of hashers is crucial, especially in production chains. The + /// purpose of storage hashers in maps is to ensure the keys of a map are /// uniformly distributed. An unbalanced map/trie can lead to inefficient performance. /// - /// In general, hashers are categorized as either cryptographically secure or not. The former is - /// slower than the latter. `Blake2` and `Twox` serve as examples of each, respectively. + /// In general, hashers are categorized as either cryptographically secure or not. The + /// former is slower than the latter. `Blake2` and `Twox` serve as examples of each, + /// respectively. /// /// As a rule of thumb: /// @@ -2465,27 +2470,31 @@ pub mod pallet_macros { /// For more information, look at the types that implement /// [`frame_support::StorageHasher`](frame_support::StorageHasher). /// - /// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to the - /// implementors section of + /// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to + /// the implementors section of /// [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher). /// /// ### Prefixes /// /// Internally, every storage type generates a "prefix". This prefix serves as the initial - /// segment of the key utilized to store values in the on-chain state (i.e., the final key used - /// in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule applies: + /// segment of the key utilized to store values in the on-chain state (i.e., the final key + /// used in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule + /// applies: /// - /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(storage_prefix)`, where + /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(storage_prefix)`, + /// > where /// > `pallet_prefix` is the name assigned to the pallet instance in /// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and - /// > `storage_prefix` is the name of the `type` aliased to a particular storage type, such as + /// > `storage_prefix` is the name of the `type` aliased to a particular storage type, such + /// > as /// > `Foo` in `type Foo = StorageValue<..>`. /// /// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is - /// required. For map types, the prefix is extended with one or more keys defined by the map. - /// + /// required. For map types, the prefix is extended with one or more keys defined by the + /// map. + /// /// ## Related Macros - /// + /// /// The following macros can be used in conjunction with the storage macro: /// /// * [`macro@getter`]: Creates a custom getter function. @@ -2497,15 +2506,14 @@ pub mod pallet_macros { mod test { // use super::*; use crate::{ - BoundedVec, storage::types::{StorageValue, ValueQuery}, traits::{ConstU32, StorageInstance}, + BoundedVec, }; use sp_io::TestExternalities; // use sp_runtime::traits::Bounded; // use sp_runtime::bounded_vec; - struct Prefix; impl StorageInstance for Prefix { fn pallet_prefix() -> &'static str { @@ -2517,14 +2525,14 @@ pub mod pallet_macros { #[docify::export] #[test] pub fn test_storage_value_try_append() { - type MyVal = StorageValue>, ValueQuery>; + type MyVal = StorageValue>, ValueQuery>; TestExternalities::default().execute_with(|| { - MyVal::set(BoundedVec::try_from(vec![42,43]).unwrap()); - assert_eq!(MyVal::get(), vec![42,43]); + MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); + assert_eq!(MyVal::get(), vec![42, 43]); // Try to append a single u32 to BoundedVec stored in `MyVal` assert_ok!(MyVal::try_append(40)); - assert_eq!(MyVal::get(), vec![42,43,40]); + assert_eq!(MyVal::get(), vec![42, 43, 40]); }); } @@ -2534,25 +2542,24 @@ pub mod pallet_macros { type MyVal = StorageValue, ValueQuery>; TestExternalities::default().execute_with(|| { - MyVal::set(vec![42,43]); - assert_eq!(MyVal::get(), vec![42,43]); + MyVal::set(vec![42, 43]); + assert_eq!(MyVal::get(), vec![42, 43]); // Append a single u32 to Vec stored in `MyVal` MyVal::append(40); - assert_eq!(MyVal::get(), vec![42,43,40]); + assert_eq!(MyVal::get(), vec![42, 43, 40]); }); } #[docify::export] #[test] pub fn test_storage_value_decode_len() { - type MyVal = StorageValue>, ValueQuery>; + type MyVal = StorageValue>, ValueQuery>; TestExternalities::default().execute_with(|| { - MyVal::set(BoundedVec::try_from(vec![42,43]).unwrap()); + MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); assert_eq!(MyVal::decode_len().unwrap(), 2); }); } - } } diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 3c21e787519a..e10be7f59aeb 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -52,7 +52,7 @@ use sp_std::prelude::*; /// [`crate::pallet_macros::storage`]. /// /// # Example -/// +/// /// ``` /// #[frame_support::pallet] /// mod pallet { @@ -74,10 +74,9 @@ use sp_std::prelude::*; /// >; /// } /// ``` -/// +/// /// The total number of items currently stored in the map can be retrieved with the /// [`count()`](#method.count) method. -/// #[doc = docify::embed!("src/storage/types/counted_map.rs", test_simple_count_works)] pub struct CountedStorageMap< Prefix, diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index b5183051c8d3..94d8f6924e9d 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -116,9 +116,9 @@ where /// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` type /// being `Value`. -/// +/// /// ## Example -/// +/// /// The `ValueQuery` implementation accommodates two generic type parameters defined by /// [`QueryKindTrait`]: `Value` and `OnEmpty`. By default, all FRAME storage items set `OnEmpty` to /// [`GetDefault`](frame_support::traits::GetDefault). This returns `Default::default()` for `Value` @@ -176,9 +176,9 @@ mod test { } struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" } const STORAGE_PREFIX: &'static str = "foo"; } @@ -192,4 +192,4 @@ mod test { assert_eq!(A::get(), 42); }); } -} \ No newline at end of file +} diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 555de5b94a12..ca6ae099d499 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -35,9 +35,9 @@ use sp_std::prelude::*; /// /// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. -/// +/// /// # Example -/// +/// /// ``` /// #[frame_support::pallet] /// mod pallet { From 88620dce2da179cbfe4ad0129dac430b8255f16f Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Tue, 17 Oct 2023 12:25:07 +0200 Subject: [PATCH 16/24] Add double map partial iter example --- .../support/src/storage/types/double_map.rs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 17c3bd635ce6..465ef26f3460 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -45,8 +45,8 @@ use sp_std::prelude::*; /// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// -/// # Example -/// +/// # Examples +/// ### Kitchen-sink /// ``` /// #[frame_support::pallet] /// mod pallet { @@ -70,6 +70,11 @@ use sp_std::prelude::*; /// >; /// } /// ``` +/// ### Partial Iteration +/// When `Hasher1` and `Hasher2` implement the +/// [`ReversibleStorageHasher`](frame_support::ReversibleStorageHasher) trait, we can iterate +/// over keys and values of the double map partially. +#[doc = docify::embed!("src/storage/types/double_map.rs", example_double_map_partial_iteration)] pub struct StorageDoubleMap< Prefix, Hasher1, @@ -990,4 +995,22 @@ mod test { assert_eq!(A::drain_prefix(4).collect::>(), vec![]); }) } + + #[docify::export] + #[test] + fn example_double_map_partial_iteration() { + use sp_std::collections::btree_set::BTreeSet; + type FooDoubleMap = StorageDoubleMap; + TestExternalities::default().execute_with(|| { + FooDoubleMap::insert(0, 0, 42); + FooDoubleMap::insert(0, 1, 43); + FooDoubleMap::insert(1, 0, 314); + let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0,).collect(); + // `collected_k2_keys` should be equal to {0,1} (ordering is random) + assert_eq!(collected_k2_keys, [0, 1].iter().copied().collect::>()); + let collected_k2_valus: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0,).collect(); + // `collected_k2_values` should be equal to {42,43} (ordering is random) + assert_eq!(collected_k2_valus, [42,43].iter().copied().collect::>()); + }); + } } From 181ac494e495f20ef0a82ad3ced9b75d933c897f Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Tue, 17 Oct 2023 13:57:07 +0200 Subject: [PATCH 17/24] Add removal to double map example --- .../support/src/storage/types/double_map.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 465ef26f3460..09095af080b0 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -70,11 +70,11 @@ use sp_std::prelude::*; /// >; /// } /// ``` -/// ### Partial Iteration +/// ### Partial Iteration & Removal /// When `Hasher1` and `Hasher2` implement the -/// [`ReversibleStorageHasher`](frame_support::ReversibleStorageHasher) trait, we can iterate -/// over keys and values of the double map partially. -#[doc = docify::embed!("src/storage/types/double_map.rs", example_double_map_partial_iteration)] +/// [`ReversibleStorageHasher`](frame_support::ReversibleStorageHasher) trait, the first key `k1` +/// can be used to partially iterate over keys and values of the double map, and to delete items. +#[doc = docify::embed!("src/storage/types/double_map.rs", example_double_map_partial_operations)] pub struct StorageDoubleMap< Prefix, Hasher1, @@ -998,7 +998,7 @@ mod test { #[docify::export] #[test] - fn example_double_map_partial_iteration() { + fn example_double_map_partial_operations() { use sp_std::collections::btree_set::BTreeSet; type FooDoubleMap = StorageDoubleMap; TestExternalities::default().execute_with(|| { @@ -1008,9 +1008,13 @@ mod test { let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0,).collect(); // `collected_k2_keys` should be equal to {0,1} (ordering is random) assert_eq!(collected_k2_keys, [0, 1].iter().copied().collect::>()); - let collected_k2_valus: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0,).collect(); + let collected_k2_values: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0,).collect(); // `collected_k2_values` should be equal to {42,43} (ordering is random) - assert_eq!(collected_k2_valus, [42,43].iter().copied().collect::>()); + assert_eq!(collected_k2_values, [42,43].iter().copied().collect::>()); + // Remove items from the map using k1 = 0 + let _ = FooDoubleMap::clear_prefix(0, u32::max_value(), None); + // Values associated with (0, _) should have been removed + assert_eq!(FooDoubleMap::iter_prefix(0,).collect::>(), vec![]); }); } } From 9c08356e05ea9386ee97b570de6e450bbaf9706f Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Tue, 17 Oct 2023 16:13:53 +0200 Subject: [PATCH 18/24] Small text fixes --- substrate/frame/support/src/lib.rs | 10 +++++----- .../support/src/storage/types/counted_map.rs | 16 ++++++++-------- .../support/src/storage/types/double_map.rs | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 70bb61f01edf..08c28ef67ae0 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2206,7 +2206,7 @@ pub mod pallet_macros { /// /// The fields of the `GenesisConfig` can in turn be populated by the chain-spec. /// - /// ## Example: + /// ## Example /// /// ``` /// #[frame_support::pallet] @@ -2266,7 +2266,7 @@ pub mod pallet_macros { /// by [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) /// into metadata. /// - /// ## Example: + /// ## Example /// /// ``` /// #[frame_support::pallet] @@ -2297,7 +2297,7 @@ pub mod pallet_macros { /// which encapsulates the different functions, alongside their arguments, except for /// `origin`. [`sp_runtime::traits::Dispatchable`] is then implemented for `enum Call`. /// - /// ## Example: + /// ## Example /// /// ``` /// #[frame_support::pallet] @@ -2346,7 +2346,7 @@ pub mod pallet_macros { /// the syntax, for example: `type Foo = StorageValue<..>`. For specific information about /// each storage type, refer to the documentation of the respective type. /// - /// ### Example: + /// ### Example /// /// ``` /// #[frame_support::pallet] @@ -2380,7 +2380,7 @@ pub mod pallet_macros { /// In both instances, declaring `` is mandatory. While it can optionally be written as /// ``, in the generated code, it is always ``. /// - /// #### Example: + /// #### Example /// /// ``` /// #[frame_support::pallet] diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index e10be7f59aeb..d47f7b3684b0 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -51,8 +51,8 @@ use sp_std::prelude::*; /// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// -/// # Example -/// +/// # Examples +/// ### Kitchen-sink /// ``` /// #[frame_support::pallet] /// mod pallet { @@ -66,7 +66,7 @@ use sp_std::prelude::*; /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] -/// pub type Foo = CountedStorageMap< +/// pub type FooCountedMap = CountedStorageMap< /// Hasher = Blake2_128Concat, /// Key = u32, /// Value = u32, @@ -74,7 +74,7 @@ use sp_std::prelude::*; /// >; /// } /// ``` -/// +/// ### Counting the Number of Items /// The total number of items currently stored in the map can be retrieved with the /// [`count()`](#method.count) method. #[doc = docify::embed!("src/storage/types/counted_map.rs", test_simple_count_works)] @@ -1208,11 +1208,11 @@ mod test { #[docify::export] #[test] fn test_simple_count_works() { - type A = CountedStorageMap; + type FooCountedMap = CountedStorageMap; TestExternalities::default().execute_with(|| { - A::insert(1, 1); - A::insert(2, 2); - assert_eq!(A::count(), 2); + FooCountedMap::insert(1, 1); + FooCountedMap::insert(2, 2); + assert_eq!(FooCountedMap::count(), 2); }); } } diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 09095af080b0..6be78a11349d 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -39,7 +39,7 @@ use sp_std::prelude::*; /// However, a double map offers functions specific to each key, enabling partial iteration and /// deletion based on one key alone. /// -/// Additionally, a double map is an alias for +/// Conceptionally, a double map is a special case of a /// [`StorageNMap`](frame_support::storage::types::StorageNMap) using two keys. /// /// For general information regarding the `#[pallet::storage]` attribute, refer to @@ -1017,4 +1017,4 @@ mod test { assert_eq!(FooDoubleMap::iter_prefix(0,).collect::>(), vec![]); }); } -} +} \ No newline at end of file From 0cefca222ce75a885b165a02252bf4ea9a50d8cb Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Tue, 17 Oct 2023 19:23:07 +0200 Subject: [PATCH 19/24] Fix cmmts in syntax code --- substrate/frame/support/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 08c28ef67ae0..36157bbf4d9c 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2390,11 +2390,11 @@ pub mod pallet_macros { /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); - /// /// Unnamed syntax, without bounding `T`. + /// /// Positional syntax, without bounding `T`. /// #[pallet::storage] /// pub type Foo = StorageValue<_, u32>; /// - /// /// Unnamed syntax, with bounding `T`. + /// /// Positional syntax, with bounding `T`. /// #[pallet::storage] /// pub type Bar = StorageValue<_, u32>; /// From 711ced94aaca8449ec43f18589d9bed05da2f8d3 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 18 Oct 2023 14:13:27 +0200 Subject: [PATCH 20/24] Some storage macro rework +fmt --- substrate/frame/support/src/lib.rs | 36 ++++++++++++++----- .../support/src/storage/types/double_map.rs | 13 +++---- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index b29fbbcae42f..d0ea47694d78 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2378,6 +2378,22 @@ pub mod pallet_macros { /// ## Storage Type Usage /// /// The following details are relevant to all of the aforementioned storage types. + /// Depending on the exact storage type, it may require the following generic parameters: + /// * [`Prefix`](#prefixes) - Used to give the storage item a unique key in the underlying + /// storage, + /// * `Value` - Type of the value being stored, + /// * `Key` - Type of the keys used to store the values, + /// * [`Hasher`](#hashers) - Used to ensure the keys of a map are uniformly distributed, + /// * [`QueryKind`](#querykind) - Used to configure how to handle queries to the underlying + /// storage, + /// * `OnEmpty` - Used to handle missing values when querying the underlying storage, + /// * `MaxValues` - _not used_. + /// + /// Each `Key` type requires its own designated `Hasher` declaration, so that + /// [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) needs two of + /// each, and [`StorageNMap`](frame_support::storage::types::StorageNMap) needs `N` such + /// pairs. Since [`StorageValue`](frame_support::storage::types::StorageValue) only stores + /// a single element, no configuration of hashers is needed. /// /// ### Syntax /// @@ -2386,8 +2402,10 @@ pub mod pallet_macros { /// 1. Named type parameters, e.g., `type Foo = StorageValue`. /// 2. Positional type parameters, e.g., `type Foo = StorageValue<_, u32>`. /// - /// In both instances, declaring `` is mandatory. While it can optionally be written as - /// ``, in the generated code, it is always ``. + /// In both instances, declaring the generic parameter `` is mandatory. Optionally, + /// it can also be explicitly declared as ``. In the compiled code, `T` will + /// automatically include the trait bound `Config`. Note that in positional syntax, the + /// first generic type parameter must be `_`. /// /// #### Example /// @@ -2413,7 +2431,7 @@ pub mod pallet_macros { /// } /// ``` /// - /// ### Query Type + /// ### QueryKind /// /// Every storage type mentioned above has a generic type called /// [`QueryKind`](frame_support::storage::types::QueryKindTrait) that determines its @@ -2443,11 +2461,11 @@ pub mod pallet_macros { /// ValueQuery>`. With `MyVal` storing a large list of bytes, `::append()` lets you /// directly add bytes to the end in storage without processing the full list. Depending on /// the storage type, additional key specifications may be needed. - #[doc = docify::embed!("src/lib.rs", test_storage_value_append)] + #[doc = docify::embed!("src/lib.rs", example_storage_value_append)] /// Similarly, there also exists a `::try_append()` method, which can be used when handling /// types where an append operation might fail, such as a /// [`BoundedVec`](frame_support::BoundedVec). - #[doc = docify::embed!("src/lib.rs", test_storage_value_try_append)] + #[doc = docify::embed!("src/lib.rs", example_storage_value_try_append)] /// ### Optimized Length Decoding /// /// All storage items — such as @@ -2455,7 +2473,7 @@ pub mod pallet_macros { /// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts — /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of /// a collection's length without the necessity of decoding the entire dataset. - #[doc = docify::embed!("src/lib.rs", test_storage_value_decode_len)] + #[doc = docify::embed!("src/lib.rs", example_storage_value_decode_len)] /// ### Hashers /// /// For all storage types, except @@ -2533,7 +2551,7 @@ pub mod pallet_macros { #[docify::export] #[test] - pub fn test_storage_value_try_append() { + pub fn example_storage_value_try_append() { type MyVal = StorageValue>, ValueQuery>; TestExternalities::default().execute_with(|| { @@ -2547,7 +2565,7 @@ pub mod pallet_macros { #[docify::export] #[test] - pub fn test_storage_value_append() { + pub fn example_storage_value_append() { type MyVal = StorageValue, ValueQuery>; TestExternalities::default().execute_with(|| { @@ -2561,7 +2579,7 @@ pub mod pallet_macros { #[docify::export] #[test] - pub fn test_storage_value_decode_len() { + pub fn example_storage_value_decode_len() { type MyVal = StorageValue>, ValueQuery>; TestExternalities::default().execute_with(|| { diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 576d9737378b..cacc14d7712a 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -71,7 +71,7 @@ use sp_std::prelude::*; /// } /// ``` /// ### Partial Iteration & Removal -/// When `Hasher1` and `Hasher2` implement the +/// When `Hasher1` and `Hasher2` implement the /// [`ReversibleStorageHasher`](frame_support::ReversibleStorageHasher) trait, the first key `k1` /// can be used to partially iterate over keys and values of the double map, and to delete items. #[doc = docify::embed!("src/storage/types/double_map.rs", example_double_map_partial_operations)] @@ -1005,21 +1005,22 @@ mod test { #[test] fn example_double_map_partial_operations() { use sp_std::collections::btree_set::BTreeSet; - type FooDoubleMap = StorageDoubleMap; + type FooDoubleMap = + StorageDoubleMap; TestExternalities::default().execute_with(|| { FooDoubleMap::insert(0, 0, 42); FooDoubleMap::insert(0, 1, 43); FooDoubleMap::insert(1, 0, 314); - let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0,).collect(); + let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0).collect(); // `collected_k2_keys` should be equal to {0,1} (ordering is random) assert_eq!(collected_k2_keys, [0, 1].iter().copied().collect::>()); - let collected_k2_values: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0,).collect(); + let collected_k2_values: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0).collect(); // `collected_k2_values` should be equal to {42,43} (ordering is random) - assert_eq!(collected_k2_values, [42,43].iter().copied().collect::>()); + assert_eq!(collected_k2_values, [42, 43].iter().copied().collect::>()); // Remove items from the map using k1 = 0 let _ = FooDoubleMap::clear_prefix(0, u32::max_value(), None); // Values associated with (0, _) should have been removed assert_eq!(FooDoubleMap::iter_prefix(0,).collect::>(), vec![]); }); } -} \ No newline at end of file +} From ed45000078e6ba8db7105679ace686b4fd73b95c Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 18 Oct 2023 15:14:28 +0200 Subject: [PATCH 21/24] Added prefixes examples, fixed headings --- substrate/frame/support/src/lib.rs | 36 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index d0ea47694d78..0ba04391f118 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2355,7 +2355,7 @@ pub mod pallet_macros { /// the syntax, for example: `type Foo = StorageValue<..>`. For specific information about /// each storage type, refer to the documentation of the respective type. /// - /// ### Example + /// #### Example /// /// ``` /// #[frame_support::pallet] @@ -2461,10 +2461,14 @@ pub mod pallet_macros { /// ValueQuery>`. With `MyVal` storing a large list of bytes, `::append()` lets you /// directly add bytes to the end in storage without processing the full list. Depending on /// the storage type, additional key specifications may be needed. + /// + /// #### Example #[doc = docify::embed!("src/lib.rs", example_storage_value_append)] /// Similarly, there also exists a `::try_append()` method, which can be used when handling /// types where an append operation might fail, such as a /// [`BoundedVec`](frame_support::BoundedVec). + /// + /// #### Example #[doc = docify::embed!("src/lib.rs", example_storage_value_try_append)] /// ### Optimized Length Decoding /// @@ -2473,6 +2477,7 @@ pub mod pallet_macros { /// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts — /// incorporate the `::decode_len()` method. This method allows for efficient retrieval of /// a collection's length without the necessity of decoding the entire dataset. + /// #### Example #[doc = docify::embed!("src/lib.rs", example_storage_value_decode_len)] /// ### Hashers /// @@ -2520,6 +2525,8 @@ pub mod pallet_macros { /// required. For map types, the prefix is extended with one or more keys defined by the /// map. /// + /// #### Example + #[doc = docify::embed!("src/lib.rs", example_storage_value_map_prefixes)] /// ## Related Macros /// /// The following macros can be used in conjunction with the storage macro: @@ -2533,13 +2540,12 @@ pub mod pallet_macros { mod test { // use super::*; use crate::{ - storage::types::{StorageValue, ValueQuery}, + hash::*, + storage::types::{StorageMap, StorageValue, ValueQuery}, traits::{ConstU32, StorageInstance}, BoundedVec, }; - use sp_io::TestExternalities; - // use sp_runtime::traits::Bounded; - // use sp_runtime::bounded_vec; + use sp_io::{hashing::twox_128, TestExternalities}; struct Prefix; impl StorageInstance for Prefix { @@ -2587,6 +2593,26 @@ pub mod pallet_macros { assert_eq!(MyVal::decode_len().unwrap(), 2); }); } + + #[docify::export] + #[test] + pub fn example_storage_value_map_prefixes() { + type MyVal = StorageValue; + type MyMap = StorageMap; + TestExternalities::default().execute_with(|| { + // Get storage key for `MyVal` StorageValue + assert_eq!( + MyVal::hashed_key().to_vec(), + [twox_128(b"test"), twox_128(b"foo")].concat() + ); + // Get storage key for `MyMap` StorageMap and `key` = 1 + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&1u16.blake2_128_concat()); + assert_eq!(MyMap::hashed_key_for(1).to_vec(), k); + }); + } } } From 26633e60cfdc8ceebaf7128667b085d867752906 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Wed, 18 Oct 2023 22:06:35 +0200 Subject: [PATCH 22/24] Make prefix example adhere to actual prefix logic --- substrate/frame/support/src/lib.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 0ba04391f118..eb952b88e81b 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2513,11 +2513,11 @@ pub mod pallet_macros { /// used in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule /// applies: /// - /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(storage_prefix)`, + /// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(STORAGE_PREFIX)`, /// > where /// > `pallet_prefix` is the name assigned to the pallet instance in /// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and - /// > `storage_prefix` is the name of the `type` aliased to a particular storage type, such + /// > `STORAGE_PREFIX` is the name of the `type` aliased to a particular storage type, such /// > as /// > `Foo` in `type Foo = StorageValue<..>`. /// @@ -2555,6 +2555,21 @@ pub mod pallet_macros { const STORAGE_PREFIX: &'static str = "foo"; } + struct Prefix1; + impl StorageInstance for Prefix1 { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "MyVal"; + } + struct Prefix2; + impl StorageInstance for Prefix2 { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "MyMap"; + } + #[docify::export] #[test] pub fn example_storage_value_try_append() { @@ -2597,18 +2612,19 @@ pub mod pallet_macros { #[docify::export] #[test] pub fn example_storage_value_map_prefixes() { - type MyVal = StorageValue; - type MyMap = StorageMap; + type MyVal = StorageValue; + type MyMap = StorageMap; TestExternalities::default().execute_with(|| { + // This example assumes `pallet_prefix` to be "test" // Get storage key for `MyVal` StorageValue assert_eq!( MyVal::hashed_key().to_vec(), - [twox_128(b"test"), twox_128(b"foo")].concat() + [twox_128(b"test"), twox_128(b"MyVal")].concat() ); // Get storage key for `MyMap` StorageMap and `key` = 1 let mut k: Vec = vec![]; k.extend(&twox_128(b"test")); - k.extend(&twox_128(b"foo")); + k.extend(&twox_128(b"MyMap")); k.extend(&1u16.blake2_128_concat()); assert_eq!(MyMap::hashed_key_for(1).to_vec(), k); }); From 126c4126e73f54b0294e6adfaebb308c6ceaff70 Mon Sep 17 00:00:00 2001 From: wentelteefje/ Date: Fri, 20 Oct 2023 17:28:36 +0200 Subject: [PATCH 23/24] Clean up storage macro page --- substrate/frame/support/src/lib.rs | 52 ++++++++++++++---------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index eb952b88e81b..382f5eace88c 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2342,7 +2342,8 @@ pub mod pallet_macros { /// /// ## Storage Types /// - /// The following storage types are supported by the FRAME macros. + /// The following storage types are supported by the `#[storage]` macro. For specific + /// information about each storage type, refer to the documentation of the respective type. /// /// * [`StorageValue`](frame_support::storage::types::StorageValue) /// * [`StorageMap`](frame_support::storage::types::StorageMap) @@ -2351,30 +2352,6 @@ pub mod pallet_macros { /// * [`StorageNMap`](frame_support::storage::types::StorageNMap) /// * [`CountedStorageNMap`](frame_support::storage::types::CountedStorageNMap) /// - /// The FRAME macros always generate a type alias for one of these types, as indicated by - /// the syntax, for example: `type Foo = StorageValue<..>`. For specific information about - /// each storage type, refer to the documentation of the respective type. - /// - /// #### Example - /// - /// ``` - /// #[frame_support::pallet] - /// mod pallet { - /// # use frame_support::pallet_prelude::*; - /// # #[pallet::config] - /// # pub trait Config: frame_system::Config {} - /// # #[pallet::pallet] - /// # pub struct Pallet(_); - /// #[pallet::storage] - /// type FooValue = StorageValue<_, u32>; - /// - /// #[pallet::storage] - /// type BarMap = StorageMap<_, Blake2_128Concat, u32, u32>; - /// - /// #[pallet::storage] - /// type BazCountedMap = CountedStorageMap<_, Blake2_128Concat, u32, u32>; - /// } - /// ``` /// ## Storage Type Usage /// /// The following details are relevant to all of the aforementioned storage types. @@ -2387,7 +2364,7 @@ pub mod pallet_macros { /// * [`QueryKind`](#querykind) - Used to configure how to handle queries to the underlying /// storage, /// * `OnEmpty` - Used to handle missing values when querying the underlying storage, - /// * `MaxValues` - _not used_. + /// * `MaxValues` - _not currently used_. /// /// Each `Key` type requires its own designated `Hasher` declaration, so that /// [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) needs two of @@ -2397,7 +2374,8 @@ pub mod pallet_macros { /// /// ### Syntax /// - /// Two general syntaxes are supported, as demonstrated below: + /// The FRAME `#[storage]` macro generates a type alias for a given storage type. + /// For this, two general syntaxes are supported, as demonstrated below: /// /// 1. Named type parameters, e.g., `type Foo = StorageValue`. /// 2. Positional type parameters, e.g., `type Foo = StorageValue<_, u32>`. @@ -2529,11 +2507,29 @@ pub mod pallet_macros { #[doc = docify::embed!("src/lib.rs", example_storage_value_map_prefixes)] /// ## Related Macros /// - /// The following macros can be used in conjunction with the storage macro: + /// The following attribute macros can be used in conjunction with the `#[storage]` macro: /// /// * [`macro@getter`]: Creates a custom getter function. /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. /// * [`macro@unbounded`]: Declares the storage item as unbounded. + /// + /// #### Example + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// /// A kitchen-sink StorageValue, with all possible additional attributes. + /// #[pallet::storage] + /// #[pallet::getter(fn foo)] + /// #[pallet::storage_prefix = "OtherFoo"] + /// #[pallet::unbounded] + /// pub type Foo = StorageValue<_, u32, ValueQuery>; + /// } + /// ``` pub use frame_support_procedural::storage; #[cfg(test)] From 198156b49af9a04b9170d7c0f48c329875301670 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 1 Nov 2023 14:08:46 +0000 Subject: [PATCH 24/24] update --- Cargo.lock | 8 +- substrate/frame/bags-list/Cargo.toml | 30 +- substrate/frame/support/src/lib.rs | 283 ++++++++---------- .../support/src/storage/types/counted_map.rs | 34 ++- .../support/src/storage/types/counted_nmap.rs | 13 + .../support/src/storage/types/double_map.rs | 62 ++-- .../frame/support/src/storage/types/map.rs | 10 + .../frame/support/src/storage/types/mod.rs | 75 ++--- .../frame/support/src/storage/types/nmap.rs | 13 + .../frame/support/src/storage/types/value.rs | 9 +- 10 files changed, 294 insertions(+), 243 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f12e16276e78..3afeeb00c570 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4409,18 +4409,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee528c501ddd15d5181997e9518e59024844eac44fd1e40cb20ddb2a8562fa" +checksum = "4235e9b248e2ba4b92007fe9c646f3adf0ffde16dc74713eacc92b8bc58d8d2f" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca01728ab2679c464242eca99f94e2ce0514b52ac9ad950e2ed03fca991231c" +checksum = "47020e12d7c7505670d1363dd53d6c23724f71a90a3ae32ff8eba40de8404626" dependencies = [ "common-path", "derive-syn-parse", diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index f4644890e2ba..c6e838f95366 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -13,17 +13,21 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.5.0", default-features = false, features = [ + "derive", +] } # primitives -sp-runtime = { path = "../../primitives/runtime", default-features = false} -sp-std = { path = "../../primitives/std", default-features = false} +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } # FRAME -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} -frame-election-provider-support = { path = "../election-provider-support", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +frame-election-provider-support = { path = "../election-provider-support", default-features = false } # third party log = { version = "0.4.17", default-features = false } @@ -31,11 +35,11 @@ docify = "0.2.4" aquamarine = { version = "0.3.2" } # Optional imports for benchmarking -frame-benchmarking = { path = "../benchmarking", default-features = false , optional = true} -pallet-balances = { path = "../balances", default-features = false , optional = true} -sp-core = { path = "../../primitives/core", default-features = false , optional = true} -sp-io = { path = "../../primitives/io", default-features = false , optional = true} -sp-tracing = { path = "../../primitives/tracing", default-features = false , optional = true} +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } +pallet-balances = { path = "../balances", default-features = false, optional = true } +sp-core = { path = "../../primitives/core", default-features = false, optional = true } +sp-io = { path = "../../primitives/io", default-features = false, optional = true } +sp-tracing = { path = "../../primitives/tracing", default-features = false, optional = true } [dev-dependencies] sp-core = { path = "../../primitives/core" } @@ -46,7 +50,7 @@ frame-election-provider-support = { path = "../election-provider-support" } frame-benchmarking = { path = "../benchmarking" } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", "frame-benchmarking?/std", diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 382f5eace88c..e68b2e56f619 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2281,10 +2281,8 @@ pub mod pallet_macros { /// #[frame_support::pallet] /// mod pallet { /// use frame_support::pallet_prelude::*; - /// /// # #[pallet::pallet] /// # pub struct Pallet(_); - /// /// #[pallet::config] /// pub trait Config: frame_system::Config { /// /// This is like a normal `Get` trait, but it will be added into metadata. @@ -2295,71 +2293,34 @@ pub mod pallet_macros { /// ``` pub use frame_support_procedural::constant; - // TODO: Add documentation - pub use frame_support_procedural::constant_name; - - /// Declares an implementation block to be the callable portion of a pallet. In other - /// words, each function in the implementation block of this section is an extrinsic that - /// can be called externally. - /// - /// Other than the `fn` attached to `Pallet`, this block will also generate an `enum Call` - /// which encapsulates the different functions, alongside their arguments, except for - /// `origin`. [`sp_runtime::traits::Dispatchable`] is then implemented for `enum Call`. - /// - /// ## Example - /// - /// ``` - /// #[frame_support::pallet] - /// mod pallet { - /// use frame_support::pallet_prelude::*; - /// - /// #[pallet::config] - /// pub trait Config: frame_system::Config { } - /// - /// #[pallet::pallet] - /// pub struct Pallet(_); - /// - /// #[pallet::call] - /// impl Pallet { - /// pub fn do_stuff(_origin: OriginFor, arg: u32) -> DispatchResult { - /// unimplemented!() - /// } - /// } - /// } - /// ``` - /// - /// TODO: Once we have default pallet config, it would also be easy to create types in the - /// example that implement `Config`. - pub use frame_support_procedural::call; - /// Declares a type alias as a storage item. Storage items are pointers to data stored /// on-chain (the *blockchain state*), under a specific key. The exact key is dependent on /// the type of the storage. /// - /// > Hypothetically, one can directly manipulate the state via - /// > [`sp_io::storage`](sp_io::storage). However, this is an advance usage and is not - /// > recommended. + /// > From the perspective of this pallet, the entire blockchain state is abstracted behind + /// > a key-value api, namely [`sp_io::storage`]. /// /// ## Storage Types /// /// The following storage types are supported by the `#[storage]` macro. For specific /// information about each storage type, refer to the documentation of the respective type. /// - /// * [`StorageValue`](frame_support::storage::types::StorageValue) - /// * [`StorageMap`](frame_support::storage::types::StorageMap) - /// * [`CountedStorageMap`](frame_support::storage::types::CountedStorageMap) - /// * [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) - /// * [`StorageNMap`](frame_support::storage::types::StorageNMap) - /// * [`CountedStorageNMap`](frame_support::storage::types::CountedStorageNMap) + /// * [`StorageValue`](crate::storage::types::StorageValue) + /// * [`StorageMap`](crate::storage::types::StorageMap) + /// * [`CountedStorageMap`](crate::storage::types::CountedStorageMap) + /// * [`StorageDoubleMap`](crate::storage::types::StorageDoubleMap) + /// * [`StorageNMap`](crate::storage::types::StorageNMap) + /// * [`CountedStorageNMap`](crate::storage::types::CountedStorageNMap) /// /// ## Storage Type Usage /// /// The following details are relevant to all of the aforementioned storage types. /// Depending on the exact storage type, it may require the following generic parameters: + /// /// * [`Prefix`](#prefixes) - Used to give the storage item a unique key in the underlying - /// storage, - /// * `Value` - Type of the value being stored, + /// storage. /// * `Key` - Type of the keys used to store the values, + /// * `Value` - Type of the value being stored, /// * [`Hasher`](#hashers) - Used to ensure the keys of a map are uniformly distributed, /// * [`QueryKind`](#querykind) - Used to configure how to handle queries to the underlying /// storage, @@ -2374,16 +2335,16 @@ pub mod pallet_macros { /// /// ### Syntax /// - /// The FRAME `#[storage]` macro generates a type alias for a given storage type. - /// For this, two general syntaxes are supported, as demonstrated below: + /// Two general syntaxes are supported, as demonstrated below: /// /// 1. Named type parameters, e.g., `type Foo = StorageValue`. /// 2. Positional type parameters, e.g., `type Foo = StorageValue<_, u32>`. /// - /// In both instances, declaring the generic parameter `` is mandatory. Optionally, - /// it can also be explicitly declared as ``. In the compiled code, `T` will - /// automatically include the trait bound `Config`. Note that in positional syntax, the - /// first generic type parameter must be `_`. + /// In both instances, declaring the generic parameter `` is mandatory. Optionally, it + /// can also be explicitly declared as ``. In the compiled code, `T` will + /// automatically include the trait bound `Config`. + /// + /// Note that in positional syntax, the first generic type parameter must be `_`. /// /// #### Example /// @@ -2395,15 +2356,15 @@ pub mod pallet_macros { /// # pub trait Config: frame_system::Config {} /// # #[pallet::pallet] /// # pub struct Pallet(_); - /// /// Positional syntax, without bounding `T`. + /// /// Positional syntax, without bounding `T`. /// #[pallet::storage] /// pub type Foo = StorageValue<_, u32>; /// - /// /// Positional syntax, with bounding `T`. + /// /// Positional syntax, with bounding `T`. /// #[pallet::storage] /// pub type Bar = StorageValue<_, u32>; /// - /// /// Named syntax. + /// /// Named syntax. /// #[pallet::storage] /// pub type Baz = StorageMap; /// } @@ -2419,14 +2380,16 @@ pub mod pallet_macros { /// There are three types of queries: /// /// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type. - /// It returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is the - /// value type. + /// It returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is + /// the value type. /// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself - /// if present; otherwise, it returns `Default::default()`. This behavior can be adjusted - /// with the `OnEmpty` generic parameter, which defaults to `OnEmpty = GetDefault`. + /// if present; otherwise, it returns `Default::default()`. This behavior can be + /// adjusted with the `OnEmpty` generic parameter, which defaults to `OnEmpty = + /// GetDefault`. /// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result`, - /// where `V` is the value type, and `E` is the pallet error type defined by the - /// [`#[pallet::error]`](frame_support::pallet_macros::error) attribute. + /// where `V` is the value type. + /// + /// See [`QueryKind`](frame_support::storage::types::QueryKindTrait) for further examples. /// /// ### Optimized Appending /// @@ -2531,101 +2494,6 @@ pub mod pallet_macros { /// } /// ``` pub use frame_support_procedural::storage; - - #[cfg(test)] - mod test { - // use super::*; - use crate::{ - hash::*, - storage::types::{StorageMap, StorageValue, ValueQuery}, - traits::{ConstU32, StorageInstance}, - BoundedVec, - }; - use sp_io::{hashing::twox_128, TestExternalities}; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct Prefix1; - impl StorageInstance for Prefix1 { - fn pallet_prefix() -> &'static str { - "test" - } - const STORAGE_PREFIX: &'static str = "MyVal"; - } - struct Prefix2; - impl StorageInstance for Prefix2 { - fn pallet_prefix() -> &'static str { - "test" - } - const STORAGE_PREFIX: &'static str = "MyMap"; - } - - #[docify::export] - #[test] - pub fn example_storage_value_try_append() { - type MyVal = StorageValue>, ValueQuery>; - - TestExternalities::default().execute_with(|| { - MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); - assert_eq!(MyVal::get(), vec![42, 43]); - // Try to append a single u32 to BoundedVec stored in `MyVal` - assert_ok!(MyVal::try_append(40)); - assert_eq!(MyVal::get(), vec![42, 43, 40]); - }); - } - - #[docify::export] - #[test] - pub fn example_storage_value_append() { - type MyVal = StorageValue, ValueQuery>; - - TestExternalities::default().execute_with(|| { - MyVal::set(vec![42, 43]); - assert_eq!(MyVal::get(), vec![42, 43]); - // Append a single u32 to Vec stored in `MyVal` - MyVal::append(40); - assert_eq!(MyVal::get(), vec![42, 43, 40]); - }); - } - - #[docify::export] - #[test] - pub fn example_storage_value_decode_len() { - type MyVal = StorageValue>, ValueQuery>; - - TestExternalities::default().execute_with(|| { - MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); - assert_eq!(MyVal::decode_len().unwrap(), 2); - }); - } - - #[docify::export] - #[test] - pub fn example_storage_value_map_prefixes() { - type MyVal = StorageValue; - type MyMap = StorageMap; - TestExternalities::default().execute_with(|| { - // This example assumes `pallet_prefix` to be "test" - // Get storage key for `MyVal` StorageValue - assert_eq!( - MyVal::hashed_key().to_vec(), - [twox_128(b"test"), twox_128(b"MyVal")].concat() - ); - // Get storage key for `MyMap` StorageMap and `key` = 1 - let mut k: Vec = vec![]; - k.extend(&twox_128(b"test")); - k.extend(&twox_128(b"MyMap")); - k.extend(&1u16.blake2_128_concat()); - assert_eq!(MyMap::hashed_key_for(1).to_vec(), k); - }); - } - } } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] @@ -2642,3 +2510,98 @@ sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); // Helper for implementing GenesisBuilder runtime API pub mod genesis_builder_helper; + +#[cfg(test)] +mod test { + // use super::*; + use crate::{ + hash::*, + storage::types::{StorageMap, StorageValue, ValueQuery}, + traits::{ConstU32, StorageInstance}, + BoundedVec, + }; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct Prefix1; + impl StorageInstance for Prefix1 { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "MyVal"; + } + struct Prefix2; + impl StorageInstance for Prefix2 { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "MyMap"; + } + + #[docify::export] + #[test] + pub fn example_storage_value_try_append() { + type MyVal = StorageValue>, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); + assert_eq!(MyVal::get(), vec![42, 43]); + // Try to append a single u32 to BoundedVec stored in `MyVal` + assert_ok!(MyVal::try_append(40)); + assert_eq!(MyVal::get(), vec![42, 43, 40]); + }); + } + + #[docify::export] + #[test] + pub fn example_storage_value_append() { + type MyVal = StorageValue, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(vec![42, 43]); + assert_eq!(MyVal::get(), vec![42, 43]); + // Append a single u32 to Vec stored in `MyVal` + MyVal::append(40); + assert_eq!(MyVal::get(), vec![42, 43, 40]); + }); + } + + #[docify::export] + #[test] + pub fn example_storage_value_decode_len() { + type MyVal = StorageValue>, ValueQuery>; + + TestExternalities::default().execute_with(|| { + MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap()); + assert_eq!(MyVal::decode_len().unwrap(), 2); + }); + } + + #[docify::export] + #[test] + pub fn example_storage_value_map_prefixes() { + type MyVal = StorageValue; + type MyMap = StorageMap; + TestExternalities::default().execute_with(|| { + // This example assumes `pallet_prefix` to be "test" + // Get storage key for `MyVal` StorageValue + assert_eq!( + MyVal::hashed_key().to_vec(), + [twox_128(b"test"), twox_128(b"MyVal")].concat() + ); + // Get storage key for `MyMap` StorageMap and `key` = 1 + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"MyMap")); + k.extend(&1u16.blake2_128_concat()); + assert_eq!(MyMap::hashed_key_for(1).to_vec(), k); + }); + } +} diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 8d483166a3fe..75fbdf2617d1 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -48,25 +48,40 @@ use sp_std::prelude::*; /// Whenever the counter needs to be updated, an additional read and write occurs to update that /// counter. /// +/// The total number of items currently stored in the map can be retrieved with the +/// [`CountedStorageMap::count`] method. +/// /// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Examples -/// ### Kitchen-sink +/// +/// Declaring a counted map: +/// /// ``` /// #[frame_support::pallet] /// mod pallet { -/// # use frame_support::pallet_prelude::*; -/// # #[pallet::config] -/// # pub trait Config: frame_system::Config {} -/// # #[pallet::pallet] -/// # pub struct Pallet(_); +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); /// /// A kitchen-sink CountedStorageMap, with all possible additional attributes. /// #[pallet::storage] /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] -/// pub type FooCountedMap = CountedStorageMap< +/// pub type Foo = CountedStorageMap< +/// _, +/// Blake2_128Concat, +/// u32, +/// u32, +/// ValueQuery, +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = CountedStorageMap< /// Hasher = Blake2_128Concat, /// Key = u32, /// Value = u32, @@ -74,9 +89,8 @@ use sp_std::prelude::*; /// >; /// } /// ``` -/// ### Counting the Number of Items -/// The total number of items currently stored in the map can be retrieved with the -/// [`count()`](#method.count) method. +/// +/// Using a counted map in action: #[doc = docify::embed!("src/storage/types/counted_map.rs", test_simple_count_works)] pub struct CountedStorageMap< Prefix, diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index b82721cd9ef5..c2c2197aceee 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -65,6 +65,19 @@ use sp_std::prelude::*; /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] /// pub type Foo = CountedStorageNMap< +/// _, +/// ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// u64, +/// ValueQuery, +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = CountedStorageNMap< /// Key = ( /// NMapKey, /// NMapKey, diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index cacc14d7712a..1002222a895c 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -39,38 +39,54 @@ use sp_std::prelude::*; /// However, a double map offers functions specific to each key, enabling partial iteration and /// deletion based on one key alone. /// -/// Conceptionally, a double map is a special case of a +/// Also, conceptually, a double map is a special case of a /// [`StorageNMap`](frame_support::storage::types::StorageNMap) using two keys. /// /// For general information regarding the `#[pallet::storage]` attribute, refer to /// [`crate::pallet_macros::storage`]. /// /// # Examples +/// /// ### Kitchen-sink +/// /// ``` /// #[frame_support::pallet] /// mod pallet { -/// # use frame_support::pallet_prelude::*; -/// # #[pallet::config] -/// # pub trait Config: frame_system::Config {} -/// # #[pallet::pallet] -/// # pub struct Pallet(_); -/// /// A kitchen-sink StorageDoubleMap, with all possible additional attributes. +/// # use frame_support::pallet_prelude::*; +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// /// A kitchen-sink StorageDoubleMap, with all possible additional attributes. /// #[pallet::storage] -/// #[pallet::getter(fn foo)] -/// #[pallet::storage_prefix = "OtherFoo"] -/// #[pallet::unbounded] +/// #[pallet::getter(fn foo)] +/// #[pallet::storage_prefix = "OtherFoo"] +/// #[pallet::unbounded] /// pub type Foo = StorageDoubleMap< -/// Hasher1 = Blake2_128Concat, -/// Key1 = u8, -/// Hasher2 = Twox64Concat, -/// Key2 = u16, -/// Value = u32, -/// QueryKind = ValueQuery -/// >; +/// _, +/// Blake2_128Concat, +/// u8, +/// Twox64Concat, +/// u16, +/// u32, +/// ValueQuery +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = StorageDoubleMap< +/// Hasher1 = Blake2_128Concat, +/// Key1 = u8, +/// Hasher2 = Twox64Concat, +/// Key2 = u16, +/// Value = u32, +/// QueryKind = ValueQuery +/// >; /// } /// ``` +/// /// ### Partial Iteration & Removal +/// /// When `Hasher1` and `Hasher2` implement the /// [`ReversibleStorageHasher`](frame_support::ReversibleStorageHasher) trait, the first key `k1` /// can be used to partially iterate over keys and values of the double map, and to delete items. @@ -770,6 +786,7 @@ mod test { use crate::{hash::*, storage::types::ValueQuery}; use sp_io::{hashing::twox_128, TestExternalities}; use sp_metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR}; + use std::collections::BTreeSet; struct Prefix; impl StorageInstance for Prefix { @@ -1004,23 +1021,26 @@ mod test { #[docify::export] #[test] fn example_double_map_partial_operations() { - use sp_std::collections::btree_set::BTreeSet; type FooDoubleMap = StorageDoubleMap; + TestExternalities::default().execute_with(|| { FooDoubleMap::insert(0, 0, 42); FooDoubleMap::insert(0, 1, 43); FooDoubleMap::insert(1, 0, 314); + + // should be equal to {0,1} (ordering is random) let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0).collect(); - // `collected_k2_keys` should be equal to {0,1} (ordering is random) assert_eq!(collected_k2_keys, [0, 1].iter().copied().collect::>()); + + // should be equal to {42,43} (ordering is random) let collected_k2_values: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0).collect(); - // `collected_k2_values` should be equal to {42,43} (ordering is random) assert_eq!(collected_k2_values, [42, 43].iter().copied().collect::>()); + // Remove items from the map using k1 = 0 let _ = FooDoubleMap::clear_prefix(0, u32::max_value(), None); // Values associated with (0, _) should have been removed - assert_eq!(FooDoubleMap::iter_prefix(0,).collect::>(), vec![]); + assert_eq!(FooDoubleMap::iter_prefix(0).collect::>(), vec![]); }); } } diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index f45613858fb3..81a3dd270d81 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -53,6 +53,16 @@ use sp_std::prelude::*; /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] /// pub type Foo = StorageMap< +/// _ +/// Blake2_128Concat, +/// u32, +/// u32, +/// ValueQuery +/// >; +/// +/// /// Alternative named syntax. +/// #[pallet::storage] +/// pub type Bar = StorageMap< /// Hasher = Blake2_128Concat, /// Key = u32, /// Value = u32, diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index 94d8f6924e9d..1d995d93e882 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -43,13 +43,17 @@ pub use value::StorageValue; /// Trait implementing how the storage optional value is converted into the queried type. /// -/// It is implemented by: +/// It is implemented most notable by: +/// /// * [`OptionQuery`] which converts an optional value to an optional value, used when querying /// storage returns an optional value. /// * [`ResultQuery`] which converts an optional value to a result value, used when querying storage /// returns a result value. /// * [`ValueQuery`] which converts an optional value to a value, used when querying storage returns /// a value. +/// +/// ## Example +#[doc = docify::embed!("src/storage/types/mod.rs", value_query_examples)] pub trait QueryKindTrait { /// Metadata for the storage kind. const METADATA: StorageEntryModifierIR; @@ -65,8 +69,7 @@ pub trait QueryKindTrait { fn from_query_to_optional_value(v: Self::Query) -> Option; } -/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` -/// type being `Option`. +/// Implements [`QueryKindTrait`] with `Query` type being `Option<_>`. /// /// NOTE: it doesn't support a generic `OnEmpty`. This means only `None` can be returned when no /// value is found. To use another `OnEmpty` implementation, `ValueQuery` can be used instead. @@ -89,8 +92,7 @@ where } } -/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` -/// type being `Result`. +/// Implements [`QueryKindTrait`] with `Query` type being `Result`. pub struct ResultQuery(sp_std::marker::PhantomData); impl QueryKindTrait for ResultQuery where @@ -114,22 +116,7 @@ where } } -/// Implements [`QueryKindTrait`](frame_support::storage::types::QueryKindTrait) with `Query` type -/// being `Value`. -/// -/// ## Example -/// -/// The `ValueQuery` implementation accommodates two generic type parameters defined by -/// [`QueryKindTrait`]: `Value` and `OnEmpty`. By default, all FRAME storage items set `OnEmpty` to -/// [`GetDefault`](frame_support::traits::GetDefault). This returns `Default::default()` for `Value` -/// types implementing [`Default`](core::default::Default) when the queried value is absent. -/// However, the behavior for missing values can be altered with a custom `OnEmpty` implementation. -#[doc = docify::embed!("src/storage/types/mod.rs", custom_onempty_implementation)] -/// Using `QueryKind = ValueQuery` in conjunction with `OnEmpty = ADefault` causes storage items to -/// return `42` when values are absent. This is demonstrated in the following example with a -/// [`StorageValue`]. For an overview of FRAME storage items and their use, refer to -/// [crate::pallet_macros::storage]. -#[doc = docify::embed!("src/storage/types/mod.rs", test_valuequery_with_custom_onempty)] +/// Implements [`QueryKindTrait`] with `Query` type being `Value`. pub struct ValueQuery; impl QueryKindTrait for ValueQuery where @@ -166,15 +153,6 @@ mod test { }; use sp_io::TestExternalities; - // A custom `OnEmpty` implementation returning 42 consistently - struct ADefault; - #[docify::export(custom_onempty_implementation)] - impl Get for ADefault { - fn get() -> u32 { - 42 - } - } - struct Prefix; impl StorageInstance for Prefix { fn pallet_prefix() -> &'static str { @@ -185,11 +163,40 @@ mod test { #[docify::export] #[test] - pub fn test_valuequery_with_custom_onempty() { - type A = StorageValue; + pub fn value_query_examples() { + /// Custom default impl to be used with `ValueQuery`. + struct UniverseSecret; + impl Get for UniverseSecret { + fn get() -> u32 { + 42 + } + } + + /// Custom default impl to be used with `ResultQuery`. + struct GetDefaultForResult; + impl Get> for GetDefaultForResult { + fn get() -> Result { + Err(()) + } + } + + type A = StorageValue; + type B = StorageValue; + type C = StorageValue, GetDefaultForResult>; + type D = StorageValue; + TestExternalities::default().execute_with(|| { - // Unset StorageValue should default to 42 - assert_eq!(A::get(), 42); + // normal value query returns default + assert_eq!(A::get(), 0); + + // option query returns none + assert_eq!(B::get(), None); + + // result query returns error + assert_eq!(C::get(), Err(())); + + // value query with custom onempty returns 42 + assert_eq!(D::get(), 42); }); } } diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index 2a76475de4e4..0723db689002 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -58,6 +58,19 @@ use sp_std::prelude::*; /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] /// pub type Foo = StorageNMap< +/// _, +/// ( +/// NMapKey, +/// NMapKey, +/// NMapKey +/// ), +/// u64, +/// ValueQuery, +/// >; +/// +/// /// Named alternative syntax. +/// #[pallet::storage] +/// pub type Bar = StorageNMap< /// Key = ( /// NMapKey, /// NMapKey, diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 09323f0e69cb..9fff1774d7b4 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -51,7 +51,14 @@ use sp_std::prelude::*; /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] -/// pub type Foo = StorageValue<_, u32, ValueQuery>; +/// pub type Foo = StorageValue<_, u32,ValueQuery>; +/// +/// /// Named alternative syntax. +/// #[pallet::storage] +/// pub type Bar = StorageValue< +/// Value = u32, +/// QueryKind = ValueQuery +/// >; /// } /// ``` pub struct StorageValue(