kaspa_mining_errors/
mempool.rs

1use kaspa_consensus_core::{
2    errors::tx::TxRuleError,
3    tx::{TransactionId, TransactionOutpoint},
4};
5use thiserror::Error;
6
7#[derive(Error, Debug, Clone, PartialEq, Eq)]
8pub enum RuleError {
9    /// A consensus transaction rule error
10    ///
11    /// Note that following variants are converted:
12    ///
13    /// - TxRuleError::ImmatureCoinbaseSpend => RuleError::RejectImmatureSpend
14    /// - TxRuleError::MissingTxOutpoints => RuleError::RejectMissingOutpoint
15    #[error(transparent)]
16    RejectTxRule(TxRuleError),
17
18    #[error("at least one outpoint of transaction is lacking a matching UTXO entry")]
19    RejectMissingOutpoint,
20
21    #[error("transaction {0} was already accepted by the consensus")]
22    RejectAlreadyAccepted(TransactionId),
23
24    #[error("transaction {0} is already in the mempool")]
25    RejectDuplicate(TransactionId),
26
27    #[error("output {0} already spent by transaction {1} in the mempool")]
28    RejectDoubleSpendInMempool(TransactionOutpoint, TransactionId),
29
30    #[error("replace by fee found no double spending transaction in the mempool")]
31    RejectRbfNoDoubleSpend,
32
33    #[error("replace by fee found more than one double spending transaction in the mempool")]
34    RejectRbfTooManyDoubleSpendingTransactions,
35
36    /// a transaction is rejected if the mempool is full
37    #[error("transaction could not be added to the mempool because it's full with transactions with higher priority")]
38    RejectMempoolIsFull,
39
40    /// An error emitted by mining\src\mempool\check_transaction_standard.rs
41    #[error("transaction {0} is not standard: {1}")]
42    RejectNonStandard(TransactionId, String),
43
44    #[error("one of the transaction inputs spends an immature UTXO: {0}")]
45    RejectImmatureSpend(TxRuleError),
46
47    #[error("transaction {0} doesn't exist in transaction pool")]
48    RejectMissingTransaction(TransactionId),
49
50    #[error("orphan transaction size of {0} bytes is larger than max allowed size of {1} bytes")]
51    RejectBadOrphanMass(u64, u64),
52
53    #[error("orphan transaction {0} is already in the orphan pool")]
54    RejectDuplicateOrphan(TransactionId),
55
56    #[error("orphan transaction {0} is double spending an input from already existing orphan {1}")]
57    RejectDoubleSpendOrphan(TransactionId, TransactionId),
58
59    #[error("transaction {0} is an orphan where orphan is disallowed")]
60    RejectDisallowedOrphan(TransactionId),
61
62    #[error("input No. {0} of {1} ({2}) doesn't exist in orphan_ids_by_previous_outpoint")]
63    RejectMissingOrphanOutpoint(usize, TransactionId, TransactionOutpoint),
64
65    #[error("transaction {0} doesn't exist in orphan pool")]
66    RejectMissingOrphanTransaction(TransactionId),
67
68    /// New behavior: a transaction is rejected if the orphan pool is full
69    #[error("number of high-priority transactions in orphan pool ({0}) has reached the maximum allowed ({1})")]
70    RejectOrphanPoolIsFull(usize, u64),
71
72    #[error("transactions in mempool form a cycle")]
73    RejectCycleInMempoolTransactions,
74
75    // TODO: This error is added for the tx_relay flow but is never constructed neither in the golang nor in this version. Discuss if it can be removed.
76    #[error("transaction {0} is invalid")]
77    RejectInvalid(TransactionId),
78
79    #[error("Rejected spam tx {0} from mempool")]
80    RejectSpamTransaction(TransactionId),
81
82    #[error("Rejected tx {0} from mempool due to incomputable storage mass")]
83    RejectStorageMassIncomputable(TransactionId),
84}
85
86impl From<NonStandardError> for RuleError {
87    fn from(item: NonStandardError) -> Self {
88        RuleError::RejectNonStandard(*item.transaction_id(), item.to_string())
89    }
90}
91
92impl From<TxRuleError> for RuleError {
93    fn from(item: TxRuleError) -> Self {
94        match item {
95            TxRuleError::ImmatureCoinbaseSpend(_, _, _, _, _) => RuleError::RejectImmatureSpend(item),
96            TxRuleError::MissingTxOutpoints => RuleError::RejectMissingOutpoint,
97            _ => RuleError::RejectTxRule(item),
98        }
99    }
100}
101
102pub type RuleResult<T> = std::result::Result<T, RuleError>;
103
104#[derive(Error, Debug, Clone, PartialEq, Eq)]
105pub enum NonStandardError {
106    #[error("transaction version {1} is not in the valid range of {2}-{3}")]
107    RejectVersion(TransactionId, u16, u16, u16),
108
109    #[error("transaction mass of {1} is larger than max allowed size of {2}")]
110    RejectMass(TransactionId, u64, u64),
111
112    #[error("transaction mass in context (including storage mass) of {1} is larger than max allowed size of {2}")]
113    RejectContextualMass(TransactionId, u64, u64),
114
115    #[error("transaction input #{1}: signature script size of {2} bytes is larger than the maximum allowed size of {3} bytes")]
116    RejectSignatureScriptSize(TransactionId, usize, u64, u64),
117
118    #[error("transaction output #{1}: the version of the scriptPublicKey is higher than the known version")]
119    RejectScriptPublicKeyVersion(TransactionId, usize),
120
121    #[error("transaction output #{1}: non-standard script form")]
122    RejectOutputScriptClass(TransactionId, usize),
123
124    #[error("transaction output #{1}: payment of {2} is dust")]
125    RejectDust(TransactionId, usize, u64),
126
127    #[error("transaction input {1}: non-standard script form")]
128    RejectInputScriptClass(TransactionId, usize),
129
130    #[error("transaction has {1} fees which is under the required amount of {2}")]
131    RejectInsufficientFee(TransactionId, u64, u64),
132
133    #[error("transaction input #{1} has {2} signature operations which is more than the allowed max amount of {3}")]
134    RejectSignatureCount(TransactionId, usize, u8, u8),
135}
136
137impl NonStandardError {
138    pub fn transaction_id(&self) -> &TransactionId {
139        match self {
140            NonStandardError::RejectVersion(id, _, _, _) => id,
141            NonStandardError::RejectMass(id, _, _) => id,
142            NonStandardError::RejectContextualMass(id, _, _) => id,
143            NonStandardError::RejectSignatureScriptSize(id, _, _, _) => id,
144            NonStandardError::RejectScriptPublicKeyVersion(id, _) => id,
145            NonStandardError::RejectOutputScriptClass(id, _) => id,
146            NonStandardError::RejectDust(id, _, _) => id,
147            NonStandardError::RejectInputScriptClass(id, _) => id,
148            NonStandardError::RejectInsufficientFee(id, _, _) => id,
149            NonStandardError::RejectSignatureCount(id, _, _, _) => id,
150        }
151    }
152}
153
154pub type NonStandardResult<T> = std::result::Result<T, NonStandardError>;