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

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

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

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

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

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

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

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

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

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

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

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

            
151
impl 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
932
fn validate_trace_environment(cli: &Cli) -> Result<()> {
211
932
	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
932
	}
225
932
	Ok(())
226
932
}
227

            
228
/// Parse command line arguments into service configuration.
229
932
pub fn run() -> Result<()> {
230
932
	let cli = Cli::from_args();
231
932
	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.node_extra_args(),
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.node_extra_args(),
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.node_extra_args(),
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.node_extra_args(),
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
					>(&mut config, &rpc_config, cli.node_extra_args())?;
373

            
374
					Ok((
375
						cmd.run(params.client, params.backend, None),
376
						params.task_manager,
377
					))
378
				}),
379
				#[cfg(feature = "moonbeam-native")]
380
				spec if spec.is_moonbeam() => runner.async_run(|mut config| {
381
					let params = moonbeam_service::new_partial::<
382
						moonbeam_service::moonbeam_runtime::RuntimeApi,
383
						moonbeam_service::MoonbeamCustomizations,
384
					>(&mut config, &rpc_config, cli.node_extra_args())?;
385

            
386
					Ok((
387
						cmd.run(params.client, params.backend, None),
388
						params.task_manager,
389
					))
390
				}),
391
				#[cfg(feature = "moonbase-native")]
392
				_ => runner.async_run(|mut config| {
393
					let params = moonbeam_service::new_partial::<
394
						moonbeam_service::moonbase_runtime::RuntimeApi,
395
						moonbeam_service::MoonbaseCustomizations,
396
					>(&mut config, &rpc_config, cli.node_extra_args())?;
397

            
398
					Ok((
399
						cmd.run(params.client, params.backend, None),
400
						params.task_manager,
401
					))
402
				}),
403
				#[cfg(not(feature = "moonbase-native"))]
404
				_ => panic!("invalid chain spec"),
405
			}
406
		}
407
		Some(Subcommand::ExportGenesisHead(params)) => {
408
			let mut builder = sc_cli::LoggerBuilder::new("");
409
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
410
			let _ = builder.init();
411

            
412
			// Cumulus approach here, we directly call the generic load_spec func
413
			let chain_spec = load_spec(
414
				params.chain.as_deref().unwrap_or_default(),
415
				params.parachain_id.unwrap_or(1000).into(),
416
				&cli.run,
417
			)?;
418
			let state_version = Cli::runtime_version(&chain_spec).state_version();
419

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

            
461
			if let Some(output) = &params.output {
462
				std::fs::write(output, output_buf)?;
463
			} else {
464
				std::io::stdout().write_all(&output_buf)?;
465
			}
466

            
467
			Ok(())
468
		}
469
		Some(Subcommand::ExportGenesisWasm(params)) => {
470
			let mut builder = sc_cli::LoggerBuilder::new("");
471
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
472
			let _ = builder.init();
473

            
474
			let raw_wasm_blob = extract_genesis_wasm(
475
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
476
			)?;
477
			let output_buf = if params.raw {
478
				raw_wasm_blob
479
			} else {
480
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
481
			};
482

            
483
			if let Some(output) = &params.output {
484
				std::fs::write(output, output_buf)?;
485
			} else {
486
				std::io::stdout().write_all(&output_buf)?;
487
			}
488

            
489
			Ok(())
490
		}
491
		Some(Subcommand::Benchmark(cmd)) => {
492
			let runner = cli.create_runner(cmd)?;
493

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

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

            
558
								cmd.run(params.client)
559
							})
560
						}
561
						#[cfg(feature = "moonbase-native")]
562
						_ => {
563
							return runner.sync_run(|mut config| {
564
								let params =
565
									moonbeam_service::new_partial::<
566
										moonbeam_service::moonbase_runtime::RuntimeApi,
567
										moonbeam_service::MoonbaseCustomizations,
568
									>(&mut config, &rpc_config, cli.node_extra_args())?;
569

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

            
596
								let db = params.backend.expose_db();
597
								let storage = params.backend.expose_storage();
598

            
599
								cmd.run(config, params.client, db, storage, None)
600
							})
601
						}
602
						#[cfg(feature = "moonbeam-native")]
603
						spec if spec.is_moonbeam() => {
604
							return runner.sync_run(|mut config| {
605
								let params =
606
									moonbeam_service::new_partial::<
607
										moonbeam_service::moonbeam_runtime::RuntimeApi,
608
										moonbeam_service::MoonbeamCustomizations,
609
									>(&mut config, &rpc_config, cli.node_extra_args())?;
610

            
611
								let db = params.backend.expose_db();
612
								let storage = params.backend.expose_storage();
613

            
614
								cmd.run(config, params.client, db, storage, None)
615
							})
616
						}
617
						#[cfg(feature = "moonbase-native")]
618
						_ => {
619
							return runner.sync_run(|mut config| {
620
								let params =
621
									moonbeam_service::new_partial::<
622
										moonbeam_service::moonbase_runtime::RuntimeApi,
623
										moonbeam_service::MoonbaseCustomizations,
624
									>(&mut config, &rpc_config, cli.node_extra_args())?;
625

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

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

            
669
					Ok((cmd.run(backend, config.chain_spec), task_manager))
670
				}
671
				#[cfg(feature = "moonbeam-native")]
672
2
				spec if spec.is_moonbeam() => {
673
					let PartialComponents {
674
						task_manager,
675
						backend,
676
						..
677
					} = moonbeam_service::new_partial::<
678
						moonbeam_service::moonbeam_runtime::RuntimeApi,
679
						moonbeam_service::MoonbeamCustomizations,
680
					>(&mut config, &rpc_config, cli.node_extra_args())?;
681

            
682
					Ok((cmd.run(backend, config.chain_spec), task_manager))
683
				}
684
				#[cfg(feature = "moonbase-native")]
685
				_ => {
686
					let PartialComponents {
687
2
						task_manager,
688
2
						backend,
689
						..
690
2
					} = moonbeam_service::new_partial::<
691
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
692
2
						moonbeam_service::MoonbaseCustomizations,
693
2
					>(&mut config, &rpc_config, cli.node_extra_args())?;
694

            
695
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
696
				}
697
				#[cfg(not(feature = "moonbase-native"))]
698
				_ => panic!("invalid chain spec"),
699
2
			})
700
		}
701
		None => {
702
926
			let runner = cli.create_runner(&(*cli.run).normalize())?;
703
926
			let collator_options = cli.run.collator_options();
704

            
705
926
			runner.run_node_until_exit(|mut config| async move {
706
926
				let hwbench = if !cli.run.no_hardware_benchmarks {
707
					config.database.path().map(|database_path| {
708
						let _ = std::fs::create_dir_all(&database_path);
709
						sc_sysinfo::gather_hwbench(
710
							Some(database_path),
711
							&SUBSTRATE_REFERENCE_HARDWARE,
712
						)
713
					})
714
				} else {
715
926
					None
716
				};
717

            
718
926
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
719

            
720
926
				let rpc_config = cli.run.new_rpc_config();
721

            
722
				// If dev service was requested, start up manual or instant seal.
723
				// Otherwise continue with the normal parachain node.
724
				// Dev service can be requested in two ways.
725
				// 1. by providing the --dev-service flag to the CLI
726
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
727
				// NOTE: the --dev flag triggers the dev service by way of number 2
728
926
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
729
926
				let para_id = extension.map(|e| e.para_id);
730

            
731
926
				let dev_service = cli.run.dev_service
732
926
					|| config.chain_spec.is_dev()
733
					|| relay_chain_id == Some("dev-service");
734
926
				if dev_service {
735
					// When running the dev service, just use Alice's author inherent
736
					//TODO maybe make the --alice etc flags work here, and consider bringing back
737
					// the author-id flag. For now, this will work.
738
926
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
739
926
						"Alice",
740
926
					));
741

            
742
926
					return match &config.chain_spec {
743
						#[cfg(feature = "moonriver-native")]
744
926
						spec if spec.is_moonriver() => moonbeam_service::new_dev::<
745
							moonbeam_service::moonriver_runtime::RuntimeApi,
746
							moonbeam_service::MoonriverCustomizations,
747
							sc_network::NetworkWorker<_, _>,
748
						>(
749
							config,
750
							para_id,
751
							author_id,
752
							cli.run.sealing,
753
							rpc_config,
754
							hwbench,
755
							cli.node_extra_args(),
756
						)
757
						.await
758
						.map_err(Into::into),
759
						#[cfg(feature = "moonbeam-native")]
760
926
						spec if spec.is_moonbeam() => moonbeam_service::new_dev::<
761
							moonbeam_service::moonbeam_runtime::RuntimeApi,
762
							moonbeam_service::MoonbeamCustomizations,
763
							sc_network::NetworkWorker<_, _>,
764
						>(
765
							config,
766
							para_id,
767
							author_id,
768
							cli.run.sealing,
769
							rpc_config,
770
							hwbench,
771
							cli.node_extra_args(),
772
						)
773
						.await
774
						.map_err(Into::into),
775
						#[cfg(feature = "moonbase-native")]
776
926
						_ => moonbeam_service::new_dev::<
777
926
							moonbeam_service::moonbase_runtime::RuntimeApi,
778
926
							moonbeam_service::MoonbaseCustomizations,
779
926
							sc_network::NetworkWorker<_, _>,
780
926
						>(
781
926
							config,
782
926
							para_id,
783
926
							author_id,
784
926
							cli.run.sealing,
785
926
							rpc_config,
786
926
							hwbench,
787
926
							cli.node_extra_args(),
788
926
						)
789
926
						.await
790
926
						.map_err(Into::into),
791
						#[cfg(not(feature = "moonbase-native"))]
792
						_ => panic!("invalid chain spec"),
793
					};
794
				}
795
				#[cfg(feature = "lazy-loading")]
796
				if let Some(lazy_loading_remote_rpc) = cli.run.lazy_loading_remote_rpc {
797
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
798
						"Alice",
799
					));
800

            
801
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
802
						state_rpc: lazy_loading_remote_rpc,
803
						from_block: cli.run.lazy_loading_block,
804
						state_overrides_path: cli.run.lazy_loading_state_overrides,
805
						runtime_override: cli.run.lazy_loading_runtime_override,
806
						delay_between_requests: cli.run.lazy_loading_delay_between_requests,
807
						max_retries_per_request: cli.run.lazy_loading_max_retries_per_request,
808
					};
809

            
810
					let spec_builder = lazy_loading::spec_builder();
811
					config.chain_spec = Box::new(spec_builder.build());
812

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

            
817
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
818
						moonbeam_runtime::RuntimeApi,
819
						moonbeam_service::MoonbeamCustomizations,
820
						sc_network::NetworkWorker<_, _>,
821
					>(
822
						config,
823
						author_id,
824
						cli.run.sealing,
825
						rpc_config,
826
						lazy_loading_config,
827
						hwbench,
828
					)
829
					.await
830
					.map_err(Into::into);
831
				}
832

            
833
				let polkadot_cli = RelayChainCli::new(
834
					&config,
835
					[RelayChainCli::executable_name().to_string()]
836
						.iter()
837
						.chain(cli.relaychain_args.iter()),
838
				);
839

            
840
				let para_id = extension.map(|e| e.para_id);
841
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
842

            
843
				let parachain_account =
844
					AccountIdConversion::<polkadot_primitives::v8::AccountId>::into_account_truncating(&id);
845

            
846
				let tokio_handle = config.tokio_handle.clone();
847
				let polkadot_config =
848
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
849
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
850

            
851
				info!("Parachain Account: {}", parachain_account);
852
				info!(
853
					"Is collating: {}",
854
					if config.role.is_authority() {
855
						"yes"
856
					} else {
857
						"no"
858
					}
859
				);
860

            
861
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
862
					warn!(
863
						"Detected relay chain node arguments together with \
864
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
865
					uses a network-related subset of all relay chain CLI options."
866
					);
867
				}
868

            
869
				match &config.chain_spec {
870
					#[cfg(feature = "moonriver-native")]
871
					spec if spec.is_moonriver() => moonbeam_service::start_node::<
872
						moonbeam_service::moonriver_runtime::RuntimeApi,
873
						moonbeam_service::MoonriverCustomizations,
874
					>(
875
						config,
876
						polkadot_config,
877
						collator_options,
878
						id,
879
						rpc_config,
880
						cli.run.block_authoring_duration,
881
						hwbench,
882
						cli.node_extra_args(),
883
					)
884
					.await
885
					.map(|r| r.0)
886
					.map_err(Into::into),
887
					#[cfg(feature = "moonbeam-native")]
888
					spec if spec.is_moonbeam() => moonbeam_service::start_node::<
889
						moonbeam_service::moonbeam_runtime::RuntimeApi,
890
						moonbeam_service::MoonbeamCustomizations,
891
					>(
892
						config,
893
						polkadot_config,
894
						collator_options,
895
						id,
896
						rpc_config,
897
						cli.run.block_authoring_duration,
898
						hwbench,
899
						cli.node_extra_args(),
900
					)
901
					.await
902
					.map(|r| r.0)
903
					.map_err(Into::into),
904
					#[cfg(feature = "moonbase-native")]
905
					_ => moonbeam_service::start_node::<
906
						moonbeam_service::moonbase_runtime::RuntimeApi,
907
						moonbeam_service::MoonbaseCustomizations,
908
					>(
909
						config,
910
						polkadot_config,
911
						collator_options,
912
						id,
913
						rpc_config,
914
						cli.run.block_authoring_duration,
915
						hwbench,
916
						cli.node_extra_args(),
917
					)
918
					.await
919
					.map(|r| r.0)
920
					.map_err(Into::into),
921
					#[cfg(not(feature = "moonbase-native"))]
922
					_ => panic!("invalid chain spec"),
923
				}
924
1852
			})
925
		}
926
	}
927
932
}
928

            
929
impl DefaultConfigurationValues for RelayChainCli {
930
	fn p2p_listen_port() -> u16 {
931
		30334
932
	}
933

            
934
	fn rpc_listen_port() -> u16 {
935
		9945
936
	}
937

            
938
	fn prometheus_listen_port() -> u16 {
939
		9616
940
	}
941
}
942

            
943
impl CliConfiguration<Self> for RelayChainCli {
944
	fn shared_params(&self) -> &SharedParams {
945
		self.base.base.shared_params()
946
	}
947

            
948
	fn import_params(&self) -> Option<&ImportParams> {
949
		self.base.base.import_params()
950
	}
951

            
952
	fn network_params(&self) -> Option<&NetworkParams> {
953
		self.base.base.network_params()
954
	}
955

            
956
	fn keystore_params(&self) -> Option<&KeystoreParams> {
957
		self.base.base.keystore_params()
958
	}
959

            
960
	fn base_path(&self) -> Result<Option<BasePath>> {
961
		Ok(self
962
			.shared_params()
963
			.base_path()?
964
			.or_else(|| Some(self.base_path.clone().into())))
965
	}
966

            
967
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<RpcEndpoint>>> {
968
		self.base.base.rpc_addr(default_listen_port)
969
	}
970

            
971
	fn prometheus_config(
972
		&self,
973
		default_listen_port: u16,
974
		chain_spec: &Box<dyn ChainSpec>,
975
	) -> Result<Option<PrometheusConfig>> {
976
		self.base
977
			.base
978
			.prometheus_config(default_listen_port, chain_spec)
979
	}
980

            
981
	fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
982
	where
983
		F: FnOnce(&mut sc_cli::LoggerBuilder),
984
	{
985
		unreachable!("PolkadotCli is never initialized; qed");
986
	}
987

            
988
	fn chain_id(&self, is_dev: bool) -> Result<String> {
989
		let chain_id = self.base.base.chain_id(is_dev)?;
990

            
991
		Ok(if chain_id.is_empty() {
992
			self.chain_id.clone().unwrap_or_default()
993
		} else {
994
			chain_id
995
		})
996
	}
997

            
998
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
999
		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(),
	))
}