1
// Copyright 2019-2025 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam 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
// Moonbeam 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 Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! This module constructs and executes the appropriate service components for the given subcommand
18

            
19
use crate::cli::{Cli, RelayChainCli, RunCmd, Subcommand};
20
use cumulus_client_cli::extract_genesis_wasm;
21
use cumulus_primitives_core::ParaId;
22
use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE};
23
use log::{info, warn};
24
use moonbeam_cli_opt::EthApi;
25

            
26
#[cfg(feature = "moonbase-native")]
27
use moonbeam_service::moonbase_runtime;
28
#[cfg(feature = "moonbeam-native")]
29
use moonbeam_service::moonbeam_runtime;
30
#[cfg(feature = "moonriver-native")]
31
use moonbeam_service::moonriver_runtime;
32

            
33
use moonbeam_service::{
34
	chain_spec, frontier_database_dir, lazy_loading, new_partial, HostFunctions, IdentifyVariant,
35
};
36
use parity_scale_codec::Encode;
37
use sc_cli::{
38
	ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
39
	NetworkParams, Result, RpcEndpoint, SharedParams, SubstrateCli,
40
};
41
use sc_service::{
42
	config::{BasePath, PrometheusConfig},
43
	DatabaseSource, PartialComponents,
44
};
45
use sp_core::hexdisplay::HexDisplay;
46
use sp_runtime::{
47
	traits::{
48
		AccountIdConversion, Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, Zero,
49
	},
50
	StateVersion,
51
};
52
use std::io::Write;
53

            
54
932
fn load_spec(
55
932
	id: &str,
56
932
	para_id: ParaId,
57
932
	run_cmd: &RunCmd,
58
932
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
59
932
	Ok(match id {
60
		// Moonbase networks
61
932
		"moonbase-alpha" | "alphanet" => Box::new(chain_spec::RawChainSpec::from_json_bytes(
62
			&include_bytes!("../../../specs/alphanet/parachain-embedded-specs-v8.json")[..],
63
		)?),
64
		#[cfg(feature = "moonbase-native")]
65
932
		"moonbase-local" => Box::new(chain_spec::moonbase::get_chain_spec(para_id)),
66
		#[cfg(feature = "moonbase-native")]
67
932
		"moonbase-dev" | "dev" | "development" => {
68
2
			Box::new(chain_spec::moonbase::development_chain_spec(None, None))
69
		}
70
		#[cfg(feature = "moonbeam-native")]
71
930
		"staking" => Box::new(chain_spec::moonbeam::get_chain_spec(para_id)),
72
		// Moonriver networks
73
930
		"moonriver" => Box::new(chain_spec::RawChainSpec::from_json_bytes(
74
			&include_bytes!("../../../specs/moonriver/parachain-embedded-specs.json")[..],
75
		)?),
76
		#[cfg(feature = "moonriver-native")]
77
930
		"moonriver-dev" => Box::new(chain_spec::moonriver::development_chain_spec(None, None)),
78
		#[cfg(feature = "moonriver-native")]
79
930
		"moonriver-local" => Box::new(chain_spec::moonriver::get_chain_spec(para_id)),
80

            
81
		// Moonbeam networks
82
930
		"moonbeam" | "" => Box::new(chain_spec::RawChainSpec::from_json_bytes(
83
			&include_bytes!("../../../specs/moonbeam/parachain-embedded-specs.json")[..],
84
		)?),
85
		#[cfg(feature = "moonbeam-native")]
86
930
		"moonbeam-dev" => Box::new(chain_spec::moonbeam::development_chain_spec(None, None)),
87
		#[cfg(feature = "moonbeam-native")]
88
930
		"moonbeam-local" => Box::new(chain_spec::moonbeam::get_chain_spec(para_id)),
89

            
90
		// Specs provided as json specify which runtime to use in their file name. For example,
91
		// `moonbeam-custom.json` uses the moonbeam runtime.
92
		// `moonbase-dev-workshop.json` uses the moonbase runtime.
93
		// If no magic strings match, then the moonbase runtime is used by default.
94
		// TODO explore CLI options to make this nicer. eg `--force-moonriver-runtime`
95
930
		path => {
96
930
			let path = std::path::PathBuf::from(path);
97

            
98
930
			let starts_with = |prefix: &str| {
99
930
				path.file_name()
100
930
					.and_then(|f| f.to_str().map(|s| s.starts_with(&prefix)))
101
930
					.unwrap_or(false)
102
930
			};
103

            
104
930
			if run_cmd.force_moonbase || starts_with("moonbase") {
105
930
				Box::new(chain_spec::moonbase::ChainSpec::from_json_file(path)?)
106
			} else if run_cmd.force_moonriver || starts_with("moonriver") {
107
				Box::new(chain_spec::moonriver::ChainSpec::from_json_file(path)?)
108
			} else {
109
				Box::new(chain_spec::moonbeam::ChainSpec::from_json_file(path)?)
110
			}
111
		}
112
	})
113
932
}
114

            
115
impl SubstrateCli for Cli {
116
2790
	fn impl_name() -> String {
117
2790
		"Moonbeam Parachain Collator".into()
118
2790
	}
119

            
120
4654
	fn impl_version() -> String {
121
4654
		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
122
4654
	}
123

            
124
1864
	fn description() -> String {
125
1864
		format!(
126
1864
			"Moonbase Parachain Collator\n\nThe command-line arguments provided first will be \
127
1864
		passed to the parachain node, while the arguments provided after -- will be passed \
128
1864
		to the relaychain node.\n\n\
129
1864
		{} [parachain-args] -- [relaychain-args]",
130
1864
			Self::executable_name()
131
		)
132
1864
	}
133

            
134
1858
	fn author() -> String {
135
1858
		env!("CARGO_PKG_AUTHORS").into()
136
1858
	}
137

            
138
1864
	fn support_url() -> String {
139
1864
		"https://github.com/moonbeam-foundation/moonbeam/issues/new".into()
140
1864
	}
141

            
142
926
	fn copyright_start_year() -> i32 {
143
926
		2019
144
926
	}
145

            
146
932
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
147
932
		load_spec(id, self.run.parachain_id.unwrap_or(1000).into(), &self.run)
148
932
	}
149
}
150

            
151
impl SubstrateCli for RelayChainCli {
152
	fn impl_name() -> String {
153
		"Moonbeam Parachain Collator".into()
154
	}
155

            
156
	fn impl_version() -> String {
157
		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
158
	}
159

            
160
	fn description() -> String {
161
		"Moonbeam Parachain Collator\n\nThe command-line arguments provided first will be \
162
		passed to the parachain node, while the arguments provided after -- will be passed \
163
		to the relaychain node.\n\n\
164
		parachain-collator [parachain-args] -- [relaychain-args]"
165
			.into()
166
	}
167

            
168
	fn author() -> String {
169
		env!("CARGO_PKG_AUTHORS").into()
170
	}
171

            
172
	fn support_url() -> String {
173
		"https://github.com/moonbeam-foundation/moonbeam/issues/new".into()
174
	}
175

            
176
	fn copyright_start_year() -> i32 {
177
		2019
178
	}
179

            
180
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
181
		match id {
182
			"westend_moonbase_relay_testnet" => Ok(Box::new(
183
				polkadot_service::WestendChainSpec::from_json_bytes(
184
					&include_bytes!("../../../specs/alphanet/westend-embedded-specs-v8.json")[..],
185
				)?,
186
			)),
187
			// If we are not using a moonbeam-centric pre-baked relay spec, then fall back to the
188
			// Polkadot service to interpret the id.
189
			_ => polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter())
190
				.load_spec(id),
191
		}
192
	}
193
}
194

            
195
932
fn validate_trace_environment(cli: &Cli) -> Result<()> {
196
932
	if (cli.run.ethapi.contains(&EthApi::Debug) || cli.run.ethapi.contains(&EthApi::Trace))
197
		&& cli
198
			.run
199
			.base
200
			.base
201
			.import_params
202
			.wasm_runtime_overrides
203
			.is_none()
204
	{
205
		return Err(
206
			"`debug` or `trace` namespaces requires `--wasm-runtime-overrides /path/to/overrides`."
207
				.into(),
208
		);
209
932
	}
210
932
	Ok(())
211
932
}
212

            
213
/// Parse command line arguments into service configuration.
214
932
pub fn run() -> Result<()> {
215
932
	let cli = Cli::from_args();
216
932
	let _ = validate_trace_environment(&cli)?;
217

            
218
6
	match &cli.subcommand {
219
4
		Some(Subcommand::BuildSpec(params)) => {
220
4
			let runner = cli.create_runner(&params.base)?;
221
4
			runner.sync_run(|config| {
222
4
				if params.mnemonic.is_some() || params.accounts.is_some() {
223
					if config.chain_spec.is_moonbeam() {
224
						params.base.run(
225
							Box::new(chain_spec::moonbeam::development_chain_spec(
226
								params.mnemonic.clone(),
227
								params.accounts,
228
							)),
229
							config.network,
230
						)
231
					} else if config.chain_spec.is_moonriver() {
232
						params.base.run(
233
							Box::new(chain_spec::moonriver::development_chain_spec(
234
								params.mnemonic.clone(),
235
								params.accounts,
236
							)),
237
							config.network,
238
						)
239
					} else {
240
						params.base.run(
241
							Box::new(chain_spec::moonbase::development_chain_spec(
242
								params.mnemonic.clone(),
243
								params.accounts,
244
							)),
245
							config.network,
246
						)
247
					}
248
				} else {
249
4
					params.base.run(config.chain_spec, config.network)
250
				}
251
4
			})
252
		}
253
		Some(Subcommand::CheckBlock(cmd)) => {
254
			let runner = cli.create_runner(cmd)?;
255
			let rpc_config = cli.run.new_rpc_config();
256
			runner.async_run(|mut config| {
257
				let (client, _, import_queue, task_manager) = moonbeam_service::new_chain_ops(
258
					&mut config,
259
					&rpc_config,
260
					cli.node_extra_args(),
261
				)?;
262
				Ok((cmd.run(client, import_queue), task_manager))
263
			})
264
		}
265
		Some(Subcommand::ExportBlocks(cmd)) => {
266
			let runner = cli.create_runner(cmd)?;
267
			let rpc_config = cli.run.new_rpc_config();
268
			runner.async_run(|mut config| {
269
				let (client, _, _, task_manager) = moonbeam_service::new_chain_ops(
270
					&mut config,
271
					&rpc_config,
272
					cli.node_extra_args(),
273
				)?;
274
				Ok((cmd.run(client, config.database), task_manager))
275
			})
276
		}
277
		Some(Subcommand::ExportState(cmd)) => {
278
			let runner = cli.create_runner(cmd)?;
279
			let rpc_config = cli.run.new_rpc_config();
280
			runner.async_run(|mut config| {
281
				let (client, _, _, task_manager) = moonbeam_service::new_chain_ops(
282
					&mut config,
283
					&rpc_config,
284
					cli.node_extra_args(),
285
				)?;
286
				Ok((cmd.run(client, config.chain_spec), task_manager))
287
			})
288
		}
289
		Some(Subcommand::ImportBlocks(cmd)) => {
290
			let runner = cli.create_runner(cmd)?;
291
			let rpc_config = cli.run.new_rpc_config();
292
			runner.async_run(|mut config| {
293
				let (client, _, import_queue, task_manager) = moonbeam_service::new_chain_ops(
294
					&mut config,
295
					&rpc_config,
296
					cli.node_extra_args(),
297
				)?;
298
				Ok((cmd.run(client, import_queue), task_manager))
299
			})
300
		}
301
		Some(Subcommand::PurgeChain(cmd)) => {
302
			let runner = cli.create_runner(cmd)?;
303
			runner.sync_run(|config| {
304
				// Although the cumulus_client_cli::PurgeCommand will extract the relay chain id,
305
				// we need to extract it here to determine whether we are running the dev service.
306
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
307
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
308
				let dev_service = cli.run.dev_service || relay_chain_id == Some("dev-service");
309

            
310
				// Remove Frontier offchain db
311
				let frontier_database_config = match config.database {
312
					DatabaseSource::RocksDb { .. } => DatabaseSource::RocksDb {
313
						path: frontier_database_dir(&config, "db"),
314
						cache_size: 0,
315
					},
316
					DatabaseSource::ParityDb { .. } => DatabaseSource::ParityDb {
317
						path: frontier_database_dir(&config, "paritydb"),
318
					},
319
					_ => {
320
						return Err(format!("Cannot purge `{:?}` database", config.database).into())
321
					}
322
				};
323
				cmd.base.run(frontier_database_config)?;
324

            
325
				if dev_service {
326
					// base refers to the encapsulated "regular" sc_cli::PurgeChain command
327
					return cmd.base.run(config.database);
328
				}
329

            
330
				let polkadot_cli = RelayChainCli::new(
331
					&config,
332
					[RelayChainCli::executable_name().to_string()]
333
						.iter()
334
						.chain(cli.relaychain_args.iter()),
335
				);
336

            
337
				let polkadot_config = SubstrateCli::create_configuration(
338
					&polkadot_cli,
339
					&polkadot_cli,
340
					config.tokio_handle.clone(),
341
				)
342
				.map_err(|err| format!("Relay chain argument error: {}", err))?;
343

            
344
				cmd.run(config, polkadot_config)
345
			})
346
		}
347
		Some(Subcommand::Revert(cmd)) => {
348
			let runner = cli.create_runner(cmd)?;
349
			let chain_spec = &runner.config().chain_spec;
350
			let rpc_config = cli.run.new_rpc_config();
351
			match chain_spec {
352
				#[cfg(feature = "moonriver-native")]
353
				spec if spec.is_moonriver() => runner.async_run(|mut config| {
354
					let params = moonbeam_service::new_partial::<
355
						moonbeam_service::moonriver_runtime::RuntimeApi,
356
						moonbeam_service::MoonriverCustomizations,
357
					>(&mut config, &rpc_config, cli.node_extra_args())?;
358

            
359
					Ok((
360
						cmd.run(params.client, params.backend, None),
361
						params.task_manager,
362
					))
363
				}),
364
				#[cfg(feature = "moonbeam-native")]
365
				spec if spec.is_moonbeam() => runner.async_run(|mut config| {
366
					let params = moonbeam_service::new_partial::<
367
						moonbeam_service::moonbeam_runtime::RuntimeApi,
368
						moonbeam_service::MoonbeamCustomizations,
369
					>(&mut config, &rpc_config, cli.node_extra_args())?;
370

            
371
					Ok((
372
						cmd.run(params.client, params.backend, None),
373
						params.task_manager,
374
					))
375
				}),
376
				#[cfg(feature = "moonbase-native")]
377
				_ => runner.async_run(|mut config| {
378
					let params = moonbeam_service::new_partial::<
379
						moonbeam_service::moonbase_runtime::RuntimeApi,
380
						moonbeam_service::MoonbaseCustomizations,
381
					>(&mut config, &rpc_config, cli.node_extra_args())?;
382

            
383
					Ok((
384
						cmd.run(params.client, params.backend, None),
385
						params.task_manager,
386
					))
387
				}),
388
				#[cfg(not(feature = "moonbase-native"))]
389
				_ => panic!("invalid chain spec"),
390
			}
391
		}
392
		Some(Subcommand::ExportGenesisHead(cmd)) => {
393
			let rpc_config = cli.run.new_rpc_config();
394
			let runner = cli.create_runner(cmd)?;
395
			runner.sync_run(|mut config| match &config.chain_spec {
396
				#[cfg(feature = "moonbeam-native")]
397
				spec if spec.is_moonbeam() => {
398
					let params = new_partial::<
399
						moonbeam_runtime::RuntimeApi,
400
						moonbeam_service::MoonbeamCustomizations,
401
					>(&mut config, &rpc_config, cli.node_extra_args())?;
402

            
403
					cmd.run(params.client)
404
				}
405
				#[cfg(feature = "moonriver-native")]
406
				spec if spec.is_moonriver() => {
407
					let params = new_partial::<
408
						moonriver_runtime::RuntimeApi,
409
						moonbeam_service::MoonriverCustomizations,
410
					>(&mut config, &rpc_config, cli.node_extra_args())?;
411

            
412
					cmd.run(params.client)
413
				}
414
				#[cfg(feature = "moonbase-native")]
415
				_ => {
416
					let params = new_partial::<
417
						moonbase_runtime::RuntimeApi,
418
						moonbeam_service::MoonbaseCustomizations,
419
					>(&mut config, &rpc_config, cli.node_extra_args())?;
420

            
421
					cmd.run(params.client)
422
				}
423
				#[cfg(not(feature = "moonbase-native"))]
424
				_ => panic!("invalid chain spec"),
425
			})
426
		}
427
		Some(Subcommand::ExportGenesisWasm(params)) => {
428
			let mut builder = sc_cli::LoggerBuilder::new("");
429
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
430
			let _ = builder.init();
431

            
432
			let raw_wasm_blob = extract_genesis_wasm(
433
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
434
			)?;
435
			let output_buf = if params.raw {
436
				raw_wasm_blob
437
			} else {
438
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
439
			};
440

            
441
			if let Some(output) = &params.output {
442
				std::fs::write(output, output_buf)?;
443
			} else {
444
				std::io::stdout().write_all(&output_buf)?;
445
			}
446

            
447
			Ok(())
448
		}
449
		Some(Subcommand::Benchmark(cmd)) => {
450
			let runner = cli.create_runner(cmd)?;
451

            
452
			// Switch on the concrete benchmark sub-command
453
			match cmd {
454
				BenchmarkCmd::Pallet(cmd) => {
455
					if cfg!(feature = "runtime-benchmarks") {
456
						let chain_spec = &runner.config().chain_spec;
457
						match chain_spec {
458
							#[cfg(feature = "moonriver-native")]
459
							spec if spec.is_moonriver() => {
460
								return runner.sync_run(|config| {
461
									cmd.run_with_spec::<HashingFor<moonriver_runtime::Block>, HostFunctions>(
462
										Some(config.chain_spec),
463
									)
464
								})
465
							}
466
							#[cfg(feature = "moonbeam-native")]
467
							spec if spec.is_moonbeam() => {
468
								return runner.sync_run(|config| {
469
									cmd.run_with_spec::<HashingFor<moonbeam_runtime::Block>, HostFunctions>(
470
										Some(config.chain_spec),
471
									)
472
								})
473
							}
474
							#[cfg(feature = "moonbase-native")]
475
							_ => {
476
								return runner.sync_run(|config| {
477
									cmd.run_with_spec::<HashingFor<moonbase_runtime::Block>, HostFunctions>(
478
										Some(config.chain_spec),
479
									)
480
								})
481
							}
482
							#[cfg(not(feature = "moonbase-native"))]
483
							_ => panic!("invalid chain spec"),
484
						}
485
					} else {
486
						Err("Benchmarking wasn't enabled when building the node. \
487
					You can enable it with `--features runtime-benchmarks`."
488
							.into())
489
					}
490
				}
491
				BenchmarkCmd::Block(cmd) => {
492
					let chain_spec = &runner.config().chain_spec;
493
					let rpc_config = cli.run.new_rpc_config();
494
					match chain_spec {
495
						#[cfg(feature = "moonriver-native")]
496
						spec if spec.is_moonriver() => {
497
							return runner.sync_run(|mut config| {
498
								let params =
499
									moonbeam_service::new_partial::<
500
										moonbeam_service::moonriver_runtime::RuntimeApi,
501
										moonbeam_service::MoonriverCustomizations,
502
									>(&mut config, &rpc_config, cli.node_extra_args())?;
503

            
504
								cmd.run(params.client)
505
							})
506
						}
507
						#[cfg(feature = "moonbeam-native")]
508
						spec if spec.is_moonbeam() => {
509
							return runner.sync_run(|mut config| {
510
								let params =
511
									moonbeam_service::new_partial::<
512
										moonbeam_service::moonbeam_runtime::RuntimeApi,
513
										moonbeam_service::MoonbeamCustomizations,
514
									>(&mut config, &rpc_config, cli.node_extra_args())?;
515

            
516
								cmd.run(params.client)
517
							})
518
						}
519
						#[cfg(feature = "moonbase-native")]
520
						_ => {
521
							return runner.sync_run(|mut config| {
522
								let params =
523
									moonbeam_service::new_partial::<
524
										moonbeam_service::moonbase_runtime::RuntimeApi,
525
										moonbeam_service::MoonbaseCustomizations,
526
									>(&mut config, &rpc_config, cli.node_extra_args())?;
527

            
528
								cmd.run(params.client)
529
							})
530
						}
531
						#[cfg(not(feature = "moonbase-native"))]
532
						_ => panic!("invalid chain spec"),
533
					}
534
				}
535
				#[cfg(not(feature = "runtime-benchmarks"))]
536
				BenchmarkCmd::Storage(_) => Err(
537
					"Storage benchmarking can be enabled with `--features runtime-benchmarks`."
538
						.into(),
539
				),
540
				#[cfg(feature = "runtime-benchmarks")]
541
				BenchmarkCmd::Storage(cmd) => {
542
					let chain_spec = &runner.config().chain_spec;
543
					let rpc_config = cli.run.new_rpc_config();
544
					match chain_spec {
545
						#[cfg(feature = "moonriver-native")]
546
						spec if spec.is_moonriver() => {
547
							return runner.sync_run(|mut config| {
548
								let params =
549
									moonbeam_service::new_partial::<
550
										moonbeam_service::moonriver_runtime::RuntimeApi,
551
										moonbeam_service::MoonriverCustomizations,
552
									>(&mut config, &rpc_config, cli.node_extra_args())?;
553

            
554
								let db = params.backend.expose_db();
555
								let storage = params.backend.expose_storage();
556

            
557
								cmd.run(config, params.client, db, storage, None)
558
							})
559
						}
560
						#[cfg(feature = "moonbeam-native")]
561
						spec if spec.is_moonbeam() => {
562
							return runner.sync_run(|mut config| {
563
								let params =
564
									moonbeam_service::new_partial::<
565
										moonbeam_service::moonbeam_runtime::RuntimeApi,
566
										moonbeam_service::MoonbeamCustomizations,
567
									>(&mut config, &rpc_config, cli.node_extra_args())?;
568

            
569
								let db = params.backend.expose_db();
570
								let storage = params.backend.expose_storage();
571

            
572
								cmd.run(config, params.client, db, storage, None)
573
							})
574
						}
575
						#[cfg(feature = "moonbase-native")]
576
						_ => {
577
							return runner.sync_run(|mut config| {
578
								let params =
579
									moonbeam_service::new_partial::<
580
										moonbeam_service::moonbase_runtime::RuntimeApi,
581
										moonbeam_service::MoonbaseCustomizations,
582
									>(&mut config, &rpc_config, cli.node_extra_args())?;
583

            
584
								let db = params.backend.expose_db();
585
								let storage = params.backend.expose_storage();
586

            
587
								cmd.run(config, params.client, db, storage, None)
588
							})
589
						}
590
						#[cfg(not(feature = "moonbase-native"))]
591
						_ => panic!("invalid chain spec"),
592
					}
593
				}
594
				BenchmarkCmd::Overhead(_) => Err("Unsupported benchmarking command".into()),
595
				BenchmarkCmd::Extrinsic(_) => Err("Unsupported benchmarking command".into()),
596
				BenchmarkCmd::Machine(cmd) => {
597
					return runner.sync_run(|config| {
598
						cmd.run(
599
							&config,
600
							frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.clone(),
601
						)
602
					});
603
				}
604
			}
605
		}
606
		Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
607
2
		Some(Subcommand::PrecompileWasm(cmd)) => {
608
2
			let runner = cli.create_runner(cmd)?;
609
2
			let rpc_config = cli.run.new_rpc_config();
610
2
			runner.async_run(|mut config| match &config.chain_spec {
611
				#[cfg(feature = "moonriver-native")]
612
2
				spec if spec.is_moonriver() => {
613
					let PartialComponents {
614
						task_manager,
615
						backend,
616
						..
617
					} = moonbeam_service::new_partial::<
618
						moonbeam_service::moonriver_runtime::RuntimeApi,
619
						moonbeam_service::MoonriverCustomizations,
620
					>(&mut config, &rpc_config, cli.node_extra_args())?;
621

            
622
					Ok((cmd.run(backend, config.chain_spec), task_manager))
623
				}
624
				#[cfg(feature = "moonbeam-native")]
625
2
				spec if spec.is_moonbeam() => {
626
					let PartialComponents {
627
						task_manager,
628
						backend,
629
						..
630
					} = moonbeam_service::new_partial::<
631
						moonbeam_service::moonbeam_runtime::RuntimeApi,
632
						moonbeam_service::MoonbeamCustomizations,
633
					>(&mut config, &rpc_config, cli.node_extra_args())?;
634

            
635
					Ok((cmd.run(backend, config.chain_spec), task_manager))
636
				}
637
				#[cfg(feature = "moonbase-native")]
638
				_ => {
639
					let PartialComponents {
640
2
						task_manager,
641
2
						backend,
642
						..
643
2
					} = moonbeam_service::new_partial::<
644
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
645
2
						moonbeam_service::MoonbaseCustomizations,
646
2
					>(&mut config, &rpc_config, cli.node_extra_args())?;
647

            
648
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
649
				}
650
				#[cfg(not(feature = "moonbase-native"))]
651
				_ => panic!("invalid chain spec"),
652
2
			})
653
		}
654
		None => {
655
926
			let runner = cli.create_runner(&(*cli.run).normalize())?;
656
926
			let collator_options = cli.run.collator_options();
657

            
658
926
			runner.run_node_until_exit(|mut config| async move {
659
926
				let hwbench = if !cli.run.no_hardware_benchmarks {
660
					config.database.path().map(|database_path| {
661
						let _ = std::fs::create_dir_all(&database_path);
662
						sc_sysinfo::gather_hwbench(
663
							Some(database_path),
664
							&SUBSTRATE_REFERENCE_HARDWARE,
665
						)
666
					})
667
				} else {
668
926
					None
669
				};
670

            
671
926
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
672

            
673
926
				let rpc_config = cli.run.new_rpc_config();
674

            
675
				// If dev service was requested, start up manual or instant seal.
676
				// Otherwise continue with the normal parachain node.
677
				// Dev service can be requested in two ways.
678
				// 1. by providing the --dev-service flag to the CLI
679
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
680
				// NOTE: the --dev flag triggers the dev service by way of number 2
681
926
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
682
926
				let para_id = extension.map(|e| e.para_id);
683

            
684
926
				let dev_service = cli.run.dev_service
685
926
					|| config.chain_spec.is_dev()
686
					|| relay_chain_id == Some("dev-service");
687
926
				if dev_service {
688
					// When running the dev service, just use Alice's author inherent
689
					//TODO maybe make the --alice etc flags work here, and consider bringing back
690
					// the author-id flag. For now, this will work.
691
926
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
692
926
						"Alice",
693
926
					));
694

            
695
926
					return match &config.chain_spec {
696
						#[cfg(feature = "moonriver-native")]
697
926
						spec if spec.is_moonriver() => moonbeam_service::new_dev::<
698
							moonbeam_service::moonriver_runtime::RuntimeApi,
699
							moonbeam_service::MoonriverCustomizations,
700
							sc_network::NetworkWorker<_, _>,
701
						>(
702
							config,
703
							para_id,
704
							author_id,
705
							cli.run.sealing,
706
							rpc_config,
707
							hwbench,
708
							cli.node_extra_args(),
709
						)
710
						.await
711
						.map_err(Into::into),
712
						#[cfg(feature = "moonbeam-native")]
713
926
						spec if spec.is_moonbeam() => moonbeam_service::new_dev::<
714
							moonbeam_service::moonbeam_runtime::RuntimeApi,
715
							moonbeam_service::MoonbeamCustomizations,
716
							sc_network::NetworkWorker<_, _>,
717
						>(
718
							config,
719
							para_id,
720
							author_id,
721
							cli.run.sealing,
722
							rpc_config,
723
							hwbench,
724
							cli.node_extra_args(),
725
						)
726
						.await
727
						.map_err(Into::into),
728
						#[cfg(feature = "moonbase-native")]
729
926
						_ => moonbeam_service::new_dev::<
730
926
							moonbeam_service::moonbase_runtime::RuntimeApi,
731
926
							moonbeam_service::MoonbaseCustomizations,
732
926
							sc_network::NetworkWorker<_, _>,
733
926
						>(
734
926
							config,
735
926
							para_id,
736
926
							author_id,
737
926
							cli.run.sealing,
738
926
							rpc_config,
739
926
							hwbench,
740
926
							cli.node_extra_args(),
741
926
						)
742
926
						.await
743
926
						.map_err(Into::into),
744
						#[cfg(not(feature = "moonbase-native"))]
745
						_ => panic!("invalid chain spec"),
746
					};
747
				}
748
				#[cfg(feature = "lazy-loading")]
749
				if let Some(lazy_loading_remote_rpc) = cli.run.lazy_loading_remote_rpc {
750
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
751
						"Alice",
752
					));
753

            
754
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
755
						state_rpc: lazy_loading_remote_rpc,
756
						from_block: cli.run.lazy_loading_block,
757
						state_overrides_path: cli.run.lazy_loading_state_overrides,
758
						runtime_override: cli.run.lazy_loading_runtime_override,
759
						delay_between_requests: cli.run.lazy_loading_delay_between_requests,
760
						max_retries_per_request: cli.run.lazy_loading_max_retries_per_request,
761
					};
762

            
763
					let spec_builder = lazy_loading::spec_builder();
764
					config.chain_spec = Box::new(spec_builder.build());
765

            
766
					// TODO: create a tokio runtime inside offchain_worker thread (otherwise it will panic)
767
					// We just disable it for now, since it is not needed
768
					config.offchain_worker.enabled = false;
769

            
770
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
771
						moonbeam_runtime::RuntimeApi,
772
						moonbeam_service::MoonbeamCustomizations,
773
						sc_network::NetworkWorker<_, _>,
774
					>(
775
						config,
776
						author_id,
777
						cli.run.sealing,
778
						rpc_config,
779
						lazy_loading_config,
780
						hwbench,
781
					)
782
					.await
783
					.map_err(Into::into);
784
				}
785

            
786
				let polkadot_cli = RelayChainCli::new(
787
					&config,
788
					[RelayChainCli::executable_name().to_string()]
789
						.iter()
790
						.chain(cli.relaychain_args.iter()),
791
				);
792

            
793
				info!("Relay Chain Client Version: {}", polkadot_cli.impl_version);
794

            
795
				let para_id = extension.map(|e| e.para_id);
796
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
797

            
798
				let parachain_account =
799
					AccountIdConversion::<polkadot_primitives::v8::AccountId>::into_account_truncating(&id);
800

            
801
				let tokio_handle = config.tokio_handle.clone();
802
				let polkadot_config =
803
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
804
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
805

            
806
				info!("Parachain Account: {}", parachain_account);
807
				info!(
808
					"Is collating: {}",
809
					if config.role.is_authority() {
810
						"yes"
811
					} else {
812
						"no"
813
					}
814
				);
815

            
816
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
817
					warn!(
818
						"Detected relay chain node arguments together with \
819
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
820
					uses a network-related subset of all relay chain CLI options."
821
					);
822
				}
823

            
824
				match &config.chain_spec {
825
					#[cfg(feature = "moonriver-native")]
826
					spec if spec.is_moonriver() => moonbeam_service::start_node::<
827
						moonbeam_service::moonriver_runtime::RuntimeApi,
828
						moonbeam_service::MoonriverCustomizations,
829
					>(
830
						config,
831
						polkadot_config,
832
						collator_options,
833
						id,
834
						rpc_config,
835
						cli.run.block_authoring_duration,
836
						hwbench,
837
						cli.node_extra_args(),
838
					)
839
					.await
840
					.map(|r| r.0)
841
					.map_err(Into::into),
842
					#[cfg(feature = "moonbeam-native")]
843
					spec if spec.is_moonbeam() => moonbeam_service::start_node::<
844
						moonbeam_service::moonbeam_runtime::RuntimeApi,
845
						moonbeam_service::MoonbeamCustomizations,
846
					>(
847
						config,
848
						polkadot_config,
849
						collator_options,
850
						id,
851
						rpc_config,
852
						cli.run.block_authoring_duration,
853
						hwbench,
854
						cli.node_extra_args(),
855
					)
856
					.await
857
					.map(|r| r.0)
858
					.map_err(Into::into),
859
					#[cfg(feature = "moonbase-native")]
860
					_ => moonbeam_service::start_node::<
861
						moonbeam_service::moonbase_runtime::RuntimeApi,
862
						moonbeam_service::MoonbaseCustomizations,
863
					>(
864
						config,
865
						polkadot_config,
866
						collator_options,
867
						id,
868
						rpc_config,
869
						cli.run.block_authoring_duration,
870
						hwbench,
871
						cli.node_extra_args(),
872
					)
873
					.await
874
					.map(|r| r.0)
875
					.map_err(Into::into),
876
					#[cfg(not(feature = "moonbase-native"))]
877
					_ => panic!("invalid chain spec"),
878
				}
879
1852
			})
880
		}
881
	}
882
932
}
883

            
884
impl DefaultConfigurationValues for RelayChainCli {
885
	fn p2p_listen_port() -> u16 {
886
		30334
887
	}
888

            
889
	fn rpc_listen_port() -> u16 {
890
		9945
891
	}
892

            
893
	fn prometheus_listen_port() -> u16 {
894
		9616
895
	}
896
}
897

            
898
impl CliConfiguration<Self> for RelayChainCli {
899
	fn shared_params(&self) -> &SharedParams {
900
		self.base.base.shared_params()
901
	}
902

            
903
	fn import_params(&self) -> Option<&ImportParams> {
904
		self.base.base.import_params()
905
	}
906

            
907
	fn network_params(&self) -> Option<&NetworkParams> {
908
		self.base.base.network_params()
909
	}
910

            
911
	fn keystore_params(&self) -> Option<&KeystoreParams> {
912
		self.base.base.keystore_params()
913
	}
914

            
915
	fn base_path(&self) -> Result<Option<BasePath>> {
916
		Ok(self
917
			.shared_params()
918
			.base_path()?
919
			.or_else(|| Some(self.base_path.clone().into())))
920
	}
921

            
922
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<RpcEndpoint>>> {
923
		self.base.base.rpc_addr(default_listen_port)
924
	}
925

            
926
	fn prometheus_config(
927
		&self,
928
		default_listen_port: u16,
929
		chain_spec: &Box<dyn ChainSpec>,
930
	) -> Result<Option<PrometheusConfig>> {
931
		self.base
932
			.base
933
			.prometheus_config(default_listen_port, chain_spec)
934
	}
935

            
936
	fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
937
	where
938
		F: FnOnce(&mut sc_cli::LoggerBuilder),
939
	{
940
		unreachable!("PolkadotCli is never initialized; qed");
941
	}
942

            
943
	fn chain_id(&self, is_dev: bool) -> Result<String> {
944
		let chain_id = self.base.base.chain_id(is_dev)?;
945

            
946
		Ok(if chain_id.is_empty() {
947
			self.chain_id.clone().unwrap_or_default()
948
		} else {
949
			chain_id
950
		})
951
	}
952

            
953
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
954
		self.base.base.role(is_dev)
955
	}
956

            
957
	fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
958
		self.base.base.transaction_pool(is_dev)
959
	}
960

            
961
	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
962
		self.base.base.rpc_methods()
963
	}
964

            
965
	fn rpc_max_connections(&self) -> Result<u32> {
966
		self.base.base.rpc_max_connections()
967
	}
968

            
969
	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
970
		self.base.base.rpc_cors(is_dev)
971
	}
972

            
973
	// fn telemetry_external_transport(&self) -> Result<Option<sc_service::config::ExtTransport>> {
974
	// 	self.base.base.telemetry_external_transport()
975
	// }
976

            
977
	fn default_heap_pages(&self) -> Result<Option<u64>> {
978
		self.base.base.default_heap_pages()
979
	}
980

            
981
	fn force_authoring(&self) -> Result<bool> {
982
		self.base.base.force_authoring()
983
	}
984

            
985
	fn disable_grandpa(&self) -> Result<bool> {
986
		self.base.base.disable_grandpa()
987
	}
988

            
989
	fn max_runtime_instances(&self) -> Result<Option<usize>> {
990
		self.base.base.max_runtime_instances()
991
	}
992

            
993
	fn announce_block(&self) -> Result<bool> {
994
		self.base.base.announce_block()
995
	}
996
}
997

            
998
/// Generate the genesis block from a given ChainSpec.
999
pub fn generate_genesis_block<Block: BlockT>(
	chain_spec: &dyn ChainSpec,
	genesis_state_version: StateVersion,
) -> std::result::Result<Block, String> {
	let storage = chain_spec.build_storage()?;
	let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
		let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
			child_content.data.clone().into_iter().collect(),
			genesis_state_version,
		);
		(sk.clone(), state_root.encode())
	});
	let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
		storage.top.clone().into_iter().chain(child_roots).collect(),
		genesis_state_version,
	);
	let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
		Vec::new(),
		genesis_state_version,
	);
	Ok(Block::new(
		<<Block as BlockT>::Header as HeaderT>::new(
			Zero::zero(),
			extrinsics_root,
			state_root,
			Default::default(),
			Default::default(),
		),
		Default::default(),
	))
}