Configure genesis state
Please read Substrate to Polkadot SDK page first.
Genesis configuration defines the initial state for storage items such as accounts, balances, genesis for custom pallets, and more. This guide demonstrates how to configure the genesis state for a pallet with the following storage items:
- A
SingleValue<T>
type for a singleStorageValue
storage item. - An
AccountMap<T>
type for simple single keyStorageMap
storage item.
Steps preview
- Add the storage items in the pallet.
- Add the genesis configuration macros in the pallet.
- Set initial values in the chain specification.
Add storage items to the pallet
- Open the
src//lib.rs
file for your pallet in a text editor. -
Add the
StorageValue
storage item.For example:
#[pallet::storage] #[pallet::getter(fn something)] pub type SingleValue<T: Config> = StorageValue< _, T::Balance >;
-
Add the
StorageMap
storage item for a map that has enumerable entries.For example:
#[pallet::storage] #[pallet::getter(fn accounts)] pub type AccountMap<T: Config> = StorageMap< _, Blake2_128Concat, T::AccountId, T::Balance >;
Add genesis configuration macros
The GenesisConfig
code should go after your storage items.
-
Add the
#[pallet::genesis_config]
attribute macro and define theGenesisConfig
struct for the storage items to initialize.#[pallet::genesis_config] pub struct GenesisConfig<T: Config> { pub single_value: T::Balance, pub account_map: Vec<(T::AccountId, T::Balance)>, }
-
Set the default value for the
GenesisConfig
struct.#[cfg(feature = "std")] impl<T: Config> Default for GenesisConfig<T> { fn default() -> Self { Self { single_value: Default::default(), account_map: Default::default() } } }
-
Add the
#[pallet::genesis_build]
attribute macro and implement theGenesisBuild
trait.#[pallet::genesis_build] impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { fn build(&self) { <SingleValue<T>>::put(&self.single_value); for (a, b) in &self.account_map { <AccountMap<T>>::insert(a, b); } } }
The
#[pallet::genesis_build]
macro allows you to execute some logic to define how theGenesisConfig
struct places something in storage.
Set initial values
After you configure the storage items and genesis configuration in your pallet, you can specify the values you want to set for the storage items in the genesis state of the chain.
In this example, assume that the construct_runtime!
macro for runtime refers to PalletSomething
as the pallet name and pallet_something
as the path to the pallet.
construct_runtime!(
pub struct Runtime
where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
PalletSomething: pallet_something,
}
)
- Open the
node/chain_spec.rs
file in a text editor. - Verify the
use node_template_runtime::BalanceConfig;
imported at the top of ourchain_spec.rs
file. -
Create a constant value of type
T::Balance
to be stored in<SingleValue<T>>
(inside thetestnet_genesis
method).const VALUE: Balance = 235813;
-
Create a vector of accounts to initialize
<AccountMap<T>>
with inside thetestnet_genesis
method.let accounts_to_map: Vec<AccountId> = vec![ get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Bob"), get_account_id_from_seed::<sr25519::Public>("Charlie"), ];
-
Add the pallet to the
GenesisConfig
clause in thetestnet_genesis
function.The convention is to use lowercase spelling of the name of your pallet in
runtime/src/lib.rs
insideconstruct_runtime!
. For pallets declared asCamelCase
for example, the convention is to refer to it ascamel_case
in thetestnet_genesis
function.For this example pallet, the code looks like this:
pallet_something: PalletSomethingConfig { single_value: VALUE, account_map: accounts_to_map.iter().cloned().map(|x| (x, VALUE)).collect(), }
This sample code maps each account from
accounts_to_map
to an amount equal toVALUE
. This pattern is very similar to theGenesisConfig
for the Balances pallet.