diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index 1f6670c9a37c4d..6976746115dd8e 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -533,23 +533,21 @@ impl BankingStage { let num_to_commit = num_to_commit.unwrap(); if num_to_commit != 0 { - let transaction_statuses = bank - .commit_transactions( - txs, - None, - &mut loaded_accounts, - &results, - tx_count, - signature_count, - ) - .processing_results; + let results = bank.commit_transactions( + txs, + None, + &mut loaded_accounts, + &results, + tx_count, + signature_count, + ); if let Some(sender) = transaction_status_sender { let post_balances = bank.collect_balances(txs); send_transaction_status_batch( - bank.clone(), + bank.slot(), batch.transactions(), - transaction_statuses, + results, TransactionBalancesSet::new(pre_balances, post_balances), sender, ); diff --git a/core/src/transaction_status_service.rs b/core/src/transaction_status_service.rs index 92ea1de13578d1..8db1a7dc0e306e 100644 --- a/core/src/transaction_status_service.rs +++ b/core/src/transaction_status_service.rs @@ -1,9 +1,6 @@ use crossbeam_channel::{Receiver, RecvTimeoutError}; use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch}; -use solana_runtime::{ - bank::{Bank, HashAgeKind}, - nonce_utils, -}; +use solana_runtime::bank::Bank; use solana_transaction_status::TransactionStatusMeta; use std::{ sync::{ @@ -48,27 +45,24 @@ impl TransactionStatusService { blockstore: &Arc, ) -> Result<(), RecvTimeoutError> { let TransactionStatusBatch { - bank, + slot, transactions, - statuses, + results, balances, } = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?; - let slot = bank.slot(); - for (((transaction, (status, hash_age_kind)), pre_balances), post_balances) in transactions + for ( + (((transaction, fee_result), (status, _hash_age_kind)), pre_balances), + post_balances, + ) in transactions .iter() - .zip(statuses) + .zip(results.fee_collection_results) + .zip(results.processing_results) .zip(balances.pre_balances) .zip(balances.post_balances) { if Bank::can_commit(&status) && !transaction.signatures.is_empty() { - let fee_calculator = match hash_age_kind { - Some(HashAgeKind::DurableNonce(_, account)) => { - nonce_utils::fee_calculator_of(&account) - } - _ => bank.get_fee_calculator(&transaction.message().recent_blockhash), - } - .expect("FeeCalculator must exist"); + let fee_calculator = fee_result.expect("FeeCalculator must exist"); let fee = fee_calculator.calculate_fee(transaction.message()); let (writable_keys, readonly_keys) = transaction.message.get_account_keys_by_lock_type(); diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index 8ea7634776b978..22eb0350eb9267 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -15,7 +15,7 @@ use solana_measure::{measure::Measure, thread_mem_usage}; use solana_metrics::{datapoint_error, inc_new_counter_debug}; use solana_rayon_threadlimit::get_thread_count; use solana_runtime::{ - bank::{Bank, TransactionBalancesSet, TransactionProcessResult, TransactionResults}, + bank::{Bank, TransactionBalancesSet, TransactionResults}, bank_forks::BankForks, transaction_batch::TransactionBatch, }; @@ -62,33 +62,22 @@ fn execute_batch( bank: &Arc, transaction_status_sender: Option, ) -> Result<()> { - let ( - TransactionResults { - fee_collection_results, - processing_results, - }, - balances, - ) = batch.bank().load_execute_and_commit_transactions( + let (results, balances) = batch.bank().load_execute_and_commit_transactions( batch, MAX_PROCESSING_AGE, transaction_status_sender.is_some(), ); + let fee_collection_results = results.fee_collection_results.clone(); if let Some(sender) = transaction_status_sender { - send_transaction_status_batch( - bank.clone(), - batch.transactions(), - processing_results, - balances, - sender, - ); + send_transaction_status_batch(bank.slot(), batch.transactions(), results, balances, sender); } let mut first_err = None; for (result, transaction) in fee_collection_results.iter().zip(batch.transactions()) { if let Err(ref err) = result { if first_err.is_none() { - first_err = Some(result.clone()); + first_err = Some(Err(err.clone())); } warn!( "Unexpected validator error: {:?}, transaction: {:?}", @@ -809,25 +798,24 @@ fn process_single_slot( } pub struct TransactionStatusBatch { - pub bank: Arc, + pub slot: Slot, pub transactions: Vec, - pub statuses: Vec, + pub results: TransactionResults, pub balances: TransactionBalancesSet, } pub type TransactionStatusSender = Sender; pub fn send_transaction_status_batch( - bank: Arc, + slot: Slot, transactions: &[Transaction], - statuses: Vec, + results: TransactionResults, balances: TransactionBalancesSet, transaction_status_sender: TransactionStatusSender, ) { - let slot = bank.slot(); if let Err(e) = transaction_status_sender.send(TransactionStatusBatch { - bank, + slot, transactions: transactions.to_vec(), - statuses, + results, balances, }) { trace!( diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 062edfd9f57ef2..c2c9b0e7e037aa 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -170,7 +170,7 @@ pub type EnteredEpochCallback = Box; pub type TransactionProcessResult = (Result<()>, Option); pub struct TransactionResults { - pub fee_collection_results: Vec>, + pub fee_collection_results: Vec>, pub processing_results: Vec, } pub struct TransactionBalancesSet { @@ -1494,7 +1494,7 @@ impl Bank { txs: &[Transaction], iteration_order: Option<&[usize]>, executed: &[TransactionProcessResult], - ) -> Vec> { + ) -> Vec> { let hash_queue = self.blockhash_queue.read().unwrap(); let mut fees = 0; let results = OrderedIterator::new(txs, iteration_order) @@ -1517,24 +1517,27 @@ impl Bank { let message = tx.message(); match *res { - Err(TransactionError::InstructionError(_, _)) => { - // credit the transaction fee even in case of InstructionError - // necessary to withdraw from account[0] here because previous - // work of doing so (in accounts.load()) is ignored by store_account() - // - // ...except nonce accounts, which will have their post-load, - // pre-execute account state stored - if !is_durable_nonce { - self.withdraw(&message.account_keys[0], fee)?; + Err(ref err) => { + if let TransactionError::InstructionError(_, _) = err { + // credit the transaction fee even in case of InstructionError + // necessary to withdraw from account[0] here because previous + // work of doing so (in accounts.load()) is ignored by store_account() + // + // ...except nonce accounts, which will have their post-load, + // pre-execute account state stored + if !is_durable_nonce { + self.withdraw(&message.account_keys[0], fee)?; + } + fees += fee; + Ok(fee_calculator) + } else { + Err(err.clone()) } - fees += fee; - Ok(()) } Ok(()) => { fees += fee; - Ok(()) + Ok(fee_calculator) } - _ => res.clone(), } }) .collect(); @@ -2121,6 +2124,9 @@ impl Bank { self.load_execute_and_commit_transactions(&batch, MAX_PROCESSING_AGE, false) .0 .fee_collection_results + .into_iter() + .map(|res| res.map(|_| ())) + .collect() } /// Create, sign, and process a Transaction from `keypair` to `to` of @@ -4919,8 +4925,8 @@ mod tests { .burn(bank.fee_calculator.lamports_per_signature * 2) .0 ); - assert_eq!(results[0], Ok(())); - assert_eq!(results[1], Ok(())); + assert_eq!(results[0], Ok(bank.fee_calculator.clone())); + assert_eq!(results[1], Ok(bank.fee_calculator.clone())); } #[test] @@ -5030,6 +5036,7 @@ mod tests { let bank = Bank::new(&genesis_config); let alice = Keypair::new(); let bob = Keypair::new(); + let fee_calculator = bank.fee_calculator.clone(); let tx1 = system_transaction::transfer(&mint_keypair, &alice.pubkey(), 1, genesis_config.hash()); @@ -5040,7 +5047,7 @@ mod tests { .load_execute_and_commit_transactions(&lock_result, MAX_PROCESSING_AGE, false) .0 .fee_collection_results; - assert_eq!(results_alice[0], Ok(())); + assert_eq!(results_alice[0], Ok(fee_calculator)); // try executing an interleaved transfer twice assert_eq!(