subspace_malicious_operator/
chain_spec.rs

1use domain_runtime_primitives::{AccountId20Converter, MultiAccountId};
2use evm_domain_runtime::{AccountId as AccountId20, EVMChainIdConfig, EVMConfig, Precompiles};
3use hex_literal::hex;
4use parity_scale_codec::Encode;
5use sc_chain_spec::GenericChainSpec;
6use sc_service::ChainType;
7use sp_core::crypto::AccountId32;
8use sp_core::{Pair, Public, sr25519};
9use sp_domains::storage::RawGenesis;
10use sp_domains::{
11    DomainRuntimeConfig, OperatorAllowList, OperatorPublicKey, PermissionedActionAllowedBy,
12    RuntimeType,
13};
14use sp_runtime::traits::{Convert, IdentifyAccount};
15use sp_runtime::{BuildStorage, MultiSigner, Percent};
16use std::marker::PhantomData;
17use std::num::NonZeroU32;
18use subspace_runtime::{
19    AllowAuthoringBy, CouncilConfig, DemocracyConfig, DomainsConfig, EnableRewardsAt,
20    RewardsConfig, RuntimeConfigsConfig, SubspaceConfig,
21};
22use subspace_runtime_primitives::{
23    AI3, AccountId, Balance, BlockNumber, CouncilDemocracyConfigParams, GenesisConfigParams,
24};
25
26fn endowed_accounts() -> Vec<(MultiAccountId, Balance)> {
27    [
28        // Alith key
29        AccountId20::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")),
30        // Baltathar key
31        AccountId20::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")),
32        // Charleth key
33        AccountId20::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")),
34        // Dorothy
35        AccountId20::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")),
36    ]
37    .into_iter()
38    .map(|k| (AccountId20Converter::convert(k), 1_000_000 * AI3))
39    .collect()
40}
41
42pub fn domain_dev_config() -> Result<GenericChainSpec, String> {
43    Ok(GenericChainSpec::builder(
44        evm_domain_runtime::WASM_BINARY.expect("WASM binary was not build, please build it!"),
45        None,
46    )
47    .with_name("Development")
48    .with_id("evm_domain_dev")
49    .with_chain_type(ChainType::Development)
50    .with_genesis_config({
51        // This is the simplest bytecode to revert without returning any data.
52        // We will pre-deploy it under all of our precompiles to ensure they can be called from
53        // within contracts.
54        // (PUSH1 0x00 PUSH1 0x00 REVERT)
55        let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD];
56
57        serde_json::to_value(evm_domain_runtime::RuntimeGenesisConfig {
58            system: evm_domain_runtime::SystemConfig::default(),
59            balances: evm_domain_runtime::BalancesConfig::default(),
60            // this is set to default and chain_id will be set into genesis during the domain
61            // instantiation on Consensus runtime.
62            evm_chain_id: EVMChainIdConfig::default(),
63            evm: EVMConfig {
64                // We need _some_ code inserted at the precompile address so that
65                // the evm will actually call the address.
66                accounts: Precompiles::used_addresses()
67                    .into_iter()
68                    .map(|addr| {
69                        (
70                            addr,
71                            fp_evm::GenesisAccount {
72                                nonce: Default::default(),
73                                balance: Default::default(),
74                                storage: Default::default(),
75                                code: revert_bytecode.clone(),
76                            },
77                        )
78                    })
79                    .collect(),
80                ..Default::default()
81            },
82            ..Default::default()
83        })
84        .map_err(|error| format!("Failed to serialize genesis config: {error}"))?
85    })
86    .build())
87}
88
89pub(crate) fn consensus_dev_sudo_account() -> AccountId32 {
90    get_account_id_from_seed("Alice")
91}
92
93pub fn create_domain_spec(chain_id: &str) -> Result<Box<dyn sc_cli::ChainSpec>, String> {
94    let chain_spec = match chain_id {
95        "dev" => domain_dev_config()?,
96        path => GenericChainSpec::from_json_file(std::path::PathBuf::from(path))?,
97    };
98    Ok(Box::new(chain_spec))
99}
100
101pub fn load_domain_chain_spec(spec_id: &str) -> Result<Box<dyn sc_cli::ChainSpec>, String> {
102    let chain_spec = match spec_id {
103        "dev" => domain_dev_config()?,
104        path => GenericChainSpec::from_json_file(std::path::PathBuf::from(path))?,
105    };
106    Ok(Box::new(chain_spec))
107}
108
109/// Get public key from keypair seed.
110fn get_public_key_from_seed<TPublic: Public>(
111    seed: &'static str,
112) -> <TPublic::Pair as Pair>::Public {
113    TPublic::Pair::from_string(&format!("//{seed}"), None)
114        .expect("Static values are valid; qed")
115        .public()
116}
117
118/// Generate an account ID from seed.
119fn get_account_id_from_seed(seed: &'static str) -> AccountId32 {
120    MultiSigner::from(get_public_key_from_seed::<sr25519::Public>(seed)).into_account()
121}
122
123/// Additional subspace specific genesis parameters.
124struct GenesisParams {
125    enable_rewards_at: EnableRewardsAt<BlockNumber>,
126    allow_authoring_by: AllowAuthoringBy,
127    pot_slot_iterations: NonZeroU32,
128    enable_domains: bool,
129    enable_dynamic_cost_of_storage: bool,
130    enable_balance_transfers: bool,
131    confirmation_depth_k: u32,
132    rewards_config: RewardsConfig,
133    domain_block_pruning_depth: u32,
134    staking_withdrawal_period: u32,
135}
136
137struct GenesisDomainParams {
138    domain_name: String,
139    operator_allow_list: OperatorAllowList<AccountId>,
140    operator_signing_key: OperatorPublicKey,
141    raw_genesis_storage: Vec<u8>,
142    initial_balances: Vec<(MultiAccountId, Balance)>,
143    permissioned_action_allowed_by: PermissionedActionAllowedBy<AccountId>,
144    domain_runtime_config: DomainRuntimeConfig,
145}
146
147pub fn dev_config() -> Result<GenericChainSpec, String> {
148    let wasm_binary = subspace_runtime::WASM_BINARY
149        .ok_or_else(|| "Development wasm not available".to_string())?;
150
151    let raw_genesis_storage = {
152        let domain_genesis_config = domain_dev_config()?;
153        let storage = domain_genesis_config
154            .build_storage()
155            .expect("Failed to build genesis storage from genesis runtime config");
156        let raw_genesis = RawGenesis::from_storage(storage);
157        raw_genesis.encode()
158    };
159
160    let GenesisConfigParams {
161        confirmation_depth_k,
162        domain_block_pruning_depth,
163        staking_withdrawal_period,
164    } = GenesisConfigParams::dev_params();
165
166    Ok(GenericChainSpec::builder(wasm_binary, None)
167        .with_name("Subspace development")
168        .with_id("subspace_dev")
169        .with_chain_type(ChainType::Development)
170        .with_genesis_config(
171            serde_json::to_value(subspace_genesis_config(
172                // Sudo account
173                get_account_id_from_seed("Alice"),
174                // Pre-funded accounts
175                vec![
176                    (get_account_id_from_seed("Alice"), Balance::MAX / 2),
177                    (get_account_id_from_seed("Bob"), 1_000 * AI3),
178                    (get_account_id_from_seed("Alice//stash"), 1_000 * AI3),
179                    (get_account_id_from_seed("Bob//stash"), 1_000 * AI3),
180                ],
181                GenesisParams {
182                    enable_rewards_at: EnableRewardsAt::Manually,
183                    allow_authoring_by: AllowAuthoringBy::Anyone,
184                    pot_slot_iterations: NonZeroU32::new(100_000_000).expect("Not zero; qed"),
185                    enable_domains: true,
186                    enable_dynamic_cost_of_storage: false,
187                    enable_balance_transfers: true,
188                    confirmation_depth_k,
189                    rewards_config: RewardsConfig {
190                        remaining_issuance: 1_000_000 * AI3,
191                        proposer_subsidy_points: Default::default(),
192                        voter_subsidy_points: Default::default(),
193                    },
194                    domain_block_pruning_depth,
195                    staking_withdrawal_period,
196                },
197                GenesisDomainParams {
198                    domain_name: "evm-domain".to_owned(),
199                    operator_allow_list: OperatorAllowList::Anyone,
200                    operator_signing_key: get_public_key_from_seed::<OperatorPublicKey>("Alice"),
201                    raw_genesis_storage: raw_genesis_storage.clone(),
202                    initial_balances: endowed_accounts(),
203                    permissioned_action_allowed_by: PermissionedActionAllowedBy::Anyone,
204                    domain_runtime_config: DomainRuntimeConfig::default_evm(),
205                },
206            ))
207            .map_err(|error| format!("Failed to serialize genesis config: {error}"))?,
208        )
209        .build())
210}
211
212/// Configure initial storage state for FRAME modules.
213fn subspace_genesis_config(
214    sudo_account: AccountId,
215    balances: Vec<(AccountId, Balance)>,
216    genesis_params: GenesisParams,
217    genesis_domain_params: GenesisDomainParams,
218) -> subspace_runtime::RuntimeGenesisConfig {
219    let GenesisParams {
220        enable_rewards_at,
221        allow_authoring_by,
222        pot_slot_iterations,
223        enable_domains,
224        enable_dynamic_cost_of_storage,
225        enable_balance_transfers,
226        confirmation_depth_k,
227        rewards_config,
228        domain_block_pruning_depth,
229        staking_withdrawal_period,
230    } = genesis_params;
231
232    subspace_runtime::RuntimeGenesisConfig {
233        system: subspace_runtime::SystemConfig::default(),
234        balances: subspace_runtime::BalancesConfig { balances },
235        transaction_payment: Default::default(),
236        sudo: subspace_runtime::SudoConfig {
237            // Assign network admin rights.
238            key: Some(sudo_account.clone()),
239        },
240        subspace: SubspaceConfig {
241            enable_rewards_at,
242            allow_authoring_by,
243            pot_slot_iterations,
244            phantom: PhantomData,
245        },
246        rewards: rewards_config,
247        council: CouncilConfig::default(),
248        democracy: DemocracyConfig::default(),
249        runtime_configs: RuntimeConfigsConfig {
250            enable_domains,
251            enable_dynamic_cost_of_storage,
252            enable_balance_transfers,
253            confirmation_depth_k,
254            council_democracy_config_params:
255                CouncilDemocracyConfigParams::<BlockNumber>::fast_params(),
256            domain_block_pruning_depth,
257            staking_withdrawal_period,
258        },
259        domains: DomainsConfig {
260            permissioned_action_allowed_by: Some(
261                genesis_domain_params.permissioned_action_allowed_by,
262            ),
263            genesis_domains: vec![sp_domains::GenesisDomain {
264                runtime_name: "evm".to_owned(),
265                runtime_type: RuntimeType::Evm,
266                runtime_version: evm_domain_runtime::VERSION,
267                raw_genesis_storage: genesis_domain_params.raw_genesis_storage,
268
269                // Domain config, mainly for placeholder the concrete value TBD
270                owner_account_id: sudo_account.clone(),
271                domain_name: genesis_domain_params.domain_name,
272                bundle_slot_probability: (1, 1),
273                operator_allow_list: genesis_domain_params.operator_allow_list,
274                signing_key: genesis_domain_params.operator_signing_key,
275                nomination_tax: Percent::from_percent(5),
276                minimum_nominator_stake: 100 * AI3,
277                initial_balances: genesis_domain_params.initial_balances,
278                domain_runtime_config: genesis_domain_params.domain_runtime_config,
279            }],
280        },
281    }
282}