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
//! Polkadot chain configurations.
18

            
19
use {
20
    beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId,
21
    cumulus_primitives_core::ParaId,
22
    dancelight_runtime::genesis_config_presets::{
23
        dancelight_development_config_genesis, dancelight_local_testnet_genesis,
24
    },
25
    dp_container_chain_genesis_data::{
26
        json::container_chain_genesis_data_from_str, ContainerChainGenesisData,
27
    },
28
    frame_support::BoundedVec,
29
    grandpa::AuthorityId as GrandpaId,
30
    polkadot_primitives::{AccountId, AssignmentId, ValidatorId},
31
    sp_authority_discovery::AuthorityId as AuthorityDiscoveryId,
32
    sp_consensus_babe::AuthorityId as BabeId,
33
    sp_core::crypto::get_public_from_string_or_panic,
34
    starlight_runtime::genesis_config_presets::{
35
        starlight_development_config_genesis, starlight_local_testnet_genesis,
36
    },
37
};
38

            
39
#[cfg(feature = "dancelight-native")]
40
use dancelight_runtime as dancelight;
41

            
42
#[cfg(feature = "starlight-native")]
43
use starlight_runtime as starlight;
44

            
45
#[cfg(feature = "dancelight-native")]
46
use sc_chain_spec::ChainType;
47
#[cfg(feature = "dancelight-native")]
48
use telemetry::TelemetryEndpoints;
49
use {
50
    sc_chain_spec::ChainSpecExtension,
51
    serde::{Deserialize, Serialize},
52
    sp_core::{sr25519, storage::well_known_keys as StorageWellKnownKeys},
53
};
54

            
55
#[cfg(feature = "dancelight-native")]
56
const DANCELIGHT_STAGING_TELEMETRY_URL: &str = "wss://telemetry.tanssi.network/submit/";
57
#[cfg(feature = "dancelight-native")]
58
const DEFAULT_PROTOCOL_ID: &str = "star";
59

            
60
/// Node `ChainSpec` extensions.
61
///
62
/// Additional parameters for some Substrate core modules,
63
/// customizable from the chain spec.
64
#[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)]
65
#[serde(rename_all = "camelCase")]
66
pub struct Extensions {
67
    /// Block numbers with known hashes.
68
    pub fork_blocks: sc_client_api::ForkBlocks<polkadot_primitives::Block>,
69
    /// Known bad block hashes.
70
    pub bad_blocks: sc_client_api::BadBlocks<polkadot_primitives::Block>,
71
    /// The light sync state.
72
    ///
73
    /// This value will be set by the `sync-state rpc` implementation.
74
    pub light_sync_state: sc_sync_state_rpc::LightSyncStateExtension,
75
}
76

            
77
// Generic chain spec, in case when we don't have the native runtime.
78
pub type GenericChainSpec = service::GenericChainSpec<Extensions>;
79

            
80
/// The `ChainSpec` parameterized for the dancelight runtime.
81
#[cfg(feature = "dancelight-native")]
82
pub type DancelightChainSpec = service::GenericChainSpec<Extensions>;
83

            
84
/// The `ChainSpec` parameterized for the starlight runtime.
85
#[cfg(feature = "starlight-native")]
86
pub type StarlightChainSpec = service::GenericChainSpec<Extensions>;
87

            
88
/// The `ChainSpec` parameterized for the dancelight runtime.
89
// Dummy chain spec, but that is fine when we don't have the native runtime.
90
#[cfg(not(feature = "dancelight-native"))]
91
pub type DancelightChainSpec = GenericChainSpec;
92

            
93
pub fn dancelight_config() -> Result<DancelightChainSpec, String> {
94
    DancelightChainSpec::from_json_bytes(
95
        &include_bytes!("../../../../../specs/solochain/dancelight-raw-specs.json")[..],
96
    )
97
}
98

            
99
pub fn tanssi_config() -> Result<StarlightChainSpec, String> {
100
    StarlightChainSpec::from_json_bytes(
101
        &include_bytes!("../../../../../specs/solochain/starlight-raw-specs.json")[..],
102
    )
103
}
104

            
105
/// Dancelight staging testnet config.
106
#[cfg(feature = "dancelight-native")]
107
pub fn dancelight_staging_testnet_config() -> Result<DancelightChainSpec, String> {
108
    Ok(DancelightChainSpec::builder(
109
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
110
        Default::default(),
111
    )
112
    .with_name("Dancelight Staging Testnet")
113
    .with_id("dancelight_staging_testnet")
114
    .with_chain_type(ChainType::Live)
115
    .with_genesis_config_preset_name("staging_testnet")
116
    .with_telemetry_endpoints(
117
        TelemetryEndpoints::new(vec![(DANCELIGHT_STAGING_TELEMETRY_URL.to_string(), 0)])
118
            .expect("Dancelight Staging telemetry url is valid; qed"),
119
    )
120
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
121
    .build())
122
}
123

            
124
/// Helper function to generate stash, controller and session key from seed
125
pub fn get_authority_keys_from_seed(
126
    seed: &str,
127
) -> (
128
    AccountId,
129
    AccountId,
130
    BabeId,
131
    GrandpaId,
132
    ValidatorId,
133
    AssignmentId,
134
    AuthorityDiscoveryId,
135
    BeefyId,
136
) {
137
    let keys = get_authority_keys_from_seed_no_beefy(seed);
138
    (
139
        keys.0,
140
        keys.1,
141
        keys.2,
142
        keys.3,
143
        keys.4,
144
        keys.5,
145
        keys.6,
146
        get_public_from_string_or_panic::<BeefyId>(seed),
147
    )
148
}
149

            
150
/// Helper function to generate stash, controller and session key from seed
151
pub fn get_authority_keys_from_seed_no_beefy(
152
    seed: &str,
153
) -> (
154
    AccountId,
155
    AccountId,
156
    BabeId,
157
    GrandpaId,
158
    ValidatorId,
159
    AssignmentId,
160
    AuthorityDiscoveryId,
161
) {
162
    (
163
        get_public_from_string_or_panic::<sr25519::Public>(&format!("{}//stash", seed)).into(),
164
        get_public_from_string_or_panic::<sr25519::Public>(seed).into(),
165
        get_public_from_string_or_panic::<BabeId>(seed),
166
        get_public_from_string_or_panic::<GrandpaId>(seed),
167
        get_public_from_string_or_panic::<ValidatorId>(seed),
168
        get_public_from_string_or_panic::<AssignmentId>(seed),
169
        get_public_from_string_or_panic::<AuthorityDiscoveryId>(seed),
170
    )
171
}
172

            
173
pub fn container_chain_genesis_data_from_path(
174
    path: &str,
175
) -> (ParaId, ContainerChainGenesisData, Vec<Vec<u8>>) {
176
    let raw_chainspec_str = std::fs::read_to_string(path)
177
        .unwrap_or_else(|_| panic!("ChainSpec for container chain not found at {:?}", path));
178

            
179
    container_chain_genesis_data_from_str(&raw_chainspec_str).unwrap_or_else(|e| {
180
        panic!(
181
            "Failed to build genesis data for container chain {:?}: {}",
182
            path, e
183
        )
184
    })
185
}
186

            
187
/// Dancelight development config (single validator Alice)
188
#[cfg(feature = "dancelight-native")]
189
12
pub fn dancelight_development_config(
190
12
    container_chains: Vec<String>,
191
12
    mock_container_chains: Vec<ParaId>,
192
12
    invulnerables: Vec<String>,
193
12
) -> Result<DancelightChainSpec, String> {
194
    // Give your base currency a unit name and decimal places
195
12
    let mut properties = sc_chain_spec::Properties::new();
196
12
    properties.insert("tokenSymbol".into(), "STAR".into());
197
12
    properties.insert("tokenDecimals".into(), 12.into());
198
12
    properties.insert("ss58Format".into(), 42.into());
199
12
    properties.insert("isEthereum".into(), false.into());
200

            
201
12
    let container_chains: Vec<_> = container_chains
202
12
        .iter()
203
12
        .map(|path| container_chain_genesis_data_from_path(path))
204
12
        .chain(
205
12
            mock_container_chains
206
12
                .iter()
207
24
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
208
        )
209
12
        .collect();
210

            
211
12
    Ok(DancelightChainSpec::builder(
212
12
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
213
12
        Default::default(),
214
    )
215
12
    .with_name("Development")
216
12
    .with_id("dancelight_dev")
217
12
    .with_chain_type(ChainType::Development)
218
12
    .with_genesis_config_patch(dancelight_development_config_genesis(
219
12
        container_chains,
220
12
        invulnerables,
221
    ))
222
12
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
223
12
    .with_properties(properties)
224
12
    .build())
225
12
}
226

            
227
/// Starlight development config (single validator Alice)
228
#[cfg(feature = "starlight-native")]
229
12
pub fn starlight_development_config(
230
12
    container_chains: Vec<String>,
231
12
    mock_container_chains: Vec<ParaId>,
232
12
    invulnerables: Vec<String>,
233
12
) -> Result<StarlightChainSpec, String> {
234
    // Give your base currency a unit name and decimal places
235
12
    let mut properties = sc_chain_spec::Properties::new();
236
12
    properties.insert("tokenSymbol".into(), "TANSSI".into());
237
12
    properties.insert("tokenDecimals".into(), 12.into());
238
12
    properties.insert("ss58Format".into(), 42.into());
239
12
    properties.insert("isEthereum".into(), false.into());
240

            
241
12
    let container_chains: Vec<_> = container_chains
242
12
        .iter()
243
12
        .map(|path| container_chain_genesis_data_from_path(path))
244
12
        .chain(
245
12
            mock_container_chains
246
12
                .iter()
247
24
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
248
        )
249
12
        .collect();
250

            
251
12
    Ok(StarlightChainSpec::builder(
252
12
        starlight::WASM_BINARY.ok_or("Starlight development wasm not available")?,
253
12
        Default::default(),
254
    )
255
12
    .with_name("Development")
256
12
    .with_id("starlight_dev")
257
12
    .with_chain_type(ChainType::Development)
258
12
    .with_genesis_config_patch(starlight_development_config_genesis(
259
12
        container_chains,
260
12
        invulnerables,
261
    ))
262
12
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
263
12
    .with_properties(properties)
264
12
    .build())
265
12
}
266

            
267
/// Dancelight local testnet config (multivalidator Alice + Bob)
268
#[cfg(feature = "dancelight-native")]
269
30
pub fn dancelight_local_testnet_config(
270
30
    container_chains: Vec<String>,
271
30
    mock_container_chains: Vec<ParaId>,
272
30
    invulnerables: Vec<String>,
273
30
    initial_authorities: Vec<String>,
274
30
) -> Result<DancelightChainSpec, String> {
275
30
    let container_chains: Vec<_> = container_chains
276
30
        .iter()
277
30
        .map(|path| container_chain_genesis_data_from_path(path))
278
30
        .chain(
279
30
            mock_container_chains
280
30
                .iter()
281
60
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
282
        )
283
30
        .collect();
284

            
285
30
    let initial_authorities = initial_authorities
286
30
        .iter()
287
60
        .map(|name| dancelight_runtime::genesis_config_presets::get_authority_keys_from_seed(name))
288
30
        .collect();
289

            
290
30
    Ok(DancelightChainSpec::builder(
291
30
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
292
30
        Default::default(),
293
    )
294
30
    .with_name("Dancelight Local Testnet")
295
30
    .with_id("dancelight_local_testnet")
296
30
    .with_chain_type(ChainType::Local)
297
30
    .with_genesis_config_patch(dancelight_local_testnet_genesis(
298
30
        container_chains,
299
30
        invulnerables,
300
30
        initial_authorities,
301
    ))
302
30
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
303
30
    .build())
304
30
}
305

            
306
/// Starlight local testnet config (multivalidator Alice + Bob)
307
#[cfg(feature = "starlight-native")]
308
30
pub fn starlight_local_testnet_config(
309
30
    container_chains: Vec<String>,
310
30
    mock_container_chains: Vec<ParaId>,
311
30
    invulnerables: Vec<String>,
312
30
    initial_authorities: Vec<String>,
313
30
) -> Result<StarlightChainSpec, String> {
314
30
    let container_chains: Vec<_> = container_chains
315
30
        .iter()
316
30
        .map(|path| container_chain_genesis_data_from_path(path))
317
30
        .chain(
318
30
            mock_container_chains
319
30
                .iter()
320
60
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
321
        )
322
30
        .collect();
323

            
324
30
    let initial_authorities = initial_authorities
325
30
        .iter()
326
60
        .map(|name| starlight_runtime::genesis_config_presets::get_authority_keys_from_seed(name))
327
30
        .collect();
328

            
329
30
    Ok(StarlightChainSpec::builder(
330
30
        starlight::WASM_BINARY.ok_or("Starlight development wasm not available")?,
331
30
        Default::default(),
332
    )
333
30
    .with_name("Starlight Local Testnet")
334
30
    .with_id("starlight_local_testnet")
335
30
    .with_chain_type(ChainType::Local)
336
30
    .with_genesis_config_patch(starlight_local_testnet_genesis(
337
30
        container_chains,
338
30
        invulnerables,
339
30
        initial_authorities,
340
    ))
341
30
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
342
30
    .build())
343
30
}
344

            
345
168
fn mock_container_chain_genesis_data(para_id: ParaId) -> ContainerChainGenesisData {
346
168
    ContainerChainGenesisData {
347
168
        storage: BoundedVec::try_from(vec![
348
168
            dp_container_chain_genesis_data::ContainerChainGenesisDataItem {
349
168
                key: StorageWellKnownKeys::CODE.to_vec(),
350
168
                value: dummy_validation_code().0,
351
168
            },
352
168
        ])
353
168
        .unwrap(),
354
168
        name: BoundedVec::try_from(format!("Container Chain {}", para_id).as_bytes().to_vec())
355
168
            .unwrap(),
356
168
        id: BoundedVec::try_from(format!("container-chain-{}", para_id).as_bytes().to_vec())
357
168
            .unwrap(),
358
168
        fork_id: None,
359
168
        extensions: BoundedVec::try_from(vec![]).unwrap(),
360
168
        properties: Default::default(),
361
168
    }
362
168
}
363

            
364
/// Create meaningless validation code.
365
168
pub fn dummy_validation_code() -> cumulus_primitives_core::relay_chain::ValidationCode {
366
168
    cumulus_primitives_core::relay_chain::ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])
367
168
}