1
// Copyright 2019-2022 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;
23
use log::{info, warn};
24
use moonbeam_cli_opt::EthApi;
25
use moonbeam_service::{
26
	chain_spec, frontier_database_dir, moonbase_runtime, moonbeam_runtime, moonriver_runtime,
27
	HostFunctions, IdentifyVariant,
28
};
29
use parity_scale_codec::Encode;
30
#[cfg(feature = "westend-native")]
31
use polkadot_service::WestendChainSpec;
32
use sc_cli::{
33
	ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
34
	NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
35
};
36
use sc_service::{
37
	config::{BasePath, PrometheusConfig},
38
	DatabaseSource, PartialComponents,
39
};
40
use sp_core::hexdisplay::HexDisplay;
41
use sp_runtime::{
42
	traits::{
43
		AccountIdConversion, Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, Zero,
44
	},
45
	StateVersion,
46
};
47
use std::{io::Write, net::SocketAddr};
48

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

            
76
		// Moonbeam networks
77
902
		"moonbeam" | "" => Box::new(chain_spec::RawChainSpec::from_json_bytes(
78
			&include_bytes!("../../../specs/moonbeam/parachain-embedded-specs.json")[..],
79
		)?),
80
		#[cfg(feature = "moonbeam-native")]
81
902
		"moonbeam-dev" => Box::new(chain_spec::moonbeam::development_chain_spec(None, None)),
82
		#[cfg(feature = "moonbeam-native")]
83
902
		"moonbeam-local" => Box::new(chain_spec::moonbeam::get_chain_spec(para_id)),
84

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

            
93
902
			let starts_with = |prefix: &str| {
94
902
				path.file_name()
95
902
					.and_then(|f| f.to_str().map(|s| s.starts_with(&prefix)))
96
902
					.unwrap_or(false)
97
902
			};
98

            
99
902
			if run_cmd.force_moonbase || starts_with("moonbase") {
100
902
				Box::new(chain_spec::moonbase::ChainSpec::from_json_file(path)?)
101
			} else if run_cmd.force_moonriver || starts_with("moonriver") {
102
				Box::new(chain_spec::moonriver::ChainSpec::from_json_file(path)?)
103
			} else {
104
				Box::new(chain_spec::moonbeam::ChainSpec::from_json_file(path)?)
105
			}
106
		}
107
	})
108
904
}
109

            
110
impl SubstrateCli for Cli {
111
2706
	fn impl_name() -> String {
112
2706
		"Moonbeam Parachain Collator".into()
113
2706
	}
114

            
115
4514
	fn impl_version() -> String {
116
4514
		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
117
4514
	}
118

            
119
904
	fn description() -> String {
120
904
		format!(
121
904
			"Moonbase Parachain Collator\n\nThe command-line arguments provided first will be \
122
904
		passed to the parachain node, while the arguments provided after -- will be passed \
123
904
		to the relaychain node.\n\n\
124
904
		{} [parachain-args] -- [relaychain-args]",
125
904
			Self::executable_name()
126
904
		)
127
904
	}
128

            
129
1802
	fn author() -> String {
130
1802
		env!("CARGO_PKG_AUTHORS").into()
131
1802
	}
132

            
133
904
	fn support_url() -> String {
134
904
		"https://github.com/PureStake/moonbeam/issues/new".into()
135
904
	}
136

            
137
898
	fn copyright_start_year() -> i32 {
138
898
		2019
139
898
	}
140

            
141
904
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
142
904
		load_spec(id, self.run.parachain_id.unwrap_or(1000).into(), &self.run)
143
904
	}
144
}
145

            
146
impl Cli {
147
	fn runtime_version(spec: &Box<dyn sc_service::ChainSpec>) -> &'static RuntimeVersion {
148
		match spec {
149
			#[cfg(feature = "moonriver-native")]
150
			spec if spec.is_moonriver() => return &moonbeam_service::moonriver_runtime::VERSION,
151
			#[cfg(feature = "moonbeam-native")]
152
			spec if spec.is_moonbeam() => return &moonbeam_service::moonbeam_runtime::VERSION,
153
			#[cfg(feature = "moonbase-native")]
154
			_ => return &moonbeam_service::moonbase_runtime::VERSION,
155
			#[cfg(not(feature = "moonbase-native"))]
156
			_ => panic!("invalid chain spec"),
157
		}
158
	}
159
}
160

            
161
impl SubstrateCli for RelayChainCli {
162
	fn impl_name() -> String {
163
		"Moonbeam Parachain Collator".into()
164
	}
165

            
166
	fn impl_version() -> String {
167
		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
168
	}
169

            
170
	fn description() -> String {
171
		"Moonbeam Parachain Collator\n\nThe command-line arguments provided first will be \
172
		passed to the parachain node, while the arguments provided after -- will be passed \
173
		to the relaychain node.\n\n\
174
		parachain-collator [parachain-args] -- [relaychain-args]"
175
			.into()
176
	}
177

            
178
	fn author() -> String {
179
		env!("CARGO_PKG_AUTHORS").into()
180
	}
181

            
182
	fn support_url() -> String {
183
		"https://github.com/PureStake/moonbeam/issues/new".into()
184
	}
185

            
186
	fn copyright_start_year() -> i32 {
187
		2019
188
	}
189

            
190
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
191
		match id {
192
			#[cfg(feature = "westend-native")]
193
			"westend_moonbase_relay_testnet" => Ok(Box::new(WestendChainSpec::from_json_bytes(
194
				&include_bytes!("../../../specs/alphanet/westend-embedded-specs-v8.json")[..],
195
			)?)),
196
			// If we are not using a moonbeam-centric pre-baked relay spec, then fall back to the
197
			// Polkadot service to interpret the id.
198
			_ => polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter())
199
				.load_spec(id),
200
		}
201
	}
202
}
203

            
204
904
fn validate_trace_environment(cli: &Cli) -> Result<()> {
205
904
	if (cli.run.ethapi.contains(&EthApi::Debug) || cli.run.ethapi.contains(&EthApi::Trace))
206
		&& cli
207
			.run
208
			.base
209
			.base
210
			.import_params
211
			.wasm_runtime_overrides
212
			.is_none()
213
	{
214
		return Err(
215
			"`debug` or `trace` namespaces requires `--wasm-runtime-overrides /path/to/overrides`."
216
				.into(),
217
		);
218
904
	}
219
904
	Ok(())
220
904
}
221

            
222
/// Parse command line arguments into service configuration.
223
904
pub fn run() -> Result<()> {
224
904
	let mut cli = Cli::from_args();
225
904
	let _ = validate_trace_environment(&cli)?;
226
	// Set --execution wasm as default
227
904
	let execution_strategies = cli.run.base.base.import_params.execution_strategies.clone();
228
904
	if execution_strategies.execution.is_none() {
229
904
		cli.run
230
904
			.base
231
904
			.base
232
904
			.import_params
233
904
			.execution_strategies
234
904
			.execution = Some(sc_cli::ExecutionStrategy::Wasm);
235
904
	}
236

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

            
317
				// Remove Frontier offchain db
318
				let frontier_database_config = match config.database {
319
					DatabaseSource::RocksDb { .. } => DatabaseSource::RocksDb {
320
						path: frontier_database_dir(&config, "db"),
321
						cache_size: 0,
322
					},
323
					DatabaseSource::ParityDb { .. } => DatabaseSource::ParityDb {
324
						path: frontier_database_dir(&config, "paritydb"),
325
					},
326
					_ => {
327
						return Err(format!("Cannot purge `{:?}` database", config.database).into())
328
					}
329
				};
330
				cmd.base.run(frontier_database_config)?;
331

            
332
				if dev_service {
333
					// base refers to the encapsulated "regular" sc_cli::PurgeChain command
334
					return cmd.base.run(config.database);
335
				}
336

            
337
				let polkadot_cli = RelayChainCli::new(
338
					&config,
339
					[RelayChainCli::executable_name().to_string()]
340
						.iter()
341
						.chain(cli.relaychain_args.iter()),
342
				);
343

            
344
				let polkadot_config = SubstrateCli::create_configuration(
345
					&polkadot_cli,
346
					&polkadot_cli,
347
					config.tokio_handle.clone(),
348
				)
349
				.map_err(|err| format!("Relay chain argument error: {}", err))?;
350

            
351
				cmd.run(config, polkadot_config)
352
			})
353
		}
354
		Some(Subcommand::Revert(cmd)) => {
355
			let runner = cli.create_runner(cmd)?;
356
			let chain_spec = &runner.config().chain_spec;
357
			let rpc_config = cli.run.new_rpc_config();
358
			match chain_spec {
359
				#[cfg(feature = "moonriver-native")]
360
				spec if spec.is_moonriver() => runner.async_run(|mut config| {
361
					let params = moonbeam_service::new_partial::<
362
						moonbeam_service::moonriver_runtime::RuntimeApi,
363
						moonbeam_service::MoonriverCustomizations,
364
					>(&mut config, &rpc_config, false)?;
365

            
366
					Ok((
367
						cmd.run(params.client, params.backend, None),
368
						params.task_manager,
369
					))
370
				}),
371
				#[cfg(feature = "moonbeam-native")]
372
				spec if spec.is_moonbeam() => runner.async_run(|mut config| {
373
					let params = moonbeam_service::new_partial::<
374
						moonbeam_service::moonbeam_runtime::RuntimeApi,
375
						moonbeam_service::MoonbeamCustomizations,
376
					>(&mut config, &rpc_config, false)?;
377

            
378
					Ok((
379
						cmd.run(params.client, params.backend, None),
380
						params.task_manager,
381
					))
382
				}),
383
				#[cfg(feature = "moonbase-native")]
384
				_ => runner.async_run(|mut config| {
385
					let params = moonbeam_service::new_partial::<
386
						moonbeam_service::moonbase_runtime::RuntimeApi,
387
						moonbeam_service::MoonbaseCustomizations,
388
					>(&mut config, &rpc_config, false)?;
389

            
390
					Ok((
391
						cmd.run(params.client, params.backend, None),
392
						params.task_manager,
393
					))
394
				}),
395
				#[cfg(not(feature = "moonbase-native"))]
396
				_ => panic!("invalid chain spec"),
397
			}
398
		}
399
		Some(Subcommand::ExportGenesisHead(params)) => {
400
			let mut builder = sc_cli::LoggerBuilder::new("");
401
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
402
			let _ = builder.init();
403

            
404
			// Cumulus approach here, we directly call the generic load_spec func
405
			let chain_spec = load_spec(
406
				params.chain.as_deref().unwrap_or_default(),
407
				params.parachain_id.unwrap_or(1000).into(),
408
				&cli.run,
409
			)?;
410
			let state_version = Cli::runtime_version(&chain_spec).state_version();
411

            
412
			let output_buf = match chain_spec {
413
				#[cfg(feature = "moonriver-native")]
414
				chain_spec if chain_spec.is_moonriver() => {
415
					let block: moonbeam_service::moonriver_runtime::Block =
416
						generate_genesis_block(&*chain_spec, state_version)?;
417
					let raw_header = block.header().encode();
418
					let output_buf = if params.raw {
419
						raw_header
420
					} else {
421
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
422
					};
423
					output_buf
424
				}
425
				#[cfg(feature = "moonbeam-native")]
426
				chain_spec if chain_spec.is_moonbeam() => {
427
					let block: moonbeam_service::moonbeam_runtime::Block =
428
						generate_genesis_block(&*chain_spec, state_version)?;
429
					let raw_header = block.header().encode();
430
					let output_buf = if params.raw {
431
						raw_header
432
					} else {
433
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
434
					};
435
					output_buf
436
				}
437
				#[cfg(feature = "moonbase-native")]
438
				_ => {
439
					let block: moonbeam_service::moonbase_runtime::Block =
440
						generate_genesis_block(&*chain_spec, state_version)?;
441
					let raw_header = block.header().encode();
442
					let output_buf = if params.raw {
443
						raw_header
444
					} else {
445
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
446
					};
447
					output_buf
448
				}
449
				#[cfg(not(feature = "moonbase-native"))]
450
				_ => panic!("invalid chain spec"),
451
			};
452

            
453
			if let Some(output) = &params.output {
454
				std::fs::write(output, output_buf)?;
455
			} else {
456
				std::io::stdout().write_all(&output_buf)?;
457
			}
458

            
459
			Ok(())
460
		}
461
		Some(Subcommand::ExportGenesisWasm(params)) => {
462
			let mut builder = sc_cli::LoggerBuilder::new("");
463
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
464
			let _ = builder.init();
465

            
466
			let raw_wasm_blob = extract_genesis_wasm(
467
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
468
			)?;
469
			let output_buf = if params.raw {
470
				raw_wasm_blob
471
			} else {
472
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
473
			};
474

            
475
			if let Some(output) = &params.output {
476
				std::fs::write(output, output_buf)?;
477
			} else {
478
				std::io::stdout().write_all(&output_buf)?;
479
			}
480

            
481
			Ok(())
482
		}
483
		Some(Subcommand::Benchmark(cmd)) => {
484
			let runner = cli.create_runner(cmd)?;
485

            
486
			// Switch on the concrete benchmark sub-command
487
			match cmd {
488
				BenchmarkCmd::Pallet(cmd) => {
489
					if cfg!(feature = "runtime-benchmarks") {
490
						let chain_spec = &runner.config().chain_spec;
491
						match chain_spec {
492
							#[cfg(feature = "moonriver-native")]
493
							spec if spec.is_moonriver() => {
494
								return runner.sync_run(|config| {
495
									cmd.run_with_spec::<HashingFor<moonriver_runtime::Block>, HostFunctions>(
496
										Some(config.chain_spec),
497
									)
498
								})
499
							}
500
							#[cfg(feature = "moonbeam-native")]
501
							spec if spec.is_moonbeam() => {
502
								return runner.sync_run(|config| {
503
									cmd.run_with_spec::<HashingFor<moonbeam_runtime::Block>, HostFunctions>(
504
										Some(config.chain_spec),
505
									)
506
								})
507
							}
508
							#[cfg(feature = "moonbase-native")]
509
							_ => {
510
								return runner.sync_run(|config| {
511
									cmd.run_with_spec::<HashingFor<moonbase_runtime::Block>, HostFunctions>(
512
										Some(config.chain_spec),
513
									)
514
								})
515
							}
516
							#[cfg(not(feature = "moonbase-native"))]
517
							_ => panic!("invalid chain spec"),
518
						}
519
					} else if cfg!(feature = "moonbase-runtime-benchmarks") {
520
						return runner.sync_run(|config| {
521
							cmd.run_with_spec::<HashingFor<moonbeam_service::moonbase_runtime::Block>, HostFunctions>(
522
								Some(config.chain_spec),
523
							)
524
						});
525
					} else {
526
						Err("Benchmarking wasn't enabled when building the node. \
527
					You can enable it with `--features runtime-benchmarks`."
528
							.into())
529
					}
530
				}
531
				BenchmarkCmd::Block(cmd) => {
532
					let chain_spec = &runner.config().chain_spec;
533
					let rpc_config = cli.run.new_rpc_config();
534
					match chain_spec {
535
						#[cfg(feature = "moonriver-native")]
536
						spec if spec.is_moonriver() => {
537
							return runner.sync_run(|mut config| {
538
								let params = moonbeam_service::new_partial::<
539
									moonbeam_service::moonriver_runtime::RuntimeApi,
540
									moonbeam_service::MoonriverCustomizations,
541
								>(&mut config, &rpc_config, false)?;
542

            
543
								cmd.run(params.client)
544
							})
545
						}
546
						#[cfg(feature = "moonbeam-native")]
547
						spec if spec.is_moonbeam() => {
548
							return runner.sync_run(|mut config| {
549
								let params = moonbeam_service::new_partial::<
550
									moonbeam_service::moonbeam_runtime::RuntimeApi,
551
									moonbeam_service::MoonbeamCustomizations,
552
								>(&mut config, &rpc_config, false)?;
553

            
554
								cmd.run(params.client)
555
							})
556
						}
557
						#[cfg(feature = "moonbase-native")]
558
						_ => {
559
							return runner.sync_run(|mut config| {
560
								let params = moonbeam_service::new_partial::<
561
									moonbeam_service::moonbase_runtime::RuntimeApi,
562
									moonbeam_service::MoonbaseCustomizations,
563
								>(&mut config, &rpc_config, false)?;
564

            
565
								cmd.run(params.client)
566
							})
567
						}
568
						#[cfg(not(feature = "moonbase-native"))]
569
						_ => panic!("invalid chain spec"),
570
					}
571
				}
572
				#[cfg(not(feature = "runtime-benchmarks"))]
573
				BenchmarkCmd::Storage(_) => Err(
574
					"Storage benchmarking can be enabled with `--features runtime-benchmarks`."
575
						.into(),
576
				),
577
				#[cfg(feature = "runtime-benchmarks")]
578
				BenchmarkCmd::Storage(cmd) => {
579
					let chain_spec = &runner.config().chain_spec;
580
					let rpc_config = cli.run.new_rpc_config();
581
					match chain_spec {
582
						#[cfg(feature = "moonriver-native")]
583
						spec if spec.is_moonriver() => {
584
							return runner.sync_run(|mut config| {
585
								let params = moonbeam_service::new_partial::<
586
									moonbeam_service::moonriver_runtime::RuntimeApi,
587
									moonbeam_service::MoonriverCustomizations,
588
								>(&mut config, &rpc_config, false)?;
589

            
590
								let db = params.backend.expose_db();
591
								let storage = params.backend.expose_storage();
592

            
593
								cmd.run(config, params.client, db, storage)
594
							})
595
						}
596
						#[cfg(feature = "moonbeam-native")]
597
						spec if spec.is_moonbeam() => {
598
							return runner.sync_run(|mut config| {
599
								let params = moonbeam_service::new_partial::<
600
									moonbeam_service::moonbeam_runtime::RuntimeApi,
601
									moonbeam_service::MoonbeamCustomizations,
602
								>(&mut config, &rpc_config, false)?;
603

            
604
								let db = params.backend.expose_db();
605
								let storage = params.backend.expose_storage();
606

            
607
								cmd.run(config, params.client, db, storage)
608
							})
609
						}
610
						#[cfg(feature = "moonbase-native")]
611
						_ => {
612
							return runner.sync_run(|mut config| {
613
								let params = moonbeam_service::new_partial::<
614
									moonbeam_service::moonbase_runtime::RuntimeApi,
615
									moonbeam_service::MoonbaseCustomizations,
616
								>(&mut config, &rpc_config, false)?;
617

            
618
								let db = params.backend.expose_db();
619
								let storage = params.backend.expose_storage();
620

            
621
								cmd.run(config, params.client, db, storage)
622
							})
623
						}
624
						#[cfg(not(feature = "moonbase-native"))]
625
						_ => panic!("invalid chain spec"),
626
					}
627
				}
628
				BenchmarkCmd::Overhead(_) => Err("Unsupported benchmarking command".into()),
629
				BenchmarkCmd::Extrinsic(_) => Err("Unsupported benchmarking command".into()),
630
				BenchmarkCmd::Machine(cmd) => {
631
					return runner.sync_run(|config| {
632
						cmd.run(
633
							&config,
634
							frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.clone(),
635
						)
636
					});
637
				}
638
			}
639
		}
640
		Some(Subcommand::TryRuntime) => Err("The `try-runtime` subcommand has been migrated to a \
641
			standalone CLI (https://github.com/paritytech/try-runtime-cli). It is no longer \
642
			being maintained here and will be removed entirely some time after January 2024. \
643
			Please remove this subcommand from your runtime and use the standalone CLI."
644
			.into()),
645
		Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
646
2
		Some(Subcommand::PrecompileWasm(cmd)) => {
647
2
			let runner = cli.create_runner(cmd)?;
648
2
			let rpc_config = cli.run.new_rpc_config();
649
2
			runner.async_run(|mut config| match &config.chain_spec {
650
				#[cfg(feature = "moonriver-native")]
651
2
				spec if spec.is_moonriver() => {
652
					let PartialComponents {
653
						task_manager,
654
						backend,
655
						..
656
					} = moonbeam_service::new_partial::<
657
						moonbeam_service::moonriver_runtime::RuntimeApi,
658
						moonbeam_service::MoonriverCustomizations,
659
					>(&mut config, &rpc_config, false)?;
660

            
661
					Ok((cmd.run(backend, config.chain_spec), task_manager))
662
				}
663
				#[cfg(feature = "moonbeam-native")]
664
2
				spec if spec.is_moonbeam() => {
665
					let PartialComponents {
666
						task_manager,
667
						backend,
668
						..
669
					} = moonbeam_service::new_partial::<
670
						moonbeam_service::moonbeam_runtime::RuntimeApi,
671
						moonbeam_service::MoonbeamCustomizations,
672
					>(&mut config, &rpc_config, false)?;
673

            
674
					Ok((cmd.run(backend, config.chain_spec), task_manager))
675
				}
676
				#[cfg(feature = "moonbase-native")]
677
				_ => {
678
					let PartialComponents {
679
2
						task_manager,
680
2
						backend,
681
						..
682
2
					} = moonbeam_service::new_partial::<
683
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
684
2
						moonbeam_service::MoonbaseCustomizations,
685
2
					>(&mut config, &rpc_config, false)?;
686

            
687
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
688
				}
689
				#[cfg(not(feature = "moonbase-native"))]
690
				_ => panic!("invalid chain spec"),
691
2
			})
692
		}
693
		None => {
694
898
			let runner = cli.create_runner(&(*cli.run).normalize())?;
695
898
			let collator_options = cli.run.collator_options();
696
898
			runner.run_node_until_exit(|config| async move {
697
898
				let hwbench = if !cli.run.no_hardware_benchmarks {
698
					config.database.path().map(|database_path| {
699
						let _ = std::fs::create_dir_all(&database_path);
700
						sc_sysinfo::gather_hwbench(Some(database_path))
701
					})
702
				} else {
703
898
					None
704
				};
705

            
706
898
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
707
898
				let para_id = extension.map(|e| e.para_id);
708
898
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
709
898

            
710
898
				let rpc_config = cli.run.new_rpc_config();
711
898

            
712
898
				// If dev service was requested, start up manual or instant seal.
713
898
				// Otherwise continue with the normal parachain node.
714
898
				// Dev service can be requested in two ways.
715
898
				// 1. by providing the --dev-service flag to the CLI
716
898
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
717
898
				// NOTE: the --dev flag triggers the dev service by way of number 2
718
898
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
719
898
				let dev_service = cli.run.dev_service
720
898
					|| config.chain_spec.is_dev()
721
					|| relay_chain_id == Some("dev-service");
722

            
723
898
				if dev_service {
724
					// When running the dev service, just use Alice's author inherent
725
					//TODO maybe make the --alice etc flags work here, and consider bringing back
726
					// the author-id flag. For now, this will work.
727
898
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
728
898
						"Alice",
729
898
					));
730
898

            
731
898
					return match &config.chain_spec {
732
						#[cfg(feature = "moonriver-native")]
733
898
						spec if spec.is_moonriver() => moonbeam_service::new_dev::<
734
							moonbeam_service::moonriver_runtime::RuntimeApi,
735
							moonbeam_service::MoonriverCustomizations,
736
							sc_network::NetworkWorker<_, _>,
737
						>(config, author_id, cli.run.sealing, rpc_config, hwbench)
738
						.await
739
						.map_err(Into::into),
740
						#[cfg(feature = "moonbeam-native")]
741
898
						spec if spec.is_moonbeam() => moonbeam_service::new_dev::<
742
							moonbeam_service::moonbeam_runtime::RuntimeApi,
743
							moonbeam_service::MoonbeamCustomizations,
744
							sc_network::NetworkWorker<_, _>,
745
						>(config, author_id, cli.run.sealing, rpc_config, hwbench)
746
						.await
747
						.map_err(Into::into),
748
						#[cfg(feature = "moonbase-native")]
749
898
						_ => moonbeam_service::new_dev::<
750
898
							moonbeam_service::moonbase_runtime::RuntimeApi,
751
898
							moonbeam_service::MoonbaseCustomizations,
752
898
							sc_network::NetworkWorker<_, _>,
753
898
						>(config, author_id, cli.run.sealing, rpc_config, hwbench)
754
						.await
755
898
						.map_err(Into::into),
756
						#[cfg(not(feature = "moonbase-native"))]
757
						_ => panic!("invalid chain spec"),
758
					};
759
				}
760

            
761
				let polkadot_cli = RelayChainCli::new(
762
					&config,
763
					[RelayChainCli::executable_name().to_string()]
764
						.iter()
765
						.chain(cli.relaychain_args.iter()),
766
				);
767

            
768
				let parachain_account =
769
					AccountIdConversion::<polkadot_primitives::v7::AccountId>::into_account_truncating(&id);
770

            
771
				let tokio_handle = config.tokio_handle.clone();
772
				let polkadot_config =
773
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
774
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
775

            
776
				info!("Parachain Account: {}", parachain_account);
777
				info!(
778
					"Is collating: {}",
779
					if config.role.is_authority() {
780
						"yes"
781
					} else {
782
						"no"
783
					}
784
				);
785

            
786
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
787
					warn!(
788
						"Detected relay chain node arguments together with \
789
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
790
					uses a network-related subset of all relay chain CLI options."
791
					);
792
				}
793

            
794
				match &config.chain_spec {
795
					#[cfg(feature = "moonriver-native")]
796
					spec if spec.is_moonriver() => moonbeam_service::start_node::<
797
						moonbeam_service::moonriver_runtime::RuntimeApi,
798
						moonbeam_service::MoonriverCustomizations,
799
					>(
800
						config,
801
						polkadot_config,
802
						collator_options,
803
						id,
804
						rpc_config,
805
						true,
806
						cli.run.block_authoring_duration,
807
						hwbench,
808
					)
809
					.await
810
					.map(|r| r.0)
811
					.map_err(Into::into),
812
					#[cfg(feature = "moonbeam-native")]
813
					spec if spec.is_moonbeam() => moonbeam_service::start_node::<
814
						moonbeam_service::moonbeam_runtime::RuntimeApi,
815
						moonbeam_service::MoonbeamCustomizations,
816
					>(
817
						config,
818
						polkadot_config,
819
						collator_options,
820
						id,
821
						rpc_config,
822
						true,
823
						cli.run.block_authoring_duration,
824
						hwbench,
825
					)
826
					.await
827
					.map(|r| r.0)
828
					.map_err(Into::into),
829
					#[cfg(feature = "moonbase-native")]
830
					_ => moonbeam_service::start_node::<
831
						moonbeam_service::moonbase_runtime::RuntimeApi,
832
						moonbeam_service::MoonbaseCustomizations,
833
					>(
834
						config,
835
						polkadot_config,
836
						collator_options,
837
						id,
838
						rpc_config,
839
						true,
840
						cli.run.block_authoring_duration,
841
						hwbench,
842
					)
843
					.await
844
					.map(|r| r.0)
845
					.map_err(Into::into),
846
					#[cfg(not(feature = "moonbase-native"))]
847
					_ => panic!("invalid chain spec"),
848
				}
849
1796
			})
850
		}
851
	}
852
904
}
853

            
854
impl DefaultConfigurationValues for RelayChainCli {
855
	fn p2p_listen_port() -> u16 {
856
		30334
857
	}
858

            
859
	fn rpc_listen_port() -> u16 {
860
		9945
861
	}
862

            
863
	fn prometheus_listen_port() -> u16 {
864
		9616
865
	}
866
}
867

            
868
impl CliConfiguration<Self> for RelayChainCli {
869
	fn shared_params(&self) -> &SharedParams {
870
		self.base.base.shared_params()
871
	}
872

            
873
	fn import_params(&self) -> Option<&ImportParams> {
874
		self.base.base.import_params()
875
	}
876

            
877
	fn network_params(&self) -> Option<&NetworkParams> {
878
		self.base.base.network_params()
879
	}
880

            
881
	fn keystore_params(&self) -> Option<&KeystoreParams> {
882
		self.base.base.keystore_params()
883
	}
884

            
885
	fn base_path(&self) -> Result<Option<BasePath>> {
886
		Ok(self
887
			.shared_params()
888
			.base_path()?
889
			.or_else(|| Some(self.base_path.clone().into())))
890
	}
891

            
892
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {
893
		self.base.base.rpc_addr(default_listen_port)
894
	}
895

            
896
	fn prometheus_config(
897
		&self,
898
		default_listen_port: u16,
899
		chain_spec: &Box<dyn ChainSpec>,
900
	) -> Result<Option<PrometheusConfig>> {
901
		self.base
902
			.base
903
			.prometheus_config(default_listen_port, chain_spec)
904
	}
905

            
906
	fn init<F>(
907
		&self,
908
		_support_url: &String,
909
		_impl_version: &String,
910
		_logger_hook: F,
911
		_config: &sc_service::Configuration,
912
	) -> Result<()>
913
	where
914
		F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration),
915
	{
916
		unreachable!("PolkadotCli is never initialized; qed");
917
	}
918

            
919
	fn chain_id(&self, is_dev: bool) -> Result<String> {
920
		let chain_id = self.base.base.chain_id(is_dev)?;
921

            
922
		Ok(if chain_id.is_empty() {
923
			self.chain_id.clone().unwrap_or_default()
924
		} else {
925
			chain_id
926
		})
927
	}
928

            
929
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
930
		self.base.base.role(is_dev)
931
	}
932

            
933
	fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
934
		self.base.base.transaction_pool(is_dev)
935
	}
936

            
937
	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
938
		self.base.base.rpc_methods()
939
	}
940

            
941
	fn rpc_max_connections(&self) -> Result<u32> {
942
		self.base.base.rpc_max_connections()
943
	}
944

            
945
	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
946
		self.base.base.rpc_cors(is_dev)
947
	}
948

            
949
	// fn telemetry_external_transport(&self) -> Result<Option<sc_service::config::ExtTransport>> {
950
	// 	self.base.base.telemetry_external_transport()
951
	// }
952

            
953
	fn default_heap_pages(&self) -> Result<Option<u64>> {
954
		self.base.base.default_heap_pages()
955
	}
956

            
957
	fn force_authoring(&self) -> Result<bool> {
958
		self.base.base.force_authoring()
959
	}
960

            
961
	fn disable_grandpa(&self) -> Result<bool> {
962
		self.base.base.disable_grandpa()
963
	}
964

            
965
	fn max_runtime_instances(&self) -> Result<Option<usize>> {
966
		self.base.base.max_runtime_instances()
967
	}
968

            
969
	fn announce_block(&self) -> Result<bool> {
970
		self.base.base.announce_block()
971
	}
972
}
973

            
974
/// Generate the genesis block from a given ChainSpec.
975
pub fn generate_genesis_block<Block: BlockT>(
976
	chain_spec: &dyn ChainSpec,
977
	genesis_state_version: StateVersion,
978
) -> std::result::Result<Block, String> {
979
	let storage = chain_spec.build_storage()?;
980

            
981
	let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
982
		let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
983
			child_content.data.clone().into_iter().collect(),
984
			genesis_state_version,
985
		);
986
		(sk.clone(), state_root.encode())
987
	});
988
	let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
989
		storage.top.clone().into_iter().chain(child_roots).collect(),
990
		genesis_state_version,
991
	);
992

            
993
	let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
994
		Vec::new(),
995
		genesis_state_version,
996
	);
997

            
998
	Ok(Block::new(
999
		<<Block as BlockT>::Header as HeaderT>::new(
			Zero::zero(),
			extrinsics_root,
			state_root,
			Default::default(),
			Default::default(),
		),
		Default::default(),
	))
}