subspace_test_client/
chain_spec.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Chain specification for the test runtime.

use sc_chain_spec::{ChainType, GenericChainSpec};
use sp_core::{sr25519, Pair, Public};
use sp_domains::{EvmType, PermissionedActionAllowedBy};
use sp_runtime::traits::{IdentifyAccount, Verify};
use std::marker::PhantomData;
use std::num::NonZeroU32;
use subspace_runtime_primitives::{AccountId, Balance, Signature, SSC};
use subspace_test_runtime::{
    AllowAuthoringBy, BalancesConfig, DomainsConfig, EnableRewardsAt, RewardsConfig,
    RuntimeGenesisConfig, SubspaceConfig, SudoConfig, SystemConfig, WASM_BINARY,
};

/// Generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
    TPublic::Pair::from_string(&format!("//{seed}"), None)
        .expect("static values are valid; qed")
        .public()
}

type AccountPublic = <Signature as Verify>::Signer;

/// Generate an account ID from seed.
pub fn get_account_id_from_seed(seed: &str) -> AccountId {
    AccountPublic::from(get_from_seed::<sr25519::Public>(seed)).into_account()
}

/// Local testnet config (multivalidator Alice + Bob).
///
/// If `private_evm` is `true`, contract creation will have an allow list, which is set to `Anyone` by default.
/// Otherwise, any account can create contracts, and the allow list can't be changed.
///
/// If the EVM owner account isn't specified, `sudo_account` will be used.
pub fn subspace_local_testnet_config(
    private_evm: bool,
    evm_owner_account: Option<AccountId>,
) -> Result<GenericChainSpec, String> {
    let evm_type = if private_evm {
        EvmType::Private {
            initial_contract_creation_allow_list: PermissionedActionAllowedBy::Anyone,
        }
    } else {
        EvmType::Public
    };

    let sudo_account = get_account_id_from_seed("Alice");
    let evm_owner_account = evm_owner_account.unwrap_or_else(|| sudo_account.clone());

    // Pre-funded accounts
    // Alice and the EVM owner get more funds that are used during domain instantiation
    let mut balances = vec![
        (get_account_id_from_seed("Alice"), 1_000_000_000 * SSC),
        (get_account_id_from_seed("Bob"), 1_000 * SSC),
        (get_account_id_from_seed("Charlie"), 1_000 * SSC),
        (get_account_id_from_seed("Dave"), 1_000 * SSC),
        (get_account_id_from_seed("Eve"), 1_000 * SSC),
        (get_account_id_from_seed("Ferdie"), 1_000 * SSC),
        (get_account_id_from_seed("Alice//stash"), 1_000 * SSC),
        (get_account_id_from_seed("Bob//stash"), 1_000 * SSC),
        (get_account_id_from_seed("Charlie//stash"), 1_000 * SSC),
        (get_account_id_from_seed("Dave//stash"), 1_000 * SSC),
        (get_account_id_from_seed("Eve//stash"), 1_000 * SSC),
        (get_account_id_from_seed("Ferdie//stash"), 1_000 * SSC),
    ];

    if let Some((_existing_account, balance)) = balances
        .iter_mut()
        .find(|(account_id, _balance)| account_id == &evm_owner_account)
    {
        *balance = 1_000_000_000 * SSC;
    } else {
        balances.push((evm_owner_account.clone(), 1_000_000_000 * SSC));
    }

    Ok(GenericChainSpec::builder(
        WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
        None,
    )
    .with_name("Local Testnet")
    .with_id("local_testnet")
    .with_chain_type(ChainType::Local)
    .with_genesis_config(
        serde_json::to_value(create_genesis_config(
            // Sudo account
            sudo_account,
            balances,
            evm_type,
            evm_owner_account,
        )?)
        .map_err(|error| format!("Failed to serialize genesis config: {error}"))?,
    )
    .with_protocol_id("subspace-test")
    .build())
}

/// Configure initial storage state for FRAME modules.
fn create_genesis_config(
    sudo_account: AccountId,
    balances: Vec<(AccountId, Balance)>,
    evm_type: EvmType,
    evm_owner_account: AccountId,
) -> Result<RuntimeGenesisConfig, String> {
    Ok(RuntimeGenesisConfig {
        system: SystemConfig::default(),
        balances: BalancesConfig { balances },
        transaction_payment: Default::default(),
        sudo: SudoConfig {
            // Assign network admin rights.
            key: Some(sudo_account.clone()),
        },
        subspace: SubspaceConfig {
            enable_rewards_at: EnableRewardsAt::Manually,
            allow_authoring_by: AllowAuthoringBy::Anyone,
            pot_slot_iterations: NonZeroU32::new(50_000_000).expect("Not zero; qed"),
            phantom: PhantomData,
        },
        rewards: RewardsConfig {
            remaining_issuance: 1_000_000 * SSC,
            proposer_subsidy_points: Default::default(),
            voter_subsidy_points: Default::default(),
        },
        domains: DomainsConfig {
            permissioned_action_allowed_by: Some(sp_domains::PermissionedActionAllowedBy::Anyone),
            genesis_domains: vec![
                crate::evm_domain_chain_spec::get_genesis_domain(evm_owner_account, evm_type)
                    .expect("hard-coded values are valid; qed"),
                crate::auto_id_domain_chain_spec::get_genesis_domain(sudo_account)
                    .expect("hard-coded values are valid; qed"),
            ],
        },
        runtime_configs: Default::default(),
    })
}