Configuring Genesis for Balances
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.
Using the
#[pallet::genesis_config]
attribute, write theGenesisConfig
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)>, }
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() } } }
Using the
#[pallet::genesis_build]
attribute, 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); } } }
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.
In
node/chain_spec.rs
, create a constant value of typeT::Balance
to be stored in<SingleValue<T>>
(inside thetestnet_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 ourchain_spec.rs
file.Create a vector of accounts to initialize
<AccountMap<T>>
with (also 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"), ];
Complete 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.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 toVALUE
. This pattern is very similar to the Balances pallet'sGenesisConfig
implementation.
Example
Related material
- Learn how to customize a chain's genesis configuration for the balances pallet.
BalancesConfig