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        self.as_ref().ok()
43    }
44
45    fn flattened_result(&self) -> TransactionResult<()> {
46        self.as_ref()
47            .map_err(|err| err.clone())
48            .and_then(|processed_tx| processed_tx.status())
49    }
50}
51
52impl ProcessedTransaction {
53    fn was_processed_with_successful_result(&self) -> bool {
54        match self {
55            Self::Executed(executed_tx) => executed_tx.execution_details.status.is_ok(),
56            Self::FeesOnly(_) => false,
57        }
58    }
59
60    pub fn status(&self) -> TransactionResult<()> {
61        match self {
62            Self::Executed(executed_tx) => executed_tx.execution_details.status.clone(),
63            Self::FeesOnly(details) => Err(TransactionError::clone(&details.load_error)),
64        }
65    }
66
67    pub fn fee_details(&self) -> FeeDetails {
68        match self {
69            Self::Executed(executed_tx) => executed_tx.loaded_transaction.fee_details,
70            Self::FeesOnly(details) => details.fee_details,
71        }
72    }
73
74    pub fn executed_transaction(&self) -> Option<&ExecutedTransaction> {
75        match self {
76            Self::Executed(context) => Some(context),
77            Self::FeesOnly { .. } => None,
78        }
79    }
80
81    pub fn execution_details(&self) -> Option<&TransactionExecutionDetails> {
82        match self {
83            Self::Executed(context) => Some(&context.execution_details),
84            Self::FeesOnly { .. } => None,
85        }
86    }
87
88    pub fn executed_units(&self) -> u64 {
89        self.execution_details()
90            .map(|detail| detail.executed_units)
91            .unwrap_or_default()
92    }
93
94    pub fn loaded_accounts_data_size(&self) -> u32 {
95        match self {
96            Self::Executed(context) => context.loaded_transaction.loaded_accounts_data_size,
97            Self::FeesOnly(details) => details.rollback_accounts.data_size() as u32,
98        }
99    }
100}