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
    crate as flashbox_runtime,
19
    crate::{
20
        AccountId, DataPreserversConfig, MaintenanceModeConfig, MigrationsConfig, RegistrarConfig,
21
        ServicesPaymentConfig, SudoConfig,
22
    },
23
    alloc::{string::String, vec, vec::Vec},
24
    cumulus_primitives_core::ParaId,
25
    dp_container_chain_genesis_data::{
26
        json::container_chain_genesis_data_from_str, ContainerChainGenesisData,
27
    },
28
    frame_support::BoundedVec,
29
    nimbus_primitives::NimbusId,
30
    pallet_configuration::HostConfiguration,
31
    sp_core::crypto::get_public_from_string_or_panic,
32
    sp_core::sr25519,
33
    sp_keyring::Sr25519Keyring,
34
    sp_runtime::{traits::AccountIdConversion, Perbill},
35
};
36

            
37
10
pub fn local(
38
10
    para_id: ParaId,
39
10
    container_chains_spec_contents: Vec<String>,
40
10
    mock_container_chains: Vec<ParaId>,
41
10
    invulnerables: Vec<String>,
42
10
) -> serde_json::Value {
43
10
    testnet_genesis(
44
        // initial collators.
45
10
        invulnerables_from_seeds(invulnerables.iter()),
46
10
        account_ids(&[
47
10
            "Alice",
48
10
            "Bob",
49
10
            "Charlie",
50
10
            "Dave",
51
10
            "Eve",
52
10
            "Ferdie",
53
10
            "Alice//stash",
54
10
            "Bob//stash",
55
10
            "Charlie//stash",
56
10
            "Dave//stash",
57
10
            "Eve//stash",
58
10
            "Ferdie//stash",
59
10
        ]),
60
10
        para_id,
61
10
        Sr25519Keyring::Alice.to_account_id(),
62
10
        &container_chains_spec_contents,
63
10
        &mock_container_chains,
64
10
        pallet_configuration::GenesisConfig {
65
10
            config: HostConfiguration {
66
10
                max_collators: 100u32,
67
10
                min_orchestrator_collators: 2u32,
68
10
                max_orchestrator_collators: 5u32,
69
10
                collators_per_container: 2u32,
70
10
                full_rotation_period: 0,
71
10
                collators_per_parathread: 1,
72
10
                parathreads_per_collator: 1,
73
10
                target_container_chain_fullness: Perbill::from_percent(80),
74
10
                max_parachain_cores_percentage: None,
75
10
                full_rotation_mode: Default::default(),
76
10
            },
77
10
            ..Default::default()
78
10
        },
79
    )
80
10
}
81

            
82
pub fn development(
83
    para_id: ParaId,
84
    container_chains_spec_contents: Vec<String>,
85
    mock_container_chains: Vec<ParaId>,
86
    invulnerables: Vec<String>,
87
) -> serde_json::Value {
88
    testnet_genesis(
89
        // initial collators.
90
        invulnerables_from_seeds(invulnerables.iter()),
91
        account_ids(&[
92
            "Alice",
93
            "Bob",
94
            "Charlie",
95
            "Dave",
96
            "Eve",
97
            "Ferdie",
98
            "Alice//stash",
99
            "Bob//stash",
100
            "Charlie//stash",
101
            "Dave//stash",
102
            "Eve//stash",
103
            "Ferdie//stash",
104
        ]),
105
        para_id,
106
        Sr25519Keyring::Alice.to_account_id(),
107
        &container_chains_spec_contents,
108
        &mock_container_chains,
109
        pallet_configuration::GenesisConfig {
110
            config: HostConfiguration {
111
                max_collators: 100u32,
112
                min_orchestrator_collators: 1u32,
113
                max_orchestrator_collators: 1u32,
114
                collators_per_container: 2u32,
115
                full_rotation_period: 0,
116
                collators_per_parathread: 1,
117
                parathreads_per_collator: 1,
118
                target_container_chain_fullness: Perbill::from_percent(80),
119
                max_parachain_cores_percentage: None,
120
                full_rotation_mode: Default::default(),
121
            },
122
            ..Default::default()
123
        },
124
    )
125
}
126

            
127
10
fn testnet_genesis(
128
10
    invulnerables: Vec<(AccountId, NimbusId)>,
129
10
    endowed_accounts: Vec<AccountId>,
130
10
    id: ParaId,
131
10
    root_key: AccountId,
132
10
    container_chains_spec_contents: &[String],
133
10
    mock_container_chains: &[ParaId],
134
10
    configuration: pallet_configuration::GenesisConfig<flashbox_runtime::Runtime>,
135
10
) -> serde_json::Value {
136
10
    let para_ids: Vec<_> = container_chains_spec_contents
137
10
        .iter()
138
10
        .map(|content_str| {
139
            container_chain_genesis_data_from_str(content_str).unwrap_or_else(|e| {
140
                panic!(
141
                    "Failed to build genesis data for container chain {:?}: {}",
142
                    content_str, e
143
                )
144
            })
145
        })
146
10
        .chain(
147
10
            mock_container_chains
148
10
                .iter()
149
20
                .map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
150
        )
151
10
        .collect();
152
    // Assign 1000 block credits to all container chains registered in genesis
153
    // Assign 100 collator assignment credits to all container chains registered in genesis
154
10
    let para_id_credits: Vec<_> = para_ids
155
10
        .iter()
156
20
        .map(|(para_id, _genesis_data, _boot_nodes)| (*para_id, 1000, 100).into())
157
10
        .collect();
158
10
    let data_preservers_bootnodes: Vec<_> = para_ids
159
10
        .iter()
160
20
        .flat_map(|(para_id, _genesis_data, bootnodes)| {
161
20
            bootnodes.clone().into_iter().map(|bootnode| {
162
                (
163
                    *para_id,
164
                    AccountId::from([0u8; 32]),
165
                    bootnode,
166
                    tp_data_preservers_common::ProviderRequest::Free,
167
                    tp_data_preservers_common::AssignmentWitness::Free,
168
                )
169
            })
170
20
        })
171
10
        .collect();
172

            
173
10
    let para_ids: Vec<_> = para_ids
174
10
        .into_iter()
175
20
        .map(|(para_id, genesis_data, _boot_nodes)| (para_id, genesis_data, None))
176
10
        .collect();
177

            
178
10
    let accounts_with_ed = [
179
10
        flashbox_runtime::StakingAccount::get(),
180
10
        flashbox_runtime::ParachainBondAccount::get(),
181
10
        flashbox_runtime::PendingRewardsAccount::get(),
182
10
        flashbox_runtime::TreasuryId::get().into_account_truncating(),
183
10
    ];
184
10
    let g = flashbox_runtime::RuntimeGenesisConfig {
185
10
        system: Default::default(),
186
        balances: flashbox_runtime::BalancesConfig {
187
10
            balances: endowed_accounts
188
10
                .iter()
189
10
                .cloned()
190
120
                .map(|k| (k, 1 << 60))
191
10
                .chain(
192
10
                    accounts_with_ed
193
10
                        .iter()
194
10
                        .cloned()
195
40
                        .map(|k| (k, flashbox_runtime::EXISTENTIAL_DEPOSIT)),
196
                )
197
10
                .collect(),
198
10
            ..Default::default()
199
        },
200
10
        parachain_info: flashbox_runtime::ParachainInfoConfig {
201
10
            parachain_id: id,
202
10
            ..Default::default()
203
10
        },
204
        invulnerables: flashbox_runtime::InvulnerablesConfig {
205
10
            invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
206
        },
207
        session: flashbox_runtime::SessionConfig {
208
10
            keys: invulnerables
209
10
                .into_iter()
210
40
                .map(|(acc, aura)| {
211
40
                    (
212
40
                        acc.clone(),                 // account id
213
40
                        acc,                         // validator id
214
40
                        template_session_keys(aura), // session keys
215
40
                    )
216
40
                })
217
10
                .collect(),
218
10
            ..Default::default()
219
        },
220
10
        parachain_system: Default::default(),
221
10
        configuration,
222
10
        registrar: RegistrarConfig {
223
10
            para_ids,
224
10
            phantom: Default::default(),
225
10
        },
226
10
        services_payment: ServicesPaymentConfig { para_id_credits },
227
10
        sudo: SudoConfig {
228
10
            key: Some(root_key),
229
10
        },
230
10
        migrations: MigrationsConfig {
231
10
            ..Default::default()
232
10
        },
233
10
        maintenance_mode: MaintenanceModeConfig {
234
10
            start_in_maintenance_mode: false,
235
10
            ..Default::default()
236
10
        },
237
10
        transaction_payment: Default::default(),
238
10
        tx_pause: Default::default(),
239
10
        treasury: Default::default(),
240
10
        data_preservers: DataPreserversConfig {
241
10
            bootnodes: data_preservers_bootnodes,
242
10
            ..Default::default()
243
10
        },
244
    };
245

            
246
10
    serde_json::to_value(g).unwrap()
247
10
}
248

            
249
// TODO: move to primitives and remove duplication from flashbox/dancebox
250
/// Helper function to turn a list of names into a list of `(AccountId, NimbusId)`
251
10
pub fn invulnerables_from_seeds<S: AsRef<str>, I: Iterator<Item = S>>(
252
10
    names: I,
253
10
) -> Vec<(AccountId, NimbusId)> {
254
10
    names
255
40
        .map(|name| {
256
40
            let name = name.as_ref();
257
40
            (
258
40
                get_public_from_string_or_panic::<sr25519::Public>(name).into(),
259
40
                get_collator_keys_from_seed(name),
260
40
            )
261
40
        })
262
10
        .collect()
263
10
}
264

            
265
/// Generate collator keys from seed.
266
///
267
/// This function's return type must always match the session keys of the chain in tuple format.
268
40
pub fn get_collator_keys_from_seed(seed: &str) -> NimbusId {
269
40
    get_public_from_string_or_panic::<NimbusId>(seed)
270
40
}
271

            
272
/// Helper function to turn a list of names into a list of `AccountId`
273
10
pub fn account_ids(names: &[&str]) -> Vec<AccountId> {
274
10
    names
275
10
        .iter()
276
120
        .map(|name| get_public_from_string_or_panic::<sr25519::Public>(name).into())
277
10
        .collect()
278
10
}
279

            
280
/// Generate the session keys from individual elements.
281
///
282
/// The input must be a tuple of individual keys (a single arg for now since we have just one key).
283
40
pub fn template_session_keys(keys: NimbusId) -> flashbox_runtime::SessionKeys {
284
40
    flashbox_runtime::SessionKeys { nimbus: keys }
285
40
}
286

            
287
20
fn mock_container_chain_genesis_data(para_id: ParaId) -> ContainerChainGenesisData {
288
20
    let mut name_buf = alloc::string::String::new();
289
20
    let mut id_buf = alloc::string::String::new();
290

            
291
    use core::fmt::Write;
292
20
    write!(name_buf, "Container Chain {}", u32::from(para_id)).unwrap();
293
20
    write!(id_buf, "container-chain-{}", u32::from(para_id)).unwrap();
294

            
295
20
    ContainerChainGenesisData {
296
20
        storage: BoundedVec::try_from(alloc::vec![]).unwrap(),
297
20
        name: BoundedVec::try_from(name_buf.into_bytes()).unwrap(),
298
20
        id: BoundedVec::try_from(id_buf.into_bytes()).unwrap(),
299
20
        fork_id: None,
300
20
        extensions: BoundedVec::try_from(alloc::vec![]).unwrap(),
301
20
        properties: Default::default(),
302
20
    }
303
20
}