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
900
fn load_spec(
50
900
	id: &str,
51
900
	para_id: ParaId,
52
900
	run_cmd: &RunCmd,
53
900
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
54
900
	Ok(match id {
55
900
		// Moonbase networks
56
900
		"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
900
		"moonbase-local" => Box::new(chain_spec::moonbase::get_chain_spec(para_id)),
61
		#[cfg(feature = "moonbase-native")]
62
900
		"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
898
		"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
898
		"moonriver-dev" => Box::new(chain_spec::moonriver::development_chain_spec(None, None)),
73
		#[cfg(feature = "moonriver-native")]
74
898
		"moonriver-local" => Box::new(chain_spec::moonriver::get_chain_spec(para_id)),
75

            
76
		// Moonbeam networks
77
898
		"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
898
		"moonbeam-dev" => Box::new(chain_spec::moonbeam::development_chain_spec(None, None)),
82
		#[cfg(feature = "moonbeam-native")]
83
898
		"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
898
		path => {
91
898
			let path = std::path::PathBuf::from(path);
92
898

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

            
99
898
			if run_cmd.force_moonbase || starts_with("moonbase") {
100
898
				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
900
}
109

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

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

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

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

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

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

            
141
900
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
142
900
		load_spec(id, self.run.parachain_id.unwrap_or(1000).into(), &self.run)
143
900
	}
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/moonbeam-foundation/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
900
fn validate_trace_environment(cli: &Cli) -> Result<()> {
205
900
	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
900
	}
219
900
	Ok(())
220
900
}
221

            
222
/// Parse command line arguments into service configuration.
223
900
pub fn run() -> Result<()> {
224
900
	let cli = Cli::from_args();
225
900
	let _ = validate_trace_environment(&cli)?;
226

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

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

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

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

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

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

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

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

            
380
					Ok((
381
						cmd.run(params.client, params.backend, None),
382
						params.task_manager,
383
					))
384
				}),
385
				#[cfg(not(feature = "moonbase-native"))]
386
				_ => panic!("invalid chain spec"),
387
			}
388
		}
389
		Some(Subcommand::ExportGenesisHead(params)) => {
390
			let mut builder = sc_cli::LoggerBuilder::new("");
391
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
392
			let _ = builder.init();
393

            
394
			// Cumulus approach here, we directly call the generic load_spec func
395
			let chain_spec = load_spec(
396
				params.chain.as_deref().unwrap_or_default(),
397
				params.parachain_id.unwrap_or(1000).into(),
398
				&cli.run,
399
			)?;
400
			let state_version = Cli::runtime_version(&chain_spec).state_version();
401

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

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

            
449
			Ok(())
450
		}
451
		Some(Subcommand::ExportGenesisWasm(params)) => {
452
			let mut builder = sc_cli::LoggerBuilder::new("");
453
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
454
			let _ = builder.init();
455

            
456
			let raw_wasm_blob = extract_genesis_wasm(
457
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
458
			)?;
459
			let output_buf = if params.raw {
460
				raw_wasm_blob
461
			} else {
462
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
463
			};
464

            
465
			if let Some(output) = &params.output {
466
				std::fs::write(output, output_buf)?;
467
			} else {
468
				std::io::stdout().write_all(&output_buf)?;
469
			}
470

            
471
			Ok(())
472
		}
473
		Some(Subcommand::Benchmark(cmd)) => {
474
			let runner = cli.create_runner(cmd)?;
475

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

            
533
								cmd.run(params.client)
534
							})
535
						}
536
						#[cfg(feature = "moonbeam-native")]
537
						spec if spec.is_moonbeam() => {
538
							return runner.sync_run(|mut config| {
539
								let params = moonbeam_service::new_partial::<
540
									moonbeam_service::moonbeam_runtime::RuntimeApi,
541
									moonbeam_service::MoonbeamCustomizations,
542
								>(&mut config, &rpc_config, false)?;
543

            
544
								cmd.run(params.client)
545
							})
546
						}
547
						#[cfg(feature = "moonbase-native")]
548
						_ => {
549
							return runner.sync_run(|mut config| {
550
								let params = moonbeam_service::new_partial::<
551
									moonbeam_service::moonbase_runtime::RuntimeApi,
552
									moonbeam_service::MoonbaseCustomizations,
553
								>(&mut config, &rpc_config, false)?;
554

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

            
580
								let db = params.backend.expose_db();
581
								let storage = params.backend.expose_storage();
582

            
583
								cmd.run(config, params.client, db, storage)
584
							})
585
						}
586
						#[cfg(feature = "moonbeam-native")]
587
						spec if spec.is_moonbeam() => {
588
							return runner.sync_run(|mut config| {
589
								let params = moonbeam_service::new_partial::<
590
									moonbeam_service::moonbeam_runtime::RuntimeApi,
591
									moonbeam_service::MoonbeamCustomizations,
592
								>(&mut config, &rpc_config, false)?;
593

            
594
								let db = params.backend.expose_db();
595
								let storage = params.backend.expose_storage();
596

            
597
								cmd.run(config, params.client, db, storage)
598
							})
599
						}
600
						#[cfg(feature = "moonbase-native")]
601
						_ => {
602
							return runner.sync_run(|mut config| {
603
								let params = moonbeam_service::new_partial::<
604
									moonbeam_service::moonbase_runtime::RuntimeApi,
605
									moonbeam_service::MoonbaseCustomizations,
606
								>(&mut config, &rpc_config, false)?;
607

            
608
								let db = params.backend.expose_db();
609
								let storage = params.backend.expose_storage();
610

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

            
651
					Ok((cmd.run(backend, config.chain_spec), task_manager))
652
				}
653
				#[cfg(feature = "moonbeam-native")]
654
2
				spec if spec.is_moonbeam() => {
655
					let PartialComponents {
656
						task_manager,
657
						backend,
658
						..
659
					} = moonbeam_service::new_partial::<
660
						moonbeam_service::moonbeam_runtime::RuntimeApi,
661
						moonbeam_service::MoonbeamCustomizations,
662
					>(&mut config, &rpc_config, false)?;
663

            
664
					Ok((cmd.run(backend, config.chain_spec), task_manager))
665
				}
666
				#[cfg(feature = "moonbase-native")]
667
				_ => {
668
					let PartialComponents {
669
2
						task_manager,
670
2
						backend,
671
						..
672
2
					} = moonbeam_service::new_partial::<
673
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
674
2
						moonbeam_service::MoonbaseCustomizations,
675
2
					>(&mut config, &rpc_config, false)?;
676

            
677
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
678
				}
679
				#[cfg(not(feature = "moonbase-native"))]
680
				_ => panic!("invalid chain spec"),
681
2
			})
682
		}
683
		None => {
684
894
			let runner = cli.create_runner(&(*cli.run).normalize())?;
685
894
			let collator_options = cli.run.collator_options();
686
894

            
687
894
			runner.run_node_until_exit(|mut config| async move {
688
894
				let hwbench = if !cli.run.no_hardware_benchmarks {
689
					config.database.path().map(|database_path| {
690
						let _ = std::fs::create_dir_all(&database_path);
691
						sc_sysinfo::gather_hwbench(Some(database_path))
692
					})
693
				} else {
694
894
					None
695
				};
696

            
697
894
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
698
894

            
699
894
				let rpc_config = cli.run.new_rpc_config();
700
894

            
701
894
				// If dev service was requested, start up manual or instant seal.
702
894
				// Otherwise continue with the normal parachain node.
703
894
				// Dev service can be requested in two ways.
704
894
				// 1. by providing the --dev-service flag to the CLI
705
894
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
706
894
				// NOTE: the --dev flag triggers the dev service by way of number 2
707
894
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
708
894
				let para_id = extension.map(|e| e.para_id);
709

            
710
894
				let dev_service = cli.run.dev_service
711
894
					|| config.chain_spec.is_dev()
712
					|| relay_chain_id == Some("dev-service");
713
894
				if dev_service {
714
					// When running the dev service, just use Alice's author inherent
715
					//TODO maybe make the --alice etc flags work here, and consider bringing back
716
					// the author-id flag. For now, this will work.
717
894
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
718
894
						"Alice",
719
894
					));
720
894

            
721
894
					return match &config.chain_spec {
722
						#[cfg(feature = "moonriver-native")]
723
894
						spec if spec.is_moonriver() => moonbeam_service::new_dev::<
724
							moonbeam_service::moonriver_runtime::RuntimeApi,
725
							moonbeam_service::MoonriverCustomizations,
726
							sc_network::NetworkWorker<_, _>,
727
						>(
728
							config,
729
							para_id,
730
							author_id,
731
							cli.run.sealing,
732
							rpc_config,
733
							hwbench,
734
						)
735
						.await
736
						.map_err(Into::into),
737
						#[cfg(feature = "moonbeam-native")]
738
894
						spec if spec.is_moonbeam() => moonbeam_service::new_dev::<
739
							moonbeam_service::moonbeam_runtime::RuntimeApi,
740
							moonbeam_service::MoonbeamCustomizations,
741
							sc_network::NetworkWorker<_, _>,
742
						>(
743
							config,
744
							para_id,
745
							author_id,
746
							cli.run.sealing,
747
							rpc_config,
748
							hwbench,
749
						)
750
						.await
751
						.map_err(Into::into),
752
						#[cfg(feature = "moonbase-native")]
753
894
						_ => moonbeam_service::new_dev::<
754
894
							moonbeam_service::moonbase_runtime::RuntimeApi,
755
894
							moonbeam_service::MoonbaseCustomizations,
756
894
							sc_network::NetworkWorker<_, _>,
757
894
						>(
758
894
							config,
759
894
							para_id,
760
894
							author_id,
761
894
							cli.run.sealing,
762
894
							rpc_config,
763
894
							hwbench,
764
894
						)
765
						.await
766
894
						.map_err(Into::into),
767
						#[cfg(not(feature = "moonbase-native"))]
768
						_ => panic!("invalid chain spec"),
769
					};
770
				}
771
				#[cfg(feature = "lazy-loading")]
772
				if let Some(fork_chain_from_rpc) = cli.run.fork_chain_from_rpc {
773
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
774
						"Alice",
775
					));
776

            
777
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
778
						state_rpc: fork_chain_from_rpc,
779
						from_block: cli.run.block,
780
						state_overrides_path: cli.run.fork_state_overrides,
781
						runtime_override: cli.run.runtime_override,
782
					};
783

            
784
					let spec_builder =
785
						chain_spec::test_spec::lazy_loading_spec_builder(Default::default());
786
					config.chain_spec = Box::new(spec_builder.build());
787

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

            
792
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
793
						moonbeam_runtime::RuntimeApi,
794
						moonbeam_service::MoonbeamCustomizations,
795
						sc_network::NetworkWorker<_, _>,
796
					>(
797
						config,
798
						author_id,
799
						cli.run.sealing,
800
						rpc_config,
801
						lazy_loading_config,
802
						hwbench,
803
					)
804
					.await
805
					.map_err(Into::into);
806
				}
807

            
808
				let polkadot_cli = RelayChainCli::new(
809
					&config,
810
					[RelayChainCli::executable_name().to_string()]
811
						.iter()
812
						.chain(cli.relaychain_args.iter()),
813
				);
814

            
815
				let para_id = extension.map(|e| e.para_id);
816
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
817

            
818
				let parachain_account =
819
					AccountIdConversion::<polkadot_primitives::v7::AccountId>::into_account_truncating(&id);
820

            
821
				let tokio_handle = config.tokio_handle.clone();
822
				let polkadot_config =
823
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
824
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
825

            
826
				info!("Parachain Account: {}", parachain_account);
827
				info!(
828
					"Is collating: {}",
829
					if config.role.is_authority() {
830
						"yes"
831
					} else {
832
						"no"
833
					}
834
				);
835

            
836
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
837
					warn!(
838
						"Detected relay chain node arguments together with \
839
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
840
					uses a network-related subset of all relay chain CLI options."
841
					);
842
				}
843

            
844
				match &config.chain_spec {
845
					#[cfg(feature = "moonriver-native")]
846
					spec if spec.is_moonriver() => moonbeam_service::start_node::<
847
						moonbeam_service::moonriver_runtime::RuntimeApi,
848
						moonbeam_service::MoonriverCustomizations,
849
					>(
850
						config,
851
						polkadot_config,
852
						collator_options,
853
						id,
854
						rpc_config,
855
						true,
856
						cli.run.block_authoring_duration,
857
						hwbench,
858
					)
859
					.await
860
					.map(|r| r.0)
861
					.map_err(Into::into),
862
					#[cfg(feature = "moonbeam-native")]
863
					spec if spec.is_moonbeam() => moonbeam_service::start_node::<
864
						moonbeam_service::moonbeam_runtime::RuntimeApi,
865
						moonbeam_service::MoonbeamCustomizations,
866
					>(
867
						config,
868
						polkadot_config,
869
						collator_options,
870
						id,
871
						rpc_config,
872
						true,
873
						cli.run.block_authoring_duration,
874
						hwbench,
875
					)
876
					.await
877
					.map(|r| r.0)
878
					.map_err(Into::into),
879
					#[cfg(feature = "moonbase-native")]
880
					_ => moonbeam_service::start_node::<
881
						moonbeam_service::moonbase_runtime::RuntimeApi,
882
						moonbeam_service::MoonbaseCustomizations,
883
					>(
884
						config,
885
						polkadot_config,
886
						collator_options,
887
						id,
888
						rpc_config,
889
						true,
890
						cli.run.block_authoring_duration,
891
						hwbench,
892
					)
893
					.await
894
					.map(|r| r.0)
895
					.map_err(Into::into),
896
					#[cfg(not(feature = "moonbase-native"))]
897
					_ => panic!("invalid chain spec"),
898
				}
899
1788
			})
900
		}
901
	}
902
900
}
903

            
904
impl DefaultConfigurationValues for RelayChainCli {
905
	fn p2p_listen_port() -> u16 {
906
		30334
907
	}
908

            
909
	fn rpc_listen_port() -> u16 {
910
		9945
911
	}
912

            
913
	fn prometheus_listen_port() -> u16 {
914
		9616
915
	}
916
}
917

            
918
impl CliConfiguration<Self> for RelayChainCli {
919
	fn shared_params(&self) -> &SharedParams {
920
		self.base.base.shared_params()
921
	}
922

            
923
	fn import_params(&self) -> Option<&ImportParams> {
924
		self.base.base.import_params()
925
	}
926

            
927
	fn network_params(&self) -> Option<&NetworkParams> {
928
		self.base.base.network_params()
929
	}
930

            
931
	fn keystore_params(&self) -> Option<&KeystoreParams> {
932
		self.base.base.keystore_params()
933
	}
934

            
935
	fn base_path(&self) -> Result<Option<BasePath>> {
936
		Ok(self
937
			.shared_params()
938
			.base_path()?
939
			.or_else(|| Some(self.base_path.clone().into())))
940
	}
941

            
942
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {
943
		self.base.base.rpc_addr(default_listen_port)
944
	}
945

            
946
	fn prometheus_config(
947
		&self,
948
		default_listen_port: u16,
949
		chain_spec: &Box<dyn ChainSpec>,
950
	) -> Result<Option<PrometheusConfig>> {
951
		self.base
952
			.base
953
			.prometheus_config(default_listen_port, chain_spec)
954
	}
955

            
956
	fn init<F>(
957
		&self,
958
		_support_url: &String,
959
		_impl_version: &String,
960
		_logger_hook: F,
961
		_config: &sc_service::Configuration,
962
	) -> Result<()>
963
	where
964
		F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration),
965
	{
966
		unreachable!("PolkadotCli is never initialized; qed");
967
	}
968

            
969
	fn chain_id(&self, is_dev: bool) -> Result<String> {
970
		let chain_id = self.base.base.chain_id(is_dev)?;
971

            
972
		Ok(if chain_id.is_empty() {
973
			self.chain_id.clone().unwrap_or_default()
974
		} else {
975
			chain_id
976
		})
977
	}
978

            
979
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
980
		self.base.base.role(is_dev)
981
	}
982

            
983
	fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
984
		self.base.base.transaction_pool(is_dev)
985
	}
986

            
987
	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
988
		self.base.base.rpc_methods()
989
	}
990

            
991
	fn rpc_max_connections(&self) -> Result<u32> {
992
		self.base.base.rpc_max_connections()
993
	}
994

            
995
	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
996
		self.base.base.rpc_cors(is_dev)
997
	}
998

            
999
	// fn telemetry_external_transport(&self) -> Result<Option<sc_service::config::ExtTransport>> {
	// 	self.base.base.telemetry_external_transport()
	// }
	fn default_heap_pages(&self) -> Result<Option<u64>> {
		self.base.base.default_heap_pages()
	}
	fn force_authoring(&self) -> Result<bool> {
		self.base.base.force_authoring()
	}
	fn disable_grandpa(&self) -> Result<bool> {
		self.base.base.disable_grandpa()
	}
	fn max_runtime_instances(&self) -> Result<Option<usize>> {
		self.base.base.max_runtime_instances()
	}
	fn announce_block(&self) -> Result<bool> {
		self.base.base.announce_block()
	}
}
/// Generate the genesis block from a given ChainSpec.
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(),
	))
}