// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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.
// Parity 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 Parity. If not, see .
//! General error types for use in ethcore.
use std::{fmt, error};
use std::time::SystemTime;
use ethereum_types::{H256, U256, Address, Bloom};
use snappy::InvalidInput;
use unexpected::{Mismatch, OutOfBounds};
use ethtrie::TrieError;
use io::*;
use header::BlockNumber;
use snapshot::Error as SnapshotError;
use engines::EngineError;
use ethkey::Error as EthkeyError;
use account_provider::SignError as AccountsError;
use transaction::Error as TransactionError;
pub use executed::{ExecutionError, CallError};
#[derive(Debug, PartialEq, Clone, Copy, Eq)]
/// Errors concerning block processing.
pub enum BlockError {
/// Block has too many uncles.
TooManyUncles(OutOfBounds),
/// Extra data is of an invalid length.
ExtraDataOutOfBounds(OutOfBounds),
/// Seal is incorrect format.
InvalidSealArity(Mismatch),
/// Block has too much gas used.
TooMuchGasUsed(OutOfBounds),
/// Uncles hash in header is invalid.
InvalidUnclesHash(Mismatch),
/// An uncle is from a generation too old.
UncleTooOld(OutOfBounds),
/// An uncle is from the same generation as the block.
UncleIsBrother(OutOfBounds),
/// An uncle is already in the chain.
UncleInChain(H256),
/// An uncle is included twice.
DuplicateUncle(H256),
/// An uncle has a parent not in the chain.
UncleParentNotInChain(H256),
/// State root header field is invalid.
InvalidStateRoot(Mismatch),
/// Gas used header field is invalid.
InvalidGasUsed(Mismatch),
/// Transactions root header field is invalid.
InvalidTransactionsRoot(Mismatch),
/// Difficulty is out of range; this can be used as an looser error prior to getting a definitive
/// value for difficulty. This error needs only provide bounds of which it is out.
DifficultyOutOfBounds(OutOfBounds),
/// Difficulty header field is invalid; this is a strong error used after getting a definitive
/// value for difficulty (which is provided).
InvalidDifficulty(Mismatch),
/// Seal element of type H256 (max_hash for Ethash, but could be something else for
/// other seal engines) is out of bounds.
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 is incorrect.
InvalidSeal,
/// Gas limit header field is invalid.
InvalidGasLimit(OutOfBounds),
/// Receipts trie root header field is invalid.
InvalidReceiptsRoot(Mismatch),
/// Timestamp header field is invalid.
InvalidTimestamp(OutOfBounds),
/// Timestamp header field is too far in future.
TemporarilyInvalid(OutOfBounds),
/// Log bloom header field is invalid.
InvalidLogBloom(Mismatch),
/// Number field of header is invalid.
InvalidNumber(Mismatch),
/// Block number isn't sensible.
RidiculousNumber(OutOfBounds),
/// Too many transactions from a particular address.
TooManyTransactions(Address),
/// Parent given is unknown.
UnknownParent(H256),
/// Uncle parent given is unknown.
UnknownUncleParent(H256),
/// No transition to epoch number.
UnknownEpochTransition(u64),
}
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),
DuplicateUncle(ref hash) => format!("Uncle {} already in the header", 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) => {
let oob = oob.map(|st| st.elapsed().unwrap_or_default().as_secs());
format!("Invalid timestamp in header: {}", oob)
},
TemporarilyInvalid(ref oob) => {
let oob = oob.map(|st| st.elapsed().unwrap_or_default().as_secs());
format!("Future timestamp in header: {}", oob)
},
InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob),
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),
UnknownEpochTransition(ref num) => format!("Unknown transition to epoch number: {}", num),
TooManyTransactions(ref address) => format!("Too many transactions from: {}", address),
};
f.write_fmt(format_args!("Block error ({})", msg))
}
}
impl error::Error for BlockError {
fn description(&self) -> &str {
"Block error"
}
}
error_chain! {
types {
ImportError, ImportErrorKind, ImportErrorResultExt, ImportErrorResult;
}
errors {
#[doc = "Already in the block chain."]
AlreadyInChain {
description("Block already in chain")
display("Block already in chain")
}
#[doc = "Already in the block queue"]
AlreadyQueued {
description("block already in the block queue")
display("block already in the block queue")
}
#[doc = "Already marked as bad from a previous import (could mean parent is bad)."]
KnownBad {
description("block known to be bad")
display("block known to be bad")
}
}
}
error_chain! {
types {
BlockImportError, BlockImportErrorKind, BlockImportErrorResultExt;
}
links {
Import(ImportError, ImportErrorKind) #[doc = "Import error"];
}
foreign_links {
Block(BlockError) #[doc = "Block error"];
Decoder(::rlp::DecoderError) #[doc = "Rlp decoding error"];
}
errors {
#[doc = "Other error"]
Other(err: String) {
description("Other error")
display("Other error {}", err)
}
}
}
impl From for BlockImportError {
fn from(e: Error) -> Self {
match e {
Error(ErrorKind::Block(block_error), _) => BlockImportErrorKind::Block(block_error).into(),
Error(ErrorKind::Import(import_error), _) => BlockImportErrorKind::Import(import_error.into()).into(),
_ => BlockImportErrorKind::Other(format!("other block import error: {:?}", e)).into(),
}
}
}
/// Api-level error for transaction import
#[derive(Debug, Clone)]
pub enum TransactionImportError {
/// Transaction error
Transaction(TransactionError),
/// Other error
Other(String),
}
impl From for TransactionImportError {
fn from(e: Error) -> Self {
match e {
Error(ErrorKind::Transaction(transaction_error), _) => TransactionImportError::Transaction(transaction_error),
_ => TransactionImportError::Other(format!("other block import error: {:?}", e)),
}
}
}
error_chain! {
types {
Error, ErrorKind, ErrorResultExt, EthcoreResult;
}
links {
Import(ImportError, ImportErrorKind) #[doc = "Error concerning block import." ];
}
foreign_links {
Io(IoError) #[doc = "Io create error"];
StdIo(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."];
Trie(TrieError) #[doc = "Error concerning TrieDBs."];
Execution(ExecutionError) #[doc = "Error concerning EVM code execution."];
Block(BlockError) #[doc = "Error concerning block processing."];
Transaction(TransactionError) #[doc = "Error concerning transaction processing."];
Snappy(InvalidInput) #[doc = "Snappy error."];
Engine(EngineError) #[doc = "Consensus vote error."];
Ethkey(EthkeyError) #[doc = "Ethkey error."];
}
errors {
#[doc = "Snapshot error."]
Snapshot(err: SnapshotError) {
description("Snapshot error.")
display("Snapshot error {}", err)
}
#[doc = "Account Provider error"]
AccountProvider(err: AccountsError) {
description("Accounts Provider error")
display("Accounts Provider error {}", err)
}
#[doc = "PoW hash is invalid or out of date."]
PowHashInvalid {
description("PoW hash is invalid or out of date.")
display("PoW hash is invalid or out of date.")
}
#[doc = "The value of the nonce or mishash is invalid."]
PowInvalid {
description("The value of the nonce or mishash is invalid.")
display("The value of the nonce or mishash is invalid.")
}
#[doc = "Unknown engine given"]
UnknownEngineName(name: String) {
description("Unknown engine name")
display("Unknown engine name ({})", name)
}
#[doc = "RLP decoding errors"]
Decoder(err: ::rlp::DecoderError) {
description("decoding value failed")
display("decoding value failed with error: {}", err)
}
}
}
/// Result of import block operation.
pub type ImportResult = EthcoreResult;
impl From for Error {
fn from(err: AccountsError) -> Error {
ErrorKind::AccountProvider(err).into()
}
}
impl From<::rlp::DecoderError> for Error {
fn from(err: ::rlp::DecoderError) -> Error {
ErrorKind::Decoder(err).into()
}
}
impl From for Error {
fn from(err: BlockImportError) -> Error {
match err {
BlockImportError(BlockImportErrorKind::Block(e), _) => ErrorKind::Block(e).into(),
BlockImportError(BlockImportErrorKind::Import(e), _) => ErrorKind::Import(e).into(),
_ => ErrorKind::Msg(format!("other block import error: {:?}", err)).into(),
}
}
}
impl From for Error {
fn from(err: SnapshotError) -> Error {
match err {
SnapshotError::Io(err) => ErrorKind::StdIo(err).into(),
SnapshotError::Trie(err) => ErrorKind::Trie(err).into(),
SnapshotError::Decoder(err) => err.into(),
other => ErrorKind::Snapshot(other).into(),
}
}
}
impl From> for Error where Error: From {
fn from(err: Box) -> Error {
Error::from(*err)
}
}