frontier_template_node/
command.rs

1use futures::TryFutureExt;
2// Substrate
3use sc_cli::{ChainSpec, SubstrateCli};
4use sc_service::DatabaseSource;
5// Frontier
6use fc_db::kv::frontier_database_dir;
7
8use crate::{
9	chain_spec,
10	cli::{Cli, Subcommand},
11	service::{self, db_config_dir},
12};
13
14#[cfg(feature = "runtime-benchmarks")]
15use crate::chain_spec::get_account_id_from_seed;
16
17impl SubstrateCli for Cli {
18	fn impl_name() -> String {
19		"Frontier Node".into()
20	}
21
22	fn impl_version() -> String {
23		env!("SUBSTRATE_CLI_IMPL_VERSION").into()
24	}
25
26	fn description() -> String {
27		env!("CARGO_PKG_DESCRIPTION").into()
28	}
29
30	fn author() -> String {
31		env!("CARGO_PKG_AUTHORS").into()
32	}
33
34	fn support_url() -> String {
35		"support.anonymous.an".into()
36	}
37
38	fn copyright_start_year() -> i32 {
39		2021
40	}
41
42	fn load_spec(&self, id: &str) -> Result<Box<dyn ChainSpec>, String> {
43		Ok(match id {
44			"dev" => {
45				let enable_manual_seal = self.sealing.map(|_| true).unwrap_or_default();
46				Box::new(chain_spec::development_config(enable_manual_seal))
47			}
48			"" | "local" => Box::new(chain_spec::local_testnet_config()),
49			path => Box::new(chain_spec::ChainSpec::from_json_file(
50				std::path::PathBuf::from(path),
51			)?),
52		})
53	}
54}
55
56/// Parse and run command line arguments
57pub fn run() -> sc_cli::Result<()> {
58	let cli = Cli::from_args();
59
60	match &cli.subcommand {
61		Some(Subcommand::Key(cmd)) => cmd.run(&cli),
62		Some(Subcommand::BuildSpec(cmd)) => {
63			let runner = cli.create_runner(cmd)?;
64			runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
65		}
66		Some(Subcommand::CheckBlock(cmd)) => {
67			let runner = cli.create_runner(cmd)?;
68			runner.async_run(|mut config| {
69				let (client, _, import_queue, task_manager, _) =
70					service::new_chain_ops(&mut config, &cli.eth)?;
71				Ok((cmd.run(client, import_queue), task_manager))
72			})
73		}
74		Some(Subcommand::ExportBlocks(cmd)) => {
75			let runner = cli.create_runner(cmd)?;
76			runner.async_run(|mut config| {
77				let (client, _, _, task_manager, _) =
78					service::new_chain_ops(&mut config, &cli.eth)?;
79				Ok((cmd.run(client, config.database), task_manager))
80			})
81		}
82		Some(Subcommand::ExportState(cmd)) => {
83			let runner = cli.create_runner(cmd)?;
84			runner.async_run(|mut config| {
85				let (client, _, _, task_manager, _) =
86					service::new_chain_ops(&mut config, &cli.eth)?;
87				Ok((cmd.run(client, config.chain_spec), task_manager))
88			})
89		}
90		Some(Subcommand::ImportBlocks(cmd)) => {
91			let runner = cli.create_runner(cmd)?;
92			runner.async_run(|mut config| {
93				let (client, _, import_queue, task_manager, _) =
94					service::new_chain_ops(&mut config, &cli.eth)?;
95				Ok((cmd.run(client, import_queue), task_manager))
96			})
97		}
98		Some(Subcommand::PurgeChain(cmd)) => {
99			let runner = cli.create_runner(cmd)?;
100			runner.sync_run(|config| {
101				// Remove Frontier offchain db
102				let db_config_dir = db_config_dir(&config);
103				match cli.eth.frontier_backend_type {
104					crate::eth::BackendType::KeyValue => {
105						let frontier_database_config = match config.database {
106							DatabaseSource::RocksDb { .. } => DatabaseSource::RocksDb {
107								path: frontier_database_dir(&db_config_dir, "db"),
108								cache_size: 0,
109							},
110							DatabaseSource::ParityDb { .. } => DatabaseSource::ParityDb {
111								path: frontier_database_dir(&db_config_dir, "paritydb"),
112							},
113							_ => {
114								return Err(format!(
115									"Cannot purge `{:?}` database",
116									config.database
117								)
118								.into())
119							}
120						};
121						cmd.run(frontier_database_config)?;
122					}
123					crate::eth::BackendType::Sql => {
124						let db_path = db_config_dir.join("sql");
125						match std::fs::remove_dir_all(&db_path) {
126							Ok(_) => {
127								println!("{:?} removed.", &db_path);
128							}
129							Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => {
130								eprintln!("{:?} did not exist.", &db_path);
131							}
132							Err(err) => {
133								return Err(
134									format!("Cannot purge `{db_path:?}` database: {err:?}").into()
135								)
136							}
137						};
138					}
139				};
140				cmd.run(config.database)
141			})
142		}
143		Some(Subcommand::Revert(cmd)) => {
144			let runner = cli.create_runner(cmd)?;
145			runner.async_run(|mut config| {
146				let (client, backend, _, task_manager, _) =
147					service::new_chain_ops(&mut config, &cli.eth)?;
148				let aux_revert = Box::new(move |client, _, blocks| {
149					sc_consensus_grandpa::revert(client, blocks)?;
150					Ok(())
151				});
152				Ok((cmd.run(client, backend, Some(aux_revert)), task_manager))
153			})
154		}
155		#[cfg(feature = "runtime-benchmarks")]
156		Some(Subcommand::Benchmark(cmd)) => {
157			use crate::benchmarking::{
158				inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder,
159			};
160			use frame_benchmarking_cli::{
161				BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE,
162			};
163			use frontier_template_runtime::{Hashing, EXISTENTIAL_DEPOSIT};
164
165			let runner = cli.create_runner(cmd)?;
166			match cmd {
167				BenchmarkCmd::Pallet(cmd) => runner
168					.sync_run(|config| cmd.run_with_spec::<Hashing, ()>(Some(config.chain_spec))),
169				BenchmarkCmd::Block(cmd) => runner.sync_run(|mut config| {
170					let (client, _, _, _, _) = service::new_chain_ops(&mut config, &cli.eth)?;
171					cmd.run(client)
172				}),
173				BenchmarkCmd::Storage(cmd) => runner.sync_run(|mut config| {
174					let (client, backend, _, _, _) = service::new_chain_ops(&mut config, &cli.eth)?;
175					let db = backend.expose_db();
176					let storage = backend.expose_storage();
177					let shared_cache = backend.expose_shared_trie_cache();
178					cmd.run(config, client, db, storage, shared_cache)
179				}),
180				BenchmarkCmd::Overhead(cmd) => runner.sync_run(|mut config| {
181					let (client, _, _, _, _) = service::new_chain_ops(&mut config, &cli.eth)?;
182					let ext_builder = RemarkBuilder::new(client.clone());
183					cmd.run(
184						config.chain_spec.name().into(),
185						client,
186						inherent_benchmark_data()?,
187						Vec::new(),
188						&ext_builder,
189						false,
190					)
191				}),
192				BenchmarkCmd::Extrinsic(cmd) => runner.sync_run(|mut config| {
193					let (client, _, _, _, _) = service::new_chain_ops(&mut config, &cli.eth)?;
194					// Register the *Remark* and *TKA* builders.
195					let ext_factory = ExtrinsicFactory(vec![
196						Box::new(RemarkBuilder::new(client.clone())),
197						Box::new(TransferKeepAliveBuilder::new(
198							client.clone(),
199							get_account_id_from_seed::<sp_core::ecdsa::Public>("Alice"),
200							EXISTENTIAL_DEPOSIT,
201						)),
202					]);
203
204					cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory)
205				}),
206				BenchmarkCmd::Machine(cmd) => {
207					runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()))
208				}
209			}
210		}
211		#[cfg(not(feature = "runtime-benchmarks"))]
212		Some(Subcommand::Benchmark) => Err("Benchmarking wasn't enabled when building the node. \
213			You can enable it with `--features runtime-benchmarks`."
214			.into()),
215		Some(Subcommand::FrontierDb(cmd)) => {
216			let runner = cli.create_runner(cmd)?;
217			runner.sync_run(|mut config| {
218				let (client, _, _, _, frontier_backend) =
219					service::new_chain_ops(&mut config, &cli.eth)?;
220				let frontier_backend = match frontier_backend {
221					fc_db::Backend::KeyValue(kv) => kv,
222					_ => panic!("Only fc_db::Backend::KeyValue supported"),
223				};
224				cmd.run(client, frontier_backend)
225			})
226		}
227		None => {
228			let runner = cli.create_runner(&cli.run)?;
229			runner.run_node_until_exit(|config| async move {
230				service::build_full(config, cli.eth, cli.sealing)
231					.map_err(Into::into)
232					.await
233			})
234		}
235	}
236}