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

            
54
912
fn load_spec(
55
912
	id: &str,
56
912
	para_id: ParaId,
57
912
	run_cmd: &RunCmd,
58
912
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
59
912
	Ok(match id {
60
912
		// Moonbase networks
61
912
		"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
912
		"moonbase-local" => Box::new(chain_spec::moonbase::get_chain_spec(para_id)),
66
		#[cfg(feature = "moonbase-native")]
67
912
		"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
910
		"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
910
		"moonriver-dev" => Box::new(chain_spec::moonriver::development_chain_spec(None, None)),
78
		#[cfg(feature = "moonriver-native")]
79
910
		"moonriver-local" => Box::new(chain_spec::moonriver::get_chain_spec(para_id)),
80

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
589
								cmd.run(params.client)
590
							})
591
						}
592
						#[cfg(feature = "moonbase-native")]
593
						_ => {
594
							return runner.sync_run(|mut config| {
595
								let params = moonbeam_service::new_partial::<
596
									moonbeam_service::moonbase_runtime::RuntimeApi,
597
									moonbeam_service::MoonbaseCustomizations,
598
								>(
599
									&mut config,
600
									&rpc_config,
601
									false,
602
									cli.run.experimental_block_import_strategy,
603
								)?;
604

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

            
635
								let db = params.backend.expose_db();
636
								let storage = params.backend.expose_storage();
637

            
638
								cmd.run(config, params.client, db, storage)
639
							})
640
						}
641
						#[cfg(feature = "moonbeam-native")]
642
						spec if spec.is_moonbeam() => {
643
							return runner.sync_run(|mut config| {
644
								let params = moonbeam_service::new_partial::<
645
									moonbeam_service::moonbeam_runtime::RuntimeApi,
646
									moonbeam_service::MoonbeamCustomizations,
647
								>(
648
									&mut config,
649
									&rpc_config,
650
									false,
651
									cli.run.experimental_block_import_strategy,
652
								)?;
653

            
654
								let db = params.backend.expose_db();
655
								let storage = params.backend.expose_storage();
656

            
657
								cmd.run(config, params.client, db, storage)
658
							})
659
						}
660
						#[cfg(feature = "moonbase-native")]
661
						_ => {
662
							return runner.sync_run(|mut config| {
663
								let params = moonbeam_service::new_partial::<
664
									moonbeam_service::moonbase_runtime::RuntimeApi,
665
									moonbeam_service::MoonbaseCustomizations,
666
								>(
667
									&mut config,
668
									&rpc_config,
669
									false,
670
									cli.run.experimental_block_import_strategy,
671
								)?;
672

            
673
								let db = params.backend.expose_db();
674
								let storage = params.backend.expose_storage();
675

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

            
721
					Ok((cmd.run(backend, config.chain_spec), task_manager))
722
				}
723
				#[cfg(feature = "moonbeam-native")]
724
2
				spec if spec.is_moonbeam() => {
725
					let PartialComponents {
726
						task_manager,
727
						backend,
728
						..
729
					} = moonbeam_service::new_partial::<
730
						moonbeam_service::moonbeam_runtime::RuntimeApi,
731
						moonbeam_service::MoonbeamCustomizations,
732
					>(
733
						&mut config,
734
						&rpc_config,
735
						false,
736
						cli.run.experimental_block_import_strategy,
737
					)?;
738

            
739
					Ok((cmd.run(backend, config.chain_spec), task_manager))
740
				}
741
				#[cfg(feature = "moonbase-native")]
742
				_ => {
743
					let PartialComponents {
744
2
						task_manager,
745
2
						backend,
746
						..
747
2
					} = moonbeam_service::new_partial::<
748
2
						moonbeam_service::moonbase_runtime::RuntimeApi,
749
2
						moonbeam_service::MoonbaseCustomizations,
750
2
					>(
751
2
						&mut config,
752
2
						&rpc_config,
753
2
						false,
754
2
						cli.run.experimental_block_import_strategy,
755
2
					)?;
756

            
757
2
					Ok((cmd.run(backend, config.chain_spec), task_manager))
758
				}
759
				#[cfg(not(feature = "moonbase-native"))]
760
				_ => panic!("invalid chain spec"),
761
2
			})
762
		}
763
		None => {
764
906
			let runner = cli.create_runner(&(*cli.run).normalize())?;
765
906
			let collator_options = cli.run.collator_options();
766
906

            
767
906
			runner.run_node_until_exit(|mut config| async move {
768
906
				let hwbench = if !cli.run.no_hardware_benchmarks {
769
					config.database.path().map(|database_path| {
770
						let _ = std::fs::create_dir_all(&database_path);
771
						sc_sysinfo::gather_hwbench(
772
							Some(database_path),
773
							&SUBSTRATE_REFERENCE_HARDWARE,
774
						)
775
					})
776
				} else {
777
906
					None
778
				};
779

            
780
906
				let extension = chain_spec::Extensions::try_get(&*config.chain_spec);
781
906

            
782
906
				let rpc_config = cli.run.new_rpc_config();
783
906

            
784
906
				// If dev service was requested, start up manual or instant seal.
785
906
				// Otherwise continue with the normal parachain node.
786
906
				// Dev service can be requested in two ways.
787
906
				// 1. by providing the --dev-service flag to the CLI
788
906
				// 2. by specifying "dev-service" in the chain spec's "relay-chain" field.
789
906
				// NOTE: the --dev flag triggers the dev service by way of number 2
790
906
				let relay_chain_id = extension.map(|e| e.relay_chain.as_str());
791
906
				let para_id = extension.map(|e| e.para_id);
792

            
793
906
				let dev_service = cli.run.dev_service
794
906
					|| config.chain_spec.is_dev()
795
					|| relay_chain_id == Some("dev-service");
796
906
				if dev_service {
797
					// When running the dev service, just use Alice's author inherent
798
					//TODO maybe make the --alice etc flags work here, and consider bringing back
799
					// the author-id flag. For now, this will work.
800
906
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
801
906
						"Alice",
802
906
					));
803
906

            
804
906
					return match &config.chain_spec {
805
						#[cfg(feature = "moonriver-native")]
806
906
						spec if spec.is_moonriver() => moonbeam_service::new_dev::<
807
							moonbeam_service::moonriver_runtime::RuntimeApi,
808
							moonbeam_service::MoonriverCustomizations,
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 = "moonbeam-native")]
821
906
						spec if spec.is_moonbeam() => moonbeam_service::new_dev::<
822
							moonbeam_service::moonbeam_runtime::RuntimeApi,
823
							moonbeam_service::MoonbeamCustomizations,
824
							sc_network::NetworkWorker<_, _>,
825
						>(
826
							config,
827
							para_id,
828
							author_id,
829
							cli.run.sealing,
830
							rpc_config,
831
							hwbench,
832
						)
833
						.await
834
						.map_err(Into::into),
835
						#[cfg(feature = "moonbase-native")]
836
906
						_ => moonbeam_service::new_dev::<
837
906
							moonbeam_service::moonbase_runtime::RuntimeApi,
838
906
							moonbeam_service::MoonbaseCustomizations,
839
906
							sc_network::NetworkWorker<_, _>,
840
906
						>(
841
906
							config,
842
906
							para_id,
843
906
							author_id,
844
906
							cli.run.sealing,
845
906
							rpc_config,
846
906
							hwbench,
847
906
						)
848
						.await
849
906
						.map_err(Into::into),
850
						#[cfg(not(feature = "moonbase-native"))]
851
						_ => panic!("invalid chain spec"),
852
					};
853
				}
854
				#[cfg(feature = "lazy-loading")]
855
				if let Some(lazy_loading_remote_rpc) = cli.run.lazy_loading_remote_rpc {
856
					let author_id = Some(chain_spec::get_from_seed::<nimbus_primitives::NimbusId>(
857
						"Alice",
858
					));
859

            
860
					let lazy_loading_config = moonbeam_cli_opt::LazyLoadingConfig {
861
						state_rpc: lazy_loading_remote_rpc,
862
						from_block: cli.run.lazy_loading_block,
863
						state_overrides_path: cli.run.lazy_loading_state_overrides,
864
						runtime_override: cli.run.lazy_loading_runtime_override,
865
						delay_between_requests: cli.run.lazy_loading_delay_between_requests,
866
						max_retries_per_request: cli.run.lazy_loading_max_retries_per_request,
867
					};
868

            
869
					let spec_builder =
870
						chain_spec::test_spec::lazy_loading_spec_builder(Default::default());
871
					config.chain_spec = Box::new(spec_builder.build());
872

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

            
877
					return moonbeam_service::lazy_loading::new_lazy_loading_service::<
878
						moonbeam_runtime::RuntimeApi,
879
						moonbeam_service::MoonbeamCustomizations,
880
						sc_network::NetworkWorker<_, _>,
881
					>(
882
						config,
883
						author_id,
884
						cli.run.sealing,
885
						rpc_config,
886
						lazy_loading_config,
887
						hwbench,
888
					)
889
					.await
890
					.map_err(Into::into);
891
				}
892

            
893
				let polkadot_cli = RelayChainCli::new(
894
					&config,
895
					[RelayChainCli::executable_name().to_string()]
896
						.iter()
897
						.chain(cli.relaychain_args.iter()),
898
				);
899

            
900
				let para_id = extension.map(|e| e.para_id);
901
				let id = ParaId::from(cli.run.parachain_id.clone().or(para_id).unwrap_or(1000));
902

            
903
				let parachain_account =
904
					AccountIdConversion::<polkadot_primitives::v8::AccountId>::into_account_truncating(&id);
905

            
906
				let tokio_handle = config.tokio_handle.clone();
907
				let polkadot_config =
908
					SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
909
						.map_err(|err| format!("Relay chain argument error: {}", err))?;
910

            
911
				info!("Parachain Account: {}", parachain_account);
912
				info!(
913
					"Is collating: {}",
914
					if config.role.is_authority() {
915
						"yes"
916
					} else {
917
						"no"
918
					}
919
				);
920

            
921
				if !rpc_config.relay_chain_rpc_urls.is_empty() && cli.relaychain_args.len() > 0 {
922
					warn!(
923
						"Detected relay chain node arguments together with \
924
					--relay-chain-rpc-url. This command starts a minimal Polkadot node that only \
925
					uses a network-related subset of all relay chain CLI options."
926
					);
927
				}
928

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

            
992
impl DefaultConfigurationValues for RelayChainCli {
993
	fn p2p_listen_port() -> u16 {
994
		30334
995
	}
996

            
997
	fn rpc_listen_port() -> u16 {
998
		9945
999
	}
	fn prometheus_listen_port() -> u16 {
		9616
	}
}
impl CliConfiguration<Self> for RelayChainCli {
	fn shared_params(&self) -> &SharedParams {
		self.base.base.shared_params()
	}
	fn import_params(&self) -> Option<&ImportParams> {
		self.base.base.import_params()
	}
	fn network_params(&self) -> Option<&NetworkParams> {
		self.base.base.network_params()
	}
	fn keystore_params(&self) -> Option<&KeystoreParams> {
		self.base.base.keystore_params()
	}
	fn base_path(&self) -> Result<Option<BasePath>> {
		Ok(self
			.shared_params()
			.base_path()?
			.or_else(|| Some(self.base_path.clone().into())))
	}
	fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<RpcEndpoint>>> {
		self.base.base.rpc_addr(default_listen_port)
	}
	fn prometheus_config(
		&self,
		default_listen_port: u16,
		chain_spec: &Box<dyn ChainSpec>,
	) -> Result<Option<PrometheusConfig>> {
		self.base
			.base
			.prometheus_config(default_listen_port, chain_spec)
	}
	fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
	where
		F: FnOnce(&mut sc_cli::LoggerBuilder),
	{
		unreachable!("PolkadotCli is never initialized; qed");
	}
	fn chain_id(&self, is_dev: bool) -> Result<String> {
		let chain_id = self.base.base.chain_id(is_dev)?;
		Ok(if chain_id.is_empty() {
			self.chain_id.clone().unwrap_or_default()
		} else {
			chain_id
		})
	}
	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
		self.base.base.role(is_dev)
	}
	fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
		self.base.base.transaction_pool(is_dev)
	}
	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
		self.base.base.rpc_methods()
	}
	fn rpc_max_connections(&self) -> Result<u32> {
		self.base.base.rpc_max_connections()
	}
	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
		self.base.base.rpc_cors(is_dev)
	}
	// fn telemetry_external_transport(&self) -> Result<Option<sc_service::config::ExtTransport>> {
	// 	self.base.base.telemetry_external_transport()
	// }
	fn default_heap_pages(&self) -> Result<Option<u64>> {
		self.base.base.default_heap_pages()
	}
	fn force_authoring(&self) -> Result<bool> {
		self.base.base.force_authoring()
	}
	fn disable_grandpa(&self) -> Result<bool> {
		self.base.base.disable_grandpa()
	}
	fn max_runtime_instances(&self) -> Result<Option<usize>> {
		self.base.base.max_runtime_instances()
	}
	fn announce_block(&self) -> Result<bool> {
		self.base.base.announce_block()
	}
}
/// Generate the genesis block from a given ChainSpec.
pub fn generate_genesis_block<Block: BlockT>(
	chain_spec: &dyn ChainSpec,
	genesis_state_version: StateVersion,
) -> std::result::Result<Block, String> {
	let storage = chain_spec.build_storage()?;
	let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
		let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
			child_content.data.clone().into_iter().collect(),
			genesis_state_version,
		);
		(sk.clone(), state_root.encode())
	});
	let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
		storage.top.clone().into_iter().chain(child_roots).collect(),
		genesis_state_version,
	);
	let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
		Vec::new(),
		genesis_state_version,
	);
	Ok(Block::new(
		<<Block as BlockT>::Header as HeaderT>::new(
			Zero::zero(),
			extrinsics_root,
			state_root,
			Default::default(),
			Default::default(),
		),
		Default::default(),
	))
}