use crate::message::Bytes;
use cfx_types::{Address, SpaceMap, H256, U256};
use primitives::{filter::FilterError, transaction::TransactionError};
use std::{error, fmt, time::SystemTime};
use thiserror::Error;
use unexpected::{Mismatch, OutOfBounds};
#[derive(Debug, PartialEq, Clone, Eq)]
pub enum BlockError {
InvalidHeight(Mismatch<u64>),
TooMuchGasUsed(OutOfBounds<U256>),
InvalidStateRoot(Mismatch<H256>),
InvalidGasUsed(Mismatch<U256>),
InvalidTransactionsRoot(Mismatch<H256>),
DifficultyOutOfBounds(OutOfBounds<U256>),
InvalidDifficulty(OutOfBounds<U256>),
InvalidProofOfWork(OutOfBounds<H256>),
InvalidGasLimit(OutOfBounds<U256>),
InvalidPackedGasLimit(OutOfBounds<U256>),
InvalidBlockSize(OutOfBounds<u64>),
InvalidBasePrice(Mismatch<SpaceMap<U256>>),
InvalidTimestamp(OutOfBounds<SystemTime>),
TemporarilyInvalid(OutOfBounds<SystemTime>),
TooManyReferees(OutOfBounds<usize>),
TooLongCustomInHeader(OutOfBounds<usize>),
TooManyTransactions(Address),
UnknownParent(H256),
DuplicateParentOrRefereeHashes(H256),
InvalidCustom(Vec<Bytes>, Vec<Bytes>),
MissingPosReference,
UnexpectedPosReference,
MissingBaseFee,
UnexpectedBaseFee,
InvalidPosReference,
}
impl fmt::Display for BlockError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::BlockError::*;
let msg = match *self {
InvalidHeight(ref mis) => format!("Invalid block height: {}", mis),
TooMuchGasUsed(ref oob) => {
format!("Block has too much gas used. {}", oob)
}
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 oob) => {
format!("Invalid block difficulty: {}", oob)
}
InvalidProofOfWork(ref oob) => {
format!("Block has invalid PoW: {}", oob)
}
InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob),
InvalidBasePrice(ref mis) => {
format!("Invalid base price: {:?}", mis)
}
InvalidPackedGasLimit(ref oob) => {
format!("Invalid packed gas limit: {}", oob)
}
InvalidBlockSize(ref oob) => format!("Invalid block size: {}", oob),
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)
}
UnknownParent(ref hash) => format!("Unknown parent: {}", hash),
TooManyReferees(ref num) => format!("Too many referees: {}", num),
TooLongCustomInHeader(ref num) => {
format!("Too long custom data in block header: {}", num)
}
TooManyTransactions(ref address) => {
format!("Too many transactions from: {}", address)
}
DuplicateParentOrRefereeHashes(ref hash) => {
format!("Duplicate parent or referee hashes: {}", hash)
}
InvalidCustom(ref header_custom, ref expected_custom_prefix) => {
format!(
"Invalid custom in header: expect prefix {:?}, get {:?}",
expected_custom_prefix, header_custom
)
}
MissingPosReference => "Missing PoS reference".into(),
UnexpectedPosReference => "Should not have PoS reference".into(),
MissingBaseFee => "Missing base fee".into(),
UnexpectedBaseFee => "Should not have base fee".into(),
InvalidPosReference => "The PoS reference is invalid".into(),
};
f.write_fmt(format_args!("Block error ({})", msg))
}
}
impl error::Error for BlockError {
fn description(&self) -> &str { "Block error" }
}
#[derive(Error, Debug)]
pub enum CoreError {
#[error(transparent)]
Block(#[from] BlockError),
#[error(transparent)]
Transaction(#[from] TransactionError),
#[error(transparent)]
Filter(#[from] FilterError),
#[error("PoW hash is invalid or out of date.")]
PowHashInvalid,
}