use { super::leader_slot_timing_metrics::LeaderExecuteAndCommitTimings, itertools::Itertools, solana_accounts_db::{ accounts::TransactionLoadResult, transaction_results::{TransactionExecutionResult, TransactionResults}, }, solana_ledger::{ blockstore_processor::TransactionStatusSender, token_balances::collect_token_balances, }, solana_measure::measure_us, solana_runtime::{ bank::{Bank, CommitTransactionCounts, TransactionBalancesSet}, bank_utils, prioritization_fee_cache::PrioritizationFeeCache, transaction_batch::TransactionBatch, vote_sender_types::ReplayVoteSender, }, solana_sdk::{pubkey::Pubkey, saturating_add_assign}, solana_transaction_status::{ token_balances::TransactionTokenBalancesSet, TransactionTokenBalance, }, std::{collections::HashMap, sync::Arc}, }; #[derive(Clone, Debug, PartialEq, Eq)] pub enum CommitTransactionDetails { Committed { compute_units: u64 }, NotCommitted, } #[derive(Default)] pub(super) struct PreBalanceInfo { pub native: Vec>, pub token: Vec>, pub mint_decimals: HashMap, } pub struct Committer { transaction_status_sender: Option, replay_vote_sender: ReplayVoteSender, prioritization_fee_cache: Arc, } impl Committer { pub fn new( transaction_status_sender: Option, replay_vote_sender: ReplayVoteSender, prioritization_fee_cache: Arc, ) -> Self { Self { transaction_status_sender, replay_vote_sender, prioritization_fee_cache, } } pub(super) fn transaction_status_sender_enabled(&self) -> bool { self.transaction_status_sender.is_some() } #[allow(clippy::too_many_arguments)] pub(super) fn commit_transactions( &self, batch: &TransactionBatch, loaded_transactions: &mut [TransactionLoadResult], execution_results: Vec, starting_transaction_index: Option, bank: &Arc, pre_balance_info: &mut PreBalanceInfo, execute_and_commit_timings: &mut LeaderExecuteAndCommitTimings, signature_count: u64, executed_transactions_count: usize, executed_non_vote_transactions_count: usize, executed_with_successful_result_count: usize, ) -> (u64, Vec) { let (last_blockhash, lamports_per_signature) = bank.last_blockhash_and_lamports_per_signature(); let executed_transactions = execution_results .iter() .zip(batch.sanitized_transactions()) .filter_map(|(execution_result, tx)| execution_result.was_executed().then_some(tx)) .collect_vec(); let (tx_results, commit_time_us) = measure_us!(bank.commit_transactions( batch.sanitized_transactions(), loaded_transactions, execution_results, last_blockhash, lamports_per_signature, CommitTransactionCounts { committed_transactions_count: executed_transactions_count as u64, committed_non_vote_transactions_count: executed_non_vote_transactions_count as u64, committed_with_failure_result_count: executed_transactions_count .saturating_sub(executed_with_successful_result_count) as u64, signature_count, }, &mut execute_and_commit_timings.execute_timings, )); execute_and_commit_timings.commit_us = commit_time_us; let commit_transaction_statuses = tx_results .execution_results .iter() .map(|execution_result| match execution_result.details() { Some(details) => CommitTransactionDetails::Committed { compute_units: details.executed_units, }, None => CommitTransactionDetails::NotCommitted, }) .collect(); let ((), find_and_send_votes_us) = measure_us!({ bank_utils::find_and_send_votes( batch.sanitized_transactions(), &tx_results, Some(&self.replay_vote_sender), ); self.collect_balances_and_send_status_batch( tx_results, bank, batch, pre_balance_info, starting_transaction_index, ); self.prioritization_fee_cache .update(bank, executed_transactions.into_iter()); }); execute_and_commit_timings.find_and_send_votes_us = find_and_send_votes_us; (commit_time_us, commit_transaction_statuses) } fn collect_balances_and_send_status_batch( &self, tx_results: TransactionResults, bank: &Arc, batch: &TransactionBatch, pre_balance_info: &mut PreBalanceInfo, starting_transaction_index: Option, ) { if let Some(transaction_status_sender) = &self.transaction_status_sender { let txs = batch.sanitized_transactions().to_vec(); let post_balances = bank.collect_balances(batch); let post_token_balances = collect_token_balances(bank, batch, &mut pre_balance_info.mint_decimals); let mut transaction_index = starting_transaction_index.unwrap_or_default(); let batch_transaction_indexes: Vec<_> = tx_results .execution_results .iter() .map(|result| { if result.was_executed() { let this_transaction_index = transaction_index; saturating_add_assign!(transaction_index, 1); this_transaction_index } else { 0 } }) .collect(); transaction_status_sender.send_transaction_status_batch( bank.clone(), txs, tx_results.execution_results, TransactionBalancesSet::new( std::mem::take(&mut pre_balance_info.native), post_balances, ), TransactionTokenBalancesSet::new( std::mem::take(&mut pre_balance_info.token), post_token_balances, ), tx_results.rent_debits, batch_transaction_indexes, ); } } }