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

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

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

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

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

            
33
use moonbeam_service::{
34
	chain_spec, frontier_database_dir, lazy_loading, HostFunctions, IdentifyVariant,
35
};
36
use parity_scale_codec::Encode;
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
946
fn load_spec(
55
946
	id: &str,
56
946
	para_id: ParaId,
57
946
	run_cmd: &RunCmd,
58
946
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
59
946
	Ok(match id {
60
946
		// Moonbase networks
61
946
		"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
946
		"moonbase-local" => Box::new(chain_spec::moonbase::get_chain_spec(para_id)),
66
		#[cfg(feature = "moonbase-native")]
67
946
		"moonbase-dev" | "dev" | "development" => {
68
2
			Box::new(chain_spec::moonbase::development_chain_spec(None, None))
69
		}
70
		#[cfg(feature = "moonbeam-native")]
71
944
		"staking" => Box::new(chain_spec::moonbeam::get_chain_spec(para_id)),
72
		// Moonriver networks
73
944
		"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
944
		"moonriver-dev" => Box::new(chain_spec::moonriver::development_chain_spec(None, None)),
78
		#[cfg(feature = "moonriver-native")]
79
944
		"moonriver-local" => Box::new(chain_spec::moonriver::get_chain_spec(para_id)),
80

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

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

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

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

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

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

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

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

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

            
146
946
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
147
946
		load_spec(id, self.run.parachain_id.unwrap_or(1000).into(), &self.run)
148
946
	}
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
			"westend_moonbase_relay_testnet" => Ok(Box::new(
198
				polkadot_service::WestendChainSpec::from_json_bytes(
199
					&include_bytes!("../../../specs/alphanet/westend-embedded-specs-v8.json")[..],
200
				)?,
201
			)),
202
			// If we are not using a moonbeam-centric pre-baked relay spec, then fall back to the
203
			// Polkadot service to interpret the id.
204
			_ => polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter())
205
				.load_spec(id),
206
		}
207
	}
208
}
209

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

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

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

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

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

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

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

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

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

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

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

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

            
435
			let output_buf = match chain_spec {
436
				#[cfg(feature = "moonriver-native")]
437
				chain_spec if chain_spec.is_moonriver() => {
438
					let block: moonbeam_service::moonriver_runtime::Block =
439
						generate_genesis_block(&*chain_spec, state_version)?;
440
					let raw_header = block.header().encode();
441
					let output_buf = if params.raw {
442
						raw_header
443
					} else {
444
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
445
					};
446
					output_buf
447
				}
448
				#[cfg(feature = "moonbeam-native")]
449
				chain_spec if chain_spec.is_moonbeam() => {
450
					let block: moonbeam_service::moonbeam_runtime::Block =
451
						generate_genesis_block(&*chain_spec, state_version)?;
452
					let raw_header = block.header().encode();
453
					let output_buf = if params.raw {
454
						raw_header
455
					} else {
456
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
457
					};
458
					output_buf
459
				}
460
				#[cfg(feature = "moonbase-native")]
461
				_ => {
462
					let block: moonbeam_service::moonbase_runtime::Block =
463
						generate_genesis_block(&*chain_spec, state_version)?;
464
					let raw_header = block.header().encode();
465
					let output_buf = if params.raw {
466
						raw_header
467
					} else {
468
						format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
469
					};
470
					output_buf
471
				}
472
				#[cfg(not(feature = "moonbase-native"))]
473
				_ => panic!("invalid chain spec"),
474
			};
475

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

            
482
			Ok(())
483
		}
484
		Some(Subcommand::ExportGenesisWasm(params)) => {
485
			let mut builder = sc_cli::LoggerBuilder::new("");
486
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
487
			let _ = builder.init();
488

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
772
940
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
773
940

            
774
940
				let rpc_config = cli.run.new_rpc_config();
775
940

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

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

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

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

            
861
					let spec_builder = lazy_loading::spec_builder();
862
					config.chain_spec = Box::new(spec_builder.build());
863

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

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

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

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

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

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

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

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

            
920
				match &config.chain_spec {
921
					#[cfg(feature = "moonriver-native")]
922
					spec if spec.is_moonriver() => moonbeam_service::start_node::<
923
						moonbeam_service::moonriver_runtime::RuntimeApi,
924
						moonbeam_service::MoonriverCustomizations,
925
					>(
926
						config,
927
						polkadot_config,
928
						collator_options,
929
						id,
930
						rpc_config,
931
						cli.run.block_authoring_duration,
932
						hwbench,
933
						cli.run.legacy_block_import_strategy,
934
						cli.run.max_pov_percentage,
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
						cli.run.block_authoring_duration,
950
						hwbench,
951
						cli.run.legacy_block_import_strategy,
952
						cli.run.max_pov_percentage,
953
					)
954
					.await
955
					.map(|r| r.0)
956
					.map_err(Into::into),
957
					#[cfg(feature = "moonbase-native")]
958
					_ => moonbeam_service::start_node::<
959
						moonbeam_service::moonbase_runtime::RuntimeApi,
960
						moonbeam_service::MoonbaseCustomizations,
961
					>(
962
						config,
963
						polkadot_config,
964
						collator_options,
965
						id,
966
						rpc_config,
967
						cli.run.block_authoring_duration,
968
						hwbench,
969
						cli.run.legacy_block_import_strategy,
970
						cli.run.max_pov_percentage,
971
					)
972
					.await
973
					.map(|r| r.0)
974
					.map_err(Into::into),
975
					#[cfg(not(feature = "moonbase-native"))]
976
					_ => panic!("invalid chain spec"),
977
				}
978
1880
			})
979
		}
980
	}
981
946
}
982

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

            
988
	fn rpc_listen_port() -> u16 {
989
		9945
990
	}
991

            
992
	fn prometheus_listen_port() -> u16 {
993
		9616
994
	}
995
}
996

            
997
impl CliConfiguration<Self> for RelayChainCli {
998
	fn shared_params(&self) -> &SharedParams {
999
		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(),
	))
}