Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Merge branch 'master' into docker
Browse files Browse the repository at this point in the history
  • Loading branch information
chevdor authored Jul 21, 2018
2 parents f22a115 + 3269611 commit 6ee3647
Show file tree
Hide file tree
Showing 42 changed files with 1,895 additions and 779 deletions.
339 changes: 188 additions & 151 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,6 @@ travis-ci = { repository = "paritytech/polkadot", branch = "master" }
maintenance = { status = "actively-developed" }
is-it-maintained-issue-resolution = { repository = "paritytech/polkadot" }
is-it-maintained-open-issues = { repository = "paritytech/polkadot" }

[profile.release]
panic = "abort"
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ one. First, get Rust (1.26.1 or later) and the support software if you don't alr

```
curl https://sh.rustup.rs -sSf | sh
sudo apt install make clang
sudo apt install make clang pkg-config libssl-dev
```

Then, install Polkadot PoC-2:
Expand Down Expand Up @@ -135,3 +135,38 @@ You can either build it yourself (it takes a while...):
cd docker
./build.sh
```

## 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 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
```
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:
```
COMPL_DIR=$HOME/.completion
mkdir -p $COMPL_DIR
cp -f target/release/completion-scripts/polkadot.bash $COMPL_DIR/
source $HOME/.bash_profile
```
10 changes: 8 additions & 2 deletions polkadot/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ 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.27", features = ["yaml"] }
clap = { version = "~2.32", features = ["yaml"] }
backtrace = "0.3"
env_logger = "0.4"
error-chain = "0.12"
log = "0.3"
atty = "0.2"
regex = "0.2"
regex = "1"
time = "0.1"
slog = "^2"
ansi_term = "0.10"
Expand Down Expand Up @@ -40,3 +42,7 @@ 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"
43 changes: 43 additions & 0 deletions polkadot/cli/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#[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);
}
4 changes: 0 additions & 4 deletions polkadot/cli/src/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ args:
value_name: KEY
help: Specify node secret key (64-character hex string)
takes_value: true
- collator:
long: collator
help: Enable collator mode
takes_value: false
- validator:
long: validator
help: Enable validator mode
Expand Down
108 changes: 81 additions & 27 deletions polkadot/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ extern crate triehash;
extern crate parking_lot;
extern crate serde;
extern crate serde_json;
extern crate names;
extern crate backtrace;

extern crate substrate_client as client;
extern crate substrate_network as network;
Expand Down Expand Up @@ -65,13 +67,14 @@ extern crate log;
pub mod error;
mod informant;
mod chain_spec;
mod panic_hook;

pub use chain_spec::ChainSpec;
pub use client::error::Error as ClientError;
pub use client::backend::Backend as ClientBackend;
pub use state_machine::Backend as StateMachineBackend;
pub use polkadot_primitives::Block as PolkadotBlock;
pub use service::{Components as ServiceComponents, Service};
pub use service::{Components as ServiceComponents, Service, CustomConfiguration};

use std::io::{self, Write, Read, stdin, stdout};
use std::fs::File;
Expand All @@ -82,12 +85,14 @@ use polkadot_primitives::BlockId;
use codec::{Decode, Encode};
use client::BlockOrigin;
use runtime_primitives::generic::SignedBlock;
use names::{Generator, Name};
use regex::Regex;

use futures::Future;
use tokio::runtime::Runtime;
use service::PruningMode;

const DEFAULT_TELEMETRY_URL: &str = "ws://telemetry.polkadot.io:1024";
const DEFAULT_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";

#[derive(Clone)]
struct SystemConfiguration {
Expand All @@ -113,7 +118,7 @@ fn load_spec(matches: &clap::ArgMatches) -> Result<(service::ChainSpec, bool), S
.map(ChainSpec::from)
.unwrap_or_else(|| if matches.is_present("dev") { ChainSpec::Development } else { ChainSpec::KrummeLanke });
let is_global = match chain_spec {
ChainSpec::KrummeLanke | ChainSpec::StagingTestnet => true,
ChainSpec::KrummeLanke => true,
_ => false,
};
let spec = chain_spec.load()?;
Expand All @@ -134,18 +139,46 @@ fn base_path(matches: &clap::ArgMatches) -> PathBuf {
pub trait Worker {
/// A future that resolves when the work is done or the node should exit.
/// This will be run on a tokio runtime.
type Work: Future<Item=(),Error=()>;
type Work: Future<Item=(),Error=()> + Send + 'static;

/// An exit scheduled for the future.
type Exit: Future<Item=(),Error=()> + Send + 'static;

/// Return configuration for the polkadot node.
// TODO: make this the full configuration, so embedded nodes don't need
// string CLI args
fn configuration(&self) -> CustomConfiguration { Default::default() }

/// Don't work, but schedule an exit.
fn exit_only(self) -> Self::Exit;

/// Do work and schedule exit.
fn work<C: ServiceComponents>(self, service: &Service<C>) -> Self::Work;
}

/// Check whether a node name is considered as valid
fn is_node_name_valid(_name: &str) -> Result<(), &str> {
const MAX_NODE_NAME_LENGTH: usize = 32;
let name = _name.to_string();
if name.chars().count() >= MAX_NODE_NAME_LENGTH {
return Err("Node name too long");
}

let invalid_chars = r"[\\.@]";
let re = Regex::new(invalid_chars).unwrap();
if re.is_match(&name) {
return Err("Node name should not contain invalid chars such as '.' and '@'");
}

let invalid_patterns = r"(https?:\\/+)?(www)+";
let re = Regex::new(invalid_patterns).unwrap();
if re.is_match(&name) {
return Err("Node name should not contain urls");
}

Ok(())
}

/// Parse command line arguments and start the node.
///
/// IANA unassigned port ranges that we could use:
Expand All @@ -159,15 +192,14 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where
T: Into<std::ffi::OsString> + Clone,
W: Worker,
{
panic_hook::set();

let yaml = load_yaml!("./cli.yml");
let matches = match clap::App::from_yaml(yaml).version(&(crate_version!().to_owned() + "\n")[..]).get_matches_from_safe(args) {
Ok(m) => m,
Err(ref e) if e.kind == clap::ErrorKind::VersionDisplayed => return Ok(()),
Err(ref e) if e.kind == clap::ErrorKind::HelpDisplayed => {
print!("{}", e);
return Ok(())
}
Err(e) => e.exit(),
let matches = match clap::App::from_yaml(yaml)
.version(&(crate_version!().to_owned() + "\n")[..])
.get_matches_from_safe(args) {
Ok(m) => m,
Err(e) => e.exit(),
};

// TODO [ToDr] Split parameters parsing from actual execution.
Expand All @@ -194,9 +226,14 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where
let (spec, is_global) = load_spec(&matches)?;
let mut config = service::Configuration::default_with_spec(spec);

if let Some(name) = matches.value_of("name") {
config.name = name.into();
info!("Node name: {}", config.name);
config.name = match matches.value_of("name") {
None => Generator::with_naming(Name::Numbered).next().unwrap(),
Some(name) => name.into(),
};
match is_node_name_valid(&config.name) {
Ok(_) => info!("Node name: {}", config.name),
Err(msg) => return Err(error::ErrorKind::Input(
format!("Invalid node name '{}'. Reason: {}. If unsure, use none.", config.name, msg)).into())
}

let base_path = base_path(&matches);
Expand All @@ -217,13 +254,7 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where
};

let role =
if matches.is_present("collator") {
info!("Starting collator");
// TODO [rob]: collation node implementation
// This isn't a thing. Different parachains will have their own collator executables and
// maybe link to libpolkadot to get a light-client.
service::Roles::LIGHT
} else if matches.is_present("light") {
if matches.is_present("light") {
info!("Starting (light)");
config.execution_strategy = service::ExecutionStrategy::NativeWhenPossible;
service::Roles::LIGHT
Expand Down Expand Up @@ -262,9 +293,10 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where
config.network.net_config_path = config.network.config_path.clone();

let port = match matches.value_of("port") {
Some(port) => port.parse().expect("Invalid p2p port value specified."),
Some(port) => port.parse().map_err(|_| "Invalid p2p port value specified.")?,
None => 30333,
};

config.network.listen_address = Some(SocketAddr::new("0.0.0.0".parse().unwrap(), port));
config.network.public_address = None;
config.network.client_version = format!("parity-polkadot/{}", crate_version!());
Expand All @@ -275,6 +307,8 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where
};
}

config.custom = worker.configuration();

config.keys = matches.values_of("key").unwrap_or_default().map(str::to_owned).collect();
if matches.is_present("dev") {
config.keys.push("Alice".into());
Expand Down Expand Up @@ -430,8 +464,8 @@ fn import_blocks<E>(matches: &clap::ArgMatches, exit: E) -> error::Result<()>
None => Box::new(stdin()),
};

info!("Importing blocks");
let count: u32 = Decode::decode(&mut file).ok_or("Error reading file")?;
info!("Importing {} blocks", count);
let mut block = 0;
for _ in 0 .. count {
if exit_recv.try_recv().is_ok() {
Expand All @@ -448,7 +482,7 @@ fn import_blocks<E>(matches: &clap::ArgMatches, exit: E) -> error::Result<()>
}
}
block += 1;
if block % 10000 == 0 {
if block % 1000 == 0 {
info!("#{}", block);
}
}
Expand Down Expand Up @@ -494,7 +528,7 @@ fn run_until_exit<C, W>(
)
};

let _ = worker.work(&service).wait();
let _ = runtime.block_on(worker.work(&service));
exit_send.fire();
Ok(())
}
Expand Down Expand Up @@ -607,7 +641,27 @@ fn init_logger(pattern: &str) {

fn kill_color(s: &str) -> String {
lazy_static! {
static ref RE: regex::Regex = regex::Regex::new("\x1b\\[[^m]+m").expect("Error initializing color regex");
static ref RE: Regex = Regex::new("\x1b\\[[^m]+m").expect("Error initializing color regex");
}
RE.replace_all(s, "").to_string()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn tests_node_name_good() {
assert!(is_node_name_valid("short name").is_ok());
}

#[test]
fn tests_node_name_bad() {
assert!(is_node_name_valid("long names are not very cool for the ui").is_err());
assert!(is_node_name_valid("Dots.not.Ok").is_err());
assert!(is_node_name_valid("http://visit.me").is_err());
assert!(is_node_name_valid("https://visit.me").is_err());
assert!(is_node_name_valid("www.visit.me").is_err());
assert!(is_node_name_valid("email@domain").is_err());
}
}
Loading

0 comments on commit 6ee3647

Please sign in to comment.