trident_svm/methods/
trident_svm_transactions.rs

1use std::collections::HashSet;
2
3use solana_clock::Clock;
4use solana_compute_budget::compute_budget_limits::ComputeBudgetLimits;
5use solana_fee_structure::FeeDetails;
6
7use solana_transaction::sanitized::SanitizedTransaction;
8use solana_transaction::Transaction;
9
10use solana_svm::account_loader::CheckedTransactionDetails;
11use solana_svm::transaction_processing_result::TransactionProcessingResultExtensions;
12use solana_svm::transaction_processor::ExecutionRecordingConfig;
13use solana_svm::transaction_processor::TransactionProcessingConfig;
14use solana_svm::transaction_processor::TransactionProcessingEnvironment;
15
16use crate::trident_svm::TridentSVM;
17use crate::types::transaction_result::TridentTransactionProcessingResult;
18
19impl TridentSVM {
20    pub fn process_transaction(
21        &mut self,
22        transaction: Transaction,
23    ) -> TridentTransactionProcessingResult {
24        let tx_processing_environment = TransactionProcessingEnvironment::<'_> {
25            feature_set: *self.feature_set,
26            ..Default::default()
27        };
28
29        let tx_processing_config = TransactionProcessingConfig::default();
30
31        // reset sysvar cache
32        self.processor.reset_sysvar_cache();
33
34        // replenish sysvar cache with sysvars from the accounts db
35        self.processor.fill_missing_sysvar_cache_entries(self);
36
37        // create sanitized transaction
38        let sanitezed_tx =
39            SanitizedTransaction::try_from_legacy_transaction(transaction, &HashSet::new())
40                .unwrap();
41
42        // get current transaction timestamp
43        let transaction_timestamp =
44            self.accounts.deserialize_sysvar::<Clock>().unix_timestamp as u64;
45
46        // execute transaction
47        let res = self.processor.load_and_execute_sanitized_transactions(
48            self,
49            &[sanitezed_tx],
50            get_transaction_check_results(1),
51            &tx_processing_environment,
52            &tx_processing_config,
53        );
54
55        // update clock
56        self.accounts.update_clock();
57
58        // return transaction processing result
59        TridentTransactionProcessingResult::new(res, transaction_timestamp)
60    }
61    pub fn process_transaction_with_settle(
62        &mut self,
63        transaction: Transaction,
64    ) -> TridentTransactionProcessingResult {
65        let tx_processing_environment = TransactionProcessingEnvironment::<'_> {
66            feature_set: *self.feature_set,
67            ..Default::default()
68        };
69
70        let tx_processing_config = TransactionProcessingConfig {
71            log_messages_bytes_limit: Some(20 * 1000),
72            recording_config: ExecutionRecordingConfig::new_single_setting(true),
73            ..Default::default()
74        };
75
76        // reset sysvar cache
77        self.processor.reset_sysvar_cache();
78
79        // replenish sysvar cache with sysvars from the accounts db
80        self.processor.fill_missing_sysvar_cache_entries(self);
81
82        // create sanitized transaction
83        let sanitezed_tx =
84            SanitizedTransaction::try_from_legacy_transaction(transaction, &HashSet::new())
85                .expect("Trident SVM is not able to create sanitized transaction");
86
87        // get current transaction timestamp
88        let transaction_timestamp =
89            self.accounts.deserialize_sysvar::<Clock>().unix_timestamp as u64;
90
91        // execute transaction
92        let result = self.processor.load_and_execute_sanitized_transactions(
93            self,
94            &[sanitezed_tx],
95            get_transaction_check_results(1),
96            &tx_processing_environment,
97            &tx_processing_config,
98        );
99
100        // update clock
101        self.accounts.update_clock();
102
103        let processed_transaction = result.processing_results[0]
104            .processed_transaction()
105            .expect("Transaction was not processed");
106
107        match &processed_transaction {
108            solana_svm::transaction_processing_result::ProcessedTransaction::Executed(
109                executed_tx,
110            ) => match &executed_tx.execution_details.status {
111                Ok(()) => {
112                    self.settle_accounts(&executed_tx.loaded_transaction.accounts);
113                }
114                Err(_transaction_error) => {
115                    // in case of transaction error, we don't need to do anything
116                }
117            },
118            solana_svm::transaction_processing_result::ProcessedTransaction::FeesOnly(
119                _transaction_error,
120            ) => {
121                // in case of transaction error, we don't need to do anything
122            }
123        }
124        TridentTransactionProcessingResult::new(result, transaction_timestamp)
125    }
126}
127
128/// This function is also a mock. In the Agave validator, the bank pre-checks
129/// transactions before providing them to the SVM API. We mock this step in
130/// PayTube, since we don't need to perform such pre-checks.
131pub(crate) fn get_transaction_check_results(
132    len: usize,
133) -> Vec<solana_transaction_error::TransactionResult<CheckedTransactionDetails>> {
134    let compute_budget_limit = ComputeBudgetLimits::default();
135    vec![
136        solana_transaction_error::TransactionResult::Ok(CheckedTransactionDetails::new(
137            None,
138            Ok(compute_budget_limit.get_compute_budget_and_limits(
139                compute_budget_limit.loaded_accounts_bytes,
140                FeeDetails::default()
141            )),
142        ));
143        len
144    ]
145}