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 #[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 #[error("transaction could not be added to the mempool because it's full with transactions with higher priority")]
38 RejectMempoolIsFull,
39
40 #[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 #[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 #[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>;