-
Notifications
You must be signed in to change notification settings - Fork 2.6k
improve FRAME storage docs #13987
base: master
Are you sure you want to change the base?
improve FRAME storage docs #13987
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -820,18 +820,66 @@ 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<u32>; | ||
/// ## Example: | ||
/// | ||
/// ``` | ||
/// #[frame_support::pallet] | ||
/// mod pallet { | ||
/// use frame_support::pallet_prelude::*; | ||
/// | ||
/// # #[pallet::pallet] | ||
/// # pub struct Pallet<T>(_); | ||
/// | ||
/// #[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<u32>; | ||
/// } | ||
/// } | ||
/// ``` | ||
#[proc_macro_attribute] | ||
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<T>(_); | ||
/// | ||
/// #[pallet::call] | ||
/// impl<T: Config> Pallet<T> { | ||
/// fn do_stuff(_origin: OriginFor<T>, arg: u32) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is weight no longer required? I think that is a good thing, but was surprised there wasn't dev mode stuff going on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be worth noting in the docs what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in dev_mode it should no longer be needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #14115 for exactly what you said about |
||
/// 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<T>(_); | ||
/// #[pallet::storage] | ||
Comment on lines
+1208
to
+1213
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whats going on here with extra hashtags? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will hide this line in the generated rust-docs. Try |
||
/// type Foo<T> = StorageValue<_, u32>; | ||
/// | ||
/// #[pallet::storage] | ||
/// type Bar<T> = StorageMap<_, Blake2_128Concat, u32, u32>; | ||
/// | ||
/// #[pallet::storage] | ||
/// type Bar<T> = StorageMap<_, Blake2_128Concat, u32, u32>; | ||
/// | ||
/// #[pallet::storage] | ||
/// type Bar<T> = 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::<Pallet<..>>()` and the name of the storage type. E.g. if runtime names | ||
/// the pallet "MyExample" then the storage `type Foo<T> = ...` 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<T> = 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<T> = StorageValue<Value = u32>`. | ||
/// 2. Unnamed generics, eg. `type Foo<T> = StorageValue<_, u32>`. | ||
/// | ||
/// In both cases, declaring `<T>` is mandatory, and it can be optionally `<T: Config>`. In the code | ||
/// generated, it is always `<T: Config>`. | ||
/// | ||
/// #### Example: | ||
/// | ||
/// ```ignore | ||
/// #[pallet::storage] | ||
/// pub(super) type MyStorage<T> = StorageMap<Hasher = Blake2_128Concat, Key = u32, Value = u32>; | ||
/// ``` | ||
/// #[frame_support::pallet] | ||
/// mod pallet { | ||
/// # use frame_support::pallet_prelude::*; | ||
/// # #[pallet::config] | ||
/// # pub trait Config: frame_system::Config {} | ||
/// # #[pallet::pallet] | ||
/// # pub struct Pallet<T>(_); | ||
/// /// Unnamed syntax, without bounding `T`. | ||
/// #[pallet::storage] | ||
/// pub type Foo<T> = StorageValue<_, u32>; | ||
/// | ||
/// /// Unnamed syntax, with bounding `T`. | ||
/// #[pallet::storage] | ||
/// pub type Bar<T: Config> = StorageValue<_, u32>; | ||
/// | ||
/// /// Named syntax. | ||
/// #[pallet::storage] | ||
/// pub type Baz<T> = 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<T> = 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() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see below that the trait
Dispatchable
shows up, but my initial intuition was to leave this word out of the docs. People understand callable. Dispatchable less so.