Every time when I start my parachain, I see Alice, Bob, Charlie, Dave,... etc and each of them has 1.1529 MUNIT on Polkadot.js.org's Accounts -> Accounts -> My Account page.

How does Polkadot.js.org get those initial account balances?

I found this code in chain_spec.rs in substrate-parachain-template repository https://github.com/substrate-developer-hub/substrate-parachain-template/blob/main/node/src/chain_spec.rs#L119 :

pub fn development_config() -> ChainSpec {
    // the same code as in local_testnet_config() below, except:
    // Name: "Development",
    // ID  : "dev",
    // ChainType::Development
    // Protocol ID and Properties: None,
pub fn local_testnet_config() -> ChainSpec {
    // Give your base currency a unit name and decimal places
    let mut properties = sc_chain_spec::Properties::new();
    properties.insert("tokenSymbol".into(), "UNIT".into());
    properties.insert("tokenDecimals".into(), 12.into());
    properties.insert("ss58Format".into(), 42.into());

        // Name
        "Local Testnet",
        // ID
        move || {
                // initial collators.
        // Bootnodes
        // Telemetry
        // Protocol ID
        // Fork ID
        // Properties
        // Extensions
        Extensions {
            relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
            para_id: 1000,

fn testnet_genesis(
    invulnerables: Vec<(AccountId, AuraId)>,
    endowed_accounts: Vec<AccountId>,
    root_key: AccountId,
    id: ParaId,
) -> GenesisConfig {
        system: SystemConfig { ... },
        balances: hero_runtime::BalancesConfig {
            balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
        parachain_info: hero_runtime::ParachainInfoConfig { parachain_id: id },

I see this balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), maps ALICE, BOB, etc.. to 1 << 60, which uses Rust's left shift operator to make ( A << B ) equivalent to A*2^B

for example:

1000 << 2 returns 1000*(2^2) = 4000

1 << 60 returns 1*(2^60) = 1.152921505×10^18, which matches what I saw in Polkadot.js.org

But both development_config() or local_testnet_config() use this testnet_genesis() to generate initial account balances.

When I ran my local parachain with a local relay chain as described in "Connect other chains" https://docs.substrate.io/tutorials/connect-other-chains/, was I running it through development_config() or local_testnet_config() ?

Both those two config functions use testnet_genesis()

fn testnet_genesis(
  invulnerables: Vec<(AccountId, AuraId)>,
  endowed_accounts: Vec<AccountId>,
  root_key: AccountId,
  id: ParaId,
){ ... }

What determines this testnet_genesis() id argument to be 1000.into(), or 2000.into(),?

When running my parachain locally with relay chain, I need to reserve paraId 2000 as described in the above "Connect other chains" tutorial.

Does this paraId 2000 determine the testnet_genesis() id argument to be 2000.into()?

2 Answers 2


Was I running it through development_config() or local_testnet_config() ?

By default, you are running it through local_testnet_config. This default configuration can be found in node/src/command.rs in the load_spec function. See here:

fn load_spec(id: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
    Ok(match id {
        "dev" => Box::new(chain_spec::development_config()),
        "template-rococo" => Box::new(chain_spec::local_testnet_config()),
        "" | "local" => Box::new(chain_spec::local_testnet_config()),
        path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),

The last match arm "" | "local" is the one that runs by default (empty string). If you wanted to change which chain-spec is used (e.g. "dev"), simply provide --chain "dev" to your run command. To go one step further, play around with the build-spec command and compare the outputted files.

#generate dev spec (uses development_config)
./target/release/<node-executable> build-spec --chain dev > dev-spec.json

#generate local spec (uses local_testnet_config)
./target/release/<node-executable> build-spec --chain local > local-spec.json

Furthermore, you are correct in noting that both development_config and local_testnet_config use testnet_genesis. So, either way (in this case) the balances will come from testnet_genesis. However, you could easily modify this file to have, for example, a testnet_genesis and dev_genesis that use different balances. You could also alter which accounts have initial balances in local_testnet_config or development_config.

What determines this testnet_genesis() id argument to be 1000.into(), or 2000.into(),?

As you noted, the paraID you register on the relay chain must be placed into the id field in the chain spec.

  • but in substrate-parachain-template's chain_spec.rs, why is id 1000 for both development_config() and local_testnet_config() while the tutorial "Connect other chains" can use paraId 2000 ?
    – Russo
    Commented Sep 7, 2022 at 16:46
  • @Russo I am not sure why the default is 1000 in the template's chain_spec. The 2000, however, is used because the relay-chain has reserved < 2000 IDs for system level & common good chains. So, the first ID available to reserve will be 2000. Commented Sep 7, 2022 at 16:58

If you're using the substrate contracts node then the balances are coming from the chain_spec.rs file.

        balances: BalancesConfig {
            // Configure endowed accounts with initial balance of 1 << 60.
            balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.