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, SUBSTRATE_REFERENCE_HARDWARE};
23
use log::{info, warn};
24
use moonbeam_cli_opt::EthApi;
25

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

            
33
use moonbeam_service::{chain_spec, frontier_database_dir, Block, HostFunctions, IdentifyVariant};
34
use parity_scale_codec::Encode;
35
#[cfg(feature = "westend-native")]
36
use polkadot_service::WestendChainSpec;
37
use sc_cli::{
38
	ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
39
	NetworkParams, Result, RpcEndpoint, SharedParams, SubstrateCli,
40
};
41
use sc_executor::WasmtimeInstantiationStrategy;
42
use sc_service::{
43
	config::{BasePath, PrometheusConfig},
44
	DatabaseSource, PartialComponents,
45
};
46
use sp_core::hexdisplay::HexDisplay;
47
use sp_runtime::{
48
	traits::{
49
		AccountIdConversion, Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, Zero,
50
	},
51
	StateVersion,
52
};
53
use std::io::Write;
54

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

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

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

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

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

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

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

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

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

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

            
143
910
	fn copyright_start_year() -> i32 {
144
910
		2019
145
910
	}
146

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

            
152
impl SubstrateCli for RelayChainCli {
153
	fn impl_name() -> String {
154
		"Moonbeam Parachain Collator".into()
155
	}
156

            
157
	fn impl_version() -> String {
158
		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
159
	}
160

            
161
	fn description() -> String {
162
		"Moonbeam Parachain Collator\n\nThe command-line arguments provided first will be \
163
		passed to the parachain node, while the arguments provided after -- will be passed \
164
		to the relaychain node.\n\n\
165
		parachain-collator [parachain-args] -- [relaychain-args]"
166
			.into()
167
	}
168

            
169
	fn author() -> String {
170
		env!("CARGO_PKG_AUTHORS").into()
171
	}
172

            
173
	fn support_url() -> String {
174
		"https://github.com/moonbeam-foundation/moonbeam/issues/new".into()
175
	}
176

            
177
	fn copyright_start_year() -> i32 {
178
		2019
179
	}
180

            
181
	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
182
		match id {
183
			#[cfg(feature = "westend-native")]
184
			"westend_moonbase_relay_testnet" => Ok(Box::new(WestendChainSpec::from_json_bytes(
185
				&include_bytes!("../../../specs/alphanet/westend-embedded-specs-v8.json")[..],
186
			)?)),
187
			// If we are not using a moonbeam-centric pre-baked relay spec, then fall back to the
188
			// Polkadot service to interpret the id.
189
			_ => polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter())
190
				.load_spec(id),
191
		}
192
	}
193
}
194

            
195
916
fn validate_trace_environment(cli: &Cli) -> Result<()> {
196
916
	if (cli.run.ethapi.contains(&EthApi::Debug) || cli.run.ethapi.contains(&EthApi::Trace))
197
		&& cli
198
			.run
199
			.base
200
			.base
201
			.import_params
202
			.wasm_runtime_overrides
203
			.is_none()
204
	{
205
		return Err(
206
			"`debug` or `trace` namespaces requires `--wasm-runtime-overrides /path/to/overrides`."
207
				.into(),
208
		);
209
916
	}
210
916
	Ok(())
211
916
}
212

            
213
/// Parse command line arguments into service configuration.
214
916
pub fn run() -> Result<()> {
215
916
	let cli = Cli::from_args();
216
916
	let _ = validate_trace_environment(&cli)?;
217

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

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

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

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

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

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

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

            
381
					Ok((
382
						cmd.run(params.client, params.backend, None),
383
						params.task_manager,
384
					))
385
				}),
386
				#[cfg(feature = "moonbase-native")]
387
				_ => runner.async_run(|mut config| {
388
					let params = moonbeam_service::new_partial::<
389
						moonbeam_service::moonbase_runtime::RuntimeApi,
390
						moonbeam_service::MoonbaseCustomizations,
391
					>(
392
						&mut config,
393
						&rpc_config,
394
						false,
395
						cli.run.experimental_block_import_strategy,
396
					)?;
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(cmd)) => {
408
			let runner = cli.create_runner(cmd)?;
409
			let chain_spec = runner.config().chain_spec.cloned_box();
410

            
411
			let mut builder = sc_cli::LoggerBuilder::new("");
412
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
413
			let _ = builder.init();
414

            
415
			let storage = chain_spec.build_storage()?;
416
			let executor = sc_executor::WasmExecutor::<HostFunctions>::builder()
417
				.with_execution_method(sc_executor::WasmExecutionMethod::Compiled {
418
					instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
419
				})
420
				.with_max_runtime_instances(runner.config().executor.max_runtime_instances)
421
				.build();
422

            
423
			let state_version = sc_chain_spec::resolve_state_version_from_wasm::<
424
				_,
425
				HashingFor<Block>,
426
			>(&storage, &executor)?;
427

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

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

            
475
			Ok(())
476
		}
477
		Some(Subcommand::ExportGenesisWasm(params)) => {
478
			let mut builder = sc_cli::LoggerBuilder::new("");
479
			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
480
			let _ = builder.init();
481

            
482
			let raw_wasm_blob = extract_genesis_wasm(
483
				&*cli.load_spec(params.chain.as_deref().unwrap_or_default())?,
484
			)?;
485
			let output_buf = if params.raw {
486
				raw_wasm_blob
487
			} else {
488
				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
489
			};
490

            
491
			if let Some(output) = &params.output {
492
				std::fs::write(output, output_buf)?;
493
			} else {
494
				std::io::stdout().write_all(&output_buf)?;
495
			}
496

            
497
			Ok(())
498
		}
499
		Some(Subcommand::Benchmark(cmd)) => {
500
			let runner = cli.create_runner(cmd)?;
501

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

            
558
								cmd.run(params.client)
559
							})
560
						}
561
						#[cfg(feature = "moonbeam-native")]
562
						spec if spec.is_moonbeam() => {
563
							return runner.sync_run(|mut config| {
564
								let params = moonbeam_service::new_partial::<
565
									moonbeam_service::moonbeam_runtime::RuntimeApi,
566
									moonbeam_service::MoonbeamCustomizations,
567
								>(
568
									&mut config,
569
									&rpc_config,
570
									false,
571
									cli.run.experimental_block_import_strategy,
572
								)?;
573

            
574
								cmd.run(params.client)
575
							})
576
						}
577
						#[cfg(feature = "moonbase-native")]
578
						_ => {
579
							return runner.sync_run(|mut config| {
580
								let params = moonbeam_service::new_partial::<
581
									moonbeam_service::moonbase_runtime::RuntimeApi,
582
									moonbeam_service::MoonbaseCustomizations,
583
								>(
584
									&mut config,
585
									&rpc_config,
586
									false,
587
									cli.run.experimental_block_import_strategy,
588
								)?;
589

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

            
620
								let db = params.backend.expose_db();
621
								let storage = params.backend.expose_storage();
622

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

            
639
								let db = params.backend.expose_db();
640
								let storage = params.backend.expose_storage();
641

            
642
								cmd.run(config, params.client, db, storage)
643
							})
644
						}
645
						#[cfg(feature = "moonbase-native")]
646
						_ => {
647
							return runner.sync_run(|mut config| {
648
								let params = moonbeam_service::new_partial::<
649
									moonbeam_service::moonbase_runtime::RuntimeApi,
650
									moonbeam_service::MoonbaseCustomizations,
651
								>(
652
									&mut config,
653
									&rpc_config,
654
									false,
655
									cli.run.experimental_block_import_strategy,
656
								)?;
657

            
658
								let db = params.backend.expose_db();
659
								let storage = params.backend.expose_storage();
660

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

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

            
724
					Ok((cmd.run(backend, config.chain_spec), task_manager))
725
				}
726
				#[cfg(feature = "moonbase-native")]
727
				_ => {
728
					let PartialComponents {
729
2
						task_manager,
730
2
						backend,
731
						..
732
2
					} = moonbeam_service::new_partial::<
733
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
734
2
						moonbeam_service::MoonbaseCustomizations,
735
2
					>(
736
2
						&mut config,
737
2
						&rpc_config,
738
2
						false,
739
2
						cli.run.experimental_block_import_strategy,
740
2
					)?;
741

            
742
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
743
				}
744
				#[cfg(not(feature = "moonbase-native"))]
745
				_ => panic!("invalid chain spec"),
746
2
			})
747
		}
748
		None => {
749
910
			let runner = cli.create_runner(&(*cli.run).normalize())?;
750
910
			let collator_options = cli.run.collator_options();
751
910

            
752
910
			runner.run_node_until_exit(|mut config| async move {
753
910
				let hwbench = if !cli.run.no_hardware_benchmarks {
754
					config.database.path().map(|database_path| {
755
						let _ = std::fs::create_dir_all(&database_path);
756
						sc_sysinfo::gather_hwbench(
757
							Some(database_path),
758
							&SUBSTRATE_REFERENCE_HARDWARE,
759
						)
760
					})
761
				} else {
762
910
					None
763
				};
764

            
765
910
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
766
910

            
767
910
				let rpc_config = cli.run.new_rpc_config();
768
910

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

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

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

            
845
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
846
						state_rpc: lazy_loading_remote_rpc,
847
						from_block: cli.run.lazy_loading_block,
848
						state_overrides_path: cli.run.lazy_loading_state_overrides,
849
						runtime_override: cli.run.lazy_loading_runtime_override,
850
						delay_between_requests: cli.run.lazy_loading_delay_between_requests,
851
						max_retries_per_request: cli.run.lazy_loading_max_retries_per_request,
852
					};
853

            
854
					let spec_builder = chain_spec::test_spec::lazy_loading_spec_builder();
855
					config.chain_spec = Box::new(spec_builder.build());
856

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

            
861
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
862
						moonbeam_runtime::RuntimeApi,
863
						moonbeam_service::MoonbeamCustomizations,
864
						sc_network::NetworkWorker<_, _>,
865
					>(
866
						config,
867
						author_id,
868
						cli.run.sealing,
869
						rpc_config,
870
						lazy_loading_config,
871
						hwbench,
872
					)
873
					.await
874
					.map_err(Into::into);
875
				}
876

            
877
				let polkadot_cli = RelayChainCli::new(
878
					&config,
879
					[RelayChainCli::executable_name().to_string()]
880
						.iter()
881
						.chain(cli.relaychain_args.iter()),
882
				);
883

            
884
				let para_id = extension.map(|e| e.para_id);
885
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
886

            
887
				let parachain_account =
888
					AccountIdConversion::<polkadot_primitives::v8::AccountId>::into_account_truncating(&id);
889

            
890
				let tokio_handle = config.tokio_handle.clone();
891
				let polkadot_config =
892
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
893
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
894

            
895
				info!("Parachain Account: {}", parachain_account);
896
				info!(
897
					"Is collating: {}",
898
					if config.role.is_authority() {
899
						"yes"
900
					} else {
901
						"no"
902
					}
903
				);
904

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

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

            
976
impl DefaultConfigurationValues for RelayChainCli {
977
	fn p2p_listen_port() -> u16 {
978
		30334
979
	}
980

            
981
	fn rpc_listen_port() -> u16 {
982
		9945
983
	}
984

            
985
	fn prometheus_listen_port() -> u16 {
986
		9616
987
	}
988
}
989

            
990
impl CliConfiguration<Self> for RelayChainCli {
991
	fn shared_params(&self) -> &SharedParams {
992
		self.base.base.shared_params()
993
	}
994

            
995
	fn import_params(&self) -> Option<&ImportParams> {
996
		self.base.base.import_params()
997
	}
998

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