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
    grandpa::AuthorityId as GrandpaId,
29
    polkadot_primitives::{AccountId, AccountPublic, AssignmentId, ValidatorId},
30
    sp_authority_discovery::AuthorityId as AuthorityDiscoveryId,
31
    sp_consensus_babe::AuthorityId as BabeId,
32
};
33

            
34
#[cfg(feature = "dancelight-native")]
35
use dancelight_runtime as dancelight;
36
#[cfg(feature = "dancelight-native")]
37
use sc_chain_spec::ChainType;
38
#[cfg(feature = "dancelight-native")]
39
use telemetry::TelemetryEndpoints;
40
use {
41
    sc_chain_spec::ChainSpecExtension,
42
    serde::{Deserialize, Serialize},
43
    sp_core::{sr25519, storage::well_known_keys as StorageWellKnownKeys, Pair, Public},
44
    sp_runtime::traits::IdentifyAccount,
45
};
46

            
47
#[cfg(feature = "dancelight-native")]
48
const DANCELIGHT_STAGING_TELEMETRY_URL: &str = "wss://telemetry.tanssi.network/submit/";
49
#[cfg(feature = "dancelight-native")]
50
const DEFAULT_PROTOCOL_ID: &str = "star";
51

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

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

            
72
/// The `ChainSpec` parameterized for the dancelight runtime.
73
#[cfg(feature = "dancelight-native")]
74
pub type DancelightChainSpec = service::GenericChainSpec<Extensions>;
75

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

            
81
pub fn dancelight_config() -> Result<DancelightChainSpec, String> {
82
    DancelightChainSpec::from_json_bytes(&include_bytes!("../chain-specs/rococo.json")[..])
83
    // FIXME: Update this to Dancelight.json once it is available
84
}
85

            
86
/// Dancelight staging testnet config.
87
#[cfg(feature = "dancelight-native")]
88
pub fn dancelight_staging_testnet_config() -> Result<DancelightChainSpec, String> {
89
    Ok(DancelightChainSpec::builder(
90
        dancelight::WASM_BINARY.ok_or("Dancelight development wasm not available")?,
91
        Default::default(),
92
    )
93
    .with_name("Dancelight Staging Testnet")
94
    .with_id("dancelight_staging_testnet")
95
    .with_chain_type(ChainType::Live)
96
    .with_genesis_config_preset_name("staging_testnet")
97
    .with_telemetry_endpoints(
98
        TelemetryEndpoints::new(vec![(DANCELIGHT_STAGING_TELEMETRY_URL.to_string(), 0)])
99
            .expect("Dancelight Staging telemetry url is valid; qed"),
100
    )
101
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
102
    .build())
103
}
104

            
105
/// Helper function to generate a crypto pair from seed
106
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
107
    TPublic::Pair::from_string(&format!("//{}", seed), None)
108
        .expect("static values are valid; qed")
109
        .public()
110
}
111

            
112
/// Helper function to generate an account ID from seed
113
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
114
where
115
    AccountPublic: From<<TPublic::Pair as Pair>::Public>,
116
{
117
    AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
118
}
119

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

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

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

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

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

            
216
/// Dancelight local testnet config (multivalidator Alice + Bob)
217
#[cfg(feature = "dancelight-native")]
218
28
pub fn dancelight_local_testnet_config(
219
28
    container_chains: Vec<String>,
220
28
    mock_container_chains: Vec<ParaId>,
221
28
    invulnerables: Vec<String>,
222
28
) -> Result<DancelightChainSpec, String> {
223
28
    let container_chains: Vec<_> = container_chains
224
28
        .iter()
225
28
        .map(|x| {
226
            container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
227
                panic!(
228
                    "Failed to build genesis data for container chain {:?}: {}",
229
                    x, e
230
                )
231
            })
232
28
        })
233
28
        .chain(
234
28
            mock_container_chains
235
28
                .iter()
236
56
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
237
28
        )
238
28
        .collect();
239
28

            
240
28
    Ok(DancelightChainSpec::builder(
241
28
        dancelight::fast_runtime_binary::WASM_BINARY
242
28
            .ok_or("Dancelight development wasm not available")?,
243
28
        Default::default(),
244
28
    )
245
28
    .with_name("Dancelight Local Testnet")
246
28
    .with_id("dancelight_local_testnet")
247
28
    .with_chain_type(ChainType::Local)
248
28
    .with_genesis_config_patch(dancelight_local_testnet_genesis(
249
28
        container_chains,
250
28
        invulnerables,
251
28
    ))
252
28
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
253
28
    .build())
254
28
}
255

            
256
84
fn mock_container_chain_genesis_data(para_id: ParaId) -> ContainerChainGenesisData {
257
84
    ContainerChainGenesisData {
258
84
        storage: vec![
259
84
            dp_container_chain_genesis_data::ContainerChainGenesisDataItem {
260
84
                key: StorageWellKnownKeys::CODE.to_vec(),
261
84
                value: dummy_validation_code().0,
262
84
            },
263
84
        ],
264
84
        name: format!("Container Chain {}", para_id).into(),
265
84
        id: format!("container-chain-{}", para_id).into(),
266
84
        fork_id: None,
267
84
        extensions: vec![],
268
84
        properties: Default::default(),
269
84
    }
270
84
}
271

            
272
/// Create meaningless validation code.
273
84
pub fn dummy_validation_code() -> cumulus_primitives_core::relay_chain::ValidationCode {
274
84
    cumulus_primitives_core::relay_chain::ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])
275
84
}