decl_storage!() { /* proc-macro */ }
Expand description

Declares strongly-typed wrappers around codec-compatible types in storage.

Example

decl_storage! {
	trait Store for Module<T: Config> as Example {
		Foo get(fn foo) config(): u32=12;
		Bar: map hasher(identity) u32 => u32;
		pub Zed build(|config| vec![(0, 0)]): map hasher(identity) u32 => u32;
	}
}

Declaration is set with the header (pub) trait Store for Module<T: Config> 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 the StorageValue trait using the StorageValue generator.

    The generator is implemented with:

    • module_prefix: module_prefix
    • storage_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 the StorageMap trait using the StorageMap generator. And StoragePrefixedMap.

    $hash representing a choice of hashing algorithms available in the Hashable trait. You will generally want to use one of three hashers:

    • blake2_128_concat: The default, safe choice. Use if you are unsure or don’t care. It is secure against user-tainted keys, fairly fast and memory-efficient and supports iteration over its keys and values. This must be used if the keys of your map can be selected en masse by untrusted users.
    • twox_64_concat: This is an insecure hasher and can only be used safely if you know that the preimages cannot be chosen at will by untrusted users. It is memory-efficient, extremely performant and supports iteration over its keys and values. You can safely use this is the key is:
      • A (slowly) incrementing index.
      • Known to be the result of a cryptographic hash (though identity is a better choice here).
      • Known to be the public key of a cryptographic key pair in existence.
    • identity: This is not a hasher at all, and just uses the key material directly. Since it does no hashing or appending, it’s the fastest possible hasher, however, it’s also the least secure. It can be used only if you know that the key will be cryptographically/securely randomly distributed over the binary encoding space. In most cases this will not be true. One case where it is true, however, if where the key is itself the result of a cryptographic hash of some existent data.

    Other hashers will tend to be “opaque” and not support iteration over the keys in the map. It is not recommended to use these.

    The generator is implemented with:

    • module_prefix: $module_prefix
    • storage_prefix: storage_name
    • Hasher: $hash

    Thus the keys are stored at:

    twox128(module_prefix) ++ twox128(storage_prefix) ++ hasher(encode(key))
    
  • Double map: Foo: double_map hasher($hash1) u32, hasher($hash2) u32 => u32: Implements the StorageDoubleMap trait using the StorageDoubleMap generator. And StoragePrefixedMap.

    $hash1 and $hash2 representing choices of hashing algorithms available in the Hashable trait. They must be chosen with care, see generator documentation.

    The generator is implemented with:

    • module_prefix: $module_prefix
    • storage_prefix: storage_name
    • Hasher1: $hash1
    • Hasher2: $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):

  • identity - Just the unrefined key material. Use only when it is known to be a secure hash already. The most efficient and iterable over keys.
  • twox_64_concat - TwoX with 64bit + key concatenated. Use only when an untrusted source cannot select and insert key values. Very efficient and iterable over keys.
  • blake2_128_concat - Blake2 with 128bit + key concatenated. Slower but safe to use in all circumstances. Iterable over keys.

Deprecated hashers, which do not support iteration over keys include:

  • twox_128 - TwoX with 128bit.
  • twox_256 - TwoX with with 256bit.
  • 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 to Module.
  • [optional] config(#field_name): field_name is optional if get is set. Will include the item in GenesisConfig.
  • [optional] build(#closure): Closure called with storage overlays.
  • [optional] max_values(#expr): expr is an expression returning a u32. It is used to implement StorageInfoTrait. Note this attribute is not available for storage value as the maximum number of values is 1.
  • #type: Storage type.
  • [optional] #default: Value returned when none.

Storage items are accessible in multiple ways:

  • The structure: Foo or Foo::<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: Config> 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::{Pallet, 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: Config<I>, I: Instance=DefaultInstance> as Example {}

Accessing the structure no requires the instance as generic parameter:

  • Foo::<I> if the value type is not generic
  • Foo::<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: Config> 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().

PoV information

To implement the trait StorageInfoTrait for storages an additional attribute can be used generate_storage_info:

decl_storage! { generate_storage_info
	trait Store for ...
}