diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 110d37a0b..3d7c148ba 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -60,6 +60,28 @@ pub enum TransactionError { InvalidGasLimit(OutOfBounds), } +impl fmt::Display for TransactionError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::TransactionError::*; + let msg = match *self { + AlreadyImported => "Already imported".into(), + Old => "No longer valid".into(), + TooCheapToReplace => "Gas price too low to replace".into(), + LimitReached => "Transaction limit reached".into(), + InsufficientGasPrice { minimal, got } => + format!("Insufficient gas price. Min={}, Given={}", minimal, got), + InsufficientBalance { balance, cost } => + format!("Insufficient balance for transaction. Balance={}, Cost={}", + balance, cost), + GasLimitExceeded { limit, got } => + format!("Gas limit exceeded. Limit={}, Given={}", limit, got), + InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), + }; + + f.write_fmt(format_args!("Transaction error ({})", msg)) + } +} + #[derive(Debug, PartialEq, Eq)] /// Errors concerning block processing. pub enum BlockError { @@ -98,7 +120,7 @@ pub enum BlockError { MismatchedH256SealElement(Mismatch), /// Proof-of-work aspect of seal, which we assume is a 256-bit value, is invalid. InvalidProofOfWork(OutOfBounds), - /// Some low-level aspect of the seal in incorrect. + /// Some low-level aspect of the seal is incorrect. InvalidSeal, /// Gas limit header field is invalid. InvalidGasLimit(OutOfBounds), @@ -121,6 +143,43 @@ pub enum BlockError { UnknownUncleParent(H256), } +impl fmt::Display for BlockError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::BlockError::*; + + let msg = match *self { + TooManyUncles(ref oob) => format!("Block has too many uncles. {}", oob), + ExtraDataOutOfBounds(ref oob) => format!("Extra block data too long. {}", oob), + InvalidSealArity(ref mis) => format!("Block seal in incorrect format: {}", mis), + TooMuchGasUsed(ref oob) => format!("Block has too much gas used. {}", oob), + InvalidUnclesHash(ref mis) => format!("Block has invalid uncles hash: {}", mis), + UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob), + UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob), + UncleInChain(ref hash) => format!("Uncle {} already in chain", hash), + UncleParentNotInChain(ref hash) => format!("Uncle {} has a parent not in the chain", hash), + InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis), + InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis), + InvalidTransactionsRoot(ref mis) => format!("Invalid transactions root in header: {}", mis), + DifficultyOutOfBounds(ref oob) => format!("Invalid block difficulty: {}", oob), + InvalidDifficulty(ref mis) => format!("Invalid block difficulty: {}", mis), + MismatchedH256SealElement(ref mis) => format!("Seal element out of bounds: {}", mis), + InvalidProofOfWork(ref oob) => format!("Block has invalid PoW: {}", oob), + InvalidSeal => "Block has invalid seal.".into(), + InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob), + InvalidReceiptsRoot(ref mis) => format!("Invalid receipts trie root in header: {}", mis), + InvalidTimestamp(ref oob) => format!("Invalid timestamp in header: {}", oob), + InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob), + InvalidParentHash(ref mis) => format!("Invalid parent hash: {}", mis), + InvalidNumber(ref mis) => format!("Invalid number in header: {}", mis), + RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), + UnknownParent(ref hash) => format!("Unknown parent: {}", hash), + UnknownUncleParent(ref hash) => format!("Unknown uncle parent: {}", hash), + }; + + f.write_fmt(format_args!("Block error ({})", msg)) + } +} + #[derive(Debug, PartialEq)] /// Import to the block queue result pub enum ImportError { @@ -132,6 +191,18 @@ pub enum ImportError { KnownBad, } +impl fmt::Display for ImportError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg = match *self { + ImportError::AlreadyInChain => "block already in chain", + ImportError::AlreadyQueued => "block already in the block queue", + ImportError::KnownBad => "block known to be bad", + }; + + f.write_fmt(format_args!("Block import error ({})", msg)) + } +} + #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum Error { @@ -155,6 +226,23 @@ pub enum Error { PowInvalid, } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Client(ref err) => f.write_fmt(format_args!("{}", err)), + Error::Util(ref err) => f.write_fmt(format_args!("{}", err)), + Error::Block(ref err) => f.write_fmt(format_args!("{}", err)), + Error::Execution(ref err) => f.write_fmt(format_args!("{}", err)), + Error::Transaction(ref err) => f.write_fmt(format_args!("{}", err)), + Error::Import(ref err) => f.write_fmt(format_args!("{}", err)), + Error::UnknownEngineName(ref name) => + f.write_fmt(format_args!("Unknown engine name ({})", name)), + Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."), + Error::PowInvalid => f.write_str("Invalid nonce or mishash"), + } + } +} + /// Result of import block operation. pub type ImportResult = Result; diff --git a/ethcore/src/types/executed.rs b/ethcore/src/types/executed.rs index f03a1c26b..fcde5a392 100644 --- a/ethcore/src/types/executed.rs +++ b/ethcore/src/types/executed.rs @@ -21,6 +21,7 @@ use util::Bytes; use trace::Trace; use types::log_entry::LogEntry; use ipc::binary::BinaryConvertError; +use std::fmt; use std::mem; use std::collections::VecDeque; @@ -104,6 +105,28 @@ pub enum ExecutionError { TransactionMalformed(String), } +impl fmt::Display for ExecutionError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::ExecutionError::*; + + let msg = match *self { + NotEnoughBaseGas { required, got } => + format!("Not enough base gas. {} is required, but only {} paid", required, got), + BlockGasLimitReached { gas_limit, gas_used, gas } => + format!("Block gas limit reached. The limit is {}, {} has \ + already been used, and {} more is required", gas_limit, gas_used, gas), + InvalidNonce { expected, got } => + format!("Invalid transaction nonce: expected {}, found {}", expected, got), + NotEnoughCash { required, got } => + format!("Cost of transaction exceeds sender balance. {} is required \ + but the sender only has {}", required, got), + Internal => "Internal evm error".into(), + TransactionMalformed(ref err) => format!("Malformed transaction: {}", err), + }; + + f.write_fmt(format_args!("Transaction execution error ({}).", msg)) + } +} /// Transaction execution result. pub type ExecutionResult = Result; diff --git a/parity/die.rs b/parity/die.rs index 7d8c87b89..c38b041f3 100644 --- a/parity/die.rs +++ b/parity/die.rs @@ -31,11 +31,16 @@ pub fn die_with_error(module: &'static str, e: ethcore::error::Error) -> ! { match e { Error::Util(UtilError::StdIo(e)) => die_with_io_error(module, e), Error::Client(ClientError::Trace(e)) => die_with_message(&format!("{}", e)), - _ => die!("{}: {:?}", module, e), + _ => { + trace!(target: module, "{:?}", e); + die!("{}: {}", module, e); + } } } pub fn die_with_io_error(module: &'static str, e: std::io::Error) -> ! { + trace!(target: module, "{:?}", e); + match e.kind() { std::io::ErrorKind::PermissionDenied => { die!("{}: No permissions to bind to specified port.", module) @@ -46,7 +51,7 @@ pub fn die_with_io_error(module: &'static str, e: std::io::Error) -> ! { std::io::ErrorKind::AddrNotAvailable => { die!("{}: Could not use specified interface or given address is invalid.", module) }, - _ => die!("{}: {:?}", module, e), + _ => die!("{}: {}", module, e), } } diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 040db3bca..3eff70717 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -21,6 +21,7 @@ use bytes::*; use secp256k1::{key, Secp256k1}; use rand::os::OsRng; use sha3::Hashable; +use std::fmt; /// Secret key for secp256k1 EC operations. 256 bit generic "hash" data. pub type Secret = H256; @@ -69,6 +70,20 @@ pub enum CryptoError { Io(::std::io::Error), } +impl fmt::Display for CryptoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg = match *self { + CryptoError::InvalidSecret => "Invalid secret key".into(), + CryptoError::InvalidPublic => "Invalid public key".into(), + CryptoError::InvalidSignature => "Invalid EC signature".into(), + CryptoError::InvalidMessage => "Invalid AES message".into(), + CryptoError::Io(ref err) => format!("I/O error: {}", err), + }; + + f.write_fmt(format_args!("Crypto error ({})", msg)) + } +} + impl From<::secp256k1::Error> for CryptoError { fn from(e: ::secp256k1::Error) -> CryptoError { match e { diff --git a/util/src/error.rs b/util/src/error.rs index 409cc0e5d..5e9f8e7a8 100644 --- a/util/src/error.rs +++ b/util/src/error.rs @@ -30,6 +30,16 @@ pub enum BaseDataError { NegativelyReferencedHash(H256), } +impl fmt::Display for BaseDataError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + BaseDataError::NegativelyReferencedHash(hash) => + f.write_fmt(format_args!("Entry {} removed from database more times \ + than it was added.", hash)), + } + } +} + #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum UtilError { @@ -57,6 +67,24 @@ pub enum UtilError { BadSize, } +impl fmt::Display for UtilError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + UtilError::Crypto(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::StdIo(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::Io(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::AddressParse(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::AddressResolve(Some(ref err)) => f.write_fmt(format_args!("{}", err)), + UtilError::AddressResolve(_) => f.write_str("Failed to resolve network address."), + UtilError::FromHex(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::BaseData(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::Network(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::Decoder(ref err) => f.write_fmt(format_args!("{}", err)), + UtilError::SimpleString(ref msg) => f.write_str(&msg), + UtilError::BadSize => f.write_str("Bad input size."), + } + } +} #[derive(Debug, PartialEq, Eq)] /// Error indicating an expected value was not found. @@ -67,6 +95,12 @@ pub struct Mismatch { pub found: T, } +impl fmt::Display for Mismatch { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_fmt(format_args!("Expected {}, found {}", self.expected, self.found)) + } +} + #[derive(Debug, PartialEq, Eq)] /// Error indicating value found is outside of a valid range. pub struct OutOfBounds { @@ -78,6 +112,19 @@ pub struct OutOfBounds { pub found: T, } +impl fmt::Display for OutOfBounds { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg = match (self.min.as_ref(), self.max.as_ref()) { + (Some(min), Some(max)) => format!("Min={}, Max={}", min, max), + (Some(min), _) => format!("Min={}", min), + (_, Some(max)) => format!("Max={}", max), + (None, None) => "".into(), + }; + + f.write_fmt(format_args!("Value {} out of bounds. {}", self.found, msg)) + } +} + impl From for UtilError { fn from(err: FromHexError) -> UtilError { UtilError::FromHex(err) diff --git a/util/src/io/mod.rs b/util/src/io/mod.rs index 40cdbc368..93805a46a 100644 --- a/util/src/io/mod.rs +++ b/util/src/io/mod.rs @@ -56,6 +56,7 @@ mod service; mod worker; use mio::{EventLoop, Token}; +use std::fmt; #[derive(Debug)] /// IO Error @@ -64,6 +65,16 @@ pub enum IoError { Mio(::std::io::Error), } +impl fmt::Display for IoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // just defer to the std implementation for now. + // we can refine the formatting when more variants are added. + match *self { + IoError::Mio(ref std_err) => std_err.fmt(f) + } + } +} + impl From<::mio::NotifyError>> for IoError where Message: Send + Clone { fn from(_err: ::mio::NotifyError>) -> IoError { IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error")) diff --git a/util/src/network/error.rs b/util/src/network/error.rs index 31e1d785b..e4705fc9e 100644 --- a/util/src/network/error.rs +++ b/util/src/network/error.rs @@ -17,6 +17,7 @@ use io::IoError; use crypto::CryptoError; use rlp::*; +use std::fmt; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum DisconnectReason @@ -56,6 +57,30 @@ impl DisconnectReason { } } +impl fmt::Display for DisconnectReason { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::DisconnectReason::*; + + let msg = match *self { + DisconnectRequested => "disconnect requested", + TCPError => "TCP error", + BadProtocol => "bad protocol", + UselessPeer => "useless peer", + TooManyPeers => "too many peers", + DuplicatePeer => "duplicate peer", + IncompatibleProtocol => "incompatible protocol", + NullIdentity => "null identity", + ClientQuit => "client quit", + UnexpectedIdentity => "unexpected identity", + LocalIdentity => "local identity", + PingTimeout => "ping timeout", + Unknown => "unknown", + }; + + f.write_str(msg) + } +} + #[derive(Debug)] /// Network error. pub enum NetworkError { @@ -73,6 +98,23 @@ pub enum NetworkError { Io(IoError), } +impl fmt::Display for NetworkError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::NetworkError::*; + + let msg = match *self { + Auth => "Authentication failure".into(), + BadProtocol => "Bad protocol".into(), + Expired => "Expired message".into(), + PeerNotFound => "Peer not found".into(), + Disconnect(ref reason) => format!("Peer disconnected: {}", reason), + Io(ref err) => format!("Socket I/O error: {}", err), + }; + + f.write_fmt(format_args!("Network error ({})", msg)) + } +} + impl From for NetworkError { fn from(_err: DecoderError) -> NetworkError { NetworkError::Auth