1use polkadot_sdk::*;
2
3use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions;
4use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE};
5use log::info;
6use parachain_template_runtime::Block;
7use sc_cli::{
8 ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
9 NetworkParams, Result, RpcEndpoint, SharedParams, SubstrateCli,
10};
11use sc_service::config::{BasePath, PrometheusConfig};
12
13use crate::{
14 chain_spec,
15 cli::{Cli, RelayChainCli, Subcommand},
16 service::new_partial,
17};
18
19fn load_spec(id: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
20 Ok(match id {
21 "dev" => Box::new(chain_spec::development_chain_spec()),
22 "template-rococo" => Box::new(chain_spec::local_chain_spec()),
23 "" | "local" => Box::new(chain_spec::local_chain_spec()),
24 path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
25 })
26}
27
28impl SubstrateCli for Cli {
29 fn impl_name() -> String {
30 "Parachain Collator Template".into()
31 }
32
33 fn impl_version() -> String {
34 env!("SUBSTRATE_CLI_IMPL_VERSION").into()
35 }
36
37 fn description() -> String {
38 format!(
39 "Parachain Collator Template\n\nThe command-line arguments provided first will be \
40 passed to the parachain node, while the arguments provided after -- will be passed \
41 to the relay chain node.\n\n\
42 {} <parachain-args> -- <relay-chain-args>",
43 Self::executable_name()
44 )
45 }
46
47 fn author() -> String {
48 env!("CARGO_PKG_AUTHORS").into()
49 }
50
51 fn support_url() -> String {
52 "https://github.com/paritytech/polkadot-sdk/issues/new".into()
53 }
54
55 fn copyright_start_year() -> i32 {
56 2020
57 }
58
59 fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
60 load_spec(id)
61 }
62}
63
64impl SubstrateCli for RelayChainCli {
65 fn impl_name() -> String {
66 "Parachain Collator Template".into()
67 }
68
69 fn impl_version() -> String {
70 env!("SUBSTRATE_CLI_IMPL_VERSION").into()
71 }
72
73 fn description() -> String {
74 format!(
75 "Parachain Collator Template\n\nThe command-line arguments provided first will be \
76 passed to the parachain node, while the arguments provided after -- will be passed \
77 to the relay chain node.\n\n\
78 {} <parachain-args> -- <relay-chain-args>",
79 Self::executable_name()
80 )
81 }
82
83 fn author() -> String {
84 env!("CARGO_PKG_AUTHORS").into()
85 }
86
87 fn support_url() -> String {
88 "https://github.com/paritytech/polkadot-sdk/issues/new".into()
89 }
90
91 fn copyright_start_year() -> i32 {
92 2020
93 }
94
95 fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
96 polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id)
97 }
98}
99
100macro_rules! construct_async_run {
101 (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{
102 let runner = $cli.create_runner($cmd)?;
103 runner.async_run(|$config| {
104 let $components = new_partial(&$config)?;
105 let task_manager = $components.task_manager;
106 { $( $code )* }.map(|v| (v, task_manager))
107 })
108 }}
109}
110
111pub fn run() -> Result<()> {
113 let cli = Cli::from_args();
114
115 match &cli.subcommand {
116 #[allow(deprecated)]
117 Some(Subcommand::BuildSpec(cmd)) => {
118 let runner = cli.create_runner(cmd)?;
119 runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
120 },
121 Some(Subcommand::CheckBlock(cmd)) => {
122 construct_async_run!(|components, cli, cmd, config| {
123 Ok(cmd.run(components.client, components.import_queue))
124 })
125 },
126 Some(Subcommand::ExportChainSpec(cmd)) => {
127 let chain_spec = cli.load_spec(&cmd.chain)?;
128 cmd.run(chain_spec)
129 },
130 Some(Subcommand::ExportBlocks(cmd)) => {
131 construct_async_run!(|components, cli, cmd, config| {
132 Ok(cmd.run(components.client, config.database))
133 })
134 },
135 Some(Subcommand::ExportState(cmd)) => {
136 construct_async_run!(|components, cli, cmd, config| {
137 Ok(cmd.run(components.client, config.chain_spec))
138 })
139 },
140 Some(Subcommand::ImportBlocks(cmd)) => {
141 construct_async_run!(|components, cli, cmd, config| {
142 Ok(cmd.run(components.client, components.import_queue))
143 })
144 },
145 Some(Subcommand::Revert(cmd)) => {
146 construct_async_run!(|components, cli, cmd, config| {
147 Ok(cmd.run(components.client, components.backend, None))
148 })
149 },
150 Some(Subcommand::PurgeChain(cmd)) => {
151 let runner = cli.create_runner(cmd)?;
152
153 runner.sync_run(|config| {
154 let polkadot_cli = RelayChainCli::new(
155 &config,
156 [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
157 );
158
159 let polkadot_config = SubstrateCli::create_configuration(
160 &polkadot_cli,
161 &polkadot_cli,
162 config.tokio_handle.clone(),
163 )
164 .map_err(|err| format!("Relay chain argument error: {err}"))?;
165
166 cmd.run(config, polkadot_config)
167 })
168 },
169 Some(Subcommand::ExportGenesisHead(cmd)) => {
170 let runner = cli.create_runner(cmd)?;
171 runner.sync_run(|config| {
172 let partials = new_partial(&config)?;
173
174 cmd.run(partials.client)
175 })
176 },
177 Some(Subcommand::ExportGenesisWasm(cmd)) => {
178 let runner = cli.create_runner(cmd)?;
179 runner.sync_run(|_config| {
180 let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?;
181 cmd.run(&*spec)
182 })
183 },
184 Some(Subcommand::Benchmark(cmd)) => {
185 let runner = cli.create_runner(cmd)?;
186 match cmd {
188 BenchmarkCmd::Pallet(cmd) =>
189 if cfg!(feature = "runtime-benchmarks") {
190 runner.sync_run(|config| cmd.run_with_spec::<sp_runtime::traits::HashingFor<Block>, ReclaimHostFunctions>(Some(config.chain_spec)))
191 } else {
192 Err("Benchmarking wasn't enabled when building the node. \
193 You can enable it with `--features runtime-benchmarks`."
194 .into())
195 },
196 BenchmarkCmd::Block(cmd) => runner.sync_run(|config| {
197 let partials = new_partial(&config)?;
198 cmd.run(partials.client)
199 }),
200 #[cfg(not(feature = "runtime-benchmarks"))]
201 BenchmarkCmd::Storage(_) => Err(sc_cli::Error::Input(
202 "Compile with --features=runtime-benchmarks \
203 to enable storage benchmarks."
204 .into(),
205 )),
206 #[cfg(feature = "runtime-benchmarks")]
207 BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| {
208 let partials = new_partial(&config)?;
209 let db = partials.backend.expose_db();
210 let storage = partials.backend.expose_storage();
211 let shared_cache = partials.backend.expose_shared_trie_cache();
212
213 cmd.run(config, partials.client.clone(), db, storage, shared_cache)
214 }),
215 BenchmarkCmd::Machine(cmd) =>
216 runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())),
217 #[allow(unreachable_patterns)]
220 _ => Err("Benchmarking sub-command unsupported".into()),
221 }
222 },
223 None => {
224 let runner = cli.create_runner(&cli.run.normalize())?;
225 let collator_options = cli.run.collator_options();
226
227 runner.run_node_until_exit(|config| async move {
228 let hwbench = (!cli.no_hardware_benchmarks)
229 .then(|| {
230 config.database.path().map(|database_path| {
231 let _ = std::fs::create_dir_all(database_path);
232 sc_sysinfo::gather_hwbench(
233 Some(database_path),
234 &SUBSTRATE_REFERENCE_HARDWARE,
235 )
236 })
237 })
238 .flatten();
239
240 let polkadot_cli = RelayChainCli::new(
241 &config,
242 [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
243 );
244
245 let tokio_handle = config.tokio_handle.clone();
246 let polkadot_config =
247 SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
248 .map_err(|err| format!("Relay chain argument error: {err}"))?;
249
250 info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
251
252 crate::service::start_parachain_node(
253 config,
254 polkadot_config,
255 collator_options,
256 hwbench,
257 )
258 .await
259 .map(|r| r.0)
260 .map_err(Into::into)
261 })
262 },
263 }
264}
265
266impl DefaultConfigurationValues for RelayChainCli {
267 fn p2p_listen_port() -> u16 {
268 30334
269 }
270
271 fn rpc_listen_port() -> u16 {
272 9945
273 }
274
275 fn prometheus_listen_port() -> u16 {
276 9616
277 }
278}
279
280impl CliConfiguration<Self> for RelayChainCli {
281 fn shared_params(&self) -> &SharedParams {
282 self.base.base.shared_params()
283 }
284
285 fn import_params(&self) -> Option<&ImportParams> {
286 self.base.base.import_params()
287 }
288
289 fn network_params(&self) -> Option<&NetworkParams> {
290 self.base.base.network_params()
291 }
292
293 fn keystore_params(&self) -> Option<&KeystoreParams> {
294 self.base.base.keystore_params()
295 }
296
297 fn base_path(&self) -> Result<Option<BasePath>> {
298 Ok(self
299 .shared_params()
300 .base_path()?
301 .or_else(|| self.base_path.clone().map(Into::into)))
302 }
303
304 fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<RpcEndpoint>>> {
305 self.base.base.rpc_addr(default_listen_port)
306 }
307
308 fn prometheus_config(
309 &self,
310 default_listen_port: u16,
311 chain_spec: &Box<dyn ChainSpec>,
312 ) -> Result<Option<PrometheusConfig>> {
313 self.base.base.prometheus_config(default_listen_port, chain_spec)
314 }
315
316 fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
317 where
318 F: FnOnce(&mut sc_cli::LoggerBuilder),
319 {
320 unreachable!("PolkadotCli is never initialized; qed");
321 }
322
323 fn chain_id(&self, is_dev: bool) -> Result<String> {
324 let chain_id = self.base.base.chain_id(is_dev)?;
325
326 Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id })
327 }
328
329 fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
330 self.base.base.role(is_dev)
331 }
332
333 fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
334 self.base.base.transaction_pool(is_dev)
335 }
336
337 fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
338 self.base.base.trie_cache_maximum_size()
339 }
340
341 fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
342 self.base.base.rpc_methods()
343 }
344
345 fn rpc_max_connections(&self) -> Result<u32> {
346 self.base.base.rpc_max_connections()
347 }
348
349 fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
350 self.base.base.rpc_cors(is_dev)
351 }
352
353 fn default_heap_pages(&self) -> Result<Option<u64>> {
354 self.base.base.default_heap_pages()
355 }
356
357 fn force_authoring(&self) -> Result<bool> {
358 self.base.base.force_authoring()
359 }
360
361 fn disable_grandpa(&self) -> Result<bool> {
362 self.base.base.disable_grandpa()
363 }
364
365 fn max_runtime_instances(&self) -> Result<Option<usize>> {
366 self.base.base.max_runtime_instances()
367 }
368
369 fn announce_block(&self) -> Result<bool> {
370 self.base.base.announce_block()
371 }
372
373 fn telemetry_endpoints(
374 &self,
375 chain_spec: &Box<dyn ChainSpec>,
376 ) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
377 self.base.base.telemetry_endpoints(chain_spec)
378 }
379
380 fn node_name(&self) -> Result<String> {
381 self.base.base.node_name()
382 }
383}