fuel_core_txpool/
error.rs1use fuel_core_types::{
2 fuel_tx::{
3 Address,
4 BlobId,
5 ContractId,
6 TxId,
7 UtxoId,
8 Word,
9 },
10 fuel_types::Nonce,
11 fuel_vm::checked_transaction::CheckError,
12};
13
14use crate::{
15 pending_pool::MissingInput,
16 ports::WasmValidityError,
17};
18
19#[derive(Clone, Debug, derive_more::Display)]
20pub enum Error {
21 #[display(fmt = "Gas price not found for block height {_0}")]
22 GasPriceNotFound(String),
23 #[display(fmt = "Database error: {_0}")]
24 Database(String),
25 #[display(fmt = "Storage error: {_0}")]
26 Storage(String),
27 #[display(fmt = "Blacklisted error: {_0}")]
28 Blacklisted(BlacklistedError),
29 #[display(fmt = "Transaction collided: {_0}")]
30 Collided(CollisionReason),
31 #[display(fmt = "Transaction input validation failed: {_0}")]
32 InputValidation(InputValidationError),
33 #[display(fmt = "Transaction dependency error: {_0}")]
34 Dependency(DependencyError),
35 #[display(fmt = "Invalid transaction data: {_0:?}")]
36 ConsensusValidity(CheckError),
37 #[display(fmt = "Error with Wasm validity: {:?}", _0)]
38 WasmValidity(WasmValidityError),
39 #[display(fmt = "Mint transaction is not allowed")]
40 MintIsDisallowed,
41 #[display(fmt = "Pool limit is hit, try to increase gas_price")]
42 NotInsertedLimitHit,
43 #[display(fmt = "Transaction is removed: {_0}")]
44 Removed(RemovedReason),
45 #[display(fmt = "Transaction has been skipped during block insertion: {_0}")]
46 SkippedTransaction(String),
47 #[display(fmt = "Too much transactions are in queue to be inserted. Can't add more")]
48 TooManyQueuedTransactions,
49 #[display(fmt = "Unable send a request because service is closed")]
50 ServiceCommunicationFailed,
51 #[display(fmt = "Request failed to be sent because service queue is full")]
52 ServiceQueueFull,
53 #[display(fmt = "The provided max fee can't cover the transaction cost. \
54 The minimal gas price should be {minimal_gas_price:?}, \
55 while it is {max_gas_price_from_fee:?}")]
56 InsufficientMaxFee {
57 max_gas_price_from_fee: Word,
59 minimal_gas_price: Word,
61 },
62 #[display(fmt = "The message input {_0:#x} was already spent")]
63 MessageInputWasAlreadySpent(Nonce),
64 #[display(fmt = "The UTXO input {_0:#x} was already spent")]
65 UtxoInputWasAlreadySpent(UtxoId),
66}
67
68impl Error {
69 pub fn is_duplicate_tx(&self) -> bool {
70 matches!(
71 self,
72 Error::InputValidation(InputValidationError::DuplicateTxId(_))
73 )
74 }
75}
76
77#[derive(Clone, Debug, derive_more::Display)]
78pub enum RemovedReason {
79 #[display(
80 fmt = "Transaction was removed because it was less worth than a new one (id: {_0}) that has been inserted"
81 )]
82 LessWorth(TxId),
83 #[display(
84 fmt = "Transaction expired because it exceeded the configured time to live `tx-pool-ttl`."
85 )]
86 Ttl,
87}
88
89#[derive(Clone, Debug, derive_more::Display)]
90pub enum BlacklistedError {
91 #[display(fmt = "The UTXO `{_0}` is blacklisted")]
92 BlacklistedUTXO(UtxoId),
93 #[display(fmt = "The owner `{_0}` is blacklisted")]
94 BlacklistedOwner(Address),
95 #[display(fmt = "The contract `{_0}` is blacklisted")]
96 BlacklistedContract(ContractId),
97 #[display(fmt = "The message `{_0}` is blacklisted")]
98 BlacklistedMessage(Nonce),
99}
100
101#[derive(Clone, Debug, derive_more::Display)]
102pub enum DependencyError {
103 #[display(fmt = "Collision is also a dependency")]
104 NotInsertedCollisionIsDependency,
105 #[display(fmt = "Transaction chain dependency is already too big")]
106 NotInsertedChainDependencyTooBig,
107 #[display(fmt = "The dependent transaction creates a diamond problem, \
108 causing cycles in the dependency graph.")]
109 DependentTransactionIsADiamondDeath,
110 #[display(fmt = "The transaction depends on a blob transaction")]
111 NotInsertedDependentOnBlob,
112}
113
114#[derive(Clone, Debug)]
115pub(crate) enum InsertionErrorType {
116 Error(Error),
117 MissingInputs(Vec<MissingInput>),
118}
119
120impl From<Error> for InsertionErrorType {
121 fn from(e: Error) -> Self {
122 InsertionErrorType::Error(e)
123 }
124}
125
126impl From<InputValidationErrorType> for InsertionErrorType {
127 fn from(e: InputValidationErrorType) -> Self {
128 match e {
129 InputValidationErrorType::Inconsistency(e) => InsertionErrorType::Error(e),
130 InputValidationErrorType::MissingInputs(e) => {
131 InsertionErrorType::MissingInputs(e)
132 }
133 }
134 }
135}
136
137pub(crate) enum InputValidationErrorType {
138 Inconsistency(Error),
139 MissingInputs(Vec<MissingInput>),
141}
142
143#[derive(Clone, Debug, derive_more::Display)]
144pub enum InputValidationError {
145 #[display(fmt = "Input output mismatch. Coin owner is different from expected input")]
146 NotInsertedIoWrongOwner,
147 #[display(fmt = "Input output mismatch. Coin output does not match expected input")]
148 NotInsertedIoWrongAmount,
149 #[display(
150 fmt = "Input output mismatch. Coin output asset_id does not match expected inputs"
151 )]
152 NotInsertedIoWrongAssetId,
153 #[display(fmt = "Input message does not match the values from database")]
154 NotInsertedIoMessageMismatch,
155 #[display(fmt = "Input output mismatch. Expected coin but output is contract")]
156 NotInsertedIoContractOutput,
157 #[display(
158 fmt = "Message id {_0:#x} does not match any received message from the DA layer."
159 )]
160 NotInsertedInputMessageUnknown(Nonce),
161 #[display(fmt = "Input dependent on a Change or Variable output")]
162 NotInsertedInputDependentOnChangeOrVariable,
163 #[display(fmt = "UTXO input does not exist: {_0:#x}")]
164 NotInsertedInputContractDoesNotExist(ContractId),
165 #[display(fmt = "BlobId is already taken {_0:#x}")]
166 NotInsertedBlobIdAlreadyTaken(BlobId),
167 #[display(fmt = "Input coin does not match the values from database")]
168 NotInsertedIoCoinMismatch,
169 #[display(fmt = "Wrong number of outputs: {_0}")]
170 WrongOutputNumber(String),
171 #[display(fmt = "UTXO (id: {_0}) does not exist")]
172 UtxoNotFound(UtxoId),
173 #[display(fmt = "Max gas can't be 0")]
174 MaxGasZero,
175 #[display(fmt = "Transaction id already exists (id: {_0})")]
176 DuplicateTxId(TxId),
177}
178
179#[derive(Debug, Clone, derive_more::Display)]
180pub enum CollisionReason {
181 #[display(
182 fmt = "Transaction with the same UTXO (id: {_0}) already exists and is more worth it"
183 )]
184 Utxo(UtxoId),
185 #[display(
186 fmt = "Transaction that create the same contract (id: {_0}) already exists and is more worth it"
187 )]
188 ContractCreation(ContractId),
189 #[display(
190 fmt = "Transaction that use the same blob (id: {_0}) already exists and is more worth it"
191 )]
192 Blob(BlobId),
193 #[display(
194 fmt = "Transaction that use the same message (id: {_0}) already exists and is more worth it"
195 )]
196 Message(Nonce),
197 #[display(fmt = "This transaction have an unknown collision")]
198 Unknown,
199 #[display(
200 fmt = "This transaction have dependencies and is colliding with multiple transactions"
201 )]
202 MultipleCollisions,
203}
204
205impl From<CheckError> for Error {
206 fn from(e: CheckError) -> Self {
207 Error::ConsensusValidity(e)
208 }
209}