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_simple_runtime::{
19
        AccountId, MaintenanceModeConfig, MigrationsConfig, PolkadotXcmConfig, Signature,
20
    },
21
    cumulus_primitives_core::ParaId,
22
    sc_chain_spec::{ChainSpecExtension, ChainSpecGroup},
23
    sc_network::config::MultiaddrWithPeerId,
24
    sc_service::ChainType,
25
    serde::{Deserialize, Serialize},
26
    sp_core::{sr25519, Pair, Public},
27
    sp_runtime::traits::{IdentifyAccount, Verify},
28
};
29

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

            
33
/// Helper function to generate a crypto pair from seed
34
26
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
35
26
    TPublic::Pair::from_string(&format!("//{}", seed), None)
36
26
        .expect("static values are valid; qed")
37
26
        .public()
38
26
}
39

            
40
/// Orcherstrator's parachain id
41
pub const ORCHESTRATOR: ParaId = ParaId::new(1000);
42

            
43
/// The extensions for the [`ChainSpec`].
44
324
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
45
#[serde(deny_unknown_fields)]
46
pub struct Extensions {
47
    /// The relay chain of the Parachain.
48
    pub relay_chain: String,
49
    /// The id of the Parachain.
50
    pub para_id: u32,
51
}
52

            
53
impl Extensions {
54
    /// Try to get the extension from the given `ChainSpec`.
55
192
    pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
56
192
        sc_chain_spec::get_extension(chain_spec.extensions())
57
192
    }
58
}
59

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

            
62
/// Helper function to generate an account ID from seed
63
26
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
64
26
where
65
26
    AccountPublic: From<<TPublic::Pair as Pair>::Public>,
66
26
{
67
26
    AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
68
26
}
69

            
70
2
pub fn development_config(para_id: ParaId, boot_nodes: Vec<String>) -> ChainSpec {
71
2
    // Give your base currency a unit name and decimal places
72
2
    let mut properties = sc_chain_spec::Properties::new();
73
2
    properties.insert("tokenSymbol".into(), "UNIT".into());
74
2
    properties.insert("tokenDecimals".into(), 12.into());
75
2
    properties.insert("ss58Format".into(), 42.into());
76
2
    properties.insert("isEthereum".into(), false.into());
77
2

            
78
2
    let mut default_funded_accounts = pre_funded_accounts();
79
2
    default_funded_accounts.sort();
80
2
    default_funded_accounts.dedup();
81
2
    let boot_nodes: Vec<MultiaddrWithPeerId> = boot_nodes
82
2
        .into_iter()
83
2
        .map(|x| {
84
            x.parse::<MultiaddrWithPeerId>()
85
                .unwrap_or_else(|e| panic!("invalid bootnode address format {:?}: {:?}", x, e))
86
2
        })
87
2
        .collect();
88
2

            
89
2
    ChainSpec::builder(
90
2
        container_chain_template_simple_runtime::WASM_BINARY
91
2
            .expect("WASM binary was not built, please build it!"),
92
2
        Extensions {
93
2
            relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
94
2
            para_id: para_id.into(),
95
2
        },
96
2
    )
97
2
    .with_name("Development")
98
2
    .with_id("dev")
99
2
    .with_chain_type(ChainType::Development)
100
2
    .with_genesis_config(testnet_genesis(
101
2
        default_funded_accounts.clone(),
102
2
        para_id,
103
2
        get_account_id_from_seed::<sr25519::Public>("Alice"),
104
2
    ))
105
2
    .with_properties(properties)
106
2
    .with_boot_nodes(boot_nodes)
107
2
    .build()
108
2
}
109

            
110
pub fn local_testnet_config(para_id: ParaId, boot_nodes: Vec<String>) -> ChainSpec {
111
    // Give your base currency a unit name and decimal places
112
    let mut properties = sc_chain_spec::Properties::new();
113
    properties.insert("tokenSymbol".into(), "UNIT".into());
114
    properties.insert("tokenDecimals".into(), 12.into());
115
    properties.insert("ss58Format".into(), 42.into());
116
    properties.insert("isEthereum".into(), false.into());
117
    let protocol_id = format!("container-chain-{}", para_id);
118

            
119
    let mut default_funded_accounts = pre_funded_accounts();
120
    default_funded_accounts.sort();
121
    default_funded_accounts.dedup();
122
    let boot_nodes: Vec<MultiaddrWithPeerId> = boot_nodes
123
        .into_iter()
124
        .map(|x| {
125
            x.parse::<MultiaddrWithPeerId>()
126
                .unwrap_or_else(|e| panic!("invalid bootnode address format {:?}: {:?}", x, e))
127
        })
128
        .collect();
129

            
130
    ChainSpec::builder(
131
        container_chain_template_simple_runtime::WASM_BINARY
132
            .expect("WASM binary was not built, please build it!"),
133
        Extensions {
134
            relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
135
            para_id: para_id.into(),
136
        },
137
    )
138
    .with_name(&format!("Simple Container {}", para_id))
139
    .with_id(&format!("simple_container_{}", para_id))
140
    .with_chain_type(ChainType::Local)
141
    .with_genesis_config(testnet_genesis(
142
        default_funded_accounts.clone(),
143
        para_id,
144
        get_account_id_from_seed::<sr25519::Public>("Alice"),
145
    ))
146
    .with_properties(properties)
147
    .with_protocol_id(&protocol_id)
148
    .with_boot_nodes(boot_nodes)
149
    .build()
150
}
151

            
152
2
fn testnet_genesis(
153
2
    endowed_accounts: Vec<AccountId>,
154
2
    id: ParaId,
155
2
    root_key: AccountId,
156
2
) -> serde_json::Value {
157
2
    let g = container_chain_template_simple_runtime::RuntimeGenesisConfig {
158
2
        balances: container_chain_template_simple_runtime::BalancesConfig {
159
2
            balances: endowed_accounts
160
2
                .iter()
161
2
                .cloned()
162
24
                .map(|k| (k, 1 << 60))
163
2
                .collect(),
164
2
        },
165
2
        parachain_info: container_chain_template_simple_runtime::ParachainInfoConfig {
166
2
            parachain_id: id,
167
2
            ..Default::default()
168
2
        },
169
2
        parachain_system: Default::default(),
170
2
        sudo: container_chain_template_simple_runtime::SudoConfig {
171
2
            key: Some(root_key),
172
2
        },
173
2
        authorities_noting: container_chain_template_simple_runtime::AuthoritiesNotingConfig {
174
2
            orchestrator_para_id: ORCHESTRATOR,
175
2
            ..Default::default()
176
2
        },
177
2
        migrations: MigrationsConfig::default(),
178
2
        maintenance_mode: MaintenanceModeConfig {
179
2
            start_in_maintenance_mode: false,
180
2
            ..Default::default()
181
2
        },
182
2
        // This should initialize it to whatever we have set in the pallet
183
2
        polkadot_xcm: PolkadotXcmConfig::default(),
184
2
        transaction_payment: Default::default(),
185
2
        tx_pause: Default::default(),
186
2
        system: Default::default(),
187
2
    };
188
2

            
189
2
    serde_json::to_value(g).unwrap()
190
2
}
191

            
192
/// Get pre-funded accounts
193
2
pub fn pre_funded_accounts() -> Vec<AccountId> {
194
2
    vec![
195
2
        get_account_id_from_seed::<sr25519::Public>("Alice"),
196
2
        get_account_id_from_seed::<sr25519::Public>("Bob"),
197
2
        get_account_id_from_seed::<sr25519::Public>("Charlie"),
198
2
        get_account_id_from_seed::<sr25519::Public>("Dave"),
199
2
        get_account_id_from_seed::<sr25519::Public>("Eve"),
200
2
        get_account_id_from_seed::<sr25519::Public>("Ferdie"),
201
2
        get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
202
2
        get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
203
2
        get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
204
2
        get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
205
2
        get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
206
2
        get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
207
2
    ]
208
2
}