moonbeam_cli/
cli.rs

1// Copyright 2019-2025 PureStake Inc.
2// This file is part of Moonbeam.
3
4// Moonbeam is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Moonbeam is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Moonbeam CLI Library. Built with clap
18//!
19//! This module defines the Moonbeam node's Command Line Interface (CLI)
20//! It is built using clap and inherits behavior from Substrate's sc_cli crate.
21
22use 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/// Sub-commands supported by the collator.
51#[derive(Debug, clap::Subcommand)]
52pub enum Subcommand {
53	/// Export the genesis state of the parachain.
54	#[clap(name = "export-genesis-state")]
55	ExportGenesisHead(ExportGenesisHeadCommand),
56
57	/// Export the genesis wasm of the parachain.
58	#[clap(name = "export-genesis-wasm")]
59	ExportGenesisWasm(ExportGenesisWasmCommand),
60
61	/// Build a chain specification.
62	BuildSpec(BuildSpecCommand),
63
64	/// Validate blocks.
65	CheckBlock(sc_cli::CheckBlockCmd),
66
67	/// Export blocks.
68	ExportBlocks(sc_cli::ExportBlocksCmd),
69
70	/// Export the state of a given block into a chain spec.
71	ExportState(sc_cli::ExportStateCmd),
72
73	/// Import blocks.
74	ImportBlocks(sc_cli::ImportBlocksCmd),
75
76	/// Remove the whole chain.
77	PurgeChain(cumulus_client_cli::PurgeChainCmd),
78
79	/// Revert the chain to a previous state.
80	Revert(sc_cli::RevertCmd),
81
82	/// Sub-commands concerned with benchmarking.
83	/// The pallet benchmarking moved to the `pallet` sub-command.
84	#[clap(subcommand)]
85	Benchmark(frame_benchmarking_cli::BenchmarkCmd),
86
87	/// Try some command against runtime state.
88	TryRuntime,
89
90	/// Key management cli utilities
91	#[clap(subcommand)]
92	Key(KeyCmd),
93
94	/// Precompile the WASM runtime into native code
95	PrecompileWasm(sc_cli::PrecompileWasmCmd),
96}
97
98#[derive(Debug, Parser)]
99pub struct BuildSpecCommand {
100	#[clap(flatten)]
101	pub base: sc_cli::BuildSpecCmd,
102
103	/// Number of accounts to be funded in the genesis
104	/// Warning: This flag implies a development spec and overrides any explicitly supplied spec
105	#[clap(long, conflicts_with = "chain")]
106	pub accounts: Option<u32>,
107
108	/// Mnemonic from which we can derive funded accounts in the genesis
109	/// Warning: This flag implies a development spec and overrides any explicitly supplied spec
110	#[clap(long, conflicts_with = "chain")]
111	pub mnemonic: Option<String>,
112}
113
114/// Command for exporting the genesis state of the parachain
115#[derive(Debug, Parser)]
116pub struct ExportGenesisHeadCommand {
117	/// Output file name or stdout if unspecified.
118	#[clap(value_parser)]
119	pub output: Option<PathBuf>,
120
121	/// Id of the parachain this state is for.
122	#[clap(long)]
123	pub parachain_id: Option<u32>,
124
125	/// Write output in binary. Default is to write in hex.
126	#[clap(short, long)]
127	pub raw: bool,
128
129	/// The name of the chain for that the genesis state should be exported.
130	#[clap(long)]
131	pub chain: Option<String>,
132}
133
134/// Command for exporting the genesis wasm file.
135#[derive(Debug, Parser)]
136pub struct ExportGenesisWasmCommand {
137	/// Output file name or stdout if unspecified.
138	#[clap(value_parser)]
139	pub output: Option<PathBuf>,
140
141	/// Write output in binary. Default is to write in hex.
142	#[clap(short, long)]
143	pub raw: bool,
144
145	/// The name of the chain for that the genesis wasm file should be exported.
146	#[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	/// Enable the development service to run without a backing relay chain
157	#[clap(long)]
158	pub dev_service: bool,
159
160	/// No-op
161	/// Deprecated in: https://github.com/moonbeam-foundation/moonbeam/pull/3204
162	#[clap(long)]
163	pub experimental_block_import_strategy: bool,
164
165	/// Enable the legacy block import strategy
166	#[clap(long)]
167	pub legacy_block_import_strategy: bool,
168
169	/// Specifies the URL used to fetch chain data via RPC.
170	///
171	/// The URL should point to the RPC endpoint of the chain being forked.
172	/// Ensure that the RPC has sufficient rate limits to handle the expected load.
173	#[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	/// Optional parameter to specify the block hash for lazy loading.
183	///
184	/// This parameter allows the user to specify a block hash from which to start loading data.
185	///
186	/// If not provided, the latest block will be used.
187	#[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	/// Optional parameter to specify state overrides during lazy loading.
197	///
198	/// This parameter allows the user to provide a path to a file containing state overrides.
199	/// The file can contain any custom state modifications that should be applied.
200	#[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	/// Optional parameter to specify a runtime override when starting the lazy loading.
210	///
211	/// If not provided, it will fetch the runtime from the block being forked.
212	#[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	/// The delay (in milliseconds) between RPC requests when using lazy loading.
217	///
218	/// This parameter controls the amount of time (in milliseconds) to wait between consecutive
219	/// RPC requests. This can help manage request rate and avoid overwhelming the server.
220	///
221	/// The default value is 100 milliseconds.
222	#[cfg(feature = "lazy-loading")]
223	#[clap(long, default_value = "100")]
224	pub lazy_loading_delay_between_requests: u32,
225
226	/// The maximum number of retries for an RPC request when using lazy loading.
227	///
228	/// The default value is 10 retries.
229	#[cfg(feature = "lazy-loading")]
230	#[clap(long, default_value = "10")]
231	pub lazy_loading_max_retries_per_request: u32,
232
233	/// When blocks should be sealed in the dev service.
234	///
235	/// Options are "instant", "manual", or timer interval in milliseconds
236	#[clap(long, default_value = "instant")]
237	pub sealing: Sealing,
238
239	/// Public authoring identity to be inserted in the author inherent
240	/// This is not currently used, but we may want a way to use it in the dev service.
241	// #[clap(long)]
242	// pub author_id: Option<NimbusId>,
243
244	/// Enable EVM tracing module on a non-authority node.
245	#[clap(long, value_delimiter = ',')]
246	pub ethapi: Vec<EthApi>,
247
248	/// Number of concurrent tracing tasks. Meant to be shared by both "debug" and "trace" modules.
249	#[clap(long, default_value = "10")]
250	pub ethapi_max_permits: u32,
251
252	/// Maximum number of trace entries a single request of `trace_filter` is allowed to return.
253	/// A request asking for more or an unbounded one going over this limit will both return an
254	/// error.
255	#[clap(long, default_value = "500")]
256	pub ethapi_trace_max_count: u32,
257
258	/// Duration (in seconds) after which the cache of `trace_filter` for a given block will be
259	/// discarded.
260	#[clap(long, default_value = "300")]
261	pub ethapi_trace_cache_duration: u64,
262
263	/// Size in bytes of the LRU cache for block data.
264	#[clap(long, default_value = "300000000")]
265	pub eth_log_block_cache: usize,
266
267	/// Size in bytes of the LRU cache for transactions statuses data.
268	#[clap(long, default_value = "300000000")]
269	pub eth_statuses_cache: usize,
270
271	/// Sets the frontier backend type (KeyValue or Sql)
272	#[arg(long, value_enum, ignore_case = true, default_value_t = FrontierBackendType::default())]
273	pub frontier_backend_type: FrontierBackendType,
274
275	// Sets the SQL backend's pool size.
276	#[arg(long, default_value = "100")]
277	pub frontier_sql_backend_pool_size: u32,
278
279	/// Sets the SQL backend's query timeout in number of VM ops.
280	#[arg(long, default_value = "10000000")]
281	pub frontier_sql_backend_num_ops_timeout: u32,
282
283	/// Sets the SQL backend's auxiliary thread limit.
284	#[arg(long, default_value = "4")]
285	pub frontier_sql_backend_thread_count: u32,
286
287	/// Sets the SQL backend's cache size in bytes.
288	/// Default value is 200MB.
289	#[arg(long, default_value = "209715200")]
290	pub frontier_sql_backend_cache_size: u64,
291
292	/// Size in bytes of data a raw tracing request is allowed to use.
293	/// Bound the size of memory, stack and storage data.
294	#[clap(long, default_value = "20000000")]
295	pub tracing_raw_max_memory_usage: usize,
296
297	/// Maximum number of logs in a query.
298	#[clap(long, default_value = "10000")]
299	pub max_past_logs: u32,
300
301	/// Maximum block range to query logs from.
302	#[clap(long, default_value = "1024")]
303	pub max_block_range: u32,
304
305	/// Force using Moonbase native runtime.
306	#[clap(long = "force-moonbase")]
307	pub force_moonbase: bool,
308
309	/// Force using Moonriver native runtime.
310	#[clap(long = "force-moonriver")]
311	pub force_moonriver: bool,
312
313	/// Id of the parachain this collator collates for.
314	#[clap(long)]
315	pub parachain_id: Option<u32>,
316
317	/// Maximum fee history cache size.
318	#[clap(long, default_value = "2048")]
319	pub fee_history_limit: u64,
320
321	/// Disable automatic hardware benchmarks.
322	///
323	/// By default these benchmarks are automatically ran at startup and measure
324	/// the CPU speed, the memory bandwidth and the disk speed.
325	///
326	/// The results are then printed out in the logs, and also sent as part of
327	/// telemetry, if telemetry is enabled.
328	#[clap(long)]
329	pub no_hardware_benchmarks: bool,
330
331	/// Removes moonbeam prefix from Prometheus metrics
332	#[clap(long)]
333	pub no_prometheus_prefix: bool,
334
335	/// Maximum duration in milliseconds to produce a block
336	#[clap(long, default_value = "2000", value_parser=block_authoring_duration_parser)]
337	pub block_authoring_duration: Duration,
338
339	/// Enable full proof-of-validation mode for Nimbus (deprecated, use --max-pov-percentage instead)
340	#[clap(long, hide = true)]
341	pub nimbus_full_pov: bool,
342
343	/// Maximum percentage of POV size to use (0-100)
344	#[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	/// Authoring style to use.
353	#[arg(long, default_value_t = AuthoringPolicy::Lookahead)]
354	pub authoring: AuthoringPolicy,
355
356	/// Export all `PoVs` build by this collator to the given folder.
357	///
358	/// This is useful for debugging issues that are occurring while validating these `PoVs` on the
359	/// relay chain.
360	#[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	/// Generate an Ethereum account.
411	#[clap(about = "This command is deprecated, please use `generate-moonbeam-key` instead.")]
412	GenerateAccountKey(GenerateAccountKey),
413	/// Generate a Moonbeam account.
414	GenerateMoonbeamKey(GenerateAccountKey),
415}
416
417impl KeyCmd {
418	/// run the key subcommands
419	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				// Force ethereum network for deprecated command
437				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	/// Relaychain arguments
464	#[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	/// The actual relay chain cli object.
482	pub base: polkadot_cli::RunCmd,
483
484	/// Optional chain id that should be passed to the relay chain.
485	pub chain_id: Option<String>,
486
487	/// The base path that should be used by the relay chain.
488	pub base_path: PathBuf,
489}
490
491impl RelayChainCli {
492	/// Parse the relay chain CLI parameters using the para chain `Configuration`.
493	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}