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 singleStorageValuestorage item. - An
AccountMap<T>type for simple single keyStorageMapstorage 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.rsfile for your pallet in a text editor. -
Add the
StorageValuestorage item.For example:
#[pallet::storage] #[pallet::getter(fn something)] pub type SingleValue<T: Config> = StorageValue< _, T::Balance >; -
Add the
StorageMapstorage 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 theGenesisConfigstruct 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
GenesisConfigstruct.#[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 theGenesisBuildtrait.#[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 theGenesisConfigstruct 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.rsfile in a text editor. - Verify the
use node_template_runtime::BalanceConfig;imported at the top of ourchain_spec.rsfile. -
Create a constant value of type
T::Balanceto be stored in<SingleValue<T>>(inside thetestnet_genesismethod).const VALUE: Balance = 235813; -
Create a vector of accounts to initialize
<AccountMap<T>>with inside thetestnet_genesismethod.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
GenesisConfigclause in thetestnet_genesisfunction.The convention is to use lowercase spelling of the name of your pallet in
runtime/src/lib.rsinsideconstruct_runtime!. For pallets declared asCamelCasefor example, the convention is to refer to it ascamel_casein thetestnet_genesisfunction.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_mapto an amount equal toVALUE. This pattern is very similar to theGenesisConfigfor the Balances pallet.
