[−][src]Macro frame_support::decl_storage
decl_storage!() { /* proc-macro */ }
Declares strongly-typed wrappers around codec-compatible types in storage.
Example
decl_storage! {
trait Store for Module<T: Trait> as Example {
Foo get(fn foo) config(): u32=12;
Bar: map hasher(blake2_256) u32 => u32;
pub Zed build(|config| vec![(0, 0)]): linked_map hasher(blake2_256) u32 => u32;
}
}
Declaration is set with the header (pub) trait Store for Module<T: Trait> as Example
,
with Store
a (pub) trait generated associating each storage item to the Module
and
as Example
setting the prefix used for storage items of this module. Example
must be unique:
another module with the same name and the same inner storage item name will conflict.
Example
is called the module prefix.
note: For instantiable modules the module prefix is prepended with instance
prefix. Instance prefix is "" for default instance and "Instance$n" for instance number $n.
Thus, instance 3 of module Example has a module prefix of Instance3Example
Basic storage consists of a name and a type; supported types are:
-
Value:
Foo: type
: Implements theStorageValue
trait using theStorageValue generator
.The generator is implemented with:
module_prefix
: module_prefixstorage_prefix
: storage_name
Thus the storage value is finally stored at:
Twox128(module_prefix) ++ Twox128(storage_prefix)
-
Map:
Foo: map hasher($hash) type => type
: Implements theStorageMap
trait using theStorageMap generator
. AndStoragePrefixedMap
.$hash
representing a choice of hashing algorithms available in theHashable
trait.blake2_256
andblake2_128_concat
are strong hasher. One should use another hasher with care, see generator documentation.The generator is implemented with:
module_prefix
: $module_prefixstorage_prefix
: storage_nameHasher
: $hash
Thus the keys are stored at:
twox128(module_prefix) ++ twox128(storage_prefix) ++ hasher(encode(key))
-
Linked map:
Foo: linked_map hasher($hash) type => type
: Implements theStorageLinkedMap
trait using theStorageLinkedMap generator
. AndStoragePrefixedMap
.$hash
representing a choice of hashing algorithms available in theHashable
trait.blake2_256
andblake2_128_concat
are strong hasher. One should use another hasher with care, see generator documentation.All key formatting logic can be accessed in a type-agnostic format via the
KeyFormat
trait, which is implemented for the storage linked map type as well.The generator key format is implemented with:
module_prefix
: $module_prefixstorage_prefix
: storage_namehead_prefix
:"HeadOf" ++ storage_name
Hasher
: $hash
Thus the keys are stored at:
Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key))
and head is stored at:
Twox128(module_prefix) ++ Twox128(head_prefix)
-
Double map:
Foo: double_map hasher($hash1) u32, hasher($hash2) u32 => u32
: Implements theStorageDoubleMap
trait using theStorageDoubleMap generator
. AndStoragePrefixedMap
.$hash1
and$hash2
representing choices of hashing algorithms available in theHashable
trait. They must be chosen with care, see generator documentation.If the first key is untrusted, a cryptographic
hasher
such asblake2_256
orblake2_128_concat
must be used. Otherwise, other values of all storage items can be compromised.If the second key is untrusted, a cryptographic
hasher
such asblake2_256
orblake2_128_concat
must be used. Otherwise, other items in storage with the same first key can be compromised.The generator is implemented with:
module_prefix
: $module_prefixstorage_prefix
: storage_nameHasher1
: $hash1Hasher2
: $hash2
Thus keys are stored at:
Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2))
Supported hashers (ordered from least to best security):
twox_64_concat
- TwoX with 64bit + key concatenated.twox_128
- TwoX with 128bit.twox_256
- TwoX with with 256bit.blake2_128_concat
- Blake2 with 128bit + key concatenated.blake2_128
- Blake2 with 128bit.blake2_256
- Blake2 with 256bit.
Basic storage can be extended as such:
#vis #name get(fn #getter) config(#field_name) build(#closure): #type = #default;
#vis
: Set the visibility of the structure.pub
or nothing.#name
: Name of the storage item, used as a prefix in storage.- [optional]
get(fn #getter)
: Implements the function #getter toModule
. - [optional]
config(#field_name)
:field_name
is optional if get is set. Will include the item inGenesisConfig
. - [optional]
build(#closure)
: Closure called with storage overlays. #type
: Storage type.- [optional]
#default
: Value returned when none.
Storage items are accessible in multiple ways:
- The structure:
Foo
orFoo::<T>
depending if the value type is generic or not. - The
Store
trait structure:<Module<T> as Store>::Foo
- The getter on the module that calls get on the structure:
Module::<T>::foo()
GenesisConfig
An optional GenesisConfig
struct for storage initialization can be defined, either
when at least one storage field requires default initialization
(both get
and config
or build
), or specifically as in:
decl_storage! {
trait Store for Module<T: Trait> as Example {
// Your storage items
}
add_extra_genesis {
config(genesis_field): GenesisFieldType;
config(genesis_field2): GenesisFieldType;
...
build(|_: &Self| {
// Modification of storage
})
}
}
This struct can be exposed as ExampleConfig
by the construct_runtime!
macro like follows:
construct_runtime!(
pub enum Runtime with ... {
...,
Example: example::{Module, Storage, ..., Config<T>},
...,
}
);
Module with Instances
The decl_storage!
macro supports building modules with instances with the following syntax
(DefaultInstance
type is optional):
trait Store for Module<T: Trait<I>, I: Instance=DefaultInstance> as Example {}
Accessing the structure no requires the instance as generic parameter:
Foo::<I>
if the value type is not genericFoo::<T, I>
if the value type is generic
Where clause
This macro supports a where clause which will be replicated to all generated types.
trait Store for Module<T: Trait> as Example where T::AccountId: std::fmt::Display {}
Limitations
Instancing and generic GenesisConfig
If your module supports instancing and you see an error like parameter
I is never used
for
your decl_storage!
, you are hitting a limitation of the current implementation. You probably
try to use an associated type of a non-instantiable trait. To solve this, add the following to
your macro call:
add_extra_genesis {
config(phantom): std::marker::PhantomData<I>,
}
...
This adds a field to your `GenesisConfig` with the name `phantom` that you can initialize with
`Default::default()`.