1use crate::{
2 common::{
3 fuel_tx::{
4 CheckError,
5 TxId,
6 UtxoId,
7 },
8 fuel_types::{
9 Bytes32,
10 ContractId,
11 MessageId,
12 },
13 fuel_vm::backtrace::Backtrace,
14 },
15 db::KvStoreError,
16 model::{
17 BlockId,
18 FuelBlock,
19 PartialFuelBlock,
20 },
21 txpool::TransactionStatus,
22};
23use fuel_vm::fuel_tx::Transaction;
24use std::error::Error as StdError;
25use thiserror::Error;
26
27pub type ExecutionBlock = ExecutionTypes<PartialFuelBlock, FuelBlock>;
31
32pub type ExecutionType<T> = ExecutionTypes<T, T>;
34
35#[derive(Debug, Clone, Copy)]
36pub enum ExecutionTypes<P, V> {
39 Production(P),
41 Validation(V),
43}
44
45#[derive(Debug)]
47pub struct ExecutionResult {
48 pub block: FuelBlock,
50 pub skipped_transactions: Vec<(Transaction, Error)>,
53 pub tx_status: Vec<TransactionExecutionStatus>,
55}
56
57#[derive(Debug, Clone)]
58pub struct TransactionExecutionStatus {
59 pub id: Bytes32,
60 pub status: TransactionStatus,
61}
62
63#[derive(Debug)]
66pub struct UncommittedResult<DbTransaction> {
67 result: ExecutionResult,
69 database_transaction: DbTransaction,
71}
72
73impl<DbTransaction> UncommittedResult<DbTransaction> {
74 pub fn new(result: ExecutionResult, database_transaction: DbTransaction) -> Self {
76 Self {
77 result,
78 database_transaction,
79 }
80 }
81
82 pub fn result(&self) -> &ExecutionResult {
84 &self.result
85 }
86
87 pub fn into(self) -> (ExecutionResult, DbTransaction) {
93 (self.result, self.database_transaction)
94 }
95
96 pub fn into_result(self) -> ExecutionResult {
98 self.result
99 }
100
101 pub fn into_transaction(self) -> DbTransaction {
103 self.database_transaction
104 }
105}
106
107#[derive(Debug, Clone, Copy)]
108pub enum ExecutionKind {
110 Production,
112 Validation,
114}
115
116#[derive(Debug, Error)]
117#[non_exhaustive]
118pub enum TransactionValidityError {
119 #[error("Coin input was already spent")]
120 CoinAlreadySpent(UtxoId),
121 #[error("Coin has not yet reached maturity")]
122 CoinHasNotMatured(UtxoId),
123 #[error("The specified coin doesn't exist")]
124 CoinDoesNotExist(UtxoId),
125 #[error("The specified message was already spent")]
126 MessageAlreadySpent(MessageId),
127 #[error(
128 "Message is not yet spendable, as it's DA height is newer than this block allows"
129 )]
130 MessageSpendTooEarly(MessageId),
131 #[error("The specified message doesn't exist")]
132 MessageDoesNotExist(MessageId),
133 #[error("Contract output index isn't valid: {0:#x}")]
134 InvalidContractInputIndex(UtxoId),
135 #[error("The transaction must have at least one coin or message input type: {0:#x}")]
136 NoCoinOrMessageInput(TxId),
137 #[error("The transaction contains predicate inputs which aren't enabled: {0:#x}")]
138 PredicateExecutionDisabled(TxId),
139 #[error(
140 "The transaction contains a predicate which failed to validate: TransactionId({0:#x})"
141 )]
142 InvalidPredicate(TxId),
143 #[error("Transaction validity: {0:#?}")]
144 Validation(#[from] CheckError),
145 #[error("Datastore error occurred")]
146 DataStoreError(Box<dyn StdError + Send + Sync>),
147}
148
149impl From<KvStoreError> for TransactionValidityError {
150 fn from(e: KvStoreError) -> Self {
151 Self::DataStoreError(Box::new(e))
152 }
153}
154
155#[derive(Error, Debug)]
156#[non_exhaustive]
157pub enum Error {
158 #[error("Transaction id was already used: {0:#x}")]
159 TransactionIdCollision(Bytes32),
160 #[error("output already exists")]
161 OutputAlreadyExists,
162 #[error("The computed fee caused an integer overflow")]
163 FeeOverflow,
164 #[error("Not supported transaction: {0:?}")]
165 NotSupportedTransaction(Box<Transaction>),
166 #[error("The first transaction in the block is not `Mint` - coinbase.")]
167 CoinbaseIsNotFirstTransaction,
168 #[error("Coinbase should have one output.")]
169 CoinbaseSeveralOutputs,
170 #[error("Coinbase outputs is invalid.")]
171 CoinbaseOutputIsInvalid,
172 #[error("Coinbase amount mismatches with expected.")]
173 CoinbaseAmountMismatch,
174 #[error("Invalid transaction: {0}")]
175 TransactionValidity(#[from] TransactionValidityError),
176 #[error("corrupted block state")]
177 CorruptedBlockState(Box<dyn StdError + Send + Sync>),
178 #[error("Transaction({transaction_id:#x}) execution error: {error:?}")]
179 VmExecution {
180 error: fuel_vm::prelude::InterpreterError,
181 transaction_id: Bytes32,
182 },
183 #[error(transparent)]
184 InvalidTransaction(#[from] CheckError),
185 #[error("Execution error with backtrace")]
186 Backtrace(Box<Backtrace>),
187 #[error("Transaction doesn't match expected result: {transaction_id:#x}")]
188 InvalidTransactionOutcome { transaction_id: Bytes32 },
189 #[error("Transaction root is invalid")]
190 InvalidTransactionRoot,
191 #[error("The amount of charged fees is invalid")]
192 InvalidFeeAmount,
193 #[error("Block id is invalid")]
194 InvalidBlockId,
195 #[error("No matching utxo for contract id ${0:#x}")]
196 ContractUtxoMissing(ContractId),
197}
198
199impl ExecutionBlock {
200 pub fn id(&self) -> Option<BlockId> {
202 match self {
203 ExecutionTypes::Production(_) => None,
204 ExecutionTypes::Validation(v) => Some(v.id()),
205 }
206 }
207
208 pub fn txs_root(&self) -> Option<Bytes32> {
210 match self {
211 ExecutionTypes::Production(_) => None,
212 ExecutionTypes::Validation(v) => Some(v.header().transactions_root),
213 }
214 }
215}
216
217impl<P, V> ExecutionTypes<P, V> {
218 pub fn map_p<Q, F>(self, f: F) -> ExecutionTypes<Q, V>
220 where
221 F: FnOnce(P) -> Q,
222 {
223 match self {
224 ExecutionTypes::Production(p) => ExecutionTypes::Production(f(p)),
225 ExecutionTypes::Validation(v) => ExecutionTypes::Validation(v),
226 }
227 }
228
229 pub fn map_v<W, F>(self, f: F) -> ExecutionTypes<P, W>
231 where
232 F: FnOnce(V) -> W,
233 {
234 match self {
235 ExecutionTypes::Production(p) => ExecutionTypes::Production(p),
236 ExecutionTypes::Validation(v) => ExecutionTypes::Validation(f(v)),
237 }
238 }
239
240 pub fn as_ref(&self) -> ExecutionTypes<&P, &V> {
242 match *self {
243 ExecutionTypes::Production(ref p) => ExecutionTypes::Production(p),
244 ExecutionTypes::Validation(ref v) => ExecutionTypes::Validation(v),
245 }
246 }
247
248 pub fn as_mut(&mut self) -> ExecutionTypes<&mut P, &mut V> {
250 match *self {
251 ExecutionTypes::Production(ref mut p) => ExecutionTypes::Production(p),
252 ExecutionTypes::Validation(ref mut v) => ExecutionTypes::Validation(v),
253 }
254 }
255
256 pub fn to_kind(&self) -> ExecutionKind {
258 match self {
259 ExecutionTypes::Production(_) => ExecutionKind::Production,
260 ExecutionTypes::Validation(_) => ExecutionKind::Validation,
261 }
262 }
263}
264
265impl<T> ExecutionType<T> {
266 pub fn map<U, F>(self, f: F) -> ExecutionType<U>
268 where
269 F: FnOnce(T) -> U,
270 {
271 match self {
272 ExecutionTypes::Production(p) => ExecutionTypes::Production(f(p)),
273 ExecutionTypes::Validation(v) => ExecutionTypes::Validation(f(v)),
274 }
275 }
276
277 pub fn filter_map<U, F>(self, f: F) -> Option<ExecutionType<U>>
279 where
280 F: FnOnce(T) -> Option<U>,
281 {
282 match self {
283 ExecutionTypes::Production(p) => f(p).map(ExecutionTypes::Production),
284 ExecutionTypes::Validation(v) => f(v).map(ExecutionTypes::Validation),
285 }
286 }
287
288 pub fn into_inner(self) -> T {
290 match self {
291 ExecutionTypes::Production(t) | ExecutionTypes::Validation(t) => t,
292 }
293 }
294
295 pub fn split(self) -> (ExecutionKind, T) {
297 let kind = self.to_kind();
298 (kind, self.into_inner())
299 }
300}
301
302impl ExecutionKind {
303 pub fn wrap<T>(self, t: T) -> ExecutionType<T> {
305 match self {
306 ExecutionKind::Production => ExecutionTypes::Production(t),
307 ExecutionKind::Validation => ExecutionTypes::Validation(t),
308 }
309 }
310}
311
312impl From<Backtrace> for Error {
313 fn from(e: Backtrace) -> Self {
314 Error::Backtrace(Box::new(e))
315 }
316}
317
318impl From<KvStoreError> for Error {
319 fn from(e: KvStoreError) -> Self {
320 Error::CorruptedBlockState(Box::new(e))
321 }
322}
323
324impl From<crate::db::Error> for Error {
325 fn from(e: crate::db::Error) -> Self {
326 Error::CorruptedBlockState(Box::new(e))
327 }
328}
329
330impl<T> core::ops::Deref for ExecutionType<T> {
331 type Target = T;
332
333 fn deref(&self) -> &Self::Target {
334 match self {
335 ExecutionTypes::Production(p) => p,
336 ExecutionTypes::Validation(v) => v,
337 }
338 }
339}
340
341impl<T> core::ops::DerefMut for ExecutionType<T> {
342 fn deref_mut(&mut self) -> &mut Self::Target {
343 match self {
344 ExecutionTypes::Production(p) => p,
345 ExecutionTypes::Validation(v) => v,
346 }
347 }
348}