// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Parity Ethereum. // Parity Ethereum 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 Ethereum 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 Ethereum. If not, see . //! General error types for use in ethcore. use std::{fmt, error}; use std::time::SystemTime; use derive_more::{Display, From}; use ethereum_types::{H256, U256, Address, Bloom}; use ethkey::Error as EthkeyError; use ethtrie::TrieError; use rlp; use snappy::InvalidInput; use snapshot::Error as SnapshotError; use types::BlockNumber; use types::transaction::Error as TransactionError; use unexpected::{Mismatch, OutOfBounds}; use engines::EngineError; pub use executed::{ExecutionError, CallError}; /// Errors concerning block processing. #[derive(Debug, Display, PartialEq, Clone, Eq)] pub enum BlockError { /// Block has too many uncles. #[display(fmt = "Block has too many uncles. {}", _0)] TooManyUncles(OutOfBounds), /// Extra data is of an invalid length. #[display(fmt = "Extra block data too long. {}", _0)] ExtraDataOutOfBounds(OutOfBounds), /// Seal is incorrect format. #[display(fmt = "Block seal in incorrect format: {}", _0)] InvalidSealArity(Mismatch), /// Block has too much gas used. #[display(fmt = "Block has too much gas used. {}", _0)] TooMuchGasUsed(OutOfBounds), /// Uncles hash in header is invalid. #[display(fmt = "Block has invalid uncles hash: {}", _0)] InvalidUnclesHash(Mismatch), /// An uncle is from a generation too old. #[display(fmt = "Uncle block is too old. {}", _0)] UncleTooOld(OutOfBounds), /// An uncle is from the same generation as the block. #[display(fmt = "Uncle from same generation as block. {}", _0)] UncleIsBrother(OutOfBounds), /// An uncle is already in the chain. #[display(fmt = "Uncle {} already in chain", _0)] UncleInChain(H256), /// An uncle is included twice. #[display(fmt = "Uncle {} already in the header", _0)] DuplicateUncle(H256), /// An uncle has a parent not in the chain. #[display(fmt = "Uncle {} has a parent not in the chain", _0)] UncleParentNotInChain(H256), /// State root header field is invalid. #[display(fmt = "Invalid state root in header: {}", _0)] InvalidStateRoot(Mismatch), /// Gas used header field is invalid. #[display(fmt = "Invalid gas used in header: {}", _0)] InvalidGasUsed(Mismatch), /// Transactions root header field is invalid. #[display(fmt = "Invalid transactions root in header: {}", _0)] 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. #[display(fmt = "Difficulty out of bounds: {}", _0)] DifficultyOutOfBounds(OutOfBounds), /// Difficulty header field is invalid; this is a strong error used after getting a definitive /// value for difficulty (which is provided). #[display(fmt = "Invalid block difficulty: {}", _0)] InvalidDifficulty(Mismatch), /// Seal element of type H256 (max_hash for Ethash, but could be something else for /// other seal engines) is out of bounds. #[display(fmt = "Seal element out of bounds: {}", _0)] MismatchedH256SealElement(Mismatch), /// Proof-of-work aspect of seal, which we assume is a 256-bit value, is invalid. #[display(fmt = "Block has invalid PoW: {}", _0)] InvalidProofOfWork(OutOfBounds), /// Some low-level aspect of the seal is incorrect. #[display(fmt = "Block has invalid seal.")] InvalidSeal, /// Gas limit header field is invalid. #[display(fmt = "Invalid gas limit: {}", _0)] InvalidGasLimit(OutOfBounds), /// Receipts trie root header field is invalid. #[display(fmt = "Invalid receipts trie root in header: {}", _0)] InvalidReceiptsRoot(Mismatch), /// Timestamp header field is invalid. #[display(fmt = "Invalid timestamp in header: {}", _0)] InvalidTimestamp(OutOfBoundsTime), /// Timestamp header field is too far in future. #[display(fmt = "Future timestamp in header: {}", _0)] TemporarilyInvalid(OutOfBoundsTime), /// Log bloom header field is invalid. #[display(fmt = "Invalid log bloom in header: {}", _0)] InvalidLogBloom(Box>), /// Number field of header is invalid. #[display(fmt = "Invalid number in header: {}", _0)] InvalidNumber(Mismatch), /// Block number isn't sensible. #[display(fmt = "Implausible block number. {}", _0)] RidiculousNumber(OutOfBounds), /// Timestamp header overflowed #[display(fmt = "Timestamp overflow")] TimestampOverflow, /// Too many transactions from a particular address. #[display(fmt = "Too many transactions from: {}", _0)] TooManyTransactions(Address), /// Parent given is unknown. #[display(fmt = "Unknown parent: {}", _0)] UnknownParent(H256), /// Uncle parent given is unknown. #[display(fmt = "Unknown uncle parent: {}", _0)] UnknownUncleParent(H256), /// No transition to epoch number. #[display(fmt = "Unknown transition to epoch number: {}", _0)] UnknownEpochTransition(u64), } /// Newtype for Display impl to show seconds #[derive(Debug, Clone, From, PartialEq, Eq)] pub struct OutOfBoundsTime(OutOfBounds); impl fmt::Display for OutOfBoundsTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let seconds = self.0 .map(|st| st.elapsed().unwrap_or_default().as_secs()); f.write_fmt(format_args!("{}", seconds)) } } impl error::Error for BlockError { fn description(&self) -> &str { "Block error" } } /// Queue error #[derive(Debug, Display, From)] pub enum QueueError { /// Queue is full #[display(fmt = "Queue is full ({})", _0)] Full(usize), /// Io channel error #[display(fmt = "Io channel error: {}", _0)] Channel(::io::IoError) } impl error::Error for QueueError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { QueueError::Channel(e) => Some(e), _ => None, } } } /// Block import Error #[derive(Debug, Display)] pub enum ImportError { /// Already in the block chain. #[display(fmt = "Block already in chain")] AlreadyInChain, /// Already in the block queue #[display(fmt = "block already in the block queue")] AlreadyQueued, /// Already marked as bad from a previous import (could mean parent is bad) #[display(fmt = "block known to be bad")] KnownBad, } impl error::Error for ImportError {} /// 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::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error), _ => TransactionImportError::Other(format!("other block import error: {:?}", e)), } } } /// Ethcore Result pub type EthcoreResult = Result; /// Ethcore Error #[derive(Debug, Display, From)] pub enum Error { /// Error concerning block import. #[display(fmt = "Import error: {}", _0)] Import(ImportError), /// Io channel queue error #[display(fmt = "Queue error: {}", _0)] Queue(QueueError), /// Io create error #[display(fmt = "Io error: {}", _0)] Io(::io::IoError), /// Error concerning the Rust standard library's IO subsystem. #[display(fmt = "Std Io error: {}", _0)] StdIo(::std::io::Error), /// Error concerning TrieDBs. #[display(fmt = "Trie error: {}", _0)] Trie(TrieError), /// Error concerning EVM code execution. #[display(fmt = "Execution error: {}", _0)] Execution(ExecutionError), /// Error concerning block processing. #[display(fmt = "Block error: {}", _0)] Block(BlockError), /// Error concerning transaction processing. #[display(fmt = "Transaction error: {}", _0)] Transaction(TransactionError), /// Snappy error #[display(fmt = "Snappy error: {}", _0)] Snappy(InvalidInput), /// Consensus vote error. #[display(fmt = "Engine error: {}", _0)] Engine(EngineError), /// Ethkey error." #[display(fmt = "Ethkey error: {}", _0)] Ethkey(EthkeyError), /// RLP decoding errors #[display(fmt = "Decoder error: {}", _0)] Decoder(rlp::DecoderError), /// Snapshot error. #[display(fmt = "Snapshot error {}", _0)] Snapshot(SnapshotError), /// PoW hash is invalid or out of date. #[display(fmt = "PoW hash is invalid or out of date.")] PowHashInvalid, /// The value of the nonce or mishash is invalid. #[display(fmt = "The value of the nonce or mishash is invalid.")] PowInvalid, /// Unknown engine given #[display(fmt = "Unknown engine name ({})", _0)] UnknownEngineName(String), /// A convenient variant for String. #[display(fmt = "{}", _0)] Msg(String), } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { Error::Io(e) => Some(e), Error::StdIo(e) => Some(e), Error::Trie(e) => Some(e), Error::Execution(e) => Some(e), Error::Block(e) => Some(e), Error::Transaction(e) => Some(e), Error::Snappy(e) => Some(e), Error::Engine(e) => Some(e), Error::Ethkey(e) => Some(e), Error::Decoder(e) => Some(e), Error::Snapshot(e) => Some(e), _ => None, } } } impl From for Error { fn from(s: String) -> Self { Error::Msg(s) } } impl From<&str> for Error { fn from(s: &str) -> Self { Error::Msg(s.into()) } } impl From> for Error where Error: From { fn from(err: Box) -> Error { Error::from(*err) } }