Commit 1fb72bf3 authored by Arkadiy Paronyan's avatar Arkadiy Paronyan Committed by Gav Wood
Browse files

Substrate CLI (#423)

* Moved chain ops to substrate-service

* moved RPC to susbstrate-service WIP

* Moved RPC to substrate-service

* Version

* Removed redundadnt messages

* substrate CLI

* Removed obsolete files

* Sorted out startup messages

* Pass executable name to CLI
parent d4696b99
......@@ -3,30 +3,18 @@ name = "polkadot-cli"
version = "0.2.0"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Polkadot node implementation in Rust."
build = "build.rs"
[dependencies]
clap = { version = "~2.32", features = ["yaml"] }
backtrace = "0.3"
env_logger = "0.4"
error-chain = "0.12"
log = "0.3"
atty = "0.2"
regex = "1"
time = "0.1"
slog = "^2"
ansi_term = "0.10"
lazy_static = "1.0"
triehash = "0.1"
ed25519 = { path = "../../substrate/ed25519" }
app_dirs = "1.2"
tokio = "0.1.7"
futures = "0.1.17"
fdlimit = "0.1"
parking_lot = "0.4"
serde_json = "1.0"
serde = "1.0"
exit-future = "0.1"
substrate-cli = { path = "../../substrate/cli" }
substrate-client = { path = "../../substrate/client" }
substrate-codec = { path = "../../substrate/codec" }
substrate-extrinsic-pool = { path = "../../substrate/extrinsic-pool" }
......@@ -42,7 +30,4 @@ polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
polkadot-service = { path = "../service" }
polkadot-transaction-pool = { path = "../transaction-pool" }
names = "0.11.0"
[build-dependencies]
clap = "~2.32"
= Polkadot CLI
== Summary
[source, toml]
----
include::Cargo.toml[lines=2..5]
----
include::doc/shell-completion.adoc[]
#[macro_use]
extern crate clap;
use std::fs;
use std::env;
use clap::Shell;
use std::path::Path;
fn main() {
build_shell_completion();
}
/// Build shell completion scripts for all known shells
/// Full list in https://github.com/kbknapp/clap-rs/blob/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9/src/app/parser.rs#L123
fn build_shell_completion() {
let shells = [Shell::Bash, Shell::Fish, Shell::Zsh, Shell::Elvish, Shell::PowerShell];
for shell in shells.iter() {
build_completion(shell);
}
}
/// Build the shell auto-completion for a given Shell
fn build_completion(shell: &Shell) {
let yml = load_yaml!("src/cli.yml");
let outdir = match env::var_os("OUT_DIR") {
None => return,
Some(dir) => dir,
};
let path = Path::new(&outdir)
.parent().unwrap()
.parent().unwrap()
.parent().unwrap()
.join("completion-scripts");
fs::create_dir(&path).ok();
let mut app = clap::App::from_yaml(&yml);
app.gen_completions(
"polkadot",
*shell,
&path);
}
== Shell completion
The Polkadot cli command supports shell auto-completion. For this to work, you will need to run the completion script matching you build and system.
Assuming you built a release version using `cargo build --release` and use `bash` run the following:
[source, shell]
source target/release/completion-scripts/polkadot.bash
You can find completion scripts for:
- bash
- fish
- zsh
- elvish
- powershell
To make this change persistent, you can proceed as follow:
.First install
[source, shell]
----
COMPL_DIR=$HOME/.completion
mkdir -p $COMPL_DIR
cp -f target/release/completion-scripts/polkadot.bash $COMPL_DIR/
echo "source $COMPL_DIR/polkadot.bash" >> $HOME/.bash_profile
source $HOME/.bash_profile
----
.Update
When you build a new version of Polkadot, the following will ensure you auto-completion script matches the current binary:
[source, shell]
----
COMPL_DIR=$HOME/.completion
mkdir -p $COMPL_DIR
cp -f target/release/completion-scripts/polkadot.bash $COMPL_DIR/
source $HOME/.bash_profile
----
......@@ -17,7 +17,6 @@
//! Predefined chains.
use service;
use std::path::PathBuf;
/// The chain specification (this should eventually be replaced by a more general JSON-based chain
/// specification).
......@@ -31,8 +30,6 @@ pub enum ChainSpec {
KrummeLanke,
/// Whatever the current runtime is with the "global testnet" defaults.
StagingTestnet,
/// Custom Genesis file.
Custom(String),
}
/// Get a chain config from a spec setting.
......@@ -43,32 +40,18 @@ impl ChainSpec {
ChainSpec::Development => service::chain_spec::development_config(),
ChainSpec::LocalTestnet => service::chain_spec::local_testnet_config(),
ChainSpec::StagingTestnet => service::chain_spec::staging_testnet_config(),
ChainSpec::Custom(f) => service::ChainSpec::from_json_file(PathBuf::from(f))?,
})
}
}
impl<'a> From<&'a str> for ChainSpec {
fn from(s: &'a str) -> Self {
pub(crate) fn from(s: &str) -> Option<Self> {
match s {
"dev" => ChainSpec::Development,
"local" => ChainSpec::LocalTestnet,
"poc-1" => ChainSpec::KrummeLanke,
"krummelanke" => ChainSpec::KrummeLanke,
"staging" => ChainSpec::StagingTestnet,
s => ChainSpec::Custom(s.into()),
"dev" => Some(ChainSpec::Development),
"local" => Some(ChainSpec::LocalTestnet),
"poc-1" => Some(ChainSpec::KrummeLanke),
"" | "krummelanke" => Some(ChainSpec::KrummeLanke),
"staging" => Some(ChainSpec::StagingTestnet),
_ => None,
}
}
}
impl From<ChainSpec> for String {
fn from(s: ChainSpec) -> String {
match s {
ChainSpec::Development => "dev".into(),
ChainSpec::LocalTestnet => "local".into(),
ChainSpec::KrummeLanke => "krummelanke".into(),
ChainSpec::StagingTestnet => "staging".into(),
ChainSpec::Custom(f) => format!("custom ({})", f),
}
}
}
name: polkadot
author: "Parity Team <admin@parity.io>"
about: Polkadot Node Rust Implementation
args:
- log:
short: l
long: log
value_name: LOG_PATTERN
help: Sets a custom logging filter
takes_value: true
- base-path:
long: base-path
short: d
value_name: PATH
help: Specify custom base path
takes_value: true
- keystore-path:
long: keystore-path
value_name: PATH
help: Specify custom keystore path
takes_value: true
- key:
long: key
value_name: STRING
help: Specify additional key seed
takes_value: true
- node-key:
long: node-key
value_name: KEY
help: Specify node secret key (64-character hex string)
takes_value: true
- validator:
long: validator
help: Enable validator mode
takes_value: false
- light:
long: light
help: Run in light client mode
takes_value: false
- dev:
long: dev
help: Run in development mode; implies --chain=dev --validator --key Alice
takes_value: false
- port:
long: port
value_name: PORT
help: Specify p2p protocol TCP port
takes_value: true
- rpc-port:
long: rpc-port
value_name: PORT
help: Specify HTTP RPC server TCP port
takes_value: true
- ws-port:
long: ws-port
value_name: PORT
help: Specify WebSockets RPC server TCP port
takes_value: true
- bootnodes:
long: bootnodes
value_name: URL
help: Specify a list of bootnodes
takes_value: true
multiple: true
- chain:
long: chain
value_name: CHAIN_SPEC
help: Specify the chain specification (one of krummelanke, dev, local or staging)
takes_value: true
- pruning:
long: pruning
value_name: PRUNING_MODE
help: Specify the pruning mode, a number of blocks to keep or "archive". Default is 256.
takes_value: true
- name:
long: name
value_name: NAME
help: The human-readable name for this node, as reported to the telemetry server, if enabled
takes_value: true
- telemetry:
short: t
long: telemetry
help: Should connect to the Polkadot telemetry server (telemetry is off by default on local chains)
takes_value: false
- no-telemetry:
long: no-telemetry
help: Should not connect to the Polkadot telemetry server (telemetry is on by default on global chains)
takes_value: false
- telemetry-url:
long: telemetry-url
value_name: TELEMETRY_URL
help: The URL of the telemetry server. Implies --telemetry
takes_value: true
- execution:
long: execution
value_name: STRATEGY
help: The means of execution used when calling into the runtime. Can be either wasm, native or both.
- min-heap-pages:
long: min-heap-pages
value_name: COUNT
help: The number of 64KB pages to allocate for Wasm execution initially.
- max-heap-pages:
long: max-heap-pages
value_name: COUNT
help: The maximum number of 64KB pages to ever allocate for Wasm execution. Don't alter this unless you know what you're doing.
subcommands:
- build-spec:
about: Build a spec.json file, outputing to stdout
args:
- raw:
long: raw
help: Force raw genesis storage output.
takes_value: false
- chain:
long: chain
value_name: CHAIN_SPEC
help: Specify the chain specification (one of krummelanke, dev, local or staging)
takes_value: true
- export-blocks:
about: Export blocks to a file
args:
- OUTPUT:
index: 1
help: Output file name or stdout if unspecified.
required: false
- chain:
long: chain
value_name: CHAIN_SPEC
help: Specify the chain specification.
takes_value: true
- base-path:
long: base-path
short: d
value_name: PATH
help: Specify custom base path.
takes_value: true
- from:
long: from
value_name: BLOCK
help: Specify starting block number. 1 by default.
takes_value: true
- to:
long: to
value_name: BLOCK
help: Specify last block number. Best block by default.
takes_value: true
- json:
long: json
help: Use JSON output rather than binary.
takes_value: false
- import-blocks:
about: Import blocks from file.
args:
- INPUT:
index: 1
help: Input file or stdin if unspecified.
required: false
- chain:
long: chain
value_name: CHAIN_SPEC
help: Specify the chain specification.
takes_value: true
- base-path:
long: base-path
short: d
value_name: PATH
help: Specify custom base path.
takes_value: true
- execution:
long: execution
value_name: STRATEGY
help: The means of execution used when calling into the runtime. Can be either wasm, native or both.
- min-heap-pages:
long: min-heap-pages
value_name: COUNT
help: The number of 64KB pages to allocate for Wasm execution initially.
- max-heap-pages:
long: max-heap-pages
value_name: COUNT
help: The maximum number of 64KB pages to ever allocate for Wasm execution. Don't alter this unless you know what you're doing.
- revert:
about: Revert chain to the previous state
args:
- NUM:
index: 1
help: Number of blocks to revert. Default is 256.
- chain:
long: chain
value_name: CHAIN_SPEC
help: Specify the chain specification.
takes_value: true
- base-path:
long: base-path
short: d
value_name: PATH
help: Specify custom base path.
takes_value: true
// Copyright 2017 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/>.
//! Initialization errors.
use client;
error_chain! {
foreign_links {
Io(::std::io::Error) #[doc="IO error"];
Cli(::clap::Error) #[doc="CLI error"];
Service(::service::Error) #[doc="Polkadot service error"];
}
links {
Client(client::error::Error, client::error::ErrorKind) #[doc="Client error"];
}
errors {
/// Input error.
Input(m: String) {
description("Invalid input"),
display("{}", m),
}
}
}
// Copyright 2017 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/>.
//! Console informant. Prints sync progress and block events. Runs on the calling thread.
use std::time::{Duration, Instant};
use futures::{Future, Stream};
use service::{Service, Components};
use tokio::runtime::TaskExecutor;
use tokio::timer::Interval;
use network::{SyncState, SyncProvider};
use client::BlockchainEvents;
use runtime_primitives::traits::{Header, As};
use substrate_extrinsic_pool::api::ExtrinsicPool;
const TIMER_INTERVAL_MS: u64 = 5000;
/// Spawn informant on the event loop
pub fn start<C>(service: &Service<C>, exit: ::exit_future::Exit, handle: TaskExecutor)
where
C: Components,
{
let interval = Interval::new(Instant::now(), Duration::from_millis(TIMER_INTERVAL_MS));
let network = service.network();
let client = service.client();
let txpool = service.extrinsic_pool();
let display_notifications = interval.map_err(|e| debug!("Timer error: {:?}", e)).for_each(move |_| {
let sync_status = network.status();
if let Ok(best_block) = client.best_block_header() {
let hash = best_block.hash();
let num_peers = sync_status.num_peers;
let status = match (sync_status.sync.state, sync_status.sync.best_seen_block) {
(SyncState::Idle, _) => "Idle".into(),
(SyncState::Downloading, None) => "Syncing".into(),
(SyncState::Downloading, Some(n)) => format!("Syncing, target=#{}", n),
};
let txpool_status = txpool.light_status();
let best_number: u64 = best_block.number().as_();
info!(target: "polkadot", "{} ({} peers), best: #{} ({})", status, sync_status.num_peers, best_number, hash);
telemetry!("system.interval"; "status" => status, "peers" => num_peers, "height" => best_number, "best" => ?hash, "txcount" => txpool_status.transaction_count);
} else {
warn!("Error getting best block information");
}
Ok(())
});
let client = service.client();
let display_block_import = client.import_notification_stream().for_each(|n| {
info!(target: "polkadot", "Imported #{} ({})", n.header.number, n.hash);
Ok(())
});
let txpool = service.extrinsic_pool();
let display_txpool_import = txpool.import_notification_stream().for_each(move |_| {
let status = txpool.light_status();
telemetry!("txpool.import"; "mem_usage" => status.mem_usage, "count" => status.transaction_count, "sender" => status.senders);
Ok(())
});
let informant_work = display_notifications.join3(display_block_import, display_txpool_import);
handle.spawn(exit.until(informant_work).map(|_| ()));
}
This diff is collapsed.
// Copyright 2017 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/>.
//! Custom panic hook with bug report link
use backtrace::Backtrace;
use std::io::{self, Write};
use std::panic::{self, PanicInfo};
use std::thread;
/// Set the panic hook
pub fn set() {
panic::set_hook(Box::new(panic_hook));
}
static ABOUT_PANIC: &str = "
This is a bug. Please report it at:
https://github.com/paritytech/polkadot/issues/new
";
fn panic_hook(info: &PanicInfo) {
let location = info.location();
let file = location.as_ref().map(|l| l.file()).unwrap_or("<unknown>");
let line = location.as_ref().map(|l| l.line()).unwrap_or(0);
let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
None => match info.payload().downcast_ref::<String>() {
Some(s) => &s[..],
None => "Box<Any>",
}
};
let thread = thread::current();
let name = thread.name().unwrap_or("<unnamed>");
let backtrace = Backtrace::new();
let mut stderr = io::stderr();
let _ = writeln!(stderr, "");
let _ = writeln!(stderr, "====================");
let _ = writeln!(stderr, "");
let _ = writeln!(stderr, "{:?}", backtrace);
let _ = writeln!(stderr, "");
let _ = writeln!(
stderr,
"Thread '{}' panicked at '{}', {}:{}",
name, msg, file, line
);
let _ = writeln!(stderr, "{}", ABOUT_PANIC);
}
......@@ -68,7 +68,7 @@ use client::BlockchainEvents;
use polkadot_api::PolkadotApi;
use polkadot_primitives::{AccountId, BlockId, SessionKey};
use polkadot_primitives::parachain::{self, BlockData, DutyRoster, HeadData, ConsolidatedIngress, Message, Id as ParaId};
use polkadot_cli::{ServiceComponents, Service, CustomConfiguration};
use polkadot_cli::{ServiceComponents, Service, CustomConfiguration, VersionInfo};
use polkadot_cli::Worker;
use tokio::timer::Deadline;
......@@ -213,7 +213,7 @@ struct CollationNode<P, E> {
impl<P, E> Worker for CollationNode<P, E> where
P: ParachainContext + Send + 'static,
E: Future<Item=(),Error=()> + Send + 'static
E: Future<Item=(),Error=()> + Send + Clone + 'static
{
type Work = Box<Future<Item=(),Error=()> + Send>;
type Exit = E;
......@@ -227,8 +227,8 @@ impl<P, E> Worker for CollationNode<P, E> where
config
}
fn exit_only(self) -> Self::Exit {
self.exit
fn exit_only(&self) -> Self::Exit {
self.exit.clone()
}
fn work<C: ServiceComponents>(self, service: &Service<C>) -> Self::Work {
......@@ -323,14 +323,15 @@ pub fn run_collator<P, E>(
para_id: ParaId,
exit: E,
key: Arc<ed25519::Pair>,
args: Vec<::std::ffi::OsString>
args: Vec<::std::ffi::OsString>,
version: VersionInfo,
) -> polkadot_cli::error::Result<()> where
P: ParachainContext + Send + 'static,
E: IntoFuture<Item=(),Error=()>,
E::Future: Send + 'static,
E::Future: Send + Clone + 'static,
{
let node_logic = CollationNode { parachain_context, exit: exit.into_future(), para_id, key };
polkadot_cli::run(args, node_logic)