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::cli::{ContainerNodeRelayChainCli, RelayChainCli},
19
    parity_scale_codec::Encode,
20
    polkadot_service::{GenericChainSpec, WestendChainSpec},
21
    sc_chain_spec::construct_genesis_block,
22
    sc_cli::{
23
        ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
24
        NetworkParams, Result, SharedParams, SubstrateCli,
25
    },
26
    sc_service::config::{BasePath, PrometheusConfig},
27
    sp_runtime::{
28
        traits::{Block as BlockT, Get, Hash as HashT, Header as HeaderT},
29
        StateVersion,
30
    },
31
    std::result::Result as StdResult,
32
};
33

            
34
/// Generate the genesis block from a given ChainSpec.
35
pub fn generate_genesis_block<Block: BlockT>(
36
    chain_spec: &dyn ChainSpec,
37
    genesis_state_version: StateVersion,
38
) -> StdResult<Block, String> {
39
    let storage = chain_spec.build_storage()?;
40

            
41
    let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
42
        let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
43
            child_content.data.clone().into_iter().collect(),
44
            genesis_state_version,
45
        );
46
        (sk.clone(), state_root.encode())
47
    });
48
    let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
49
        storage.top.clone().into_iter().chain(child_roots).collect(),
50
        genesis_state_version,
51
    );
52

            
53
    Ok(construct_genesis_block(state_root, genesis_state_version))
54
}
55

            
56
impl<N: Get<&'static str>> DefaultConfigurationValues for ContainerNodeRelayChainCli<N> {
57
    fn p2p_listen_port() -> u16 {
58
        30334
59
    }
60

            
61
    fn rpc_listen_port() -> u16 {
62
        9945
63
    }
64

            
65
    fn prometheus_listen_port() -> u16 {
66
        9616
67
    }
68
}
69

            
70
impl<N: Get<&'static str>> CliConfiguration<Self> for ContainerNodeRelayChainCli<N> {
71
    fn shared_params(&self) -> &SharedParams {
72
        self.base.base.shared_params()
73
    }
74

            
75
    fn import_params(&self) -> Option<&ImportParams> {
76
        self.base.base.import_params()
77
    }
78

            
79
    fn network_params(&self) -> Option<&NetworkParams> {
80
        self.base.base.network_params()
81
    }
82

            
83
    fn keystore_params(&self) -> Option<&KeystoreParams> {
84
        self.base.base.keystore_params()
85
    }
86

            
87
    fn base_path(&self) -> Result<Option<BasePath>> {
88
        Ok(self
89
            .shared_params()
90
            .base_path()?
91
            .or_else(|| Some(self.base_path.clone().into())))
92
    }
93

            
94
    fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<sc_cli::RpcEndpoint>>> {
95
        self.base.base.rpc_addr(default_listen_port)
96
    }
97

            
98
    fn prometheus_config(
99
        &self,
100
        default_listen_port: u16,
101
        chain_spec: &Box<dyn ChainSpec>,
102
    ) -> Result<Option<PrometheusConfig>> {
103
        self.base
104
            .base
105
            .prometheus_config(default_listen_port, chain_spec)
106
    }
107

            
108
    fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
109
    where
110
        F: FnOnce(&mut sc_cli::LoggerBuilder),
111
    {
112
        unreachable!("PolkadotCli is never initialized; qed");
113
    }
114

            
115
    fn chain_id(&self, is_dev: bool) -> Result<String> {
116
        let chain_id = self.base.base.chain_id(is_dev)?;
117

            
118
        Ok(if chain_id.is_empty() {
119
            self.chain_id.clone().unwrap_or_default()
120
        } else {
121
            chain_id
122
        })
123
    }
124

            
125
    fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
126
        self.base.base.role(is_dev)
127
    }
128

            
129
    fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
130
        self.base.base.transaction_pool(is_dev)
131
    }
132

            
133
    fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
134
        self.base.base.trie_cache_maximum_size()
135
    }
136

            
137
    fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
138
        self.base.base.rpc_methods()
139
    }
140

            
141
    fn rpc_max_connections(&self) -> Result<u32> {
142
        self.base.base.rpc_max_connections()
143
    }
144

            
145
    fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
146
        self.base.base.rpc_cors(is_dev)
147
    }
148

            
149
    fn default_heap_pages(&self) -> Result<Option<u64>> {
150
        self.base.base.default_heap_pages()
151
    }
152

            
153
    fn force_authoring(&self) -> Result<bool> {
154
        self.base.base.force_authoring()
155
    }
156

            
157
    fn disable_grandpa(&self) -> Result<bool> {
158
        self.base.base.disable_grandpa()
159
    }
160

            
161
    fn max_runtime_instances(&self) -> Result<Option<usize>> {
162
        self.base.base.max_runtime_instances()
163
    }
164

            
165
    fn announce_block(&self) -> Result<bool> {
166
        self.base.base.announce_block()
167
    }
168

            
169
    fn telemetry_endpoints(
170
        &self,
171
        chain_spec: &Box<dyn ChainSpec>,
172
    ) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
173
        self.base.base.telemetry_endpoints(chain_spec)
174
    }
175

            
176
    fn node_name(&self) -> Result<String> {
177
        self.base.base.node_name()
178
    }
179
}
180

            
181
impl<N: Get<&'static str>> SubstrateCli for ContainerNodeRelayChainCli<N> {
182
2
    fn impl_version() -> String {
183
2
        env!("SUBSTRATE_CLI_IMPL_VERSION").into()
184
2
    }
185

            
186
    fn author() -> String {
187
        env!("CARGO_PKG_AUTHORS").into()
188
    }
189

            
190
    fn support_url() -> String {
191
        "https://github.com/moondance-labs/tanssi/issues/new".into()
192
    }
193

            
194
    fn copyright_start_year() -> i32 {
195
        2020
196
    }
197

            
198
    fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
199
        polkadot_cli::Cli::from_iter([Self::executable_name()].iter()).load_spec(id)
200
    }
201

            
202
    fn impl_name() -> String {
203
        format!("Container Chain {} Node", N::get())
204
    }
205

            
206
    fn description() -> String {
207
        format!(
208
            "Container Chain {} Node\n\nThe command-line arguments provided first will be \
209
        passed to the orchestrator node, while the arguments provided after -- will be passed \
210
        to the relay chain node.\n\n\
211
        {} <orchestrator-args> -- <relay-chain-args>",
212
            N::get(),
213
            ContainerNodeRelayChainCli::<N>::executable_name()
214
        )
215
    }
216
}
217

            
218
impl SubstrateCli for RelayChainCli {
219
    fn impl_name() -> String {
220
        "Tanssi Collator".into()
221
    }
222

            
223
8
    fn impl_version() -> String {
224
8
        env!("SUBSTRATE_CLI_IMPL_VERSION").into()
225
8
    }
226

            
227
    fn description() -> String {
228
        format!(
229
            "Tanssi Collator\n\nThe command-line arguments provided first will be \
230
		passed to the parachain node, while the arguments provided after -- will be passed \
231
		to the relay chain node.\n\n\
232
		{} <parachain-args> -- <relay-chain-args>",
233
            Self::executable_name()
234
        )
235
    }
236

            
237
    fn author() -> String {
238
        env!("CARGO_PKG_AUTHORS").into()
239
    }
240

            
241
    fn support_url() -> String {
242
        "https://github.com/moondance-labs/tanssi/issues/new".into()
243
    }
244

            
245
    fn copyright_start_year() -> i32 {
246
        2020
247
    }
248

            
249
    fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
250
        const STARLIGHT_RAW_SPECS: &[u8] =
251
            include_bytes!("../../../specs/solochain/starlight-raw-specs.json");
252

            
253
        match id {
254
            "westend_moonbase_relay_testnet" => Ok(Box::new(WestendChainSpec::from_json_bytes(
255
                &include_bytes!("../../../specs/dancebox/alphanet-relay-raw-specs.json")[..],
256
            )?)),
257
            // Default to starlight if this is a solochain node. Else default to polkadot default.
258
            "" if self.solochain => Ok(Box::new(GenericChainSpec::from_json_bytes(
259
                STARLIGHT_RAW_SPECS,
260
            )?)),
261
            "starlight" | "tanssi" => Ok(Box::new(GenericChainSpec::from_json_bytes(
262
                STARLIGHT_RAW_SPECS,
263
            )?)),
264
            "dancelight" => Ok(Box::new(GenericChainSpec::from_json_bytes(
265
                &include_bytes!("../../../specs/solochain/dancelight-raw-specs.json")[..],
266
            )?)),
267
            // If we are not using a pre-baked relay spec, then fall back to the
268
            // Polkadot service to interpret the id.
269
            id => polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter())
270
                .load_spec(id),
271
        }
272
    }
273
}
274

            
275
impl DefaultConfigurationValues for RelayChainCli {
276
    fn p2p_listen_port() -> u16 {
277
        30334
278
    }
279

            
280
    fn rpc_listen_port() -> u16 {
281
        9945
282
    }
283

            
284
    fn prometheus_listen_port() -> u16 {
285
        9616
286
    }
287
}
288

            
289
impl CliConfiguration<Self> for RelayChainCli {
290
    fn shared_params(&self) -> &SharedParams {
291
        self.base.base.shared_params()
292
    }
293

            
294
    fn import_params(&self) -> Option<&ImportParams> {
295
        self.base.base.import_params()
296
    }
297

            
298
    fn network_params(&self) -> Option<&NetworkParams> {
299
        self.base.base.network_params()
300
    }
301

            
302
    fn keystore_params(&self) -> Option<&KeystoreParams> {
303
        self.base.base.keystore_params()
304
    }
305

            
306
    fn base_path(&self) -> Result<Option<BasePath>> {
307
        Ok(self
308
            .shared_params()
309
            .base_path()?
310
            .or_else(|| Some(self.base_path.clone().into())))
311
    }
312

            
313
    fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<sc_cli::RpcEndpoint>>> {
314
        self.base.base.rpc_addr(default_listen_port)
315
    }
316

            
317
    fn prometheus_config(
318
        &self,
319
        default_listen_port: u16,
320
        chain_spec: &Box<dyn ChainSpec>,
321
    ) -> Result<Option<PrometheusConfig>> {
322
        self.base
323
            .base
324
            .prometheus_config(default_listen_port, chain_spec)
325
    }
326

            
327
    fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
328
    where
329
        F: FnOnce(&mut sc_cli::LoggerBuilder),
330
    {
331
        unreachable!("PolkadotCli is never initialized; qed");
332
    }
333

            
334
    fn chain_id(&self, is_dev: bool) -> Result<String> {
335
        let chain_id = self.base.base.chain_id(is_dev)?;
336

            
337
        Ok(if chain_id.is_empty() {
338
            self.chain_id.clone().unwrap_or_default()
339
        } else {
340
            chain_id
341
        })
342
    }
343

            
344
    fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
345
        self.base.base.role(is_dev)
346
    }
347

            
348
    fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
349
        self.base.base.transaction_pool(is_dev)
350
    }
351

            
352
    fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
353
        self.base.base.trie_cache_maximum_size()
354
    }
355

            
356
    fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
357
        self.base.base.rpc_methods()
358
    }
359

            
360
    fn rpc_max_connections(&self) -> Result<u32> {
361
        self.base.base.rpc_max_connections()
362
    }
363

            
364
    fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
365
        self.base.base.rpc_cors(is_dev)
366
    }
367

            
368
    fn default_heap_pages(&self) -> Result<Option<u64>> {
369
        self.base.base.default_heap_pages()
370
    }
371

            
372
    fn force_authoring(&self) -> Result<bool> {
373
        self.base.base.force_authoring()
374
    }
375

            
376
    fn disable_grandpa(&self) -> Result<bool> {
377
        self.base.base.disable_grandpa()
378
    }
379

            
380
    fn max_runtime_instances(&self) -> Result<Option<usize>> {
381
        self.base.base.max_runtime_instances()
382
    }
383

            
384
    fn announce_block(&self) -> Result<bool> {
385
        self.base.base.announce_block()
386
    }
387

            
388
    fn telemetry_endpoints(
389
        &self,
390
        chain_spec: &Box<dyn ChainSpec>,
391
    ) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
392
        self.base.base.telemetry_endpoints(chain_spec)
393
    }
394

            
395
    fn node_name(&self) -> Result<String> {
396
        self.base.base.node_name()
397
    }
398
}