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::{chain_spec, frontier_database_dir, HostFunctions, IdentifyVariant};
34
use parity_scale_codec::Encode;
35
#[cfg(feature = "westend-native")]
36
use polkadot_service::WestendChainSpec;
37
use sc_cli::{
38
	ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
39
	NetworkParams, Result, RpcEndpoint, RuntimeVersion, 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
940
fn load_spec(
55
940
	id: &str,
56
940
	para_id: ParaId,
57
940
	run_cmd: &RunCmd,
58
940
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
59
940
	Ok(match id {
60
940
		// Moonbase networks
61
940
		"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
940
		"moonbase-local" => Box::new(chain_spec::moonbase::get_chain_spec(para_id)),
66
		#[cfg(feature = "moonbase-native")]
67
940
		"moonbase-dev" | "dev" | "development" => {
68
2
			Box::new(chain_spec::moonbase::development_chain_spec(None, None))
69
		}
70
		#[cfg(feature = "moonbeam-native")]
71
938
		"staking" => Box::new(chain_spec::test_spec::staking_spec(para_id)),
72
		// Moonriver networks
73
938
		"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
938
		"moonriver-dev" => Box::new(chain_spec::moonriver::development_chain_spec(None, None)),
78
		#[cfg(feature = "moonriver-native")]
79
938
		"moonriver-local" => Box::new(chain_spec::moonriver::get_chain_spec(para_id)),
80

            
81
		// Moonbeam networks
82
938
		"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
938
		"moonbeam-dev" => Box::new(chain_spec::moonbeam::development_chain_spec(None, None)),
87
		#[cfg(feature = "moonbeam-native")]
88
938
		"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
938
		path => {
96
938
			let path = std::path::PathBuf::from(path);
97
938

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

            
104
938
			if run_cmd.force_moonbase || starts_with("moonbase") {
105
938
				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
940
}
114

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

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

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

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

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

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

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

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

            
166
impl SubstrateCli for RelayChainCli {
167
	fn impl_name() -> String {
168
		"Moonbeam Parachain Collator".into()
169
	}
170

            
171
	fn impl_version() -> String {
172
		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
173
	}
174

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

            
183
	fn author() -> String {
184
		env!("CARGO_PKG_AUTHORS").into()
185
	}
186

            
187
	fn support_url() -> String {
188
		"https://github.com/moonbeam-foundation/moonbeam/issues/new".into()
189
	}
190

            
191
	fn copyright_start_year() -> i32 {
192
		2019
193
	}
194

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

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

            
227
/// Parse command line arguments into service configuration.
228
940
pub fn run() -> Result<()> {
229
940
	let cli = Cli::from_args();
230
940
	let _ = validate_trace_environment(&cli)?;
231

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

            
324
				// Remove Frontier offchain db
325
				let frontier_database_config = match config.database {
326
					DatabaseSource::RocksDb { .. } => DatabaseSource::RocksDb {
327
						path: frontier_database_dir(&config, "db"),
328
						cache_size: 0,
329
					},
330
					DatabaseSource::ParityDb { .. } => DatabaseSource::ParityDb {
331
						path: frontier_database_dir(&config, "paritydb"),
332
					},
333
					_ => {
334
						return Err(format!("Cannot purge `{:?}` database", config.database).into())
335
					}
336
				};
337
				cmd.base.run(frontier_database_config)?;
338

            
339
				if dev_service {
340
					// base refers to the encapsulated "regular" sc_cli::PurgeChain command
341
					return cmd.base.run(config.database);
342
				}
343

            
344
				let polkadot_cli = RelayChainCli::new(
345
					&config,
346
					[RelayChainCli::executable_name().to_string()]
347
						.iter()
348
						.chain(cli.relaychain_args.iter()),
349
				);
350

            
351
				let polkadot_config = SubstrateCli::create_configuration(
352
					&polkadot_cli,
353
					&polkadot_cli,
354
					config.tokio_handle.clone(),
355
				)
356
				.map_err(|err| format!("Relay chain argument error: {}", err))?;
357

            
358
				cmd.run(config, polkadot_config)
359
			})
360
		}
361
		Some(Subcommand::Revert(cmd)) => {
362
			let runner = cli.create_runner(cmd)?;
363
			let chain_spec = &runner.config().chain_spec;
364
			let rpc_config = cli.run.new_rpc_config();
365
			match chain_spec {
366
				#[cfg(feature = "moonriver-native")]
367
				spec if spec.is_moonriver() => runner.async_run(|mut config| {
368
					let params = moonbeam_service::new_partial::<
369
						moonbeam_service::moonriver_runtime::RuntimeApi,
370
						moonbeam_service::MoonriverCustomizations,
371
					>(
372
						&mut config,
373
						&rpc_config,
374
						false,
375
						cli.run.legacy_block_import_strategy,
376
					)?;
377

            
378
					Ok((
379
						cmd.run(params.client, params.backend, None),
380
						params.task_manager,
381
					))
382
				}),
383
				#[cfg(feature = "moonbeam-native")]
384
				spec if spec.is_moonbeam() => runner.async_run(|mut config| {
385
					let params = moonbeam_service::new_partial::<
386
						moonbeam_service::moonbeam_runtime::RuntimeApi,
387
						moonbeam_service::MoonbeamCustomizations,
388
					>(
389
						&mut config,
390
						&rpc_config,
391
						false,
392
						cli.run.legacy_block_import_strategy,
393
					)?;
394

            
395
					Ok((
396
						cmd.run(params.client, params.backend, None),
397
						params.task_manager,
398
					))
399
				}),
400
				#[cfg(feature = "moonbase-native")]
401
				_ => runner.async_run(|mut config| {
402
					let params = moonbeam_service::new_partial::<
403
						moonbeam_service::moonbase_runtime::RuntimeApi,
404
						moonbeam_service::MoonbaseCustomizations,
405
					>(
406
						&mut config,
407
						&rpc_config,
408
						false,
409
						cli.run.legacy_block_import_strategy,
410
					)?;
411

            
412
					Ok((
413
						cmd.run(params.client, params.backend, None),
414
						params.task_manager,
415
					))
416
				}),
417
				#[cfg(not(feature = "moonbase-native"))]
418
				_ => panic!("invalid chain spec"),
419
			}
420
		}
421
		Some(Subcommand::ExportGenesisHead(params)) => {
422
			let mut builder = sc_cli::LoggerBuilder::new("");
423
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
424
			let _ = builder.init();
425

            
426
			// Cumulus approach here, we directly call the generic load_spec func
427
			let chain_spec = load_spec(
428
				params.chain.as_deref().unwrap_or_default(),
429
				params.parachain_id.unwrap_or(1000).into(),
430
				&cli.run,
431
			)?;
432
			let state_version = Cli::runtime_version(&chain_spec).state_version();
433

            
434
			let output_buf = match chain_spec {
435
				#[cfg(feature = "moonriver-native")]
436
				chain_spec if chain_spec.is_moonriver() => {
437
					let block: moonbeam_service::moonriver_runtime::Block =
438
						generate_genesis_block(&*chain_spec, state_version)?;
439
					let raw_header = block.header().encode();
440
					let output_buf = if params.raw {
441
						raw_header
442
					} else {
443
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
444
					};
445
					output_buf
446
				}
447
				#[cfg(feature = "moonbeam-native")]
448
				chain_spec if chain_spec.is_moonbeam() => {
449
					let block: moonbeam_service::moonbeam_runtime::Block =
450
						generate_genesis_block(&*chain_spec, state_version)?;
451
					let raw_header = block.header().encode();
452
					let output_buf = if params.raw {
453
						raw_header
454
					} else {
455
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
456
					};
457
					output_buf
458
				}
459
				#[cfg(feature = "moonbase-native")]
460
				_ => {
461
					let block: moonbeam_service::moonbase_runtime::Block =
462
						generate_genesis_block(&*chain_spec, state_version)?;
463
					let raw_header = block.header().encode();
464
					let output_buf = if params.raw {
465
						raw_header
466
					} else {
467
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
468
					};
469
					output_buf
470
				}
471
				#[cfg(not(feature = "moonbase-native"))]
472
				_ => panic!("invalid chain spec"),
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::ExportGenesisWasm(params)) => {
484
			let mut builder = sc_cli::LoggerBuilder::new("");
485
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
486
			let _ = builder.init();
487

            
488
			let raw_wasm_blob = extract_genesis_wasm(
489
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
490
			)?;
491
			let output_buf = if params.raw {
492
				raw_wasm_blob
493
			} else {
494
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
495
			};
496

            
497
			if let Some(output) = &params.output {
498
				std::fs::write(output, output_buf)?;
499
			} else {
500
				std::io::stdout().write_all(&output_buf)?;
501
			}
502

            
503
			Ok(())
504
		}
505
		Some(Subcommand::Benchmark(cmd)) => {
506
			let runner = cli.create_runner(cmd)?;
507

            
508
			// Switch on the concrete benchmark sub-command
509
			match cmd {
510
				BenchmarkCmd::Pallet(cmd) => {
511
					if cfg!(feature = "runtime-benchmarks") {
512
						let chain_spec = &runner.config().chain_spec;
513
						match chain_spec {
514
							#[cfg(feature = "moonriver-native")]
515
							spec if spec.is_moonriver() => {
516
								return runner.sync_run(|config| {
517
									cmd.run_with_spec::<HashingFor<moonriver_runtime::Block>, HostFunctions>(
518
										Some(config.chain_spec),
519
									)
520
								})
521
							}
522
							#[cfg(feature = "moonbeam-native")]
523
							spec if spec.is_moonbeam() => {
524
								return runner.sync_run(|config| {
525
									cmd.run_with_spec::<HashingFor<moonbeam_runtime::Block>, HostFunctions>(
526
										Some(config.chain_spec),
527
									)
528
								})
529
							}
530
							#[cfg(feature = "moonbase-native")]
531
							_ => {
532
								return runner.sync_run(|config| {
533
									cmd.run_with_spec::<HashingFor<moonbase_runtime::Block>, HostFunctions>(
534
										Some(config.chain_spec),
535
									)
536
								})
537
							}
538
							#[cfg(not(feature = "moonbase-native"))]
539
							_ => panic!("invalid chain spec"),
540
						}
541
					} else {
542
						Err("Benchmarking wasn't enabled when building the node. \
543
					You can enable it with `--features runtime-benchmarks`."
544
							.into())
545
					}
546
				}
547
				BenchmarkCmd::Block(cmd) => {
548
					let chain_spec = &runner.config().chain_spec;
549
					let rpc_config = cli.run.new_rpc_config();
550
					match chain_spec {
551
						#[cfg(feature = "moonriver-native")]
552
						spec if spec.is_moonriver() => {
553
							return runner.sync_run(|mut config| {
554
								let params = moonbeam_service::new_partial::<
555
									moonbeam_service::moonriver_runtime::RuntimeApi,
556
									moonbeam_service::MoonriverCustomizations,
557
								>(
558
									&mut config,
559
									&rpc_config,
560
									false,
561
									cli.run.legacy_block_import_strategy,
562
								)?;
563

            
564
								cmd.run(params.client)
565
							})
566
						}
567
						#[cfg(feature = "moonbeam-native")]
568
						spec if spec.is_moonbeam() => {
569
							return runner.sync_run(|mut config| {
570
								let params = moonbeam_service::new_partial::<
571
									moonbeam_service::moonbeam_runtime::RuntimeApi,
572
									moonbeam_service::MoonbeamCustomizations,
573
								>(
574
									&mut config,
575
									&rpc_config,
576
									false,
577
									cli.run.legacy_block_import_strategy,
578
								)?;
579

            
580
								cmd.run(params.client)
581
							})
582
						}
583
						#[cfg(feature = "moonbase-native")]
584
						_ => {
585
							return runner.sync_run(|mut config| {
586
								let params = moonbeam_service::new_partial::<
587
									moonbeam_service::moonbase_runtime::RuntimeApi,
588
									moonbeam_service::MoonbaseCustomizations,
589
								>(
590
									&mut config,
591
									&rpc_config,
592
									false,
593
									cli.run.legacy_block_import_strategy,
594
								)?;
595

            
596
								cmd.run(params.client)
597
							})
598
						}
599
						#[cfg(not(feature = "moonbase-native"))]
600
						_ => panic!("invalid chain spec"),
601
					}
602
				}
603
				#[cfg(not(feature = "runtime-benchmarks"))]
604
				BenchmarkCmd::Storage(_) => Err(
605
					"Storage benchmarking can be enabled with `--features runtime-benchmarks`."
606
						.into(),
607
				),
608
				#[cfg(feature = "runtime-benchmarks")]
609
				BenchmarkCmd::Storage(cmd) => {
610
					let chain_spec = &runner.config().chain_spec;
611
					let rpc_config = cli.run.new_rpc_config();
612
					match chain_spec {
613
						#[cfg(feature = "moonriver-native")]
614
						spec if spec.is_moonriver() => {
615
							return runner.sync_run(|mut config| {
616
								let params = moonbeam_service::new_partial::<
617
									moonbeam_service::moonriver_runtime::RuntimeApi,
618
									moonbeam_service::MoonriverCustomizations,
619
								>(
620
									&mut config,
621
									&rpc_config,
622
									false,
623
									cli.run.legacy_block_import_strategy,
624
								)?;
625

            
626
								let db = params.backend.expose_db();
627
								let storage = params.backend.expose_storage();
628

            
629
								cmd.run(config, params.client, db, storage)
630
							})
631
						}
632
						#[cfg(feature = "moonbeam-native")]
633
						spec if spec.is_moonbeam() => {
634
							return runner.sync_run(|mut config| {
635
								let params = moonbeam_service::new_partial::<
636
									moonbeam_service::moonbeam_runtime::RuntimeApi,
637
									moonbeam_service::MoonbeamCustomizations,
638
								>(
639
									&mut config,
640
									&rpc_config,
641
									false,
642
									cli.run.legacy_block_import_strategy,
643
								)?;
644

            
645
								let db = params.backend.expose_db();
646
								let storage = params.backend.expose_storage();
647

            
648
								cmd.run(config, params.client, db, storage)
649
							})
650
						}
651
						#[cfg(feature = "moonbase-native")]
652
						_ => {
653
							return runner.sync_run(|mut config| {
654
								let params = moonbeam_service::new_partial::<
655
									moonbeam_service::moonbase_runtime::RuntimeApi,
656
									moonbeam_service::MoonbaseCustomizations,
657
								>(
658
									&mut config,
659
									&rpc_config,
660
									false,
661
									cli.run.legacy_block_import_strategy,
662
								)?;
663

            
664
								let db = params.backend.expose_db();
665
								let storage = params.backend.expose_storage();
666

            
667
								cmd.run(config, params.client, db, storage)
668
							})
669
						}
670
						#[cfg(not(feature = "moonbase-native"))]
671
						_ => panic!("invalid chain spec"),
672
					}
673
				}
674
				BenchmarkCmd::Overhead(_) => Err("Unsupported benchmarking command".into()),
675
				BenchmarkCmd::Extrinsic(_) => Err("Unsupported benchmarking command".into()),
676
				BenchmarkCmd::Machine(cmd) => {
677
					return runner.sync_run(|config| {
678
						cmd.run(
679
							&config,
680
							frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.clone(),
681
						)
682
					});
683
				}
684
			}
685
		}
686
		Some(Subcommand::TryRuntime) => Err("The `try-runtime` subcommand has been migrated to a \
687
			standalone CLI (https://github.com/paritytech/try-runtime-cli). It is no longer \
688
			being maintained here and will be removed entirely some time after January 2024. \
689
			Please remove this subcommand from your runtime and use the standalone CLI."
690
			.into()),
691
		Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
692
2
		Some(Subcommand::PrecompileWasm(cmd)) => {
693
2
			let runner = cli.create_runner(cmd)?;
694
2
			let rpc_config = cli.run.new_rpc_config();
695
2
			runner.async_run(|mut config| match &config.chain_spec {
696
				#[cfg(feature = "moonriver-native")]
697
2
				spec if spec.is_moonriver() => {
698
					let PartialComponents {
699
						task_manager,
700
						backend,
701
						..
702
					} = moonbeam_service::new_partial::<
703
						moonbeam_service::moonriver_runtime::RuntimeApi,
704
						moonbeam_service::MoonriverCustomizations,
705
					>(
706
						&mut config,
707
						&rpc_config,
708
						false,
709
						cli.run.legacy_block_import_strategy,
710
					)?;
711

            
712
					Ok((cmd.run(backend, config.chain_spec), task_manager))
713
				}
714
				#[cfg(feature = "moonbeam-native")]
715
2
				spec if spec.is_moonbeam() => {
716
					let PartialComponents {
717
						task_manager,
718
						backend,
719
						..
720
					} = moonbeam_service::new_partial::<
721
						moonbeam_service::moonbeam_runtime::RuntimeApi,
722
						moonbeam_service::MoonbeamCustomizations,
723
					>(
724
						&mut config,
725
						&rpc_config,
726
						false,
727
						cli.run.legacy_block_import_strategy,
728
					)?;
729

            
730
					Ok((cmd.run(backend, config.chain_spec), task_manager))
731
				}
732
				#[cfg(feature = "moonbase-native")]
733
				_ => {
734
					let PartialComponents {
735
2
						task_manager,
736
2
						backend,
737
						..
738
2
					} = moonbeam_service::new_partial::<
739
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
740
2
						moonbeam_service::MoonbaseCustomizations,
741
2
					>(
742
2
						&mut config,
743
2
						&rpc_config,
744
2
						false,
745
2
						cli.run.legacy_block_import_strategy,
746
2
					)?;
747

            
748
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
749
				}
750
				#[cfg(not(feature = "moonbase-native"))]
751
				_ => panic!("invalid chain spec"),
752
2
			})
753
		}
754
		None => {
755
934
			let runner = cli.create_runner(&(*cli.run).normalize())?;
756
934
			let collator_options = cli.run.collator_options();
757
934

            
758
934
			runner.run_node_until_exit(|mut config| async move {
759
934
				let hwbench = if !cli.run.no_hardware_benchmarks {
760
					config.database.path().map(|database_path| {
761
						let _ = std::fs::create_dir_all(&database_path);
762
						sc_sysinfo::gather_hwbench(
763
							Some(database_path),
764
							&SUBSTRATE_REFERENCE_HARDWARE,
765
						)
766
					})
767
				} else {
768
934
					None
769
				};
770

            
771
934
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
772
934

            
773
934
				let rpc_config = cli.run.new_rpc_config();
774
934

            
775
934
				// If dev service was requested, start up manual or instant seal.
776
934
				// Otherwise continue with the normal parachain node.
777
934
				// Dev service can be requested in two ways.
778
934
				// 1. by providing the --dev-service flag to the CLI
779
934
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
780
934
				// NOTE: the --dev flag triggers the dev service by way of number 2
781
934
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
782
934
				let para_id = extension.map(|e| e.para_id);
783

            
784
934
				let dev_service = cli.run.dev_service
785
934
					|| config.chain_spec.is_dev()
786
					|| relay_chain_id == Some("dev-service");
787
934
				if dev_service {
788
					// When running the dev service, just use Alice's author inherent
789
					//TODO maybe make the --alice etc flags work here, and consider bringing back
790
					// the author-id flag. For now, this will work.
791
934
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
792
934
						"Alice",
793
934
					));
794
934

            
795
934
					return match &config.chain_spec {
796
						#[cfg(feature = "moonriver-native")]
797
934
						spec if spec.is_moonriver() => moonbeam_service::new_dev::<
798
							moonbeam_service::moonriver_runtime::RuntimeApi,
799
							moonbeam_service::MoonriverCustomizations,
800
							sc_network::NetworkWorker<_, _>,
801
						>(
802
							config,
803
							para_id,
804
							author_id,
805
							cli.run.sealing,
806
							rpc_config,
807
							hwbench,
808
						)
809
						.await
810
						.map_err(Into::into),
811
						#[cfg(feature = "moonbeam-native")]
812
934
						spec if spec.is_moonbeam() => moonbeam_service::new_dev::<
813
							moonbeam_service::moonbeam_runtime::RuntimeApi,
814
							moonbeam_service::MoonbeamCustomizations,
815
							sc_network::NetworkWorker<_, _>,
816
						>(
817
							config,
818
							para_id,
819
							author_id,
820
							cli.run.sealing,
821
							rpc_config,
822
							hwbench,
823
						)
824
						.await
825
						.map_err(Into::into),
826
						#[cfg(feature = "moonbase-native")]
827
934
						_ => moonbeam_service::new_dev::<
828
934
							moonbeam_service::moonbase_runtime::RuntimeApi,
829
934
							moonbeam_service::MoonbaseCustomizations,
830
934
							sc_network::NetworkWorker<_, _>,
831
934
						>(
832
934
							config,
833
934
							para_id,
834
934
							author_id,
835
934
							cli.run.sealing,
836
934
							rpc_config,
837
934
							hwbench,
838
934
						)
839
						.await
840
934
						.map_err(Into::into),
841
						#[cfg(not(feature = "moonbase-native"))]
842
						_ => panic!("invalid chain spec"),
843
					};
844
				}
845
				#[cfg(feature = "lazy-loading")]
846
				if let Some(lazy_loading_remote_rpc) = cli.run.lazy_loading_remote_rpc {
847
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
848
						"Alice",
849
					));
850

            
851
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
852
						state_rpc: lazy_loading_remote_rpc,
853
						from_block: cli.run.lazy_loading_block,
854
						state_overrides_path: cli.run.lazy_loading_state_overrides,
855
						runtime_override: cli.run.lazy_loading_runtime_override,
856
						delay_between_requests: cli.run.lazy_loading_delay_between_requests,
857
						max_retries_per_request: cli.run.lazy_loading_max_retries_per_request,
858
					};
859

            
860
					let spec_builder = chain_spec::test_spec::lazy_loading_spec_builder();
861
					config.chain_spec = Box::new(spec_builder.build());
862

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

            
867
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
868
						moonbeam_runtime::RuntimeApi,
869
						moonbeam_service::MoonbeamCustomizations,
870
						sc_network::NetworkWorker<_, _>,
871
					>(
872
						config,
873
						author_id,
874
						cli.run.sealing,
875
						rpc_config,
876
						lazy_loading_config,
877
						hwbench,
878
					)
879
					.await
880
					.map_err(Into::into);
881
				}
882

            
883
				let polkadot_cli = RelayChainCli::new(
884
					&config,
885
					[RelayChainCli::executable_name().to_string()]
886
						.iter()
887
						.chain(cli.relaychain_args.iter()),
888
				);
889

            
890
				let para_id = extension.map(|e| e.para_id);
891
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
892

            
893
				let parachain_account =
894
					AccountIdConversion::<polkadot_primitives::v8::AccountId>::into_account_truncating(&id);
895

            
896
				let tokio_handle = config.tokio_handle.clone();
897
				let polkadot_config =
898
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
899
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
900

            
901
				info!("Parachain Account: {}", parachain_account);
902
				info!(
903
					"Is collating: {}",
904
					if config.role.is_authority() {
905
						"yes"
906
					} else {
907
						"no"
908
					}
909
				);
910

            
911
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
912
					warn!(
913
						"Detected relay chain node arguments together with \
914
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
915
					uses a network-related subset of all relay chain CLI options."
916
					);
917
				}
918

            
919
				match &config.chain_spec {
920
					#[cfg(feature = "moonriver-native")]
921
					spec if spec.is_moonriver() => moonbeam_service::start_node::<
922
						moonbeam_service::moonriver_runtime::RuntimeApi,
923
						moonbeam_service::MoonriverCustomizations,
924
					>(
925
						config,
926
						polkadot_config,
927
						collator_options,
928
						id,
929
						rpc_config,
930
						true,
931
						cli.run.block_authoring_duration,
932
						hwbench,
933
						cli.run.legacy_block_import_strategy,
934
						cli.run.nimbus_full_pov,
935
					)
936
					.await
937
					.map(|r| r.0)
938
					.map_err(Into::into),
939
					#[cfg(feature = "moonbeam-native")]
940
					spec if spec.is_moonbeam() => moonbeam_service::start_node::<
941
						moonbeam_service::moonbeam_runtime::RuntimeApi,
942
						moonbeam_service::MoonbeamCustomizations,
943
					>(
944
						config,
945
						polkadot_config,
946
						collator_options,
947
						id,
948
						rpc_config,
949
						true,
950
						cli.run.block_authoring_duration,
951
						hwbench,
952
						cli.run.legacy_block_import_strategy,
953
						cli.run.nimbus_full_pov,
954
					)
955
					.await
956
					.map(|r| r.0)
957
					.map_err(Into::into),
958
					#[cfg(feature = "moonbase-native")]
959
					_ => moonbeam_service::start_node::<
960
						moonbeam_service::moonbase_runtime::RuntimeApi,
961
						moonbeam_service::MoonbaseCustomizations,
962
					>(
963
						config,
964
						polkadot_config,
965
						collator_options,
966
						id,
967
						rpc_config,
968
						true,
969
						cli.run.block_authoring_duration,
970
						hwbench,
971
						cli.run.legacy_block_import_strategy,
972
						cli.run.nimbus_full_pov,
973
					)
974
					.await
975
					.map(|r| r.0)
976
					.map_err(Into::into),
977
					#[cfg(not(feature = "moonbase-native"))]
978
					_ => panic!("invalid chain spec"),
979
				}
980
1868
			})
981
		}
982
	}
983
940
}
984

            
985
impl DefaultConfigurationValues for RelayChainCli {
986
	fn p2p_listen_port() -> u16 {
987
		30334
988
	}
989

            
990
	fn rpc_listen_port() -> u16 {
991
		9945
992
	}
993

            
994
	fn prometheus_listen_port() -> u16 {
995
		9616
996
	}
997
}
998

            
999
impl CliConfiguration<Self> for RelayChainCli {
	fn shared_params(&self) -> &SharedParams {
		self.base.base.shared_params()
	}
	fn import_params(&self) -> Option<&ImportParams> {
		self.base.base.import_params()
	}
	fn network_params(&self) -> Option<&NetworkParams> {
		self.base.base.network_params()
	}
	fn keystore_params(&self) -> Option<&KeystoreParams> {
		self.base.base.keystore_params()
	}
	fn base_path(&self) -> Result<Option<BasePath>> {
		Ok(self
			.shared_params()
			.base_path()?
			.or_else(|| Some(self.base_path.clone().into())))
	}
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<RpcEndpoint>>> {
		self.base.base.rpc_addr(default_listen_port)
	}
	fn prometheus_config(
		&self,
		default_listen_port: u16,
		chain_spec: &Box<dyn ChainSpec>,
	) -> Result<Option<PrometheusConfig>> {
		self.base
			.base
			.prometheus_config(default_listen_port, chain_spec)
	}
	fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
	where
		F: FnOnce(&mut sc_cli::LoggerBuilder),
	{
		unreachable!("PolkadotCli is never initialized; qed");
	}
	fn chain_id(&self, is_dev: bool) -> Result<String> {
		let chain_id = self.base.base.chain_id(is_dev)?;
		Ok(if chain_id.is_empty() {
			self.chain_id.clone().unwrap_or_default()
		} else {
			chain_id
		})
	}
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
		self.base.base.role(is_dev)
	}
	fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
		self.base.base.transaction_pool(is_dev)
	}
	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
		self.base.base.rpc_methods()
	}
	fn rpc_max_connections(&self) -> Result<u32> {
		self.base.base.rpc_max_connections()
	}
	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
		self.base.base.rpc_cors(is_dev)
	}
	// 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(),
	))
}