solana_svm/
transaction_processing_result.rs

1use {
2    crate::{
3        account_loader::FeesOnlyTransaction,
4        transaction_execution_result::{ExecutedTransaction, TransactionExecutionDetails},
5    },
6    solana_fee_structure::FeeDetails,
7    solana_transaction_error::{TransactionError, TransactionResult},
8};
9
10pub type TransactionProcessingResult = TransactionResult<ProcessedTransaction>;
11
12pub trait TransactionProcessingResultExtensions {
13    fn was_processed(&self) -> bool;
14    fn was_processed_with_successful_result(&self) -> bool;
15    fn processed_transaction(&self) -> Option<&ProcessedTransaction>;
16    fn flattened_result(&self) -> TransactionResult<()>;
17}
18
19#[derive(Debug)]
20pub enum ProcessedTransaction {
21    /// Transaction was executed, but if execution failed, all account state changes
22    /// will be rolled back except deducted fees and any advanced nonces
23    Executed(Box<ExecutedTransaction>),
24    /// Transaction was not able to be executed but fees are able to be
25    /// collected and any nonces are advanceable
26    FeesOnly(Box<FeesOnlyTransaction>),
27}
28
29impl TransactionProcessingResultExtensions for TransactionProcessingResult {
30    fn was_processed(&self) -> bool {
31        self.is_ok()
32    }
33
34    fn was_processed_with_successful_result(&self) -> bool {
35        match self {
36            Ok(processed_tx) => processed_tx.was_processed_with_successful_result(),
37            Err(_) => false,
38        }
39    }
40
41    fn processed_transaction(&self) -> Option<&ProcessedTransaction> {
42        match self {
43            Ok(processed_tx) => Some(processed_tx),
44            Err(_) => None,
45        }
46    }
47
48    fn flattened_result(&self) -> TransactionResult<()> {
49        self.as_ref()
50            .map_err(|err| err.clone())
51            .and_then(|processed_tx| processed_tx.status())
52    }
53}
54
55impl ProcessedTransaction {
56    fn was_processed_with_successful_result(&self) -> bool {
57        match self {
58            Self::Executed(executed_tx) => executed_tx.execution_details.status.is_ok(),
59            Self::FeesOnly(_) => false,
60        }
61    }
62
63    pub fn status(&self) -> TransactionResult<()> {
64        match self {
65            Self::Executed(executed_tx) => executed_tx.execution_details.status.clone(),
66            Self::FeesOnly(details) => Err(TransactionError::clone(&details.load_error)),
67        }
68    }
69
70    pub fn fee_details(&self) -> FeeDetails {
71        match self {
72            Self::Executed(executed_tx) => executed_tx.loaded_transaction.fee_details,
73            Self::FeesOnly(details) => details.fee_details,
74        }
75    }
76
77    pub fn executed_transaction(&self) -> Option<&ExecutedTransaction> {
78        match self {
79            Self::Executed(context) => Some(context),
80            Self::FeesOnly { .. } => None,
81        }
82    }
83
84    pub fn execution_details(&self) -> Option<&TransactionExecutionDetails> {
85        match self {
86            Self::Executed(context) => Some(&context.execution_details),
87            Self::FeesOnly { .. } => None,
88        }
89    }
90
91    pub fn executed_units(&self) -> u64 {
92        self.execution_details()
93            .map(|detail| detail.executed_units)
94            .unwrap_or_default()
95    }
96
97    pub fn loaded_accounts_data_size(&self) -> u32 {
98        match self {
99            Self::Executed(context) => context.loaded_transaction.loaded_accounts_data_size,
100            Self::FeesOnly(details) => details.rollback_accounts.data_size() as u32,
101        }
102    }
103}