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
135
136
137
138
139
140
//! Chain specification for the evm domain.

use crate::chain_spec::get_from_seed;
use codec::Encode;
use domain_runtime_primitives::AccountId20Converter;
use evm_domain_test_runtime::{
    AccountId as AccountId20, Precompiles, RuntimeGenesisConfig, Signature,
};
use sc_chain_spec::{ChainType, GenericChainSpec, NoExtension};
use sp_core::{ecdsa, Pair, Public};
use sp_domains::storage::RawGenesis;
use sp_domains::{DomainId, GenesisDomain, OperatorAllowList, OperatorPublicKey, RuntimeType};
use sp_runtime::traits::{Convert, IdentifyAccount, Verify};
use sp_runtime::{BuildStorage, Percent};
use subspace_runtime_primitives::{AccountId, Balance, SSC};
use subspace_test_runtime::{MaxDomainBlockSize, MaxDomainBlockWeight};

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

/// Helper function to generate an account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId20
where
    AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
    AccountPublic::from(
        TPublic::Pair::from_string(&format!("//{seed}"), None)
            .expect("static values are valid; qed")
            .public(),
    )
    .into_account()
}

pub(crate) fn endowed_accounts() -> Vec<AccountId20> {
    vec![
        get_account_id_from_seed::<ecdsa::Public>("Alice"),
        get_account_id_from_seed::<ecdsa::Public>("Bob"),
        get_account_id_from_seed::<ecdsa::Public>("Charlie"),
        get_account_id_from_seed::<ecdsa::Public>("Dave"),
        get_account_id_from_seed::<ecdsa::Public>("Eve"),
        get_account_id_from_seed::<ecdsa::Public>("Ferdie"),
        get_account_id_from_seed::<ecdsa::Public>("Alice//stash"),
        get_account_id_from_seed::<ecdsa::Public>("Bob//stash"),
        get_account_id_from_seed::<ecdsa::Public>("Charlie//stash"),
        get_account_id_from_seed::<ecdsa::Public>("Dave//stash"),
        get_account_id_from_seed::<ecdsa::Public>("Eve//stash"),
        get_account_id_from_seed::<ecdsa::Public>("Ferdie//stash"),
    ]
}

/// Get the genesis config of the evm domain
pub fn testnet_evm_genesis() -> RuntimeGenesisConfig {
    // This is the simplest bytecode to revert without returning any data.
    // We will pre-deploy it under all of our precompiles to ensure they can be called from
    // within contracts.
    // (PUSH1 0x00 PUSH1 0x00 REVERT)
    let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD];

    RuntimeGenesisConfig {
        system: evm_domain_test_runtime::SystemConfig::default(),
        balances: evm_domain_test_runtime::BalancesConfig::default(),
        evm_chain_id: evm_domain_test_runtime::EVMChainIdConfig {
            chain_id: 100,
            ..Default::default()
        },
        evm: evm_domain_test_runtime::EVMConfig {
            // We need _some_ code inserted at the precompile address so that
            // the evm will actually call the address.
            accounts: Precompiles::used_addresses()
                .into_iter()
                .map(|addr| {
                    (
                        addr,
                        fp_evm::GenesisAccount {
                            nonce: Default::default(),
                            balance: Default::default(),
                            storage: Default::default(),
                            code: revert_bytecode.clone(),
                        },
                    )
                })
                .collect(),
            ..Default::default()
        },
        self_domain_id: evm_domain_test_runtime::SelfDomainIdConfig {
            // Set the domain id of the genesis domain to an arbitrary value
            // it should be overwritten with the correct value
            domain_id: Some(DomainId::new(123)),
            ..Default::default()
        },
        ..Default::default()
    }
}

pub fn get_genesis_domain(
    sudo_account: subspace_runtime_primitives::AccountId,
) -> Result<GenesisDomain<AccountId, Balance>, String> {
    let raw_genesis_storage = {
        let domain_chain_spec = GenericChainSpec::<NoExtension, ()>::builder(
            evm_domain_test_runtime::WASM_BINARY
                .ok_or_else(|| "Development wasm not available".to_string())?,
            None,
        )
        .with_chain_type(ChainType::Development)
        .with_genesis_config(
            serde_json::to_value(testnet_evm_genesis())
                .map_err(|error| format!("Failed to serialize genesis config: {error}"))?,
        )
        .build();
        let storage = domain_chain_spec
            .build_storage()
            .expect("Failed to build genesis storage from genesis runtime config");
        let raw_genesis = RawGenesis::from_storage(storage);
        raw_genesis.encode()
    };

    Ok(GenesisDomain {
        runtime_name: "evm".to_owned(),
        runtime_type: RuntimeType::Evm,
        runtime_version: evm_domain_test_runtime::VERSION,
        raw_genesis_storage,

        // Domain config, mainly for placeholder the concrete value TBD
        owner_account_id: sudo_account,
        domain_name: "evm-domain".to_owned(),
        max_block_size: MaxDomainBlockSize::get(),
        max_block_weight: MaxDomainBlockWeight::get(),
        bundle_slot_probability: (1, 1),
        target_bundles_per_block: 10,
        operator_allow_list: OperatorAllowList::Anyone,

        signing_key: get_from_seed::<OperatorPublicKey>("Alice"),
        minimum_nominator_stake: 100 * SSC,
        nomination_tax: Percent::from_percent(5),
        initial_balances: endowed_accounts()
            .iter()
            .cloned()
            .map(|k| (AccountId20Converter::convert(k), 2_000_000 * SSC))
            .collect(),
    })
}