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_path, 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
120
#[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!("../chain-specs/dancelight-raw-specs.json")[..],
96
    )
97
}
98

            
99
pub fn tanssi_config() -> Result<StarlightChainSpec, String> {
100
    StarlightChainSpec::from_json_bytes(
101
        &include_bytes!("../chain-specs/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
/// Dancelight development config (single validator Alice)
174
#[cfg(feature = "dancelight-native")]
175
12
pub fn dancelight_development_config(
176
12
    container_chains: Vec<String>,
177
12
    mock_container_chains: Vec<ParaId>,
178
12
    invulnerables: Vec<String>,
179
12
) -> Result<DancelightChainSpec, String> {
180
12
    // Give your base currency a unit name and decimal places
181
12
    let mut properties = sc_chain_spec::Properties::new();
182
12
    properties.insert("tokenSymbol".into(), "STAR".into());
183
12
    properties.insert("tokenDecimals".into(), 12.into());
184
12
    properties.insert("ss58Format".into(), 42.into());
185
12
    properties.insert("isEthereum".into(), false.into());
186
12

            
187
12
    let container_chains: Vec<_> = container_chains
188
12
        .iter()
189
12
        .map(|x| {
190
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
191
                panic!(
192
                    "Failed to build genesis data for container chain {:?}: {}",
193
                    x, e
194
                )
195
            })
196
12
        })
197
12
        .chain(
198
12
            mock_container_chains
199
12
                .iter()
200
24
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
201
12
        )
202
12
        .collect();
203
12

            
204
12
    Ok(DancelightChainSpec::builder(
205
12
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
206
12
        Default::default(),
207
12
    )
208
12
    .with_name("Development")
209
12
    .with_id("dancelight_dev")
210
12
    .with_chain_type(ChainType::Development)
211
12
    .with_genesis_config_patch(dancelight_development_config_genesis(
212
12
        container_chains,
213
12
        invulnerables,
214
12
    ))
215
12
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
216
12
    .with_properties(properties)
217
12
    .build())
218
12
}
219

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

            
234
12
    let container_chains: Vec<_> = container_chains
235
12
        .iter()
236
12
        .map(|x| {
237
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
238
                panic!(
239
                    "Failed to build genesis data for container chain {:?}: {}",
240
                    x, e
241
                )
242
            })
243
12
        })
244
12
        .chain(
245
12
            mock_container_chains
246
12
                .iter()
247
24
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
248
12
        )
249
12
        .collect();
250
12

            
251
12
    Ok(StarlightChainSpec::builder(
252
12
        starlight::WASM_BINARY.ok_or("Starlight development wasm not available")?,
253
12
        Default::default(),
254
12
    )
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
12
    ))
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
) -> Result<DancelightChainSpec, String> {
274
30
    let container_chains: Vec<_> = container_chains
275
30
        .iter()
276
30
        .map(|x| {
277
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
278
                panic!(
279
                    "Failed to build genesis data for container chain {:?}: {}",
280
                    x, e
281
                )
282
            })
283
30
        })
284
30
        .chain(
285
30
            mock_container_chains
286
30
                .iter()
287
60
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
288
30
        )
289
30
        .collect();
290
30

            
291
30
    Ok(DancelightChainSpec::builder(
292
30
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
293
30
        Default::default(),
294
30
    )
295
30
    .with_name("Dancelight Local Testnet")
296
30
    .with_id("dancelight_local_testnet")
297
30
    .with_chain_type(ChainType::Local)
298
30
    .with_genesis_config_patch(dancelight_local_testnet_genesis(
299
30
        container_chains,
300
30
        invulnerables,
301
30
    ))
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
) -> Result<StarlightChainSpec, String> {
313
30
    let container_chains: Vec<_> = container_chains
314
30
        .iter()
315
30
        .map(|x| {
316
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
317
                panic!(
318
                    "Failed to build genesis data for container chain {:?}: {}",
319
                    x, e
320
                )
321
            })
322
30
        })
323
30
        .chain(
324
30
            mock_container_chains
325
30
                .iter()
326
60
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
327
30
        )
328
30
        .collect();
329
30

            
330
30
    Ok(StarlightChainSpec::builder(
331
30
        starlight::WASM_BINARY.ok_or("Starlight development wasm not available")?,
332
30
        Default::default(),
333
30
    )
334
30
    .with_name("Starlight Local Testnet")
335
30
    .with_id("starlight_local_testnet")
336
30
    .with_chain_type(ChainType::Local)
337
30
    .with_genesis_config_patch(starlight_local_testnet_genesis(
338
30
        container_chains,
339
30
        invulnerables,
340
30
    ))
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
}