1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use {
18
    container_chain_template_frontier_runtime::{
19
        AccountId, EVMChainIdConfig, EVMConfig, MaintenanceModeConfig, MigrationsConfig,
20
        PolkadotXcmConfig, Precompiles,
21
    },
22
    cumulus_primitives_core::ParaId,
23
    fp_evm::GenesisAccount,
24
    hex_literal::hex,
25
    node_common::chain_spec::Extensions,
26
    sc_network::config::MultiaddrWithPeerId,
27
    sc_service::ChainType,
28
};
29

            
30
/// Specialized `ChainSpec` for the normal parachain runtime.
31
pub type ChainSpec = sc_service::GenericChainSpec<Extensions>;
32

            
33
/// Orcherstrator's parachain id
34
pub const ORCHESTRATOR: ParaId = ParaId::new(1000);
35

            
36
2
pub fn development_config(para_id: ParaId, boot_nodes: Vec<String>) -> ChainSpec {
37
2
    // Give your base currency a unit name and decimal places
38
2
    let mut properties = sc_chain_spec::Properties::new();
39
2
    properties.insert("tokenSymbol".into(), "UNIT".into());
40
2
    properties.insert("tokenDecimals".into(), 18.into());
41
2
    properties.insert("ss58Format".into(), 42.into());
42
2
    properties.insert("isEthereum".into(), true.into());
43
2

            
44
2
    let mut default_funded_accounts = pre_funded_accounts();
45
2
    default_funded_accounts.sort();
46
2
    default_funded_accounts.dedup();
47
2
    let boot_nodes: Vec<MultiaddrWithPeerId> = boot_nodes
48
2
        .into_iter()
49
2
        .map(|x| {
50
            x.parse::<MultiaddrWithPeerId>()
51
                .unwrap_or_else(|e| panic!("invalid bootnode address format {:?}: {:?}", x, e))
52
2
        })
53
2
        .collect();
54
2

            
55
2
    ChainSpec::builder(
56
2
        container_chain_template_frontier_runtime::WASM_BINARY
57
2
            .expect("WASM binary was not built, please build it!"),
58
2
        Extensions {
59
2
            relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
60
2
            para_id: para_id.into(),
61
2
        },
62
2
    )
63
2
    .with_name("Development")
64
2
    .with_id("dev")
65
2
    .with_chain_type(ChainType::Development)
66
2
    .with_genesis_config(testnet_genesis(
67
2
        default_funded_accounts.clone(),
68
2
        para_id,
69
2
        AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
70
2
    ))
71
2
    .with_properties(properties)
72
2
    .with_boot_nodes(boot_nodes)
73
2
    .build()
74
2
}
75

            
76
pub fn local_testnet_config(para_id: ParaId, boot_nodes: Vec<String>) -> ChainSpec {
77
    // Give your base currency a unit name and decimal places
78
    let mut properties = sc_chain_spec::Properties::new();
79
    properties.insert("tokenSymbol".into(), "UNIT".into());
80
    properties.insert("tokenDecimals".into(), 18.into());
81
    properties.insert("ss58Format".into(), 42.into());
82
    properties.insert("isEthereum".into(), true.into());
83
    let protocol_id = format!("container-chain-{}", para_id);
84

            
85
    let mut default_funded_accounts = pre_funded_accounts();
86
    default_funded_accounts.sort();
87
    default_funded_accounts.dedup();
88
    let boot_nodes: Vec<MultiaddrWithPeerId> = boot_nodes
89
        .into_iter()
90
        .map(|x| {
91
            x.parse::<MultiaddrWithPeerId>()
92
                .unwrap_or_else(|e| panic!("invalid bootnode address format {:?}: {:?}", x, e))
93
        })
94
        .collect();
95

            
96
    ChainSpec::builder(
97
        container_chain_template_frontier_runtime::WASM_BINARY
98
            .expect("WASM binary was not built, please build it!"),
99
        Extensions {
100
            relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
101
            para_id: para_id.into(),
102
        },
103
    )
104
    .with_name(&format!("Frontier Container {}", para_id))
105
    .with_id(&format!("frontier_container_{}", para_id))
106
    .with_chain_type(ChainType::Local)
107
    .with_genesis_config(testnet_genesis(
108
        default_funded_accounts.clone(),
109
        para_id,
110
        AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
111
    ))
112
    .with_properties(properties)
113
    .with_protocol_id(&protocol_id)
114
    .with_boot_nodes(boot_nodes)
115
    .build()
116
}
117

            
118
2
fn testnet_genesis(
119
2
    endowed_accounts: Vec<AccountId>,
120
2
    id: ParaId,
121
2
    root_key: AccountId,
122
2
) -> serde_json::Value {
123
2
    // This is the simplest bytecode to revert without returning any data.
124
2
    // We will pre-deploy it under all of our precompiles to ensure they can be called from
125
2
    // within contracts.
126
2
    // (PUSH1 0x00 PUSH1 0x00 REVERT)
127
2
    let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD];
128
2

            
129
2
    let g = container_chain_template_frontier_runtime::RuntimeGenesisConfig {
130
2
        system: Default::default(),
131
2
        balances: container_chain_template_frontier_runtime::BalancesConfig {
132
2
            balances: endowed_accounts
133
2
                .iter()
134
2
                .cloned()
135
8
                .map(|k| (k, 1 << 80))
136
2
                .collect(),
137
2
            ..Default::default()
138
2
        },
139
2
        parachain_info: container_chain_template_frontier_runtime::ParachainInfoConfig {
140
2
            parachain_id: id,
141
2
            ..Default::default()
142
2
        },
143
2
        parachain_system: Default::default(),
144
2
        // EVM compatibility
145
2
        // We should change this to something different than Moonbeam
146
2
        // For now moonwall is very tailored for moonbeam so we need it for tests
147
2
        evm_chain_id: EVMChainIdConfig {
148
2
            chain_id: 1281,
149
2
            ..Default::default()
150
2
        },
151
2
        evm: EVMConfig {
152
2
            // We need _some_ code inserted at the precompile address so that
153
2
            // the evm will actually call the address.
154
2
            accounts: Precompiles::used_addresses()
155
26
                .map(|addr| {
156
26
                    (
157
26
                        addr.into(),
158
26
                        GenesisAccount {
159
26
                            nonce: Default::default(),
160
26
                            balance: Default::default(),
161
26
                            storage: Default::default(),
162
26
                            code: revert_bytecode.clone(),
163
26
                        },
164
26
                    )
165
26
                })
166
2
                .collect(),
167
2
            ..Default::default()
168
2
        },
169
2
        ethereum: Default::default(),
170
2
        base_fee: Default::default(),
171
2
        transaction_payment: Default::default(),
172
2
        sudo: container_chain_template_frontier_runtime::SudoConfig {
173
2
            key: Some(root_key),
174
2
        },
175
2
        authorities_noting: container_chain_template_frontier_runtime::AuthoritiesNotingConfig {
176
2
            orchestrator_para_id: ORCHESTRATOR,
177
2
            ..Default::default()
178
2
        },
179
2
        migrations: MigrationsConfig {
180
2
            ..Default::default()
181
2
        },
182
2
        maintenance_mode: MaintenanceModeConfig {
183
2
            start_in_maintenance_mode: false,
184
2
            ..Default::default()
185
2
        },
186
2
        // This should initialize it to whatever we have set in the pallet
187
2
        polkadot_xcm: PolkadotXcmConfig::default(),
188
2
        tx_pause: Default::default(),
189
2
    };
190
2

            
191
2
    serde_json::to_value(g).unwrap()
192
2
}
193

            
194
/// Get pre-funded accounts
195
2
pub fn pre_funded_accounts() -> Vec<AccountId> {
196
2
    // These addresses are derived from Substrate's canonical mnemonic:
197
2
    // bottom drive obey lake curtain smoke basket hold race lonely fit walk
198
2
    vec![
199
2
        AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")), // Alith
200
2
        AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
201
2
        AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
202
2
        AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
203
2
    ]
204
2
}