1use futures::TryFutureExt;
2use sc_cli::{ChainSpec, SubstrateCli};
4use sc_service::DatabaseSource;
5use 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
56pub 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 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 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}