ckb_verification/
error.rs

1use ckb_error::{def_error_base_on_kind, prelude::*, Error};
2use ckb_types::{core::Version, packed::Byte32};
3use derive_more::Display;
4
5pub use ckb_types::core::{
6    error::{TransactionError, TransactionErrorSource},
7    EpochNumberWithFraction,
8};
9
10/// A list specifying categories of ckb header error.
11///
12/// This list is intended to grow over time and it is not recommended to exhaustively match against it.
13///
14/// It is used with the [`HeaderError`].
15///
16/// [`HeaderError`]: ../ckb_verification/struct.HeaderError.html
17#[derive(Debug, PartialEq, Eq, Clone, Copy, Display)]
18pub enum HeaderErrorKind {
19    /// It indicates that the underlying error is [`InvalidParentError`].
20    ///
21    /// [`InvalidParentError`]: ../ckb_verification/struct.InvalidParentError.html
22    InvalidParent,
23    /// It indicates that the underlying error is [`PowError`].
24    ///
25    /// [`PowError`]: ../ckb_verification/enum.PowError.html
26    Pow,
27    /// It indicates that the underlying error is [`TimestampError`].
28    ///
29    /// [`TimestampError`]: ../ckb_verification/enum.TimestampError.html
30    Timestamp,
31    /// It indicates that the underlying error is [`NumberError`].
32    ///
33    /// [`NumberError`]: ../ckb_verification/struct.NumberError.html
34    Number,
35    /// It indicates that the underlying error is [`EpochError`].
36    ///
37    /// [`EpochError`]: ../ckb_verification/enum.EpochError.html
38    Epoch,
39    /// It indicates that the underlying error is [`BlockVersionError`].
40    ///
41    /// [`BlockVersionError`]: ../ckb_verification/struct.BlockVersionError.html
42    Version,
43}
44
45def_error_base_on_kind!(
46    HeaderError,
47    HeaderErrorKind,
48    "Errors due the fact that the header rule is not respected."
49);
50
51/// A list specifying categories of ckb block error.
52///
53/// This list is intended to grow over time and it is not recommended to exhaustively match against it.
54///
55/// It is used with the [`BlockError`].
56///
57/// [`BlockError`]: ../ckb_verification/struct.BlockError.html
58#[derive(Debug, PartialEq, Eq, Clone, Copy, Display)]
59pub enum BlockErrorKind {
60    /// There are duplicated proposal transactions.
61    ProposalTransactionDuplicate,
62
63    /// There are duplicate committed transactions.
64    CommitTransactionDuplicate,
65
66    /// The calculated Merkle tree hash of proposed transactions does not match the one in the header.
67    ProposalTransactionsHash,
68
69    /// The calculated Merkle tree hash of committed transactions does not match the one in the header.
70    TransactionsRoot,
71
72    /// The calculated dao field does not match with the one in the header.
73    InvalidDAO,
74
75    /// It indicates that the underlying error is [`BlockTransactionsError`].
76    ///
77    /// [`BlockTransactionsError`]: ../ckb_verification/struct.BlockTransactionsError.html
78    BlockTransactions,
79
80    /// It indicates that the underlying error is [`UnknownParentError`].
81    ///
82    /// [`UnknownParentError`]: ../ckb_verification/struct.UnknownParentError.html
83    UnknownParent,
84
85    /// It indicates that the underlying error is [`UnclesError`].
86    ///
87    /// [`UnclesError`]: ../ckb_verification/enum.UnclesError.html
88    Uncles,
89
90    /// It indicates that the underlying error is [`CellbaseError`].
91    ///
92    /// [`CellbaseError`]: ../ckb_verification/enum.CellbaseError.html
93    Cellbase,
94
95    /// It indicates that the underlying error is [`CommitError`].
96    ///
97    /// [`CommitError`]: ../ckb_verification/struct.CommitError.html
98    Commit,
99
100    /// The number of block proposals exceeds limit.
101    ExceededMaximumProposalsLimit,
102
103    /// Total cycles of the block transactions exceed limit.
104    ExceededMaximumCycles,
105
106    /// Total bytes of block exceeds limit.
107    ExceededMaximumBlockBytes,
108
109    /// Empty block extension.
110    EmptyBlockExtension,
111
112    /// Total bytes of block extension exceeds limit.
113    ExceededMaximumBlockExtensionBytes,
114
115    /// No block extension.
116    ///
117    /// The block extension should be existed after light client supported.
118    NoBlockExtension,
119
120    /// The data length of block extension mismatches.
121    InvalidBlockExtension,
122
123    /// The block has unknown field.
124    UnknownFields,
125
126    /// The calculated extra-hash does not match with the one in the header.
127    InvalidExtraHash,
128
129    /// The calculated hash of chain root does not match with the one in the header.
130    InvalidChainRoot,
131}
132
133def_error_base_on_kind!(
134    BlockError,
135    BlockErrorKind,
136    "Errors due the fact that the block rule is not respected."
137);
138
139/// Errors occur during block transactions verification.
140#[derive(Error, Debug)]
141#[error("BlockTransactionsError(index: {index}, error: {error})")]
142pub struct BlockTransactionsError {
143    /// The index of the first erroneous transaction.
144    pub index: u32,
145    /// The underlying error to that erroneous transaction.
146    pub error: Error,
147}
148
149/// Cannot access the parent block to the canonical chain.
150#[derive(Error, Debug, PartialEq, Eq, Clone)]
151#[error("UnknownParentError(parent_hash: {parent_hash})")]
152pub struct UnknownParentError {
153    /// The hash of parent block.
154    pub parent_hash: Byte32,
155}
156
157/// Errors due to the fact that the 2pc rule is not respected.
158///
159/// See also [Two-Step Transaction Confirmation](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0020-ckb-consensus-protocol/0020-ckb-consensus-protocol.md#two-step-transaction-confirmation)
160#[derive(Error, Debug, PartialEq, Eq, Clone, Display)]
161pub enum CommitError {
162    /// There are blocks required at 2pc verification but not found.
163    AncestorNotFound,
164    /// There are block transactions that have not been proposed in the proposal window.
165    Invalid,
166}
167
168/// Errors due to the fact that the cellbase rule is not respected.
169///
170/// See more about cellbase transaction: [cellbase transaction]
171///
172/// [cellbase transaction]: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#exceptions
173#[derive(Error, Debug, PartialEq, Eq, Clone, Display)]
174pub enum CellbaseError {
175    /// The cellbase input is unexpected. The structure reference of correct cellbase input: [`new_cellbase_input`].
176    ///
177    /// [`new_cellbase_input`]: https://github.com/nervosnetwork/ckb/blob/ee0ccecd87013821a2e68120ba3510393c0373e7/util/types/src/extension/shortcuts.rs#L107-L109
178    InvalidInput,
179    /// The cellbase output capacity is not equal to the total block reward.
180    InvalidRewardAmount,
181    /// The cellbase output lock does not match with the target lock.
182    ///
183    /// As for 0 ~ PROPOSAL_WINDOW.farthest blocks, cellbase outputs should be empty; otherwise, lock of first cellbase output should match with the target block.
184    ///
185    /// Assumes the current block number is `i`, then its target block is that: (1) on that same chain with current block; (2) number is `i - PROPOSAL_WINDOW.farthest - 1`.
186    InvalidRewardTarget,
187    /// The cellbase witness is not in [`CellbaseWitness`] format.
188    ///
189    /// [`CellbaseWitness`]: ../ckb_types/packed/struct.CellbaseWitness.html
190    InvalidWitness,
191    /// The cellbase type script is not none.
192    InvalidTypeScript,
193    /// The length of cellbase outputs and outputs-data should be equal and less than `1`.
194    InvalidOutputQuantity,
195    /// There are multiple cellbase transactions inside the same block.
196    InvalidQuantity,
197    /// The first block transaction is not a valid cellbase transaction.
198    ///
199    /// See also [`is_cellbase`].
200    ///
201    /// [`is_cellbase`]: https://github.com/nervosnetwork/ckb/blob/ee0ccecd87013821a2e68120ba3510393c0373e7/util/types/src/core/views.rs#L387-L389
202    InvalidPosition,
203    /// The cellbase output-data is not empty.
204    InvalidOutputData,
205}
206
207/// Errors due to the fact that the uncle rule is not respected.
208#[derive(Error, Debug, PartialEq, Eq, Clone)]
209pub enum UnclesError {
210    /// The number of block uncles exceeds limit.
211    #[error("OverCount(max: {max}, actual: {actual})")]
212    OverCount {
213        /// The limited number of block uncles.
214        max: u32,
215        /// The actual number of block uncles.
216        actual: u32,
217    },
218
219    /// There is an uncle whose number is greater than or equal to current block number.
220    #[error("InvalidNumber")]
221    InvalidNumber,
222
223    /// There is an uncle who belongs to a different epoch from the current block.
224    #[error("InvalidTarget")]
225    InvalidTarget,
226
227    /// There is an uncle who belongs to a different epoch from the current block.
228    #[error("InvalidDifficultyEpoch")]
229    InvalidDifficultyEpoch,
230
231    /// There is an uncle whose proposals-hash does not match with the calculated result.
232    #[error("ProposalsHash")]
233    ProposalsHash,
234
235    /// There is an uncle whose proposals have duplicated items.
236    #[error("ProposalDuplicate")]
237    ProposalDuplicate,
238
239    /// There are duplicated uncles in the current block.
240    #[error("Duplicate({0})")]
241    Duplicate(Byte32),
242
243    /// There is an uncle that has already been included before.
244    #[error("DoubleInclusion({0})")]
245    DoubleInclusion(Byte32),
246
247    /// The depth of uncle descendant exceeds limit.
248    #[error("DescendantLimit")]
249    DescendantLimit,
250
251    /// The number of uncle proposals exceeds limit.
252    #[error("ExceededMaximumProposalsLimit")]
253    ExceededMaximumProposalsLimit,
254}
255
256/// The block version is unexpected.
257#[derive(Error, Debug, PartialEq, Eq, Clone)]
258#[error("BlockVersionError(expected: {expected}, actual: {actual})")]
259pub struct BlockVersionError {
260    /// The expected block version.
261    pub expected: Version,
262    /// The actual block version.
263    pub actual: Version,
264}
265
266/// The block's parent is marked as invalid.
267#[derive(Error, Debug, PartialEq, Eq, Clone)]
268#[error("InvalidParentError(parent_hash: {parent_hash})")]
269pub struct InvalidParentError {
270    /// The parent block hash.
271    pub parent_hash: Byte32,
272}
273
274/// Errors due to the fact that the pow rule is not respected.
275#[derive(Error, Debug, PartialEq, Eq, Clone)]
276pub enum PowError {
277    /// Error occurs during PoW verification.
278    #[error("InvalidNonce: please set logger.filter to \"info,ckb-pow=debug\" for detailed PoW verification information")]
279    InvalidNonce,
280}
281
282/// Errors due to the fact that the block timestamp rule is not respected.
283#[derive(Error, Debug, PartialEq, Eq, Clone)]
284pub enum TimestampError {
285    /// The block timestamp is older than the allowed oldest timestamp.
286    #[error("BlockTimeTooOld(min: {min}, actual: {actual})")]
287    BlockTimeTooOld {
288        /// The allowed oldest block timestamp.
289        min: u64,
290        /// The actual block timestamp.
291        actual: u64,
292    },
293
294    /// The block timestamp is newer than the allowed newest timestamp.
295    #[error("BlockTimeTooNew(max: {max}, actual: {actual})")]
296    BlockTimeTooNew {
297        /// The allowed newest block timestamp.
298        max: u64,
299        /// The actual block timestamp.
300        actual: u64,
301    },
302}
303
304impl TimestampError {
305    /// Return `true` if this error is `TimestampError::BlockTimeTooNew`.
306    #[doc(hidden)]
307    pub fn is_too_new(&self) -> bool {
308        match self {
309            Self::BlockTimeTooOld { .. } => false,
310            Self::BlockTimeTooNew { .. } => true,
311        }
312    }
313}
314
315/// The block number is not equal to parent number + `1`.
316/// Specially genesis block number is `0`.
317#[derive(Error, Debug, PartialEq, Eq, Clone)]
318#[error("NumberError(expected: {expected}, actual: {actual})")]
319pub struct NumberError {
320    /// The expected block number.
321    pub expected: u64,
322    /// The actual block number.
323    pub actual: u64,
324}
325
326/// Errors due to the fact that the block epoch is not expected.
327#[derive(Error, Debug, PartialEq, Eq, Clone)]
328pub enum EpochError {
329    /// The format of header epoch is malformed.
330    #[error("Malformed(value: {value:#})")]
331    Malformed {
332        /// The malformed header epoch.
333        value: EpochNumberWithFraction,
334    },
335
336    /// The header epoch is not continuous.
337    #[error("NonContinuous(current: {current:#}, parent: {parent:#})")]
338    NonContinuous {
339        /// The current header epoch.
340        current: EpochNumberWithFraction,
341        /// The parent header epoch.
342        parent: EpochNumberWithFraction,
343    },
344
345    /// The compact-target of block epoch is unexpected.
346    #[error("TargetMismatch(expected: {expected:x}, actual: {actual:x})")]
347    TargetMismatch {
348        /// The expected compact-target of block epoch.
349        expected: u32,
350        /// The actual compact-target of block epoch.
351        actual: u32,
352    },
353
354    /// The number of block epoch is unexpected.
355    #[error("NumberMismatch(expected: {expected}, actual: {actual})")]
356    NumberMismatch {
357        /// The expected number of block epoch.
358        expected: u64,
359        /// The actual number of block epoch.
360        actual: u64,
361    },
362}
363
364impl HeaderError {
365    /// Downcast `HeaderError` to `TimestampError` then check [`TimestampError::is_too_new`].
366    ///
367    /// Note: if the header is invalid, that may also be grounds for disconnecting the peer,
368    /// However, there is a circumstance where that does not hold:
369    /// if the header's timestamp is more than ALLOWED_FUTURE_BLOCKTIME ahead of our current time.
370    /// In that case, the header may become valid in the future,
371    /// and we don't want to disconnect a peer merely for serving us one too-far-ahead block header,
372    /// to prevent an attacker from splitting the network by mining a block right at the ALLOWED_FUTURE_BLOCKTIME boundary.
373    ///
374    /// [`TimestampError::is_too_new`]
375    #[doc(hidden)]
376    pub fn is_too_new(&self) -> bool {
377        self.downcast_ref::<TimestampError>()
378            .map(|e| e.is_too_new())
379            .unwrap_or(false)
380    }
381}