1use clap::Parser;
23use moonbeam_cli_opt::{
24 account_key::{GenerateAccountKey, Network},
25 AuthoringPolicy, EthApi, FrontierBackendType, NodeExtraArgs, Sealing,
26};
27use moonbeam_service::chain_spec;
28use sc_cli::{Error as CliError, SubstrateCli};
29use std::path::PathBuf;
30use std::time::Duration;
31use url::Url;
32
33#[cfg(feature = "lazy-loading")]
34fn parse_block_hash(s: &str) -> Result<sp_core::H256, String> {
35 use std::str::FromStr;
36 sp_core::H256::from_str(s).map_err(|err| err.to_string())
37}
38
39fn validate_url(arg: &str) -> Result<Url, String> {
40 let url = Url::parse(arg).map_err(|e| e.to_string())?;
41
42 let scheme = url.scheme();
43 if scheme == "http" || scheme == "https" {
44 Ok(url)
45 } else {
46 Err(format!("'{}' URL scheme not supported.", url.scheme()))
47 }
48}
49
50#[derive(Debug, clap::Subcommand)]
52pub enum Subcommand {
53 #[clap(name = "export-genesis-state")]
55 ExportGenesisHead(ExportGenesisHeadCommand),
56
57 #[clap(name = "export-genesis-wasm")]
59 ExportGenesisWasm(ExportGenesisWasmCommand),
60
61 BuildSpec(BuildSpecCommand),
63
64 CheckBlock(sc_cli::CheckBlockCmd),
66
67 ExportBlocks(sc_cli::ExportBlocksCmd),
69
70 ExportState(sc_cli::ExportStateCmd),
72
73 ImportBlocks(sc_cli::ImportBlocksCmd),
75
76 PurgeChain(cumulus_client_cli::PurgeChainCmd),
78
79 Revert(sc_cli::RevertCmd),
81
82 #[clap(subcommand)]
85 Benchmark(frame_benchmarking_cli::BenchmarkCmd),
86
87 TryRuntime,
89
90 #[clap(subcommand)]
92 Key(KeyCmd),
93
94 PrecompileWasm(sc_cli::PrecompileWasmCmd),
96}
97
98#[derive(Debug, Parser)]
99pub struct BuildSpecCommand {
100 #[clap(flatten)]
101 pub base: sc_cli::BuildSpecCmd,
102
103 #[clap(long, conflicts_with = "chain")]
106 pub accounts: Option<u32>,
107
108 #[clap(long, conflicts_with = "chain")]
111 pub mnemonic: Option<String>,
112}
113
114#[derive(Debug, Parser)]
116pub struct ExportGenesisHeadCommand {
117 #[clap(value_parser)]
119 pub output: Option<PathBuf>,
120
121 #[clap(long)]
123 pub parachain_id: Option<u32>,
124
125 #[clap(short, long)]
127 pub raw: bool,
128
129 #[clap(long)]
131 pub chain: Option<String>,
132}
133
134#[derive(Debug, Parser)]
136pub struct ExportGenesisWasmCommand {
137 #[clap(value_parser)]
139 pub output: Option<PathBuf>,
140
141 #[clap(short, long)]
143 pub raw: bool,
144
145 #[clap(long)]
147 pub chain: Option<String>,
148}
149
150#[derive(Debug, Parser)]
151#[group(skip)]
152pub struct RunCmd {
153 #[clap(flatten)]
154 pub base: cumulus_client_cli::RunCmd,
155
156 #[clap(long)]
158 pub dev_service: bool,
159
160 #[clap(long)]
163 pub experimental_block_import_strategy: bool,
164
165 #[clap(long)]
167 pub legacy_block_import_strategy: bool,
168
169 #[cfg(feature = "lazy-loading")]
174 #[clap(long)]
175 #[arg(
176 long,
177 value_parser = validate_url,
178 alias = "fork-chain-from-rpc"
179 )]
180 pub lazy_loading_remote_rpc: Option<Url>,
181
182 #[cfg(feature = "lazy-loading")]
188 #[arg(
189 long,
190 value_name = "BLOCK",
191 value_parser = parse_block_hash,
192 alias = "block"
193 )]
194 pub lazy_loading_block: Option<sp_core::H256>,
195
196 #[cfg(feature = "lazy-loading")]
201 #[clap(
202 long,
203 value_name = "PATH",
204 value_parser,
205 alias = "fork-state-overrides"
206 )]
207 pub lazy_loading_state_overrides: Option<PathBuf>,
208
209 #[cfg(feature = "lazy-loading")]
213 #[clap(long, value_name = "PATH", value_parser, alias = "runtime-override")]
214 pub lazy_loading_runtime_override: Option<PathBuf>,
215
216 #[cfg(feature = "lazy-loading")]
223 #[clap(long, default_value = "100")]
224 pub lazy_loading_delay_between_requests: u32,
225
226 #[cfg(feature = "lazy-loading")]
230 #[clap(long, default_value = "10")]
231 pub lazy_loading_max_retries_per_request: u32,
232
233 #[clap(long, default_value = "instant")]
237 pub sealing: Sealing,
238
239 #[clap(long, value_delimiter = ',')]
246 pub ethapi: Vec<EthApi>,
247
248 #[clap(long, default_value = "10")]
250 pub ethapi_max_permits: u32,
251
252 #[clap(long, default_value = "500")]
256 pub ethapi_trace_max_count: u32,
257
258 #[clap(long, default_value = "300")]
261 pub ethapi_trace_cache_duration: u64,
262
263 #[clap(long, default_value = "300000000")]
265 pub eth_log_block_cache: usize,
266
267 #[clap(long, default_value = "300000000")]
269 pub eth_statuses_cache: usize,
270
271 #[arg(long, value_enum, ignore_case = true, default_value_t = FrontierBackendType::default())]
273 pub frontier_backend_type: FrontierBackendType,
274
275 #[arg(long, default_value = "100")]
277 pub frontier_sql_backend_pool_size: u32,
278
279 #[arg(long, default_value = "10000000")]
281 pub frontier_sql_backend_num_ops_timeout: u32,
282
283 #[arg(long, default_value = "4")]
285 pub frontier_sql_backend_thread_count: u32,
286
287 #[arg(long, default_value = "209715200")]
290 pub frontier_sql_backend_cache_size: u64,
291
292 #[clap(long, default_value = "20000000")]
295 pub tracing_raw_max_memory_usage: usize,
296
297 #[clap(long, default_value = "10000")]
299 pub max_past_logs: u32,
300
301 #[clap(long, default_value = "1024")]
303 pub max_block_range: u32,
304
305 #[clap(long = "force-moonbase")]
307 pub force_moonbase: bool,
308
309 #[clap(long = "force-moonriver")]
311 pub force_moonriver: bool,
312
313 #[clap(long)]
315 pub parachain_id: Option<u32>,
316
317 #[clap(long, default_value = "2048")]
319 pub fee_history_limit: u64,
320
321 #[clap(long)]
329 pub no_hardware_benchmarks: bool,
330
331 #[clap(long)]
333 pub no_prometheus_prefix: bool,
334
335 #[clap(long, default_value = "2000", value_parser=block_authoring_duration_parser)]
337 pub block_authoring_duration: Duration,
338
339 #[clap(long, hide = true)]
341 pub nimbus_full_pov: bool,
342
343 #[arg(
345 long,
346 conflicts_with = "nimbus_full_pov",
347 default_value = "50",
348 default_value_if("nimbus_full_pov", "true", "100")
349 )]
350 pub max_pov_percentage: u32,
351
352 #[arg(long, default_value_t = AuthoringPolicy::Lookahead)]
354 pub authoring: AuthoringPolicy,
355
356 #[arg(long)]
361 pub export_pov_to_path: Option<PathBuf>,
362}
363
364fn block_authoring_duration_parser(s: &str) -> Result<Duration, String> {
365 Ok(Duration::from_millis(clap_num::number_range(
366 s, 250, 2_000,
367 )?))
368}
369
370impl RunCmd {
371 pub fn new_rpc_config(&self) -> moonbeam_cli_opt::RpcConfig {
372 moonbeam_cli_opt::RpcConfig {
373 ethapi: self.ethapi.clone(),
374 ethapi_max_permits: self.ethapi_max_permits,
375 ethapi_trace_max_count: self.ethapi_trace_max_count,
376 ethapi_trace_cache_duration: self.ethapi_trace_cache_duration,
377 eth_log_block_cache: self.eth_log_block_cache,
378 eth_statuses_cache: self.eth_statuses_cache,
379 fee_history_limit: self.fee_history_limit,
380 max_past_logs: self.max_past_logs,
381 max_block_range: self.max_block_range,
382 relay_chain_rpc_urls: self.base.relay_chain_rpc_urls.clone(),
383 tracing_raw_max_memory_usage: self.tracing_raw_max_memory_usage,
384 frontier_backend_config: match self.frontier_backend_type {
385 FrontierBackendType::KeyValue => moonbeam_cli_opt::FrontierBackendConfig::KeyValue,
386 FrontierBackendType::Sql => moonbeam_cli_opt::FrontierBackendConfig::Sql {
387 pool_size: self.frontier_sql_backend_pool_size,
388 num_ops_timeout: self.frontier_sql_backend_num_ops_timeout,
389 thread_count: self.frontier_sql_backend_thread_count,
390 cache_size: self.frontier_sql_backend_cache_size,
391 },
392 },
393 no_prometheus_prefix: self.no_prometheus_prefix,
394 }
395 }
396}
397
398impl std::ops::Deref for RunCmd {
399 type Target = cumulus_client_cli::RunCmd;
400
401 fn deref(&self) -> &Self::Target {
402 &self.base
403 }
404}
405
406#[derive(Debug, clap::Subcommand)]
407pub enum KeyCmd {
408 #[clap(flatten)]
409 BaseCli(sc_cli::KeySubcommand),
410 #[clap(about = "This command is deprecated, please use `generate-moonbeam-key` instead.")]
412 GenerateAccountKey(GenerateAccountKey),
413 GenerateMoonbeamKey(GenerateAccountKey),
415}
416
417impl KeyCmd {
418 pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), CliError> {
420 match self {
421 KeyCmd::BaseCli(cmd) => cmd.run(cli),
422 KeyCmd::GenerateAccountKey(cmd) => {
423 let deprecation_msg = r#"
424
425 Warning: This command is deprecated, please use `generate-moonbeam-key` instead.
426
427 The `generate-account-key` command used Ethereum's derivation path (m/44'/60'/0'/0/n)
428 while `generate-moonbeam-key` uses Moonbeam's derivation path (m/44'/1284'/0'/0/n).
429 Furthermore, it supports derivation paths for Moonriver, Moonbase, and Ethereum.
430
431 For more information, see: https://github.com/moonbeam-foundation/moonbeam/pull/3090
432
433 "#;
434 eprintln!("{}", ansi_term::Colour::Yellow.paint(deprecation_msg));
435
436 let mut cmd = cmd.clone();
438 cmd.network = Network::Ethereum;
439 cmd.run();
440 Ok(())
441 }
442 KeyCmd::GenerateMoonbeamKey(cmd) => {
443 cmd.run();
444 Ok(())
445 }
446 }
447 }
448}
449
450#[derive(Debug, Parser)]
451#[clap(
452 propagate_version = true,
453 args_conflicts_with_subcommands = true,
454 subcommand_negates_reqs = true
455)]
456pub struct Cli {
457 #[clap(subcommand)]
458 pub subcommand: Option<Subcommand>,
459
460 #[clap(flatten)]
461 pub run: RunCmd,
462
463 #[clap(raw = true)]
465 pub relaychain_args: Vec<String>,
466}
467
468impl Cli {
469 pub(crate) fn node_extra_args(&self) -> NodeExtraArgs {
470 NodeExtraArgs {
471 authoring_policy: self.run.authoring,
472 export_pov: self.run.export_pov_to_path.clone(),
473 max_pov_percentage: Some(self.run.max_pov_percentage),
474 legacy_block_import_strategy: self.run.legacy_block_import_strategy,
475 }
476 }
477}
478
479#[derive(Debug)]
480pub struct RelayChainCli {
481 pub base: polkadot_cli::RunCmd,
483
484 pub chain_id: Option<String>,
486
487 pub base_path: PathBuf,
489}
490
491impl RelayChainCli {
492 pub fn new<'a>(
494 para_config: &sc_service::Configuration,
495 relay_chain_args: impl Iterator<Item = &'a String>,
496 ) -> Self {
497 let extension = chain_spec::Extensions::try_get(&*para_config.chain_spec);
498 let chain_id = extension.map(|e| e.relay_chain.clone());
499 let base_path = para_config.base_path.path().join("polkadot");
500 Self {
501 base_path,
502 chain_id,
503 base: polkadot_cli::RunCmd::parse_from(relay_chain_args),
504 }
505 }
506}