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

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

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

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

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

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

            
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, 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, net::SocketAddr};
53

            
54
902
fn load_spec(
55
902
	id: &str,
56
902
	para_id: ParaId,
57
902
	run_cmd: &RunCmd,
58
902
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
59
902
	Ok(match id {
60
902
		// Moonbase networks
61
902
		"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
902
		"moonbase-local" => Box::new(chain_spec::moonbase::get_chain_spec(para_id)),
66
		#[cfg(feature = "moonbase-native")]
67
902
		"moonbase-dev" | "dev" | "development" => {
68
2
			Box::new(chain_spec::moonbase::development_chain_spec(None, None))
69
		}
70
		#[cfg(all(feature = "test-spec", feature = "moonbeam-native"))]
71
		"staking" => Box::new(chain_spec::test_spec::staking_spec(para_id)),
72
		// Moonriver networks
73
900
		"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
900
		"moonriver-dev" => Box::new(chain_spec::moonriver::development_chain_spec(None, None)),
78
		#[cfg(feature = "moonriver-native")]
79
900
		"moonriver-local" => Box::new(chain_spec::moonriver::get_chain_spec(para_id)),
80

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

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

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

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

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

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

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

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

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

            
146
902
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
147
902
		load_spec(id, self.run.parachain_id.unwrap_or(1000).into(), &self.run)
148
902
	}
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
902
fn validate_trace_environment(cli: &Cli) -> Result<()> {
210
902
	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
902
	}
224
902
	Ok(())
225
902
}
226

            
227
/// Parse command line arguments into service configuration.
228
902
pub fn run() -> Result<()> {
229
902
	let cli = Cli::from_args();
230
902
	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) =
272
					moonbeam_service::new_chain_ops(&mut config, &rpc_config)?;
273
				Ok((cmd.run(client, import_queue), task_manager))
274
			})
275
		}
276
		Some(Subcommand::ExportBlocks(cmd)) => {
277
			let runner = cli.create_runner(cmd)?;
278
			let rpc_config = cli.run.new_rpc_config();
279
			runner.async_run(|mut config| {
280
				let (client, _, _, task_manager) =
281
					moonbeam_service::new_chain_ops(&mut config, &rpc_config)?;
282
				Ok((cmd.run(client, config.database), task_manager))
283
			})
284
		}
285
		Some(Subcommand::ExportState(cmd)) => {
286
			let runner = cli.create_runner(cmd)?;
287
			let rpc_config = cli.run.new_rpc_config();
288
			runner.async_run(|mut config| {
289
				let (client, _, _, task_manager) =
290
					moonbeam_service::new_chain_ops(&mut config, &rpc_config)?;
291
				Ok((cmd.run(client, config.chain_spec), task_manager))
292
			})
293
		}
294
		Some(Subcommand::ImportBlocks(cmd)) => {
295
			let runner = cli.create_runner(cmd)?;
296
			let rpc_config = cli.run.new_rpc_config();
297
			runner.async_run(|mut config| {
298
				let (client, _, import_queue, task_manager) =
299
					moonbeam_service::new_chain_ops(&mut config, &rpc_config)?;
300
				Ok((cmd.run(client, import_queue), task_manager))
301
			})
302
		}
303
		Some(Subcommand::PurgeChain(cmd)) => {
304
			let runner = cli.create_runner(cmd)?;
305
			runner.sync_run(|config| {
306
				// Although the cumulus_client_cli::PurgeCommand will extract the relay chain id,
307
				// we need to extract it here to determine whether we are running the dev service.
308
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
309
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
310
				let dev_service = cli.run.dev_service || relay_chain_id == Some("dev-service");
311

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

            
327
				if dev_service {
328
					// base refers to the encapsulated "regular" sc_cli::PurgeChain command
329
					return cmd.base.run(config.database);
330
				}
331

            
332
				let polkadot_cli = RelayChainCli::new(
333
					&config,
334
					[RelayChainCli::executable_name().to_string()]
335
						.iter()
336
						.chain(cli.relaychain_args.iter()),
337
				);
338

            
339
				let polkadot_config = SubstrateCli::create_configuration(
340
					&polkadot_cli,
341
					&polkadot_cli,
342
					config.tokio_handle.clone(),
343
				)
344
				.map_err(|err| format!("Relay chain argument error: {}", err))?;
345

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

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

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

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

            
399
			// Cumulus approach here, we directly call the generic load_spec func
400
			let chain_spec = load_spec(
401
				params.chain.as_deref().unwrap_or_default(),
402
				params.parachain_id.unwrap_or(1000).into(),
403
				&cli.run,
404
			)?;
405
			let state_version = Cli::runtime_version(&chain_spec).state_version();
406

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

            
448
			if let Some(output) = &params.output {
449
				std::fs::write(output, output_buf)?;
450
			} else {
451
				std::io::stdout().write_all(&output_buf)?;
452
			}
453

            
454
			Ok(())
455
		}
456
		Some(Subcommand::ExportGenesisWasm(params)) => {
457
			let mut builder = sc_cli::LoggerBuilder::new("");
458
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
459
			let _ = builder.init();
460

            
461
			let raw_wasm_blob = extract_genesis_wasm(
462
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
463
			)?;
464
			let output_buf = if params.raw {
465
				raw_wasm_blob
466
			} else {
467
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
468
			};
469

            
470
			if let Some(output) = &params.output {
471
				std::fs::write(output, output_buf)?;
472
			} else {
473
				std::io::stdout().write_all(&output_buf)?;
474
			}
475

            
476
			Ok(())
477
		}
478
		Some(Subcommand::Benchmark(cmd)) => {
479
			let runner = cli.create_runner(cmd)?;
480

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

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

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

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

            
588
								let db = params.backend.expose_db();
589
								let storage = params.backend.expose_storage();
590

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

            
602
								let db = params.backend.expose_db();
603
								let storage = params.backend.expose_storage();
604

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

            
616
								let db = params.backend.expose_db();
617
								let storage = params.backend.expose_storage();
618

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

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

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

            
685
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
686
				}
687
				#[cfg(not(feature = "moonbase-native"))]
688
				_ => panic!("invalid chain spec"),
689
2
			})
690
		}
691
		None => {
692
896
			let runner = cli.create_runner(&(*cli.run).normalize())?;
693
896
			let collator_options = cli.run.collator_options();
694
896

            
695
896
			runner.run_node_until_exit(|mut config| async move {
696
896
				let hwbench = if !cli.run.no_hardware_benchmarks {
697
					config.database.path().map(|database_path| {
698
						let _ = std::fs::create_dir_all(&database_path);
699
						sc_sysinfo::gather_hwbench(Some(database_path))
700
					})
701
				} else {
702
896
					None
703
				};
704

            
705
896
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
706
896

            
707
896
				let rpc_config = cli.run.new_rpc_config();
708
896

            
709
896
				// If dev service was requested, start up manual or instant seal.
710
896
				// Otherwise continue with the normal parachain node.
711
896
				// Dev service can be requested in two ways.
712
896
				// 1. by providing the --dev-service flag to the CLI
713
896
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
714
896
				// NOTE: the --dev flag triggers the dev service by way of number 2
715
896
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
716
896
				let para_id = extension.map(|e| e.para_id);
717

            
718
896
				let dev_service = cli.run.dev_service
719
896
					|| config.chain_spec.is_dev()
720
					|| relay_chain_id == Some("dev-service");
721
896
				if dev_service {
722
					// When running the dev service, just use Alice's author inherent
723
					//TODO maybe make the --alice etc flags work here, and consider bringing back
724
					// the author-id flag. For now, this will work.
725
896
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
726
896
						"Alice",
727
896
					));
728
896

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

            
785
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
786
						state_rpc: fork_chain_from_rpc,
787
						from_block: cli.run.block,
788
						state_overrides_path: cli.run.fork_state_overrides,
789
						runtime_override: cli.run.runtime_override,
790
					};
791

            
792
					let spec_builder =
793
						chain_spec::test_spec::lazy_loading_spec_builder(Default::default());
794
					config.chain_spec = Box::new(spec_builder.build());
795

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

            
800
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
801
						moonbeam_runtime::RuntimeApi,
802
						moonbeam_service::MoonbeamCustomizations,
803
						sc_network::NetworkWorker<_, _>,
804
					>(
805
						config,
806
						author_id,
807
						cli.run.sealing,
808
						rpc_config,
809
						lazy_loading_config,
810
						hwbench,
811
					)
812
					.await
813
					.map_err(Into::into);
814
				}
815

            
816
				let polkadot_cli = RelayChainCli::new(
817
					&config,
818
					[RelayChainCli::executable_name().to_string()]
819
						.iter()
820
						.chain(cli.relaychain_args.iter()),
821
				);
822

            
823
				let para_id = extension.map(|e| e.para_id);
824
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
825

            
826
				let parachain_account =
827
					AccountIdConversion::<polkadot_primitives::v7::AccountId>::into_account_truncating(&id);
828

            
829
				let tokio_handle = config.tokio_handle.clone();
830
				let polkadot_config =
831
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
832
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
833

            
834
				info!("Parachain Account: {}", parachain_account);
835
				info!(
836
					"Is collating: {}",
837
					if config.role.is_authority() {
838
						"yes"
839
					} else {
840
						"no"
841
					}
842
				);
843

            
844
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
845
					warn!(
846
						"Detected relay chain node arguments together with \
847
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
848
					uses a network-related subset of all relay chain CLI options."
849
					);
850
				}
851

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

            
912
impl DefaultConfigurationValues for RelayChainCli {
913
	fn p2p_listen_port() -> u16 {
914
		30334
915
	}
916

            
917
	fn rpc_listen_port() -> u16 {
918
		9945
919
	}
920

            
921
	fn prometheus_listen_port() -> u16 {
922
		9616
923
	}
924
}
925

            
926
impl CliConfiguration<Self> for RelayChainCli {
927
	fn shared_params(&self) -> &SharedParams {
928
		self.base.base.shared_params()
929
	}
930

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

            
935
	fn network_params(&self) -> Option<&NetworkParams> {
936
		self.base.base.network_params()
937
	}
938

            
939
	fn keystore_params(&self) -> Option<&KeystoreParams> {
940
		self.base.base.keystore_params()
941
	}
942

            
943
	fn base_path(&self) -> Result<Option<BasePath>> {
944
		Ok(self
945
			.shared_params()
946
			.base_path()?
947
			.or_else(|| Some(self.base_path.clone().into())))
948
	}
949

            
950
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {
951
		self.base.base.rpc_addr(default_listen_port)
952
	}
953

            
954
	fn prometheus_config(
955
		&self,
956
		default_listen_port: u16,
957
		chain_spec: &Box<dyn ChainSpec>,
958
	) -> Result<Option<PrometheusConfig>> {
959
		self.base
960
			.base
961
			.prometheus_config(default_listen_port, chain_spec)
962
	}
963

            
964
	fn init<F>(
965
		&self,
966
		_support_url: &String,
967
		_impl_version: &String,
968
		_logger_hook: F,
969
		_config: &sc_service::Configuration,
970
	) -> Result<()>
971
	where
972
		F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration),
973
	{
974
		unreachable!("PolkadotCli is never initialized; qed");
975
	}
976

            
977
	fn chain_id(&self, is_dev: bool) -> Result<String> {
978
		let chain_id = self.base.base.chain_id(is_dev)?;
979

            
980
		Ok(if chain_id.is_empty() {
981
			self.chain_id.clone().unwrap_or_default()
982
		} else {
983
			chain_id
984
		})
985
	}
986

            
987
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
988
		self.base.base.role(is_dev)
989
	}
990

            
991
	fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
992
		self.base.base.transaction_pool(is_dev)
993
	}
994

            
995
	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
996
		self.base.base.rpc_methods()
997
	}
998

            
999
	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(),
	))
}