kaspa_consensus_core/errors/
block.rs1use 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 #[error("cannot add block body to a pruned block")]
153 PrunedBlock,
154}
155
156pub type BlockProcessResult<T> = std::result::Result<T, RuleError>;