Configure genesis state

Genesis configuration defines the initial state for things such as accounts, balances, genesis for custom pallets, and more. This guide explains how to configure the genesis of a pallet with 2 simple storage items.

Implement genesis inside your pallet

For the sake of this guide, we'll assume you have a pallet <SingleValue<T>> and <AccountMap<T>>.

For example:

#[pallet::storage]
#[pallet::getter(fn something)]
pub type SingleValue<T: Config> = StorageValue<_, T::Balance>;

// A map that has enumerable entries.
#[pallet::storage]
#[pallet::getter(fn accounts)]
pub type AccountMap<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance>;

The GenesisConfig code should go after your storage items.

  1. Using the #[pallet::genesis_config] attribute, write the GenesisConfig struct for your pallet.

    #[pallet::genesis_config]
    pub struct GenesisConfig<T: Config> {
    	pub single_value: T::Balance,
    	pub account_map: Vec<(T::AccountId, T::Balance)>,
    }
  2. 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() }
    	}
    }
  3. Using the #[pallet::genesis_build] attribute, implement the GenesisBuild 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);
    		}
    	}
    }

    This allows you to execute some logic to define how the GenesisConfig struct places something in storage.

Configure your node's chain spec

All that's left to do is to specify what values we want to put in the genesis state of our chain. We'll assume our pallet is called pallet_something, declared as PalletSomething in our runtime's construct_runtime! macro.

  1. In node/chain_spec.rs, create a constant value of type T::Balance to be stored in <SingleValue<T>> (inside the testnet_genesis method).

    const VALUE: Balance = 235813;

    Note that this step also implies that we have use node_template_runtime::Balance; imported at the top of our chain_spec.rs file.

  2. Create a vector of accounts to initialize <AccountMap<T>> with (also inside the testnet_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"),
    	];
  3. Complete the GenesisConfig clause in the testnet_genesis function.

    The convention is to use lowercase spelling of the name of your pallet in runtime/src/lib.rs inside construct_runtime!. For pallets declared as CamelCase for example, the convention is to refer to it as camel_case in the testnet_genesis function.

    In our example, this looks like:

    pallet_something: PalletSomethingConfig {
    	single_value: VALUE,
    	account_map: accounts_to_map.iter().cloned().map(|x| (x, VALUE)).collect(),
    }

    In the above code, we're mapping each account from accounts_to_map to an amount equal to VALUE. This pattern is very similar to the Balances pallet's GenesisConfig implementation.

Example