1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright 2019 Conflux Foundation. All rights reserved.
// Conflux is free software and distributed under GNU General Public License.
// See http://www.gnu.org/licenses/

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)]
/// Errors concerning block processing.
pub enum BlockError {
    /// Number field of header is invalid.
    InvalidHeight(Mismatch<u64>),
    /// Block has too much gas used.
    TooMuchGasUsed(OutOfBounds<U256>),
    /// State root header field is invalid.
    InvalidStateRoot(Mismatch<H256>),
    /// Gas used header field is invalid.
    InvalidGasUsed(Mismatch<U256>),
    /// Transactions root header field is invalid.
    InvalidTransactionsRoot(Mismatch<H256>),
    /// 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<U256>),
    /// Difficulty header field is invalid; this is a strong error used after
    /// getting a definitive value for difficulty (which is provided).
    InvalidDifficulty(OutOfBounds<U256>),
    /// Proof-of-work aspect of seal, which we assume is a 256-bit value, is
    /// invalid.
    InvalidProofOfWork(OutOfBounds<H256>),
    /// Gas limit header field is invalid.
    InvalidGasLimit(OutOfBounds<U256>),
    /// Total gas limits of transactions in block is out of bound.
    InvalidPackedGasLimit(OutOfBounds<U256>),
    /// Total rlp sizes of transactions in block is out of bound.
    InvalidBlockSize(OutOfBounds<u64>),
    InvalidBasePrice(Mismatch<SpaceMap<U256>>),
    /// Timestamp header field is invalid.
    InvalidTimestamp(OutOfBounds<SystemTime>),
    /// Timestamp header field is too far in future.
    TemporarilyInvalid(OutOfBounds<SystemTime>),
    /// Too many referees in a block
    TooManyReferees(OutOfBounds<usize>),
    /// Too long custom data in header
    TooLongCustomInHeader(OutOfBounds<usize>),
    /// Too many transactions from a particular address.
    TooManyTransactions(Address),
    /// Parent given is unknown.
    UnknownParent(H256),
    /// Duplicate parent or referee hashes exist.
    DuplicateParentOrRefereeHashes(H256),
    /// The value in `custom` does not match the specification.
    InvalidCustom(Vec<Bytes>, Vec<Bytes>),
    /// Should have a PoS reference but it's not set.
    MissingPosReference,
    /// Should not have a PoS reference but it's set.
    UnexpectedPosReference,
    /// Should have a base fee but it's not set.
    MissingBaseFee,
    /// Should not have a base fee but it's set.
    UnexpectedBaseFee,
    /// The PoS reference violates the validity rule (it should extend the PoS
    /// reference of the parent and referees).
    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,
}