command.rs 12 KB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

use log::info;
Seun Lanlege's avatar
Seun Lanlege committed
18
use service::{IdentifyVariant, self};
19
use sc_cli::{SubstrateCli, RuntimeVersion, Role};
Gavin Wood's avatar
Gavin Wood committed
20
use crate::cli::{Cli, Subcommand};
21
use futures::future::TryFutureExt;
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#[derive(thiserror::Error, Debug)]
pub enum Error {
	#[error(transparent)]
	PolkadotService(#[from] service::Error),

	#[error(transparent)]
	SubstrateCli(#[from] sc_cli::Error),

	#[error(transparent)]
	SubstrateService(#[from] sc_service::Error),

	#[error("Other: {0}")]
	Other(String),
}

impl std::convert::From<String> for Error {
	fn from(s: String) -> Self {
		Self::Other(s)
	}
}

type Result<T> = std::result::Result<T, Error>;

Gavin Wood's avatar
Gavin Wood committed
46
47
48
49
50
51
52
fn get_exec_name() -> Option<String> {
	std::env::current_exe()
		.ok()
		.and_then(|pb| pb.file_name().map(|s| s.to_os_string()))
		.and_then(|s| s.into_string().ok())
}

53
impl SubstrateCli for Cli {
54
	fn impl_name() -> String { "Parity Polkadot".into() }
55

56
	fn impl_version() -> String { env!("SUBSTRATE_CLI_IMPL_VERSION").into() }
57

58
	fn description() -> String { env!("CARGO_PKG_DESCRIPTION").into() }
59

60
	fn author() -> String { env!("CARGO_PKG_AUTHORS").into() }
61

62
	fn support_url() -> String { "https://github.com/paritytech/polkadot/issues/new".into() }
63
64
65

	fn copyright_start_year() -> i32 { 2017 }

66
	fn executable_name() -> String { "polkadot".into() }
67
68

	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
Gavin Wood's avatar
Gavin Wood committed
69
70
		let id = if id == "" {
			let n = get_exec_name().unwrap_or_default();
71
			["polkadot", "kusama", "westend", "rococo"].iter()
Gavin Wood's avatar
Gavin Wood committed
72
73
74
75
				.cloned()
				.find(|&chain| n.starts_with(chain))
				.unwrap_or("polkadot")
		} else { id };
76
		Ok(match id {
Wei Tang's avatar
Wei Tang committed
77
78
79
80
81
82
			"polkadot-dev" | "dev" => Box::new(service::chain_spec::polkadot_development_config()?),
			"polkadot-local" => Box::new(service::chain_spec::polkadot_local_testnet_config()?),
			"polkadot-staging" => Box::new(service::chain_spec::polkadot_staging_testnet_config()?),
			"kusama-dev" => Box::new(service::chain_spec::kusama_development_config()?),
			"kusama-local" => Box::new(service::chain_spec::kusama_local_testnet_config()?),
			"kusama-staging" => Box::new(service::chain_spec::kusama_staging_testnet_config()?),
Gavin Wood's avatar
Gavin Wood committed
83
			"polkadot" => Box::new(service::chain_spec::polkadot_config()?),
84
			"westend" => Box::new(service::chain_spec::westend_config()?),
Gavin Wood's avatar
Gavin Wood committed
85
			"kusama" => Box::new(service::chain_spec::kusama_config()?),
Wei Tang's avatar
Wei Tang committed
86
87
88
			"westend-dev" => Box::new(service::chain_spec::westend_development_config()?),
			"westend-local" => Box::new(service::chain_spec::westend_local_testnet_config()?),
			"westend-staging" => Box::new(service::chain_spec::westend_staging_testnet_config()?),
89
90
91
			"rococo-staging" => Box::new(service::chain_spec::rococo_staging_testnet_config()?),
			"rococo-local" => Box::new(service::chain_spec::rococo_local_testnet_config()?),
			"rococo" => Box::new(service::chain_spec::rococo_config()?),
92
			"wococo" => Box::new(service::chain_spec::wococo_config()?),
93
94
95
96
97
98
99
100
101
			path => {
				let path = std::path::PathBuf::from(path);

				let starts_with = |prefix: &str| {
					path.file_name().map(|f| f.to_str().map(|s| s.starts_with(&prefix))).flatten().unwrap_or(false)
				};

				// When `force_*` is given or the file name starts with the name of one of the known chains,
				// we use the chain spec for the specific chain.
102
				if self.run.force_rococo || starts_with("rococo") || starts_with("wococo") {
103
104
					Box::new(service::RococoChainSpec::from_json_file(path)?)
				} else if self.run.force_kusama || starts_with("kusama") {
105
106
107
108
109
110
					Box::new(service::KusamaChainSpec::from_json_file(path)?)
				} else if self.run.force_westend || starts_with("westend") {
					Box::new(service::WestendChainSpec::from_json_file(path)?)
				} else {
					Box::new(service::PolkadotChainSpec::from_json_file(path)?)
				}
111
112
113
			},
		})
	}
114
115
116
117
118
119

	fn native_runtime_version(spec: &Box<dyn service::ChainSpec>) -> &'static RuntimeVersion {
		if spec.is_kusama() {
			&service::kusama_runtime::VERSION
		} else if spec.is_westend() {
			&service::westend_runtime::VERSION
120
		} else if spec.is_rococo() || spec.is_wococo() {
121
			&service::rococo_runtime::VERSION
122
123
124
125
		} else {
			&service::polkadot_runtime::VERSION
		}
	}
126
}
Gavin Wood's avatar
Gavin Wood committed
127

128
129
130
131
132
133
134
135
136
137
138
139
140
141
fn set_default_ss58_version(spec: &Box<dyn service::ChainSpec>) {
	use sp_core::crypto::Ss58AddressFormat;

	let ss58_version = if spec.is_kusama() {
		Ss58AddressFormat::KusamaAccount
	} else if spec.is_westend() {
		Ss58AddressFormat::SubstrateAccount
	} else {
		Ss58AddressFormat::PolkadotAccount
	};

	sp_core::crypto::set_default_ss58_version(ss58_version);
}

142
143
144
145
const DEV_ONLY_ERROR_PATTERN: &'static str =
	"can only use subcommand with --chain [polkadot-dev, kusama-dev, westend-dev], got ";

fn ensure_dev(spec: &Box<dyn service::ChainSpec>) -> std::result::Result<(), String> {
Kian Paimani's avatar
Kian Paimani committed
146
147
148
149
150
	if spec.is_dev() {
		Ok(())
	} else {
		Err(format!("{}{}", DEV_ONLY_ERROR_PATTERN, spec.id()))
	}
151
152
}

Gavin Wood's avatar
Gavin Wood committed
153
/// Parses polkadot specific CLI arguments and run the service.
154
155
156
157
pub fn run() -> Result<()> {
	let cli = Cli::from_args();

	match &cli.subcommand {
Gavin Wood's avatar
Gavin Wood committed
158
		None => {
159
160
			let runner = cli.create_runner(&cli.run.base)
				.map_err(Error::from)?;
161
			let chain_spec = &runner.config().chain_spec;
162
163
164

			set_default_ss58_version(chain_spec);

165
166
167
168
169
			let grandpa_pause = if cli.run.grandpa_pause.is_empty() {
				None
			} else {
				Some((cli.run.grandpa_pause[0], cli.run.grandpa_pause[1]))
			};
Gavin Wood's avatar
Gavin Wood committed
170

171
			if chain_spec.is_kusama() {
Gavin Wood's avatar
Gavin Wood committed
172
173
174
175
176
				info!("----------------------------");
				info!("This chain is not in any way");
				info!("      endorsed by the       ");
				info!("     KUSAMA FOUNDATION      ");
				info!("----------------------------");
177
			}
Gavin Wood's avatar
Gavin Wood committed
178

179
			let jaeger_agent = cli.run.jaeger_agent;
180

181
			runner.run_node_until_exit(move |config| async move {
182
183
				let role = config.role.clone();

184
				let task_manager = match role {
185
					Role::Light => service::build_light(config).map(|(task_manager, _)| task_manager),
186
187
					_ => service::build_full(
						config,
188
						service::IsCollator::No,
189
						grandpa_pause,
190
						jaeger_agent,
191
						None,
192
					).map(|full| full.task_manager)
193
194
195
				}?;
				Ok::<_, Error>(task_manager)
			})
Gavin Wood's avatar
Gavin Wood committed
196
		},
197
198
		Some(Subcommand::BuildSpec(cmd)) => {
			let runner = cli.create_runner(cmd)?;
199
200
201
			Ok(runner.sync_run(|config| {
				cmd.run(config.chain_spec, config.network)
			})?)
202
203
		},
		Some(Subcommand::CheckBlock(cmd)) => {
204
205
			let runner = cli.create_runner(cmd)
				.map_err(Error::SubstrateCli)?;
206
207
208
209
210
			let chain_spec = &runner.config().chain_spec;

			set_default_ss58_version(chain_spec);

			runner.async_run(|mut config| {
211
212
				let (client, _, import_queue, task_manager) = service::new_chain_ops(&mut config, None)?;
				Ok((cmd.run(client, import_queue).map_err(Error::SubstrateCli), task_manager))
213
214
215
216
			})
		},
		Some(Subcommand::ExportBlocks(cmd)) => {
			let runner = cli.create_runner(cmd)?;
217
			let chain_spec = &runner.config().chain_spec;
218
219

			set_default_ss58_version(chain_spec);
Gavin Wood's avatar
Gavin Wood committed
220

221
			Ok(runner.async_run(|mut config| {
222
				let (client, _, _, task_manager) = service::new_chain_ops(&mut config, None)
223
224
225
					.map_err(Error::PolkadotService)?;
				Ok((cmd.run(client, config.database).map_err(Error::SubstrateCli), task_manager))
			})?)
226
227
228
229
230
231
232
		},
		Some(Subcommand::ExportState(cmd)) => {
			let runner = cli.create_runner(cmd)?;
			let chain_spec = &runner.config().chain_spec;

			set_default_ss58_version(chain_spec);

233
234
235
236
			Ok(runner.async_run(|mut config| {
				let (client, _, _, task_manager) = service::new_chain_ops(&mut config, None)?;
				Ok((cmd.run(client, config.chain_spec).map_err(Error::SubstrateCli), task_manager))
			})?)
237
238
239
240
241
242
243
		},
		Some(Subcommand::ImportBlocks(cmd)) => {
			let runner = cli.create_runner(cmd)?;
			let chain_spec = &runner.config().chain_spec;

			set_default_ss58_version(chain_spec);

244
245
246
247
			Ok(runner.async_run(|mut config| {
				let (client, _, import_queue, task_manager) = service::new_chain_ops(&mut config, None)?;
				Ok((cmd.run(client, import_queue).map_err(Error::SubstrateCli), task_manager))
			})?)
248
249
250
		},
		Some(Subcommand::PurgeChain(cmd)) => {
			let runner = cli.create_runner(cmd)?;
251
			Ok(runner.sync_run(|config| cmd.run(config.database))?)
252
253
254
255
256
257
258
		},
		Some(Subcommand::Revert(cmd)) => {
			let runner = cli.create_runner(cmd)?;
			let chain_spec = &runner.config().chain_spec;

			set_default_ss58_version(chain_spec);

259
260
			Ok(runner.async_run(|mut config| {
				let (client, backend, _, task_manager) = service::new_chain_ops(&mut config, None)?;
Kian Paimani's avatar
Kian Paimani committed
261
				Ok((cmd.run(client, backend).map_err(Error::SubstrateCli), task_manager))
262
			})?)
Gavin Wood's avatar
Gavin Wood committed
263
		},
264
		Some(Subcommand::PvfPrepareWorker(cmd)) => {
Cecile Tonglet's avatar
Cecile Tonglet committed
265
			let mut builder = sc_cli::LoggerBuilder::new("");
266
267
			builder.with_colors(false);
			let _ = builder.init();
Gavin Wood's avatar
Gavin Wood committed
268

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
			#[cfg(any(target_os = "android", feature = "browser"))]
			{
				return Err(
					sc_cli::Error::Input("PVF preparation workers are not supported under this platform".into()).into()
				);
			}

			#[cfg(not(any(target_os = "android", feature = "browser")))]
			{
				polkadot_node_core_pvf::prepare_worker_entrypoint(&cmd.socket_path);
				Ok(())
			}
		},
		Some(Subcommand::PvfExecuteWorker(cmd)) => {
			let mut builder = sc_cli::LoggerBuilder::new("");
			builder.with_colors(false);
			let _ = builder.init();

			#[cfg(any(target_os = "android", feature = "browser"))]
			{
				return Err(
					sc_cli::Error::Input("PVF execution workers are not supported under this platform".into()).into()
				);
			}

			#[cfg(not(any(target_os = "android", feature = "browser")))]
			{
				polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path);
Gavin Wood's avatar
Gavin Wood committed
297
298
299
				Ok(())
			}
		},
300
		Some(Subcommand::Benchmark(cmd)) => {
301
302
			let runner = cli.create_runner(cmd)?;
			let chain_spec = &runner.config().chain_spec;
303
			set_default_ss58_version(chain_spec);
304

305
			ensure_dev(chain_spec).map_err(Error::Other)?;
Kian Paimani's avatar
Kian Paimani committed
306
			if chain_spec.is_kusama() {
307
308
309
310
311
312
313
314
315
316
				Ok(runner.sync_run(|config| {
					cmd.run::<service::kusama_runtime::Block, service::KusamaExecutor>(config)
						.map_err(|e| Error::SubstrateCli(e))
				})?)
			} else if chain_spec.is_westend() {
				Ok(runner.sync_run(|config| {
					cmd.run::<service::westend_runtime::Block, service::WestendExecutor>(config)
						.map_err(|e| Error::SubstrateCli(e))
				})?)
			} else {
Kian Paimani's avatar
Kian Paimani committed
317
318
319
320
321
				// else we assume it is polkadot.
				Ok(runner.sync_run(|config| {
					cmd.run::<service::polkadot_runtime::Block, service::PolkadotExecutor>(config)
						.map_err(|e| Error::SubstrateCli(e))
				})?)
322
			}
323
		},
324
		Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
Kian Paimani's avatar
Kian Paimani committed
325
326
327
328
329
330
		#[cfg(feature = "try-runtime")]
		Some(Subcommand::TryRuntime(cmd)) => {
			let runner = cli.create_runner(cmd)?;
			let chain_spec = &runner.config().chain_spec;
			set_default_ss58_version(chain_spec);

331
332
333
334
335
336
337
338
			use sc_service::TaskManager;
			let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry);
			let task_manager = TaskManager::new(
				runner.config().task_executor.clone(),
				*registry,
			).map_err(|e| Error::SubstrateService(sc_service::Error::Prometheus(e)))?;

			ensure_dev(chain_spec).map_err(Error::Other)?;
Kian Paimani's avatar
Kian Paimani committed
339
			if chain_spec.is_kusama() {
340
341
				runner.async_run(|config| {
					Ok((cmd.run::<
Kian Paimani's avatar
Kian Paimani committed
342
343
						service::kusama_runtime::Block,
						service::KusamaExecutor,
344
345
346
347
348
349
350
351
352
353
					>(config).map_err(Error::SubstrateCli), task_manager))
				})
			} else if chain_spec.is_westend() {
				runner.async_run(|config| {
					Ok((cmd.run::<
						service::westend_runtime::Block,
						service::WestendExecutor,
					>(config).map_err(Error::SubstrateCli), task_manager))
				})
			} else {
Kian Paimani's avatar
Kian Paimani committed
354
355
356
357
358
359
360
				// else we assume it is polkadot.
				runner.async_run(|config| {
					Ok((cmd.run::<
						service::polkadot_runtime::Block,
						service::PolkadotExecutor,
					>(config).map_err(Error::SubstrateCli), task_manager))
				})
361
			}
Kian Paimani's avatar
Kian Paimani committed
362
		}
363
364
	}?;
	Ok(())
Gavin Wood's avatar
Gavin Wood committed
365
}