diff --git a/Cargo.lock b/Cargo.lock index 289e0c2c02b8a..0e6e8e847a01b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5516,7 +5516,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.2.5", + "clap 4.2.7", "flate2", "fs_extra", "git2", diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index abfa21b331b0e..0b59776cf5775 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -820,11 +820,22 @@ pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { /// 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; +/// ## 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; +/// } /// } /// ``` #[proc_macro_attribute] @@ -832,6 +843,43 @@ pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// Declares an implementation block to be the dispatchable 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 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`. +#[proc_macro_attribute] +pub fn call(_: 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.: /// @@ -1023,6 +1071,11 @@ pub fn extra_constants(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +#[proc_macro_attribute] +pub fn constant_name(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// The `#[pallet::error]` attribute allows you to define an error enum that will be returned /// from the dispatchable when an error occurs. The information for this error type is then /// stored in metadata. @@ -1124,60 +1177,159 @@ 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. +/// Declares a type alias as a storage item. Storage items are pointers to data stored onchain (the +/// *blockchain state*), under a specific key. The exact key is dependant on the type of the +/// storage. /// -/// Item should be defined as: +/// > Hypothetically, one can directly manipulate the state via [`sp_io::storage`]. However, this is +/// > an advance usage and is not recommended. /// -/// ```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, ...>; -/// ``` +/// ## Storage Types /// -/// or with unnamed generic: +/// The following storage types are supported by the FRAME macros. +/// +/// * `StorageValue`. +/// * `StorageMap`. +/// * `CountedStorageMap`. +/// * `StorageDoubleMap`. +/// * `StorageNMap`. +/// +/// TODO: properly link to `frame_support::storage` types. +/// +/// The FRAME macros always generate a type alias to either of these types, as indicated by the eg. +/// `type Foo = StorageValue<..>` syntax. For specific information about each storage type, see each +/// respective type's documentation. +/// +/// ### Example: /// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<_, $some_generics, ...>; +/// ``` +/// #[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 Bar = StorageMap<_, Blake2_128Concat, u32, u32>; +/// +/// #[pallet::storage] +/// type Bar = CountedStorageMap<_, Blake2_128Concat, u32, u32>; +/// } /// ``` /// -/// 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")`. +/// ## Related Macros /// -/// E.g: +/// The following macros are related to the storage macro and can be used in combination of it. +/// +/// * [`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 illuminated below: +/// +/// 1. Named generics, eg. `type Foo = StorageValue`. +/// 2. Unnamed generics, eg. `type Foo = StorageValue<_, u32>`. +/// +/// In both cases, declaring `` is mandatory, and it can be optionally ``. In the code +/// generated, it is always ``. +/// +/// #### Example: /// -/// ```ignore -/// #[pallet::storage] -/// pub(super) type MyStorage = StorageMap; /// ``` +/// #[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 +/// +/// All storage types defined above have one generic type that specifies the type of "query". This +/// refers to the type of value that is returned when _querying_ the storage, for example via a +/// `::get()` method. +/// +/// 3 types of queries can be used: +/// +/// 1. `OptionQuery`: This is the default query type. It returns `Some(_)` if the value is present, +/// `None` otherwise. 1. `ValueQuery`: It returns `T`, where `T` is the type +/// 2. `DefaultQuery`: it returns the value itself if the value is present, `Default::default` +/// otherwise. +/// 3. `ResultQuery`: it returns `Ok(_)` if the value is present, `Err(_)` otherwise. +/// +/// TODO: check the documentation of each these. +/// +/// ### Appending +/// +/// TODO +/// +/// ### Optimized Length Decoding. +/// +/// TODO +/// +/// ### Hashers +/// +/// For all storage types, except `StorageValue`, a set of hashers need to be specified. The choice +/// of hashers is not something to be taken lightly, particularly in production chains. The point of +/// storage hashers in maps is to ensure the keys of an map are uniformly distributed, as an +/// unbalanced map/trie would lead to inefficient performance. +/// +/// In general, hashers are either cryptographically secure or not. The former is slower than the +/// latter. `Blake2` and `Twox` are 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 (eg. `AccountId`), then use of cryptographically secure hashers are NOT required. +/// 2. If the map keys are controllable by the end users, cryptographically secure hashers should +/// be used. +/// +/// see [`frame_support::hash`] for more information, namely the types that implement +/// [`frame_support::hash::StorageHasher`]. +/// +/// Lastly, usage of hashers with "concat" are suggested to have reversible hashes. See +/// [`hash::ReversibleStorageHasher`] implementors. +/// +/// ### Prefixes +/// +/// Under the hood, all storage types generate a "prefix". This prefix is used as the first part of +/// the key that is used to store value in the onchain state (ie final key used in +/// `sp_io::storage`). For all storage types, the following rule holds: +/// +/// The storage prefix starts with `twox128(pallet_prefix) ++ twox128(storage_prefix)`, where +/// `pallet_prefix` is the chosen name of the instance of the pallet in +/// [`frame_support::construct_runtime`], and `storage_prefix` is the name of the `type` aliased to +/// a storage type, for example `Foo` in `type Foo = StorageValue<..>`. /// -/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ -/// Twox128(b"OtherName")`. +/// For [`frame_support::storage::StorageValue`], no further key is needed. For all maps types the +/// aforementioned key is appended by one or more keys defined by the map. #[proc_macro_attribute] pub fn storage(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index e57942cbe0667..a38d2a3cc3355 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -35,8 +35,8 @@ use sp_io::MultiRemovalResults; 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 common information about the `#[pallet::storage]` attribute, see +/// [`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/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 08ac1709c4b68..6cfd62637b856 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -31,22 +31,43 @@ use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::SaturatedConversion; 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. +/// Type representing a "double map" in storage. A "double map" is a mapping of a set of two keys to +/// a value of a given type stored onchain. /// -/// 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` is somewhat similar to a map with key `(k1, k2)` as its +/// key. But, a double map provides function specific to each key individually, allowing partial +/// iteration and deletion based on one key. +/// +/// Moreover, a double map is an alias for an [`crate::storage::StorageMMap`] with two keys. +/// +/// For common information about the `#[pallet::storage]` attribute, see +/// [`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/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 2110732b2f69c..b96ad34cfcd39 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -31,19 +31,35 @@ use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::SaturatedConversion; use sp_std::prelude::*; -/// A type that allow to store value for given key. Allowing to insert/remove/iterate on values. +/// Type representing a "map" in storage. A "storage map" is a mapping of keys to values of a given +/// type stored onchain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key)) -/// ``` +/// For common information about the `#[pallet::storage]` attribute, see +/// [`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/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 9b63ca7b0f417..876f702491bb3 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -33,24 +33,40 @@ use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; 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)`. +/// Type representing a "NMap" in storage. An "NMap" is a mapping of a set of arbitrary number of +/// keys to a value of a given type stored onchain. /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) -/// ++ Twox128(Prefix::STORAGE_PREFIX) -/// ++ Hasher1(encode(key1)) -/// ++ Hasher2(encode(key2)) -/// ++ ... -/// ++ HasherN(encode(keyN)) -/// ``` +/// This is superset of [`crate::storage::StorageDoubleMap`]. +/// +/// For common information about the `#[pallet::storage]` attribute, see +/// [`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/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index d5fbb0656bbd1..b075adb47363b 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Storage value type. Implements StorageValue trait and its method directly. +//! Storage value type. See [`StorageValue`] for more information. use crate::{ metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}, @@ -30,12 +30,31 @@ use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::SaturatedConversion; use sp_std::prelude::*; -/// A type that allow to store a value. +/// Type representing a "value" in storage. A "storage value" is a single value of a given type +/// stored onchain. +/// +/// For common information about the `#[pallet::storage]` attribute, see +/// [`crate::pallet_macros::storage`]. +/// +/// # Example /// -/// Each value is stored at: -/// ```nocompile -/// Twox128(Prefix::pallet_prefix()) ++ Twox128(Prefix::STORAGE_PREFIX) /// ``` +/// #[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)>, );