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

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

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

            
167
/// Dancelight development config (single validator Alice)
168
#[cfg(feature = "dancelight-native")]
169
12
pub fn dancelight_development_config(
170
12
    container_chains: Vec<String>,
171
12
    mock_container_chains: Vec<ParaId>,
172
12
    invulnerables: Vec<String>,
173
12
) -> Result<DancelightChainSpec, String> {
174
12
    // Give your base currency a unit name and decimal places
175
12
    let mut properties = sc_chain_spec::Properties::new();
176
12
    properties.insert("tokenSymbol".into(), "STAR".into());
177
12
    properties.insert("tokenDecimals".into(), 12.into());
178
12
    properties.insert("ss58Format".into(), 42.into());
179
12
    properties.insert("isEthereum".into(), false.into());
180
12

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

            
198
12
    Ok(DancelightChainSpec::builder(
199
12
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
200
12
        Default::default(),
201
12
    )
202
12
    .with_name("Development")
203
12
    .with_id("dancelight_dev")
204
12
    .with_chain_type(ChainType::Development)
205
12
    .with_genesis_config_patch(dancelight_development_config_genesis(
206
12
        container_chains,
207
12
        invulnerables,
208
12
    ))
209
12
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
210
12
    .with_properties(properties)
211
12
    .build())
212
12
}
213

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

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

            
245
12
    Ok(StarlightChainSpec::builder(
246
12
        starlight::WASM_BINARY.ok_or("Starlight development wasm not available")?,
247
12
        Default::default(),
248
12
    )
249
12
    .with_name("Development")
250
12
    .with_id("starlight_dev")
251
12
    .with_chain_type(ChainType::Development)
252
12
    .with_genesis_config_patch(starlight_development_config_genesis(
253
12
        container_chains,
254
12
        invulnerables,
255
12
    ))
256
12
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
257
12
    .with_properties(properties)
258
12
    .build())
259
12
}
260

            
261
/// Dancelight local testnet config (multivalidator Alice + Bob)
262
#[cfg(feature = "dancelight-native")]
263
30
pub fn dancelight_local_testnet_config(
264
30
    container_chains: Vec<String>,
265
30
    mock_container_chains: Vec<ParaId>,
266
30
    invulnerables: Vec<String>,
267
30
) -> Result<DancelightChainSpec, String> {
268
30
    let container_chains: Vec<_> = container_chains
269
30
        .iter()
270
30
        .map(|x| {
271
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
272
                panic!(
273
                    "Failed to build genesis data for container chain {:?}: {}",
274
                    x, e
275
                )
276
            })
277
30
        })
278
30
        .chain(
279
30
            mock_container_chains
280
30
                .iter()
281
60
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
282
30
        )
283
30
        .collect();
284
30

            
285
30
    Ok(DancelightChainSpec::builder(
286
30
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
287
30
        Default::default(),
288
30
    )
289
30
    .with_name("Dancelight Local Testnet")
290
30
    .with_id("dancelight_local_testnet")
291
30
    .with_chain_type(ChainType::Local)
292
30
    .with_genesis_config_patch(dancelight_local_testnet_genesis(
293
30
        container_chains,
294
30
        invulnerables,
295
30
    ))
296
30
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
297
30
    .build())
298
30
}
299

            
300
/// Starlight local testnet config (multivalidator Alice + Bob)
301
#[cfg(feature = "starlight-native")]
302
30
pub fn starlight_local_testnet_config(
303
30
    container_chains: Vec<String>,
304
30
    mock_container_chains: Vec<ParaId>,
305
30
    invulnerables: Vec<String>,
306
30
) -> Result<StarlightChainSpec, String> {
307
30
    let container_chains: Vec<_> = container_chains
308
30
        .iter()
309
30
        .map(|x| {
310
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
311
                panic!(
312
                    "Failed to build genesis data for container chain {:?}: {}",
313
                    x, e
314
                )
315
            })
316
30
        })
317
30
        .chain(
318
30
            mock_container_chains
319
30
                .iter()
320
60
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
321
30
        )
322
30
        .collect();
323
30

            
324
30
    Ok(StarlightChainSpec::builder(
325
30
        starlight::WASM_BINARY.ok_or("Starlight development wasm not available")?,
326
30
        Default::default(),
327
30
    )
328
30
    .with_name("Starlight Local Testnet")
329
30
    .with_id("starlight_local_testnet")
330
30
    .with_chain_type(ChainType::Local)
331
30
    .with_genesis_config_patch(starlight_local_testnet_genesis(
332
30
        container_chains,
333
30
        invulnerables,
334
30
    ))
335
30
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
336
30
    .build())
337
30
}
338

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

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