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::{sr25519, Pair, Public};
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    AccountId, Balance, BlockNumber, CouncilDemocracyConfigParams, SSC,
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 * SSC))
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}
134
135struct GenesisDomainParams {
136    domain_name: String,
137    operator_allow_list: OperatorAllowList<AccountId>,
138    operator_signing_key: OperatorPublicKey,
139    raw_genesis_storage: Vec<u8>,
140    initial_balances: Vec<(MultiAccountId, Balance)>,
141    permissioned_action_allowed_by: PermissionedActionAllowedBy<AccountId>,
142    domain_runtime_config: DomainRuntimeConfig,
143}
144
145pub fn dev_config() -> Result<GenericChainSpec, String> {
146    let wasm_binary = subspace_runtime::WASM_BINARY
147        .ok_or_else(|| "Development wasm not available".to_string())?;
148
149    let raw_genesis_storage = {
150        let domain_genesis_config = domain_dev_config()?;
151        let storage = domain_genesis_config
152            .build_storage()
153            .expect("Failed to build genesis storage from genesis runtime config");
154        let raw_genesis = RawGenesis::from_storage(storage);
155        raw_genesis.encode()
156    };
157
158    Ok(GenericChainSpec::builder(wasm_binary, None)
159        .with_name("Subspace development")
160        .with_id("subspace_dev")
161        .with_chain_type(ChainType::Development)
162        .with_genesis_config(
163            serde_json::to_value(subspace_genesis_config(
164                // Sudo account
165                get_account_id_from_seed("Alice"),
166                // Pre-funded accounts
167                vec![
168                    (get_account_id_from_seed("Alice"), Balance::MAX / 2),
169                    (get_account_id_from_seed("Bob"), 1_000 * SSC),
170                    (get_account_id_from_seed("Alice//stash"), 1_000 * SSC),
171                    (get_account_id_from_seed("Bob//stash"), 1_000 * SSC),
172                ],
173                GenesisParams {
174                    enable_rewards_at: EnableRewardsAt::Manually,
175                    allow_authoring_by: AllowAuthoringBy::Anyone,
176                    pot_slot_iterations: NonZeroU32::new(100_000_000).expect("Not zero; qed"),
177                    enable_domains: true,
178                    enable_dynamic_cost_of_storage: false,
179                    enable_balance_transfers: true,
180                    confirmation_depth_k: 5,
181                    rewards_config: RewardsConfig {
182                        remaining_issuance: 1_000_000 * SSC,
183                        proposer_subsidy_points: Default::default(),
184                        voter_subsidy_points: Default::default(),
185                    },
186                },
187                GenesisDomainParams {
188                    domain_name: "evm-domain".to_owned(),
189                    operator_allow_list: OperatorAllowList::Anyone,
190                    operator_signing_key: get_public_key_from_seed::<OperatorPublicKey>("Alice"),
191                    raw_genesis_storage: raw_genesis_storage.clone(),
192                    initial_balances: endowed_accounts(),
193                    permissioned_action_allowed_by: PermissionedActionAllowedBy::Anyone,
194                    domain_runtime_config: DomainRuntimeConfig::default_evm(),
195                },
196            ))
197            .map_err(|error| format!("Failed to serialize genesis config: {error}"))?,
198        )
199        .build())
200}
201
202/// Configure initial storage state for FRAME modules.
203fn subspace_genesis_config(
204    sudo_account: AccountId,
205    balances: Vec<(AccountId, Balance)>,
206    genesis_params: GenesisParams,
207    genesis_domain_params: GenesisDomainParams,
208) -> subspace_runtime::RuntimeGenesisConfig {
209    let GenesisParams {
210        enable_rewards_at,
211        allow_authoring_by,
212        pot_slot_iterations,
213        enable_domains,
214        enable_dynamic_cost_of_storage,
215        enable_balance_transfers,
216        confirmation_depth_k,
217        rewards_config,
218    } = genesis_params;
219
220    subspace_runtime::RuntimeGenesisConfig {
221        system: subspace_runtime::SystemConfig::default(),
222        balances: subspace_runtime::BalancesConfig { balances },
223        transaction_payment: Default::default(),
224        sudo: subspace_runtime::SudoConfig {
225            // Assign network admin rights.
226            key: Some(sudo_account.clone()),
227        },
228        subspace: SubspaceConfig {
229            enable_rewards_at,
230            allow_authoring_by,
231            pot_slot_iterations,
232            phantom: PhantomData,
233        },
234        rewards: rewards_config,
235        council: CouncilConfig::default(),
236        democracy: DemocracyConfig::default(),
237        runtime_configs: RuntimeConfigsConfig {
238            enable_domains,
239            enable_dynamic_cost_of_storage,
240            enable_balance_transfers,
241            confirmation_depth_k,
242            council_democracy_config_params:
243                CouncilDemocracyConfigParams::<BlockNumber>::fast_params(),
244        },
245        domains: DomainsConfig {
246            permissioned_action_allowed_by: Some(
247                genesis_domain_params.permissioned_action_allowed_by,
248            ),
249            genesis_domains: vec![sp_domains::GenesisDomain {
250                runtime_name: "evm".to_owned(),
251                runtime_type: RuntimeType::Evm,
252                runtime_version: evm_domain_runtime::VERSION,
253                raw_genesis_storage: genesis_domain_params.raw_genesis_storage,
254
255                // Domain config, mainly for placeholder the concrete value TBD
256                owner_account_id: sudo_account.clone(),
257                domain_name: genesis_domain_params.domain_name,
258                bundle_slot_probability: (1, 1),
259                operator_allow_list: genesis_domain_params.operator_allow_list,
260                signing_key: genesis_domain_params.operator_signing_key,
261                nomination_tax: Percent::from_percent(5),
262                minimum_nominator_stake: 100 * SSC,
263                initial_balances: genesis_domain_params.initial_balances,
264                domain_runtime_config: genesis_domain_params.domain_runtime_config,
265            }],
266        },
267    }
268}