kaspa_consensus_core/errors/
block.rs

1use std::{collections::HashMap, fmt::Display};
2
3use crate::{
4    constants,
5    errors::{coinbase::CoinbaseError, tx::TxRuleError},
6    tx::{TransactionId, TransactionOutpoint},
7    BlueWorkType,
8};
9use itertools::Itertools;
10use kaspa_hashes::Hash;
11use thiserror::Error;
12
13#[derive(Clone, Debug)]
14pub struct VecDisplay<T: Display>(pub Vec<T>);
15impl<T: Display> Display for VecDisplay<T> {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        write!(f, "[{}]", self.0.iter().map(|item| item.to_string()).join(", "))
18    }
19}
20
21#[derive(Clone, Debug)]
22pub struct TwoDimVecDisplay<T: Display + Clone>(pub Vec<Vec<T>>);
23impl<T: Display + Clone> Display for TwoDimVecDisplay<T> {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(f, "[\n\t{}\n]", self.0.iter().cloned().map(|item| VecDisplay(item).to_string()).join(", \n\t"))
26    }
27}
28
29#[derive(Error, Debug, Clone)]
30pub enum RuleError {
31    #[error("wrong block version: got {0} but expected {}", constants::BLOCK_VERSION)]
32    WrongBlockVersion(u16),
33
34    #[error("the block timestamp is too far into the future: block timestamp is {0} but maximum timestamp allowed is {1}")]
35    TimeTooFarIntoTheFuture(u64, u64),
36
37    #[error("block has no parents")]
38    NoParents,
39
40    #[error("block has too many parents: got {0} when the limit is {1}")]
41    TooManyParents(usize, usize),
42
43    #[error("block has ORIGIN as one of its parents")]
44    OriginParent,
45
46    #[error("parent {0} is an ancestor of parent {1}")]
47    InvalidParentsRelation(Hash, Hash),
48
49    #[error("parent {0} is invalid")]
50    InvalidParent(Hash),
51
52    #[error("block has missing parents: {0:?}")]
53    MissingParents(Vec<Hash>),
54
55    #[error("pruning point {0} is not in the past of this block")]
56    PruningViolation(Hash),
57
58    #[error("expected header daa score {0} but got {1}")]
59    UnexpectedHeaderDaaScore(u64, u64),
60
61    #[error("expected header blue score {0} but got {1}")]
62    UnexpectedHeaderBlueScore(u64, u64),
63
64    #[error("expected header blue work {0} but got {1}")]
65    UnexpectedHeaderBlueWork(BlueWorkType, BlueWorkType),
66
67    #[error("block difficulty of {0} is not the expected value of {1}")]
68    UnexpectedDifficulty(u32, u32),
69
70    #[error("block timestamp of {0} is not after expected {1}")]
71    TimeTooOld(u64, u64),
72
73    #[error("block is known to be invalid")]
74    KnownInvalid,
75
76    #[error("block merges {0} blocks > {1} merge set size limit")]
77    MergeSetTooBig(u64, u64),
78
79    #[error("block is violating bounded merge depth")]
80    ViolatingBoundedMergeDepth,
81
82    #[error("invalid merkle root: header indicates {0} but calculated value is {1}")]
83    BadMerkleRoot(Hash, Hash),
84
85    #[error("block has no transactions")]
86    NoTransactions,
87
88    #[error("block first transaction is not coinbase")]
89    FirstTxNotCoinbase,
90
91    #[error("block has second coinbase transaction as index {0}")]
92    MultipleCoinbases(usize),
93
94    #[error("bad coinbase payload: {0}")]
95    BadCoinbasePayload(CoinbaseError),
96
97    #[error("coinbase blue score of {0} is not the expected value of {1}")]
98    BadCoinbasePayloadBlueScore(u64, u64),
99
100    #[error("transaction in isolation validation failed for tx {0}: {1}")]
101    TxInIsolationValidationFailed(TransactionId, TxRuleError),
102
103    #[error("block exceeded mass limit of {0}")]
104    ExceedsMassLimit(u64),
105
106    #[error("transaction {0} has mass field of {1} but mass should be at least {2}")]
107    MassFieldTooLow(TransactionId, u64, u64),
108
109    #[error("outpoint {0} is spent more than once on the same block")]
110    DoubleSpendInSameBlock(TransactionOutpoint),
111
112    #[error("outpoint {0} is created and spent on the same block")]
113    ChainedTransaction(TransactionOutpoint),
114
115    #[error("transaction in context validation failed for tx {0}: {1}")]
116    TxInContextFailed(TransactionId, TxRuleError),
117
118    #[error("wrong coinbase subsidy: expected {0} but got {1}")]
119    WrongSubsidy(u64, u64),
120
121    #[error("transaction {0} is found more than once in the block")]
122    DuplicateTransactions(TransactionId),
123
124    #[error("block has invalid proof-of-work")]
125    InvalidPoW,
126
127    #[error("expected header pruning point is {0} but got {1}")]
128    WrongHeaderPruningPoint(Hash, Hash),
129
130    #[error("expected indirect parents {0} but got {1}")]
131    UnexpectedIndirectParents(TwoDimVecDisplay<Hash>, TwoDimVecDisplay<Hash>),
132
133    #[error("block {0} UTXO commitment is invalid - block header indicates {1}, but calculated value is {2}")]
134    BadUTXOCommitment(Hash, Hash, Hash),
135
136    #[error("block {0} accepted ID merkle root is invalid - block header indicates {1}, but calculated value is {2}")]
137    BadAcceptedIDMerkleRoot(Hash, Hash, Hash),
138
139    #[error("coinbase transaction is not built as expected")]
140    BadCoinbaseTransaction,
141
142    #[error("{0} non-coinbase transactions (out of {1}) are invalid in UTXO context")]
143    InvalidTransactionsInUtxoContext(usize, usize),
144
145    #[error("invalid transactions in new block template")]
146    InvalidTransactionsInNewBlock(HashMap<TransactionId, TxRuleError>),
147
148    #[error("DAA window data has only {0} entries")]
149    InsufficientDaaWindowSize(usize),
150
151    /// Currently this error is never created because it is impossible to submit such a block
152    #[error("cannot add block body to a pruned block")]
153    PrunedBlock,
154}
155
156pub type BlockProcessResult<T> = std::result::Result<T, RuleError>;