Skip to content

Commit

Permalink
improve error handling in cli (paritytech#7436)
Browse files Browse the repository at this point in the history
* other error variant should carry a dyn Error

* introduce thiserror for error derive, add explicit error variants, cleanup dependencies

* cleanup handle dev-deps of sc-cli too

* Update client/cli/src/error.rs

Co-authored-by: Bastian Köcher <[email protected]>

Co-authored-by: Bernhard Schuster <[email protected]>
Co-authored-by: Bastian Köcher <[email protected]>
  • Loading branch information
3 people authored Oct 27, 2020
1 parent 4d3a372 commit d8ffae4
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 83 deletions.
22 changes: 5 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 2 additions & 16 deletions client/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@ readme = "README.md"
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
derive_more = "0.99.2"
log = "0.4.8"
log = "0.4.11"
atty = "0.2.13"
regex = "1.3.4"
time = "0.1.42"
ansi_term = "0.12.1"
lazy_static = "1.4.0"
tokio = { version = "0.2.21", features = [ "signal", "rt-core", "rt-threaded", "blocking" ] }
futures = "0.3.4"
fdlimit = "0.2.1"
Expand All @@ -30,7 +27,6 @@ rand = "0.7.3"
bip39 = "0.6.0-beta.1"
serde_json = "1.0.41"
sc-keystore = { version = "2.0.0", path = "../keystore" }
sc-informant = { version = "0.8.0", path = "../informant" }
sp-panic-handler = { version = "2.0.0", path = "../../primitives/panic-handler" }
sc-client-api = { version = "2.0.0", path = "../api" }
sp-blockchain = { version = "2.0.0", path = "../../primitives/blockchain" }
Expand All @@ -41,34 +37,24 @@ sp-version = { version = "2.0.0", path = "../../primitives/version" }
sp-core = { version = "2.0.0", path = "../../primitives/core" }
sp-keystore = { version = "0.8.0", path = "../../primitives/keystore" }
sc-service = { version = "0.8.0", default-features = false, path = "../service" }
sp-state-machine = { version = "0.8.0", path = "../../primitives/state-machine" }
sc-telemetry = { version = "2.0.0", path = "../telemetry" }
substrate-prometheus-endpoint = { path = "../../utils/prometheus" , version = "0.8.0"}
sp-keyring = { version = "2.0.0", path = "../../primitives/keyring" }
sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" }
sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" }
sc-finality-grandpa = { version = "0.8.0", path = "../finality-grandpa" }
names = "0.11.0"
structopt = "0.3.8"
sc-tracing = { version = "2.0.0", path = "../tracing" }
chrono = "0.4.10"
parity-util-mem = { version = "0.7.0", default-features = false, features = ["primitive-types"] }
serde = "1.0.111"
tracing = "0.1.10"
tracing-log = "0.1.1"
tracing-subscriber = "0.2.10"
sc-cli-proc-macro = { version = "2.0.0", path = "./proc-macro" }
thiserror = "1.0.21"

[target.'cfg(not(target_os = "unknown"))'.dependencies]
rpassword = "4.0.1"

[target.'cfg(target_family = "unix")'.dependencies]
nix = "0.17.0"

[dev-dependencies]
tempfile = "3.1.0"
sp-io = { version = "2.0.0-rc3", path = "../../primitives/io" }
sp-application-crypto = { version = "2.0.0-alpha.2", default-features = false, path = "../../primitives/application-crypto" }

[features]
wasmtime = [
Expand Down
11 changes: 5 additions & 6 deletions client/cli/src/commands/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,27 @@ impl InsertCmd {
pub fn run(&self) -> Result<(), Error> {
let suri = utils::read_uri(self.suri.as_ref())?;
let base_path = self.shared_params.base_path.as_ref()
.ok_or_else(|| Error::Other("please supply base path".into()))?;
.ok_or_else(|| Error::MissingBasePath)?;

let (keystore, public) = match self.keystore_params.keystore_config(base_path)? {
KeystoreConfig::Path { path, password } => {
let public = with_crypto_scheme!(
self.crypto_scheme.scheme,
to_vec(&suri, password.clone())
)?;
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)
.map_err(|e| format!("{}", e))?);
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?);
(keystore, public)
},
_ => unreachable!("keystore_config always returns path and password; qed")
};

let key_type = KeyTypeId::try_from(self.key_type.as_str())
.map_err(|_| {
Error::Other("Cannot convert argument to keytype: argument should be 4-character string".into())
.map_err(|_e| {
Error::KeyTypeInvalid
})?;

SyncCryptoStore::insert_unknown(&*keystore, key_type, &suri, &public[..])
.map_err(|e| Error::Other(format!("{:?}", e)))?;
.map_err(|_| Error::KeyStoreOperation)?;

Ok(())
}
Expand Down
3 changes: 1 addition & 2 deletions client/cli/src/commands/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,7 @@ pub fn decode_hex<T: AsRef<[u8]>>(message: T) -> Result<Vec<u8>, Error> {
if message[..2] == [b'0', b'x'] {
message = &message[2..]
}
hex::decode(message)
.map_err(|e| Error::Other(format!("Invalid hex ({})", e)))
Ok(hex::decode(message)?)
}

/// checks if message is Some, otherwise reads message from stdin and optionally decodes hex
Expand Down
18 changes: 8 additions & 10 deletions client/cli/src/commands/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,27 +77,25 @@ fn verify<Pair>(sig_data: Vec<u8>, message: Vec<u8>, uri: &str) -> error::Result
{
let mut signature = Pair::Signature::default();
if sig_data.len() != signature.as_ref().len() {
return Err(error::Error::Other(format!(
"signature has an invalid length. read {} bytes, expected {} bytes",
sig_data.len(),
signature.as_ref().len(),
)));
return Err(
error::Error::SignatureInvalidLength {
read: sig_data.len(),
expected: signature.as_ref().len(),
}
);
}
signature.as_mut().copy_from_slice(&sig_data);

let pubkey = if let Ok(pubkey_vec) = hex::decode(uri) {
Pair::Public::from_slice(pubkey_vec.as_slice())
} else {
Pair::Public::from_string(uri)
.map_err(|_| {
error::Error::Other(format!("Invalid URI; expecting either a secret URI or a public URI."))
})?
Pair::Public::from_string(uri)?
};

if Pair::verify(&signature, &message, &pubkey) {
println!("Signature verifies correctly.");
} else {
return Err(error::Error::Other("Signature invalid.".into()))
return Err(error::Error::SignatureInvalid)
}

Ok(())
Expand Down
88 changes: 57 additions & 31 deletions client/cli/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,61 +18,87 @@

//! Initialization errors.

use sp_core::crypto;

/// Result type alias for the CLI.
pub type Result<T> = std::result::Result<T, Error>;

/// Error type for the CLI.
#[derive(Debug, derive_more::Display, derive_more::From)]
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Io error
Io(std::io::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
/// Cli error
Cli(structopt::clap::Error),
#[error(transparent)]
Cli(#[from] structopt::clap::Error),
/// Service error
Service(sc_service::Error),
#[error(transparent)]
Service(#[from] sc_service::Error),
/// Client error
Client(sp_blockchain::Error),
#[error(transparent)]
Client(#[from] sp_blockchain::Error),
/// scale codec error
Codec(parity_scale_codec::Error),
#[error(transparent)]
Codec(#[from] parity_scale_codec::Error),
/// Input error
#[from(ignore)]
#[error("Invalid input: {0}")]
Input(String),
/// Invalid listen multiaddress
#[display(fmt="Invalid listen multiaddress")]
#[from(ignore)]
#[error("Invalid listen multiaddress")]
InvalidListenMultiaddress,
/// Other uncategorized error.
#[from(ignore)]
/// Application specific error chain sequence forwarder.
#[error(transparent)]
Application(#[from] Box<dyn std::error::Error>),
/// URI error.
#[error("Invalid URI; expecting either a secret URI or a public URI.")]
InvalidUri(crypto::PublicError),
/// Signature length mismatch.
#[error("Signature has an invalid length. Read {read} bytes, expected {expected} bytes")]
SignatureInvalidLength {
/// Amount of signature bytes read.
read: usize,
/// Expected number of signature bytes.
expected: usize,
},
/// Missing base path argument.
#[error("The base path is missing, please provide one")]
MissingBasePath,
/// Unknown key type specifier or missing key type specifier.
#[error("Unknown key type, must be a known 4-character sequence")]
KeyTypeInvalid,
/// Signature verification failed.
#[error("Signature verification failed")]
SignatureInvalid,
/// Storing a given key failed.
#[error("Key store operation failed")]
KeyStoreOperation,
/// An issue with the underlying key storage was encountered.
#[error("Key storage issue encountered")]
KeyStorage(#[from] sc_keystore::Error),
/// Bytes are not decodable when interpreted as hexadecimal string.
#[error("Invalid hex base data")]
HexDataConversion(#[from] hex::FromHexError),
/// Shortcut type to specify types on the fly, discouraged.
#[deprecated = "Use `Forwarded` with an error type instead."]
#[error("Other: {0}")]
Other(String),
}

/// Must be implemented explicitly because `derive_more` won't generate this
/// case due to conflicting derive for `Other(String)`.
impl std::convert::From<String> for Error {
fn from(s: String) -> Error {
Error::Input(s)
impl std::convert::From<&str> for Error {
fn from(s: &str) -> Error {
Error::Input(s.to_string())
}
}

impl std::convert::From<&str> for Error {
fn from(s: &str) -> Error {
impl std::convert::From<String> for Error {
fn from(s: String) -> Error {
Error::Input(s.to_string())
}
}

impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(ref err) => Some(err),
Error::Cli(ref err) => Some(err),
Error::Service(ref err) => Some(err),
Error::Client(ref err) => Some(err),
Error::Codec(ref err) => Some(err),
Error::Input(_) => None,
Error::InvalidListenMultiaddress => None,
Error::Other(_) => None,
}
impl std::convert::From<crypto::PublicError> for Error {
fn from(e: crypto::PublicError) -> Error {
Error::InvalidUri(e)
}
}
2 changes: 2 additions & 0 deletions client/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_imports)]
#![warn(unused_crate_dependencies)]

pub mod arg_enums;
mod commands;
Expand Down
2 changes: 1 addition & 1 deletion frame/offences/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ where
let time_slot = offence.time_slot();
let validator_set_count = offence.validator_set_count();

// Go through all offenders in the offence report and find all offenders that was spotted
// Go through all offenders in the offence report and find all offenders that were spotted
// in unique reports.
let TriageOutcome { concurrent_offenders } = match Self::triage_offence_report::<O>(
reporters,
Expand Down

0 comments on commit d8ffae4

Please sign in to comment.