From 404fc1570d722709344876dc91799edd576056bf Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Sun, 29 Nov 2020 12:21:55 -0700 Subject: [PATCH] runtime: Replace `HashAgeKind` with `NonceRollbackInfo` --- core/src/banking_stage.rs | 30 +- core/src/transaction_status_service.rs | 11 +- ledger/src/blockstore_processor.rs | 12 +- runtime/src/accounts.rs | 208 +++++++------- runtime/src/bank.rs | 363 ++++++++++++------------- runtime/src/bank_utils.rs | 4 +- 6 files changed, 304 insertions(+), 324 deletions(-) diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index b584c63db7..e1338da9d1 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -23,7 +23,7 @@ use solana_perf::{ }; use solana_runtime::{ accounts_db::ErrorCounters, - bank::{Bank, TransactionBalancesSet, TransactionProcessResult}, + bank::{Bank, TransactionBalancesSet, TransactionCheckResult, TransactionExecutionResult}, bank_utils, transaction_batch::TransactionBatch, vote_sender_types::ReplayVoteSender, @@ -460,7 +460,7 @@ impl BankingStage { fn record_transactions( bank_slot: Slot, txs: &[Transaction], - results: &[TransactionProcessResult], + results: &[TransactionExecutionResult], poh: &Arc>, ) -> (Result, Vec) { let mut processed_generation = Measure::start("record::process_generation"); @@ -578,7 +578,7 @@ impl BankingStage { bank.clone(), batch.transactions(), batch.iteration_order_vec(), - tx_results.processing_results, + tx_results.execution_results, TransactionBalancesSet::new(pre_balances, post_balances), inner_instructions, transaction_logs, @@ -719,7 +719,7 @@ impl BankingStage { // This function returns a vector containing index of all valid transactions. A valid // transaction has result Ok() as the value fn filter_valid_transaction_indexes( - valid_txs: &[TransactionProcessResult], + valid_txs: &[TransactionCheckResult], transaction_indexes: &[usize], ) -> Vec { let valid_transactions = valid_txs @@ -1093,7 +1093,6 @@ mod tests { get_tmp_ledger_path, }; use solana_perf::packet::to_packets; - use solana_runtime::bank::HashAgeKind; use solana_sdk::{ instruction::InstructionError, signature::{Keypair, Signer}, @@ -1457,10 +1456,7 @@ mod tests { system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()), ]; - let mut results = vec![ - (Ok(()), Some(HashAgeKind::Extant)), - (Ok(()), Some(HashAgeKind::Extant)), - ]; + let mut results = vec![(Ok(()), None), (Ok(()), None)]; let _ = BankingStage::record_transactions( bank.slot(), &transactions, @@ -1476,7 +1472,7 @@ mod tests { 1, SystemError::ResultWithNegativeLamports.into(), )), - Some(HashAgeKind::Extant), + None, ); let (res, retryable) = BankingStage::record_transactions( bank.slot(), @@ -1652,10 +1648,10 @@ mod tests { &[ (Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None), - (Ok(()), Some(HashAgeKind::Extant)), + (Ok(()), None), (Err(TransactionError::BlockhashNotFound), None), - (Ok(()), Some(HashAgeKind::Extant)), - (Ok(()), Some(HashAgeKind::Extant)), + (Ok(()), None), + (Ok(()), None), ], &[2, 4, 5, 9, 11, 13] ), @@ -1665,12 +1661,12 @@ mod tests { assert_eq!( BankingStage::filter_valid_transaction_indexes( &[ - (Ok(()), Some(HashAgeKind::Extant)), + (Ok(()), None), (Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None), - (Ok(()), Some(HashAgeKind::Extant)), - (Ok(()), Some(HashAgeKind::Extant)), - (Ok(()), Some(HashAgeKind::Extant)), + (Ok(()), None), + (Ok(()), None), + (Ok(()), None), ], &[1, 6, 7, 9, 31, 43] ), diff --git a/core/src/transaction_status_service.rs b/core/src/transaction_status_service.rs index 1645f2db8e..3a71742daa 100644 --- a/core/src/transaction_status_service.rs +++ b/core/src/transaction_status_service.rs @@ -1,7 +1,10 @@ use crossbeam_channel::{Receiver, RecvTimeoutError}; use itertools::izip; use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch}; -use solana_runtime::{bank::Bank, transaction_utils::OrderedIterator}; +use solana_runtime::{ + bank::{Bank, NonceRollbackInfo}, + transaction_utils::OrderedIterator, +}; use solana_transaction_status::{InnerInstructions, TransactionStatusMeta}; use std::{ sync::{ @@ -58,7 +61,7 @@ impl TransactionStatusService { let slot = bank.slot(); for ( (_, transaction), - (status, hash_age_kind), + (status, nonce_rollback), pre_balances, post_balances, inner_instructions, @@ -72,8 +75,8 @@ impl TransactionStatusService { transaction_logs ) { if Bank::can_commit(&status) && !transaction.signatures.is_empty() { - let fee_calculator = hash_age_kind - .and_then(|hash_age_kind| hash_age_kind.fee_calculator()) + let fee_calculator = nonce_rollback + .map(|nonce_rollback| nonce_rollback.fee_calculator()) .unwrap_or_else(|| { bank.get_fee_calculator(&transaction.message().recent_blockhash) }) diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index 9f689ae630..e66af7a7c9 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -16,8 +16,8 @@ use solana_metrics::{datapoint_error, inc_new_counter_debug}; use solana_rayon_threadlimit::get_thread_count; use solana_runtime::{ bank::{ - Bank, InnerInstructionsList, TransactionBalancesSet, TransactionLogMessages, - TransactionProcessResult, TransactionResults, + Bank, InnerInstructionsList, TransactionBalancesSet, TransactionExecutionResult, + TransactionLogMessages, TransactionResults, }, bank_forks::BankForks, bank_utils, @@ -115,7 +115,7 @@ fn execute_batch( let TransactionResults { fee_collection_results, - processing_results, + execution_results, .. } = tx_results; @@ -124,7 +124,7 @@ fn execute_batch( bank.clone(), batch.transactions(), batch.iteration_order_vec(), - processing_results, + execution_results, balances, inner_instructions, transaction_logs, @@ -1029,7 +1029,7 @@ pub struct TransactionStatusBatch { pub bank: Arc, pub transactions: Vec, pub iteration_order: Option>, - pub statuses: Vec, + pub statuses: Vec, pub balances: TransactionBalancesSet, pub inner_instructions: Vec>, pub transaction_logs: Vec, @@ -1041,7 +1041,7 @@ pub fn send_transaction_status_batch( bank: Arc, transactions: &[Transaction], iteration_order: Option>, - statuses: Vec, + statuses: Vec, balances: TransactionBalancesSet, inner_instructions: Vec>, transaction_logs: Vec, diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 09c1cd03a6..371140886f 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -4,7 +4,9 @@ use crate::{ }, accounts_index::{AccountsIndex, Ancestors}, append_vec::StoredAccount, - bank::{HashAgeKind, TransactionProcessResult}, + bank::{ + NonceRollbackFull, NonceRollbackInfo, TransactionCheckResult, TransactionExecutionResult, + }, blockhash_queue::BlockhashQueue, rent_collector::RentCollector, system_instruction_processor::{get_system_account_kind, SystemAccountKind}, @@ -63,7 +65,10 @@ pub type TransactionAccounts = Vec; pub type TransactionRent = u64; pub type TransactionLoaders = Vec>; -pub type TransactionLoadResult = (TransactionAccounts, TransactionLoaders, TransactionRent); +pub type TransactionLoadResult = ( + Result<(TransactionAccounts, TransactionLoaders, TransactionRent)>, + Option, +); pub enum AccountAddressFilter { Exclude, // exclude all addresses matching the filter @@ -300,12 +305,12 @@ impl Accounts { ancestors: &Ancestors, txs: &[Transaction], txs_iteration_order: Option<&[usize]>, - lock_results: Vec, + lock_results: Vec, hash_queue: &BlockhashQueue, error_counters: &mut ErrorCounters, rent_collector: &RentCollector, feature_set: &FeatureSet, - ) -> Vec<(Result, Option)> { + ) -> Vec { let accounts_index = &self.accounts_db.accounts_index; let fee_config = FeeConfig { @@ -315,10 +320,10 @@ impl Accounts { OrderedIterator::new(txs, txs_iteration_order) .zip(lock_results.into_iter()) .map(|etx| match etx { - ((_, tx), (Ok(()), hash_age_kind)) => { - let fee_calculator = hash_age_kind + ((_, tx), (Ok(()), nonce_rollback)) => { + let fee_calculator = nonce_rollback .as_ref() - .and_then(|hash_age_kind| hash_age_kind.fee_calculator()) + .map(|nonce_rollback| nonce_rollback.fee_calculator()) .unwrap_or_else(|| { hash_queue .get_fee_calculator(&tx.message().recent_blockhash) @@ -327,7 +332,7 @@ impl Accounts { let fee = if let Some(fee_calculator) = fee_calculator { fee_calculator.calculate_fee_with_config(tx.message(), &fee_config) } else { - return (Err(TransactionError::BlockhashNotFound), hash_age_kind); + return (Err(TransactionError::BlockhashNotFound), None); }; let load_res = self.load_tx_accounts( @@ -342,7 +347,7 @@ impl Accounts { ); let (accounts, rents) = match load_res { Ok((a, r)) => (a, r), - Err(e) => return (Err(e), hash_age_kind), + Err(e) => return (Err(e), None), }; let load_res = Self::load_loaders( @@ -354,22 +359,26 @@ impl Accounts { ); let loaders = match load_res { Ok(loaders) => loaders, - Err(e) => return (Err(e), hash_age_kind), + Err(e) => return (Err(e), None), }; - // Update hash_age_kind with fee-subtracted accounts - let hash_age_kind = if let Some(hash_age_kind) = hash_age_kind { - match hash_age_kind.finish_partial(tx.message(), &accounts) { - Ok(hash_age_kind) => Some(hash_age_kind), - Err(e) => return (Err(e), Some(hash_age_kind)), + // Update nonce_rollback with fee-subtracted accounts + let nonce_rollback = if let Some(nonce_rollback) = nonce_rollback { + match NonceRollbackFull::from_partial( + nonce_rollback, + tx.message(), + &accounts, + ) { + Ok(nonce_rollback) => Some(nonce_rollback), + Err(e) => return (Err(e), None), } } else { None }; - (Ok((accounts, loaders, rents)), hash_age_kind) + (Ok((accounts, loaders, rents)), nonce_rollback) } - (_, (Err(e), hash_age_kind)) => (Err(e), hash_age_kind), + (_, (Err(e), _nonce_rollback)) => (Err(e), None), }) .collect() } @@ -754,8 +763,8 @@ impl Accounts { slot: Slot, txs: &[Transaction], txs_iteration_order: Option<&[usize]>, - res: &[TransactionProcessResult], - loaded: &mut [(Result, Option)], + res: &[TransactionExecutionResult], + loaded: &mut [TransactionLoadResult], rent_collector: &RentCollector, last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), fix_recent_blockhashes_sysvar_delay: bool, @@ -792,15 +801,15 @@ impl Accounts { &self, txs: &'a [Transaction], txs_iteration_order: Option<&'a [usize]>, - res: &'a [TransactionProcessResult], - loaded: &'a mut [(Result, Option)], + res: &'a [TransactionExecutionResult], + loaded: &'a mut [TransactionLoadResult], rent_collector: &RentCollector, last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), fix_recent_blockhashes_sysvar_delay: bool, rent_fix_enabled: bool, ) -> Vec<(&'a Pubkey, &'a Account)> { let mut accounts = Vec::with_capacity(loaded.len()); - for (i, ((raccs, _hash_age_kind), (_, tx))) in loaded + for (i, ((raccs, _nonce_rollback), (_, tx))) in loaded .iter_mut() .zip(OrderedIterator::new(txs, txs_iteration_order)) .enumerate() @@ -808,20 +817,22 @@ impl Accounts { if raccs.is_err() { continue; } - let (res, hash_age_kind) = &res[i]; - let maybe_nonce = match (res, hash_age_kind) { - (Ok(_), Some(HashAgeKind::DurableNonceFull(pubkey, acc, maybe_fee_account))) => { + let (res, nonce_rollback) = &res[i]; + let maybe_nonce_rollback = match (res, nonce_rollback) { + (Ok(_), Some(nonce_rollback)) => { + let pubkey = nonce_rollback.nonce_address(); + let acc = nonce_rollback.nonce_account(); + let maybe_fee_account = nonce_rollback.fee_account(); Some((pubkey, acc, maybe_fee_account)) } - ( - Err(TransactionError::InstructionError(_, _)), - Some(HashAgeKind::DurableNonceFull(pubkey, acc, maybe_fee_account)), - ) => Some((pubkey, acc, maybe_fee_account)), - (_, Some(HashAgeKind::DurableNoncePartial(_, _))) => { - panic!("collect: unexpected HashAgeKind variant") + (Err(TransactionError::InstructionError(_, _)), Some(nonce_rollback)) => { + let pubkey = nonce_rollback.nonce_address(); + let acc = nonce_rollback.nonce_account(); + let maybe_fee_account = nonce_rollback.fee_account(); + Some((pubkey, acc, maybe_fee_account)) } - (Ok(_), _hash_age_kind) => None, - (Err(_), _hash_age_kind) => continue, + (Ok(_), _nonce_rollback) => None, + (Err(_), _nonce_rollback) => continue, }; let message = &tx.message(); @@ -838,7 +849,7 @@ impl Accounts { account, key, res, - maybe_nonce, + maybe_nonce_rollback, last_blockhash_with_fee_calculator, fix_recent_blockhashes_sysvar_delay, ); @@ -848,10 +859,10 @@ impl Accounts { let is_fee_payer = Some(i) == fee_payer_index; if message.is_writable(i) && (res.is_ok() - || (maybe_nonce.is_some() && (is_nonce_account || is_fee_payer))) + || (maybe_nonce_rollback.is_some() && (is_nonce_account || is_fee_payer))) { if res.is_err() { - match (is_nonce_account, is_fee_payer, maybe_nonce) { + match (is_nonce_account, is_fee_payer, maybe_nonce_rollback) { // nonce is fee-payer, state updated in `prepare_if_nonce_account()` (true, true, Some((_, _, None))) => (), // nonce not fee-payer, state updated in `prepare_if_nonce_account()` @@ -882,11 +893,11 @@ pub fn prepare_if_nonce_account( account: &mut Account, account_pubkey: &Pubkey, tx_result: &Result<()>, - maybe_nonce: Option<(&Pubkey, &Account, &Option)>, + maybe_nonce_rollback: Option<(&Pubkey, &Account, Option<&Account>)>, last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), fix_recent_blockhashes_sysvar_delay: bool, ) -> bool { - if let Some((nonce_key, nonce_acc, _maybe_fee_account)) = maybe_nonce { + if let Some((nonce_key, nonce_acc, _maybe_fee_account)) = maybe_nonce_rollback { if account_pubkey == nonce_key { let overwrite = if tx_result.is_err() { // Nonce TX failed with an InstructionError. Roll back @@ -947,7 +958,7 @@ mod tests { // TODO: all the bank tests are bank specific, issue: 2194 use super::*; - use crate::{bank::HashAgeKind, rent_collector::RentCollector}; + use crate::rent_collector::RentCollector; use solana_sdk::{ account::Account, epoch_schedule::EpochSchedule, @@ -972,7 +983,7 @@ mod tests { fee_calculator: &FeeCalculator, rent_collector: &RentCollector, error_counters: &mut ErrorCounters, - ) -> Vec<(Result, Option)> { + ) -> Vec { let mut hash_queue = BlockhashQueue::new(100); hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator); let accounts = Accounts::new(Vec::new(), &ClusterType::Development); @@ -985,7 +996,7 @@ mod tests { &ancestors, &[tx], None, - vec![(Ok(()), Some(HashAgeKind::Extant))], + vec![(Ok(()), None)], &hash_queue, error_counters, rent_collector, @@ -998,7 +1009,7 @@ mod tests { ka: &[(Pubkey, Account)], fee_calculator: &FeeCalculator, error_counters: &mut ErrorCounters, - ) -> Vec<(Result, Option)> { + ) -> Vec { let rent_collector = RentCollector::default(); load_accounts_with_fee_and_rent(tx, ka, fee_calculator, &rent_collector, error_counters) } @@ -1007,7 +1018,7 @@ mod tests { tx: Transaction, ka: &[(Pubkey, Account)], error_counters: &mut ErrorCounters, - ) -> Vec<(Result, Option)> { + ) -> Vec { let fee_calculator = FeeCalculator::default(); load_accounts_with_fee(tx, ka, &fee_calculator, error_counters) } @@ -1032,10 +1043,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::AccountNotFound), - Some(HashAgeKind::Extant) - ) + (Err(TransactionError::AccountNotFound), None,) ); } @@ -1061,10 +1069,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::AccountNotFound), - Some(HashAgeKind::Extant) - ), + (Err(TransactionError::AccountNotFound), None,), ); } @@ -1098,10 +1103,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::ProgramAccountNotFound), - Some(HashAgeKind::Extant) - ) + (Err(TransactionError::ProgramAccountNotFound), None,) ); } @@ -1135,10 +1137,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0].clone(), - ( - Err(TransactionError::InsufficientFundsForFee), - Some(HashAgeKind::Extant) - ), + (Err(TransactionError::InsufficientFundsForFee), None,), ); } @@ -1168,10 +1167,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::InvalidAccountForFee), - Some(HashAgeKind::Extant) - ), + (Err(TransactionError::InvalidAccountForFee), None,), ); } @@ -1219,7 +1215,7 @@ mod tests { &mut error_counters, ); assert_eq!(loaded_accounts.len(), 1); - let (load_res, _hash_age_kind) = &loaded_accounts[0]; + let (load_res, _nonce_rollback) = &loaded_accounts[0]; let (tx_accounts, _loaders, _rents) = load_res.as_ref().unwrap(); assert_eq!(tx_accounts[0].lamports, min_balance); @@ -1233,7 +1229,7 @@ mod tests { &mut error_counters, ); assert_eq!(loaded_accounts.len(), 1); - let (load_res, _hash_age_kind) = &loaded_accounts[0]; + let (load_res, _nonce_rollback) = &loaded_accounts[0]; assert_eq!(*load_res, Err(TransactionError::InsufficientFundsForFee)); // Fee leaves non-zero, but sub-min_balance balance fails @@ -1246,7 +1242,7 @@ mod tests { &mut error_counters, ); assert_eq!(loaded_accounts.len(), 1); - let (load_res, _hash_age_kind) = &loaded_accounts[0]; + let (load_res, _nonce_rollback) = &loaded_accounts[0]; assert_eq!(*load_res, Err(TransactionError::InsufficientFundsForFee)); } @@ -1283,14 +1279,14 @@ mod tests { match &loaded_accounts[0] { ( Ok((transaction_accounts, transaction_loaders, _transaction_rents)), - _hash_age_kind, + _nonce_rollback, ) => { assert_eq!(transaction_accounts.len(), 3); assert_eq!(transaction_accounts[0], accounts[0].1); assert_eq!(transaction_loaders.len(), 1); assert_eq!(transaction_loaders[0].len(), 0); } - (Err(e), _hash_age_kind) => Err(e).unwrap(), + (Err(e), _nonce_rollback) => Err(e).unwrap(), } } @@ -1356,10 +1352,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::CallChainTooDeep), - Some(HashAgeKind::Extant) - ) + (Err(TransactionError::CallChainTooDeep), None,) ); } @@ -1394,10 +1387,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::InvalidProgramForExecution), - Some(HashAgeKind::Extant) - ) + (Err(TransactionError::InvalidProgramForExecution), None,) ); } @@ -1432,10 +1422,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::ProgramAccountNotFound), - Some(HashAgeKind::Extant) - ) + (Err(TransactionError::ProgramAccountNotFound), None,) ); } @@ -1469,10 +1456,7 @@ mod tests { assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], - ( - Err(TransactionError::InvalidProgramForExecution), - Some(HashAgeKind::Extant) - ) + (Err(TransactionError::InvalidProgramForExecution), None,) ); } @@ -1521,7 +1505,7 @@ mod tests { match &loaded_accounts[0] { ( Ok((transaction_accounts, transaction_loaders, _transaction_rents)), - _hash_age_kind, + _nonce_rollback, ) => { assert_eq!(transaction_accounts.len(), 3); assert_eq!(transaction_accounts[0], accounts[0].1); @@ -1535,7 +1519,7 @@ mod tests { } } } - (Err(e), _hash_age_kind) => Err(e).unwrap(), + (Err(e), _nonce_rollback) => Err(e).unwrap(), } } @@ -1807,10 +1791,7 @@ mod tests { let tx1 = Transaction::new(&[&keypair1], message, Hash::default()); let txs = vec![tx0, tx1]; - let loaders = vec![ - (Ok(()), Some(HashAgeKind::Extant)), - (Ok(()), Some(HashAgeKind::Extant)), - ]; + let loaders = vec![(Ok(()), None), (Ok(()), None)]; let account0 = Account::new(1, 0, &Pubkey::default()); let account1 = Account::new(2, 0, &Pubkey::default()); @@ -1825,7 +1806,7 @@ mod tests { transaction_loaders0, transaction_rent0, )), - Some(HashAgeKind::Extant), + None, ); let transaction_accounts1 = vec![account1, account2]; @@ -1837,7 +1818,7 @@ mod tests { transaction_loaders1, transaction_rent1, )), - Some(HashAgeKind::Extant), + None, ); let mut loaded = vec![loaded0, loaded1]; @@ -1913,10 +1894,7 @@ mod tests { accounts.accounts_db.clean_accounts(None); } - fn load_accounts_no_store( - accounts: &Accounts, - tx: Transaction, - ) -> Vec<(Result, Option)> { + fn load_accounts_no_store(accounts: &Accounts, tx: Transaction) -> Vec { let rent_collector = RentCollector::default(); let fee_calculator = FeeCalculator::new(10); let mut hash_queue = BlockhashQueue::new(100); @@ -1928,7 +1906,7 @@ mod tests { &ancestors, &[tx], None, - vec![(Ok(()), Some(HashAgeKind::Extant))], + vec![(Ok(()), None)], &hash_queue, &mut error_counters, &rent_collector, @@ -1989,12 +1967,12 @@ mod tests { account: &mut Account, account_pubkey: &Pubkey, tx_result: &Result<()>, - maybe_nonce: Option<(&Pubkey, &Account, &Option)>, + maybe_nonce_rollback: Option<(&Pubkey, &Account, Option<&Account>)>, last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), expect_account: &Account, ) -> bool { // Verify expect_account's relationship - match maybe_nonce { + match maybe_nonce_rollback { Some((nonce_pubkey, _nonce_account, _maybe_fee_account)) if nonce_pubkey == account_pubkey && tx_result.is_ok() => { @@ -2012,7 +1990,7 @@ mod tests { account, account_pubkey, tx_result, - maybe_nonce, + maybe_nonce_rollback, last_blockhash_with_fee_calculator, true, ); @@ -2041,7 +2019,11 @@ mod tests { &mut post_account, &post_account_pubkey, &Ok(()), - Some((&pre_account_pubkey, &pre_account, &maybe_fee_account)), + Some(( + &pre_account_pubkey, + &pre_account, + maybe_fee_account.as_ref() + )), &(last_blockhash, last_fee_calculator), &expect_account, )); @@ -2088,7 +2070,11 @@ mod tests { &mut post_account, &Pubkey::new(&[1u8; 32]), &Ok(()), - Some((&pre_account_pubkey, &pre_account, &maybe_fee_account)), + Some(( + &pre_account_pubkey, + &pre_account, + maybe_fee_account.as_ref() + )), &(last_blockhash, last_fee_calculator), &expect_account, )); @@ -2124,7 +2110,11 @@ mod tests { 0, InstructionError::InvalidArgument, )), - Some((&pre_account_pubkey, &pre_account, &maybe_fee_account)), + Some(( + &pre_account_pubkey, + &pre_account, + maybe_fee_account.as_ref() + )), &(last_blockhash, last_fee_calculator), &expect_account, )); @@ -2158,7 +2148,7 @@ mod tests { let nonce_account_pre = Account::new_data(42, &nonce_state, &system_program::id()).unwrap(); let from_account_pre = Account::new(4242, 0, &Pubkey::default()); - let hash_age_kind = Some(HashAgeKind::DurableNonceFull( + let nonce_rollback = Some(NonceRollbackFull::new( nonce_address, nonce_account_pre.clone(), Some(from_account_pre.clone()), @@ -2168,7 +2158,7 @@ mod tests { 1, InstructionError::InvalidArgument, )), - hash_age_kind.clone(), + nonce_rollback.clone(), )]; let nonce_state = @@ -2196,7 +2186,7 @@ mod tests { let transaction_rent = 0; let loaded = ( Ok((transaction_accounts, transaction_loaders, transaction_rent)), - hash_age_kind, + nonce_rollback, ); let mut loaded = vec![loaded]; @@ -2263,7 +2253,7 @@ mod tests { })); let nonce_account_pre = Account::new_data(42, &nonce_state, &system_program::id()).unwrap(); - let hash_age_kind = Some(HashAgeKind::DurableNonceFull( + let nonce_rollback = Some(NonceRollbackFull::new( nonce_address, nonce_account_pre.clone(), None, @@ -2273,7 +2263,7 @@ mod tests { 1, InstructionError::InvalidArgument, )), - hash_age_kind.clone(), + nonce_rollback.clone(), )]; let nonce_state = @@ -2301,7 +2291,7 @@ mod tests { let transaction_rent = 0; let loaded = ( Ok((transaction_accounts, transaction_loaders, transaction_rent)), - hash_age_kind, + nonce_rollback, ); let mut loaded = vec![loaded]; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index b83526d72b..ad2a0a4597 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -369,10 +369,11 @@ impl StatusCacheRc { } } -pub type TransactionProcessResult = (Result<()>, Option); +pub type TransactionCheckResult = (Result<()>, Option); +pub type TransactionExecutionResult = (Result<()>, Option); pub struct TransactionResults { pub fee_collection_results: Vec>, - pub processing_results: Vec, + pub execution_results: Vec, pub overwritten_vote_accounts: Vec, } pub struct TransactionBalancesSet { @@ -444,65 +445,113 @@ pub struct TransactionLogCollector { pub mentioned_address_map: HashMap>, } -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum HashAgeKind { - Extant, - DurableNoncePartial(Pubkey, Account), - DurableNonceFull(Pubkey, Account, Option), +pub trait NonceRollbackInfo { + fn nonce_address(&self) -> &Pubkey; + fn nonce_account(&self) -> &Account; + fn fee_calculator(&self) -> Option; + fn fee_account(&self) -> Option<&Account>; } -impl HashAgeKind { - pub fn is_durable_nonce(&self) -> bool { - match self { - Self::Extant => false, - Self::DurableNoncePartial(_, _) => true, - Self::DurableNonceFull(_, _, _) => true, +#[derive(Clone, Debug, Default, PartialEq)] +pub struct NonceRollbackPartial { + nonce_address: Pubkey, + nonce_account: Account, +} + +impl NonceRollbackPartial { + pub fn new(nonce_address: Pubkey, nonce_account: Account) -> Self { + Self { + nonce_address, + nonce_account, } } +} - pub fn fee_calculator(&self) -> Option> { - match self { - Self::Extant => None, - Self::DurableNoncePartial(_, account) => { - Some(nonce_account::fee_calculator_of(account)) - } - Self::DurableNonceFull(_, account, _) => { - Some(nonce_account::fee_calculator_of(account)) - } +impl NonceRollbackInfo for NonceRollbackPartial { + fn nonce_address(&self) -> &Pubkey { + &self.nonce_address + } + fn nonce_account(&self) -> &Account { + &self.nonce_account + } + fn fee_calculator(&self) -> Option { + nonce_account::fee_calculator_of(&self.nonce_account) + } + fn fee_account(&self) -> Option<&Account> { + None + } +} + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct NonceRollbackFull { + nonce_address: Pubkey, + nonce_account: Account, + fee_account: Option, +} + +impl NonceRollbackFull { + #[cfg(test)] + pub fn new( + nonce_address: Pubkey, + nonce_account: Account, + fee_account: Option, + ) -> Self { + Self { + nonce_address, + nonce_account, + fee_account, } } - - pub fn finish_partial(&self, message: &Message, accounts: &[Account]) -> Result { - match self { - HashAgeKind::Extant => Ok(HashAgeKind::Extant), - HashAgeKind::DurableNoncePartial(pubkey, account) => { - let fee_payer = message - .account_keys - .iter() - .enumerate() - .find(|(i, k)| Accounts::is_non_loader_key(message, k, *i)) - .and_then(|(i, k)| accounts.get(i).cloned().map(|a| (*k, a))); - if let Some((fee_pubkey, fee_account)) = fee_payer { - if fee_pubkey == *pubkey { - Ok(HashAgeKind::DurableNonceFull(*pubkey, fee_account, None)) - } else { - Ok(HashAgeKind::DurableNonceFull( - *pubkey, - account.clone(), - Some(fee_account), - )) - } - } else { - Err(TransactionError::AccountNotFound) - } - } - HashAgeKind::DurableNonceFull(_, _, _) => { - panic!("update: unexpected HashAgeKind variant") + pub fn from_partial( + partial: NonceRollbackPartial, + message: &Message, + accounts: &[Account], + ) -> Result { + let NonceRollbackPartial { + nonce_address, + nonce_account, + } = partial; + let fee_payer = message + .account_keys + .iter() + .enumerate() + .find(|(i, k)| Accounts::is_non_loader_key(message, k, *i)) + .and_then(|(i, k)| accounts.get(i).cloned().map(|a| (*k, a))); + if let Some((fee_pubkey, fee_account)) = fee_payer { + if fee_pubkey == nonce_address { + Ok(Self { + nonce_address, + nonce_account: fee_account, + fee_account: None, + }) + } else { + Ok(Self { + nonce_address, + nonce_account, + fee_account: Some(fee_account), + }) } + } else { + Err(TransactionError::AccountNotFound) } } } +impl NonceRollbackInfo for NonceRollbackFull { + fn nonce_address(&self) -> &Pubkey { + &self.nonce_address + } + fn nonce_account(&self) -> &Account { + &self.nonce_account + } + fn fee_calculator(&self) -> Option { + nonce_account::fee_calculator_of(&self.nonce_account) + } + fn fee_account(&self) -> Option<&Account> { + self.fee_account.as_ref() + } +} + // Bank's common fields shared by all supported snapshot versions for deserialization. // Sync fields with BankFieldsToSerialize! This is paired with it. // All members are made public to remain Bank's members private and to make versioned deserializer workable on this @@ -2117,11 +2166,11 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - res: &[TransactionProcessResult], + res: &[TransactionExecutionResult], ) { let mut status_cache = self.src.status_cache.write().unwrap(); for (i, (_, tx)) in OrderedIterator::new(txs, iteration_order).enumerate() { - let (res, _hash_age_kind) = &res[i]; + let (res, _nonce_rollback) = &res[i]; if Self::can_commit(res) && !tx.signatures.is_empty() { status_cache.insert( &tx.message().recent_blockhash, @@ -2255,9 +2304,9 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - results: Vec, + results: Vec, error_counters: &mut ErrorCounters, - ) -> Vec<(Result, Option)> { + ) -> Vec { self.rc.accounts.load_accounts( &self.ancestors, txs, @@ -2277,7 +2326,7 @@ impl Bank { lock_results: Vec>, max_age: usize, error_counters: &mut ErrorCounters, - ) -> Vec { + ) -> Vec { let hash_queue = self.blockhash_queue.read().unwrap(); OrderedIterator::new(txs, iteration_order) .zip(lock_results.into_iter()) @@ -2286,9 +2335,9 @@ impl Bank { let message = tx.message(); let hash_age = hash_queue.check_hash_age(&message.recent_blockhash, max_age); if hash_age == Some(true) { - (Ok(()), Some(HashAgeKind::Extant)) + (Ok(()), None) } else if let Some((pubkey, acc)) = self.check_tx_durable_nonce(&tx) { - (Ok(()), Some(HashAgeKind::DurableNoncePartial(pubkey, acc))) + (Ok(()), Some(NonceRollbackPartial::new(pubkey, acc))) } else if hash_age == Some(false) { error_counters.blockhash_too_old += 1; (Err(TransactionError::BlockhashNotFound), None) @@ -2306,9 +2355,9 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - lock_results: Vec, + lock_results: Vec, error_counters: &mut ErrorCounters, - ) -> Vec { + ) -> Vec { let rcache = self.src.status_cache.read().unwrap(); OrderedIterator::new(txs, iteration_order) .zip(lock_results.into_iter()) @@ -2317,7 +2366,7 @@ impl Bank { return lock_res; } { - let (lock_res, hash_age_kind) = &lock_res; + let (lock_res, _nonce_rollback) = &lock_res; if lock_res.is_ok() && rcache .get_signature_status( @@ -2328,10 +2377,7 @@ impl Bank { .is_some() { error_counters.duplicate_signature += 1; - return ( - Err(TransactionError::DuplicateSignature), - hash_age_kind.clone(), - ); + return (Err(TransactionError::DuplicateSignature), None); } } lock_res @@ -2343,9 +2389,9 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - lock_results: Vec, + lock_results: Vec, error_counters: &mut ErrorCounters, - ) -> Vec { + ) -> Vec { OrderedIterator::new(txs, iteration_order) .zip(lock_results.into_iter()) .map(|((_, tx), lock_res)| { @@ -2401,7 +2447,7 @@ impl Bank { lock_results: &[Result<()>], max_age: usize, mut error_counters: &mut ErrorCounters, - ) -> Vec { + ) -> Vec { let age_results = self.check_age( txs, iteration_order, @@ -2627,8 +2673,8 @@ impl Bank { enable_cpi_recording: bool, enable_log_recording: bool, ) -> ( - Vec<(Result, Option)>, - Vec, + Vec, + Vec, Vec>, Vec, Vec, @@ -2678,12 +2724,12 @@ impl Bank { .bpf_compute_budget .unwrap_or_else(|| BpfComputeBudget::new(&self.feature_set)); - let executed: Vec = loaded_accounts + let executed: Vec = loaded_accounts .iter_mut() .zip(OrderedIterator::new(txs, batch.iteration_order())) .map(|(accs, (_, tx))| match accs { - (Err(e), hash_age_kind) => (Err(e.clone()), hash_age_kind.clone()), - (Ok((accounts, loaders, _rents)), hash_age_kind) => { + (Err(e), _nonce_rollback) => (Err(e.clone()), None), + (Ok((accounts, loaders, _rents)), nonce_rollback) => { signature_count += u64::from(tx.message().header.num_required_signatures); let executors = self.get_executors(&tx.message, &loaders); @@ -2742,10 +2788,16 @@ impl Bank { self.update_executors(executors); - if let Err(TransactionError::InstructionError(_, _)) = &process_result { - error_counters.instruction_error += 1; - } - (process_result, hash_age_kind.clone()) + let nonce_rollback = + if let Err(TransactionError::InstructionError(_, _)) = &process_result { + error_counters.instruction_error += 1; + nonce_rollback.clone() + } else if process_result.is_err() { + None + } else { + nonce_rollback.clone() + }; + (process_result, nonce_rollback) } }) .collect(); @@ -2764,7 +2816,7 @@ impl Bank { let transaction_log_collector_config = self.transaction_log_collector_config.read().unwrap(); - for (i, ((r, _hash_age_kind), tx)) in executed.iter().zip(txs.iter()).enumerate() { + for (i, ((r, _nonce_rollback), tx)) in executed.iter().zip(txs.iter()).enumerate() { if let Some(debug_keys) = &self.transaction_debug_keys { for key in &tx.message.account_keys { if debug_keys.contains(key) { @@ -2849,7 +2901,7 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - executed: &[TransactionProcessResult], + executed: &[TransactionExecutionResult], ) -> Vec> { let hash_queue = self.blockhash_queue.read().unwrap(); let mut fees = 0; @@ -2860,10 +2912,10 @@ impl Bank { let results = OrderedIterator::new(txs, iteration_order) .zip(executed.iter()) - .map(|((_, tx), (res, hash_age_kind))| { - let (fee_calculator, is_durable_nonce) = hash_age_kind + .map(|((_, tx), (res, nonce_rollback))| { + let (fee_calculator, is_durable_nonce) = nonce_rollback .as_ref() - .and_then(|hash_age_kind| hash_age_kind.fee_calculator()) + .map(|nonce_rollback| nonce_rollback.fee_calculator()) .map(|maybe_fee_calculator| (maybe_fee_calculator, true)) .unwrap_or_else(|| { ( @@ -2909,8 +2961,8 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - loaded_accounts: &mut [(Result, Option)], - executed: &[TransactionProcessResult], + loaded_accounts: &mut [TransactionLoadResult], + executed: &[TransactionExecutionResult], tx_count: u64, signature_count: u64, ) -> TransactionResults { @@ -2927,7 +2979,7 @@ impl Bank { if executed .iter() - .any(|(res, _hash_age_kind)| Self::can_commit(res)) + .any(|(res, _nonce_rollback)| Self::can_commit(res)) { self.is_delta.store(true, Relaxed); } @@ -2958,7 +3010,7 @@ impl Bank { TransactionResults { fee_collection_results, - processing_results: executed.to_vec(), + execution_results: executed.to_vec(), overwritten_vote_accounts, } } @@ -3107,12 +3159,12 @@ impl Bank { fn collect_rent( &self, - res: &[TransactionProcessResult], - loaded_accounts: &[(Result, Option)], + res: &[TransactionExecutionResult], + loaded_accounts: &[TransactionLoadResult], ) { let mut collected_rent: u64 = 0; - for (i, (raccs, _hash_age_kind)) in loaded_accounts.iter().enumerate() { - let (res, _hash_age_kind) = &res[i]; + for (i, (raccs, _nonce_rollback)) in loaded_accounts.iter().enumerate() { + let (res, _nonce_rollback) = &res[i]; if res.is_err() || raccs.is_err() { continue; } @@ -4079,16 +4131,16 @@ impl Bank { &self, txs: &[Transaction], iteration_order: Option<&[usize]>, - res: &[TransactionProcessResult], - loaded: &[(Result, Option)], + res: &[TransactionExecutionResult], + loaded: &[TransactionLoadResult], ) -> Vec { let mut overwritten_vote_accounts = vec![]; - for (i, ((raccs, _load_hash_age_kind), (transaction_index, tx))) in loaded + for (i, ((raccs, _load_nonce_rollback), (transaction_index, tx))) in loaded .iter() .zip(OrderedIterator::new(txs, iteration_order)) .enumerate() { - let (res, _res_hash_age_kind) = &res[i]; + let (res, _res_nonce_rollback) = &res[i]; if res.is_err() || raccs.is_err() { continue; } @@ -4596,73 +4648,25 @@ pub(crate) mod tests { use std::{result, thread::Builder, time::Duration}; #[test] - fn test_hash_age_kind_is_durable_nonce() { - assert!( - HashAgeKind::DurableNoncePartial(Pubkey::default(), Account::default()) - .is_durable_nonce() - ); - assert!( - HashAgeKind::DurableNonceFull(Pubkey::default(), Account::default(), None) - .is_durable_nonce() - ); - assert!(HashAgeKind::DurableNonceFull( - Pubkey::default(), - Account::default(), - Some(Account::default()) - ) - .is_durable_nonce()); - assert!(!HashAgeKind::Extant.is_durable_nonce()); - } - - #[test] - fn test_hash_age_kind_fee_calculator() { + fn test_nonce_rollback_info() { + let nonce_authority = keypair_from_seed(&[0; 32]).unwrap(); + let nonce_address = nonce_authority.pubkey(); + let fee_calculator = FeeCalculator::new(42); let state = nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { authority: Pubkey::default(), blockhash: Hash::new_unique(), - fee_calculator: FeeCalculator::default(), + fee_calculator: fee_calculator.clone(), })); - let account = Account::new_data(42, &state, &system_program::id()).unwrap(); + let nonce_account = Account::new_data(43, &state, &system_program::id()).unwrap(); - assert_eq!(HashAgeKind::Extant.fee_calculator(), None); - assert_eq!( - HashAgeKind::DurableNoncePartial(Pubkey::default(), account.clone()).fee_calculator(), - Some(Some(FeeCalculator::default())) - ); - assert_eq!( - HashAgeKind::DurableNoncePartial(Pubkey::default(), Account::default()) - .fee_calculator(), - Some(None) - ); - assert_eq!( - HashAgeKind::DurableNonceFull(Pubkey::default(), account, Some(Account::default())) - .fee_calculator(), - Some(Some(FeeCalculator::default())) - ); - assert_eq!( - HashAgeKind::DurableNonceFull( - Pubkey::default(), - Account::default(), - Some(Account::default()) - ) - .fee_calculator(), - Some(None) - ); - } + // NonceRollbackPartial create + NonceRollbackInfo impl + let partial = NonceRollbackPartial::new(nonce_address, nonce_account.clone()); + assert_eq!(*partial.nonce_address(), nonce_address); + assert_eq!(*partial.nonce_account(), nonce_account); + assert_eq!(partial.fee_calculator(), Some(fee_calculator.clone())); + assert_eq!(partial.fee_account(), None); - #[test] - #[should_panic(expected = "update: unexpected HashAgeKind variant")] - fn test_hash_age_kind_finish_partial_full_panics() { - drop( - HashAgeKind::DurableNonceFull(Pubkey::default(), Account::default(), None) - .finish_partial(&Message::default(), &[]), - ); - } - - #[test] - fn test_hash_age_kind_finish_partial() { - let nonce_authority = keypair_from_seed(&[0; 32]).unwrap(); - let nonce_address = nonce_authority.pubkey(); let from = keypair_from_seed(&[1; 32]).unwrap(); let from_address = from.pubkey(); let to_address = Pubkey::new_unique(); @@ -4672,9 +4676,8 @@ pub(crate) mod tests { ]; let message = Message::new(&instructions, Some(&from_address)); - let from_account = Account::new(1, 0, &Pubkey::default()); - let nonce_account = Account::new(2, 0, &Pubkey::default()); - let to_account = Account::new(3, 0, &Pubkey::default()); + let from_account = Account::new(44, 0, &Pubkey::default()); + let to_account = Account::new(45, 0, &Pubkey::default()); let recent_blockhashes_sysvar_account = Account::new(4, 0, &Pubkey::default()); let accounts = [ from_account.clone(), @@ -4683,41 +4686,29 @@ pub(crate) mod tests { recent_blockhashes_sysvar_account.clone(), ]; - assert_eq!( - HashAgeKind::Extant.finish_partial(&message, &accounts), - Ok(HashAgeKind::Extant) - ); - - let hash_age_kind = HashAgeKind::DurableNoncePartial(nonce_address, nonce_account.clone()); - assert_eq!( - hash_age_kind.finish_partial(&message, &accounts), - Ok(HashAgeKind::DurableNonceFull( - nonce_address, - nonce_account.clone(), - Some(from_account.clone()) - )), - ); - - assert_eq!( - hash_age_kind.finish_partial(&message, &[]), - Err(TransactionError::AccountNotFound), - ); + // NonceRollbackFull create + NonceRollbackInfo impl + let full = NonceRollbackFull::from_partial(partial.clone(), &message, &accounts).unwrap(); + assert_eq!(*full.nonce_address(), nonce_address); + assert_eq!(*full.nonce_account(), nonce_account); + assert_eq!(full.fee_calculator(), Some(fee_calculator)); + assert_eq!(full.fee_account(), Some(&from_account)); let message = Message::new(&instructions, Some(&nonce_address)); let accounts = [ - nonce_account.clone(), + nonce_account, from_account, to_account, recent_blockhashes_sysvar_account, ]; + // Nonce account is fee-payer + let full = NonceRollbackFull::from_partial(partial.clone(), &message, &accounts).unwrap(); + assert_eq!(full.fee_account(), None); + + // NonceRollbackFull create, fee-payer not in account_keys fails assert_eq!( - hash_age_kind.finish_partial(&message, &accounts), - Ok(HashAgeKind::DurableNonceFull( - nonce_address, - nonce_account, - None - )), + NonceRollbackFull::from_partial(partial, &message, &[]).unwrap_err(), + TransactionError::AccountNotFound, ); } @@ -7117,13 +7108,13 @@ pub(crate) mod tests { system_transaction::transfer(&mint_keypair, &key.pubkey(), 5, genesis_config.hash()); let results = vec![ - (Ok(()), Some(HashAgeKind::Extant)), + (Ok(()), None), ( Err(TransactionError::InstructionError( 1, SystemError::ResultWithNegativeLamports.into(), )), - Some(HashAgeKind::Extant), + None, ), ]; let initial_balance = bank.get_balance(&leader); @@ -9112,19 +9103,19 @@ pub(crate) mod tests { assert_eq!(transaction_balances_set.pre_balances.len(), 3); assert_eq!(transaction_balances_set.post_balances.len(), 3); - assert!(transaction_results.processing_results[0].0.is_ok()); + assert!(transaction_results.execution_results[0].0.is_ok()); assert_eq!(transaction_balances_set.pre_balances[0], vec![8, 11, 1]); assert_eq!(transaction_balances_set.post_balances[0], vec![5, 13, 1]); // Failed transactions still produce balance sets // This is a TransactionError - not possible to charge fees - assert!(transaction_results.processing_results[1].0.is_err()); + assert!(transaction_results.execution_results[1].0.is_err()); assert_eq!(transaction_balances_set.pre_balances[1], vec![0, 0, 1]); assert_eq!(transaction_balances_set.post_balances[1], vec![0, 0, 1]); // Failed transactions still produce balance sets // This is an InstructionError - fees charged - assert!(transaction_results.processing_results[2].0.is_err()); + assert!(transaction_results.execution_results[2].0.is_err()); assert_eq!(transaction_balances_set.pre_balances[2], vec![9, 0, 1]); assert_eq!(transaction_balances_set.post_balances[2], vec![8, 0, 1]); } diff --git a/runtime/src/bank_utils.rs b/runtime/src/bank_utils.rs index e6009471ae..6530269043 100644 --- a/runtime/src/bank_utils.rs +++ b/runtime/src/bank_utils.rs @@ -32,13 +32,13 @@ pub fn find_and_send_votes( vote_sender: Option<&ReplayVoteSender>, ) { let TransactionResults { - processing_results, + execution_results, overwritten_vote_accounts, .. } = tx_results; if let Some(vote_sender) = vote_sender { for old_account in overwritten_vote_accounts { - assert!(processing_results[old_account.transaction_result_index] + assert!(execution_results[old_account.transaction_result_index] .0 .is_ok()); let transaction = &txs[old_account.transaction_index];