From 3f63ed9a72b90e19c14eaee983729204af25e226 Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Wed, 31 Mar 2021 23:59:19 +0000 Subject: [PATCH] removes OrderedIterator and transaction batch iteration order (#16153) In TransactionBatch, https://github.com/solana-labs/solana/blob/e50f59844/runtime/src/transaction_batch.rs#L4-L11 lock_results[i] is aligned with transactions[iteration_order[i]]: https://github.com/solana-labs/solana/blob/e50f59844/runtime/src/bank.rs#L2414-L2424 https://github.com/solana-labs/solana/blob/e50f59844/runtime/src/accounts.rs#L788-L817 However load_and_execute_transactions is iterating over lock_results[iteration_order[i]] https://github.com/solana-labs/solana/blob/e50f59844/runtime/src/bank.rs#L2878-L2889 and then returning i as for the index of the retryable transaction. If iteratorion_order is [1, 2, 0], and i is 0, then: lock_results[iteration_order[i]] = lock_results[1] which corresponds to transactions[iteration_order[1]] = transactions[2] so neither i = 0, nor iteration_order[i] = 1 gives the correct index for the corresponding transaction (which is 2). This commit removes OrderedIterator and transaction batch iteration order entirely. There is only one place in blockstore processor which the iteration order is not ordinal: https://github.com/solana-labs/solana/blob/e50f59844/ledger/src/blockstore_processor.rs#L269-L271 It seems like, instead of using an iteration order, that can shuffle entry transactions in-place. --- core/benches/banking_stage.rs | 2 +- core/src/banking_stage.rs | 5 +- core/src/replay_stage.rs | 4 +- core/src/transaction_status_service.rs | 10 +- ledger/src/blockstore_processor.rs | 109 +++++++------- program-test/src/lib.rs | 11 +- programs/bpf/tests/programs.rs | 4 +- runtime/benches/transaction_utils.rs | 18 --- runtime/src/accounts.rs | 64 +++------ runtime/src/bank.rs | 176 ++++++++--------------- runtime/src/lib.rs | 1 - runtime/src/transaction_batch.rs | 22 +-- runtime/src/transaction_utils.rs | 81 ----------- transaction-status/src/token_balances.rs | 6 +- 14 files changed, 161 insertions(+), 352 deletions(-) delete mode 100644 runtime/benches/transaction_utils.rs delete mode 100644 runtime/src/transaction_utils.rs diff --git a/core/benches/banking_stage.rs b/core/benches/banking_stage.rs index 84a3b32ee..f4f122e97 100644 --- a/core/benches/banking_stage.rs +++ b/core/benches/banking_stage.rs @@ -302,7 +302,7 @@ fn simulate_process_entries( hash: next_hash(&bank.last_blockhash(), 1, &tx_vector), transactions: tx_vector, }; - process_entries(&bank, &[entry], randomize_txs, None, None).unwrap(); + process_entries(&bank, &mut [entry], randomize_txs, None, None).unwrap(); } #[allow(clippy::same_item_push)] diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index 6fde4ed2a..5a7ad8b06 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -754,7 +754,6 @@ impl BankingStage { if num_to_commit != 0 { let tx_results = bank.commit_transactions( txs, - None, &mut loaded_accounts, &results, tx_count, @@ -769,7 +768,6 @@ impl BankingStage { transaction_status_sender.send_transaction_status_batch( bank.clone(), batch.transactions(), - batch.iteration_order_vec(), tx_results.execution_results, TransactionBalancesSet::new(pre_balances, post_balances), TransactionTokenBalancesSet::new(pre_token_balances, post_token_balances), @@ -810,7 +808,7 @@ impl BankingStage { let mut lock_time = Measure::start("lock_time"); // Once accounts are locked, other threads cannot encode transactions that will modify the // same account state - let batch = bank.prepare_batch(txs, None); + let batch = bank.prepare_batch(txs); lock_time.stop(); let (result, mut retryable_txs) = Self::process_and_record_transactions_locked( @@ -1003,7 +1001,6 @@ impl BankingStage { }; let result = bank.check_transactions( transactions, - None, &filter, (MAX_PROCESSING_AGE) .saturating_sub(max_tx_fwd_delay) diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 80bee083e..283ac0ce7 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -3103,7 +3103,7 @@ pub(crate) mod tests { let fail_tx = system_transaction::transfer(&mint_keypair, &keypair2.pubkey(), 2, Hash::default()); let entry_3 = next_entry(&entry_2.hash, 1, vec![fail_tx]); - let entries = vec![entry_1, entry_2, entry_3]; + let mut entries = vec![entry_1, entry_2, entry_3]; let shreds = entries_to_test_shreds(entries.clone(), slot, previous_slot, true, 0); blockstore.insert_shreds(shreds, None, false).unwrap(); @@ -3122,7 +3122,7 @@ pub(crate) mod tests { // that they are matched properly by get_rooted_block let _result = blockstore_processor::process_entries( &bank, - &entries, + &mut entries, true, Some(TransactionStatusSender { sender: transaction_status_sender, diff --git a/core/src/transaction_status_service.rs b/core/src/transaction_status_service.rs index babf80350..2cf3cbb53 100644 --- a/core/src/transaction_status_service.rs +++ b/core/src/transaction_status_service.rs @@ -4,9 +4,8 @@ use solana_ledger::{ blockstore::Blockstore, blockstore_processor::{TransactionStatusBatch, TransactionStatusMessage}, }; -use solana_runtime::{ - bank::{Bank, InnerInstructionsList, NonceRollbackInfo, TransactionLogMessages}, - transaction_utils::OrderedIterator, +use solana_runtime::bank::{ + Bank, InnerInstructionsList, NonceRollbackInfo, TransactionLogMessages, }; use solana_transaction_status::{InnerInstructions, TransactionStatusMeta}; use std::{ @@ -58,7 +57,6 @@ impl TransactionStatusService { TransactionStatusMessage::Batch(TransactionStatusBatch { bank, transactions, - iteration_order, statuses, balances, token_balances, @@ -80,7 +78,7 @@ impl TransactionStatusService { Box::new(std::iter::repeat_with(Vec::new)) }; for ( - (_, transaction), + transaction, (status, nonce_rollback), pre_balances, post_balances, @@ -89,7 +87,7 @@ impl TransactionStatusService { inner_instructions, log_messages, ) in izip!( - OrderedIterator::new(&transactions, iteration_order.as_deref()), + &transactions, statuses, balances.pre_balances, balances.post_balances, diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index 074704825..cf3832f9a 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -25,7 +25,6 @@ use solana_runtime::{ bank_utils, commitment::VOTE_THRESHOLD_SIZE, transaction_batch::TransactionBatch, - transaction_utils::OrderedIterator, vote_account::ArcVoteAccount, vote_sender_types::ReplayVoteSender, }; @@ -76,10 +75,7 @@ fn get_first_error( fee_collection_results: Vec>, ) -> Option<(Result<()>, Signature)> { let mut first_err = None; - for (result, (_, transaction)) in fee_collection_results.iter().zip(OrderedIterator::new( - batch.transactions(), - batch.iteration_order(), - )) { + 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(), transaction.signatures[0])); @@ -149,7 +145,6 @@ fn execute_batch( transaction_status_sender.send_transaction_status_batch( bank.clone(), batch.transactions(), - batch.iteration_order_vec(), execution_results, balances, token_balances, @@ -208,7 +203,7 @@ fn execute_batches( /// 4. Update the leader scheduler, goto 1 pub fn process_entries( bank: &Arc, - entries: &[Entry], + entries: &mut [Entry], randomize: bool, transaction_status_sender: Option, replay_vote_sender: Option<&ReplayVoteSender>, @@ -228,9 +223,10 @@ pub fn process_entries( result } +// Note: If randomize is true this will shuffle entries' transactions in-place. fn process_entries_with_callback( bank: &Arc, - entries: &[Entry], + entries: &mut [Entry], randomize: bool, entry_callback: Option<&ProcessCallback>, transaction_status_sender: Option, @@ -240,6 +236,12 @@ fn process_entries_with_callback( // accumulator for entries that can be processed in parallel let mut batches = vec![]; let mut tick_hashes = vec![]; + if randomize { + let mut rng = thread_rng(); + for entry in entries.iter_mut() { + entry.transactions.shuffle(&mut rng); + } + } for entry in entries { if entry.is_tick() { // If it's a tick, save it for later @@ -265,17 +267,8 @@ fn process_entries_with_callback( } // else loop on processing the entry loop { - let iteration_order = if randomize { - let mut iteration_order: Vec = (0..entry.transactions.len()).collect(); - iteration_order.shuffle(&mut thread_rng()); - Some(iteration_order) - } else { - None - }; - // try to lock the accounts - let batch = bank.prepare_batch(&entry.transactions, iteration_order); - + let batch = bank.prepare_batch(&entry.transactions); let first_lock_err = first_err(batch.lock_results()); // if locking worked @@ -677,7 +670,7 @@ pub fn confirm_slot( ) -> result::Result<(), BlockstoreProcessorError> { let slot = bank.slot(); - let (entries, num_shreds, slot_full) = { + let (mut entries, num_shreds, slot_full) = { let mut load_elapsed = Measure::start("load_elapsed"); let load_result = blockstore .get_slot_entries_with_shred_info(slot, progress.num_shreds, allow_dead_slots) @@ -738,10 +731,11 @@ pub fn confirm_slot( let mut replay_elapsed = Measure::start("replay_elapsed"); let mut execute_timings = ExecuteTimings::default(); + // Note: This will shuffle entries' transactions in-place. let process_result = process_entries_with_callback( bank, - &entries, - true, + &mut entries, + true, // shuffle transactions. entry_callback, transaction_status_sender, replay_vote_sender, @@ -1113,7 +1107,6 @@ pub enum TransactionStatusMessage { pub struct TransactionStatusBatch { pub bank: Arc, pub transactions: Vec, - pub iteration_order: Option>, pub statuses: Vec, pub balances: TransactionBalancesSet, pub token_balances: TransactionTokenBalancesSet, @@ -1132,7 +1125,6 @@ impl TransactionStatusSender { &self, bank: Arc, transactions: &[Transaction], - iteration_order: Option>, statuses: Vec, balances: TransactionBalancesSet, token_balances: TransactionTokenBalancesSet, @@ -1150,7 +1142,6 @@ impl TransactionStatusSender { .send(TransactionStatusMessage::Batch(TransactionStatusBatch { bank, transactions: transactions.to_vec(), - iteration_order, statuses, balances, token_balances, @@ -1897,7 +1888,8 @@ pub mod tests { } = create_genesis_config(2); let bank = Arc::new(Bank::new(&genesis_config)); let keypair = Keypair::new(); - let slot_entries = create_ticks(genesis_config.ticks_per_slot, 1, genesis_config.hash()); + let mut slot_entries = + create_ticks(genesis_config.ticks_per_slot, 1, genesis_config.hash()); let tx = system_transaction::transfer( &mint_keypair, &keypair.pubkey(), @@ -1912,7 +1904,7 @@ pub mod tests { ); // Now ensure the TX is accepted despite pointing to the ID of an empty entry. - process_entries(&bank, &slot_entries, true, None, None).unwrap(); + process_entries(&bank, &mut slot_entries, true, None, None).unwrap(); assert_eq!(bank.process_transaction(&tx), Ok(())); } @@ -2117,7 +2109,10 @@ pub mod tests { // ensure bank can process a tick assert_eq!(bank.tick_height(), 0); let tick = next_entry(&genesis_config.hash(), 1, vec![]); - assert_eq!(process_entries(&bank, &[tick], true, None, None), Ok(())); + assert_eq!( + process_entries(&bank, &mut [tick], true, None, None), + Ok(()) + ); assert_eq!(bank.tick_height(), 1); } @@ -2150,7 +2145,7 @@ pub mod tests { ); let entry_2 = next_entry(&entry_1.hash, 1, vec![tx]); assert_eq!( - process_entries(&bank, &[entry_1, entry_2], true, None, None), + process_entries(&bank, &mut [entry_1, entry_2], true, None, None), Ok(()) ); assert_eq!(bank.get_balance(&keypair1.pubkey()), 2); @@ -2208,7 +2203,7 @@ pub mod tests { assert_eq!( process_entries( &bank, - &[entry_1_to_mint, entry_2_to_3_mint_to_1], + &mut [entry_1_to_mint, entry_2_to_3_mint_to_1], false, None, None, @@ -2280,7 +2275,7 @@ pub mod tests { assert!(process_entries( &bank, - &[entry_1_to_mint.clone(), entry_2_to_3_mint_to_1.clone()], + &mut [entry_1_to_mint.clone(), entry_2_to_3_mint_to_1.clone()], false, None, None, @@ -2294,13 +2289,13 @@ pub mod tests { // Check all accounts are unlocked let txs1 = &entry_1_to_mint.transactions[..]; let txs2 = &entry_2_to_3_mint_to_1.transactions[..]; - let batch1 = bank.prepare_batch(txs1, None); + let batch1 = bank.prepare_batch(txs1); for result in batch1.lock_results() { assert!(result.is_ok()); } // txs1 and txs2 have accounts that conflict, so we must drop txs1 first drop(batch1); - let batch2 = bank.prepare_batch(txs2, None); + let batch2 = bank.prepare_batch(txs2); for result in batch2.lock_results() { assert!(result.is_ok()); } @@ -2388,7 +2383,7 @@ pub mod tests { assert!(process_entries( &bank, - &[ + &mut [ entry_1_to_mint, entry_2_to_3_and_1_to_mint, entry_conflict_itself, @@ -2443,7 +2438,7 @@ pub mod tests { system_transaction::transfer(&keypair2, &keypair4.pubkey(), 1, bank.last_blockhash()); let entry_2 = next_entry(&entry_1.hash, 1, vec![tx]); assert_eq!( - process_entries(&bank, &[entry_1, entry_2], true, None, None), + process_entries(&bank, &mut [entry_1, entry_2], true, None, None), Ok(()) ); assert_eq!(bank.get_balance(&keypair3.pubkey()), 1); @@ -2477,7 +2472,7 @@ pub mod tests { let present_account = AccountSharedData::new(1, 10, &Pubkey::default()); bank.store_account(&present_account_key.pubkey(), &present_account); - let entries: Vec<_> = (0..NUM_TRANSFERS) + let mut entries: Vec<_> = (0..NUM_TRANSFERS) .step_by(NUM_TRANSFERS_PER_ENTRY) .map(|i| { let mut transactions = (0..NUM_TRANSFERS_PER_ENTRY) @@ -2503,7 +2498,10 @@ pub mod tests { next_entry_mut(&mut hash, 0, transactions) }) .collect(); - assert_eq!(process_entries(&bank, &entries, true, None, None), Ok(())); + assert_eq!( + process_entries(&bank, &mut entries, true, None, None), + Ok(()) + ); } #[test] @@ -2563,7 +2561,10 @@ pub mod tests { // Transfer lamports to each other let entry = next_entry(&bank.last_blockhash(), 1, tx_vector); - assert_eq!(process_entries(&bank, &[entry], true, None, None), Ok(())); + assert_eq!( + process_entries(&bank, &mut [entry], true, None, None), + Ok(()) + ); bank.squash(); // Even number keypair should have balance of 2 * initial_lamports and @@ -2621,7 +2622,13 @@ pub mod tests { system_transaction::transfer(&keypair1, &keypair4.pubkey(), 1, bank.last_blockhash()); let entry_2 = next_entry(&tick.hash, 1, vec![tx]); assert_eq!( - process_entries(&bank, &[entry_1, tick, entry_2.clone()], true, None, None), + process_entries( + &bank, + &mut [entry_1, tick, entry_2.clone()], + true, + None, + None + ), Ok(()) ); assert_eq!(bank.get_balance(&keypair3.pubkey()), 1); @@ -2632,7 +2639,7 @@ pub mod tests { system_transaction::transfer(&keypair2, &keypair3.pubkey(), 1, bank.last_blockhash()); let entry_3 = next_entry(&entry_2.hash, 1, vec![tx]); assert_eq!( - process_entries(&bank, &[entry_3], true, None, None), + process_entries(&bank, &mut [entry_3], true, None, None), Err(TransactionError::AccountNotFound) ); } @@ -2712,7 +2719,7 @@ pub mod tests { ); assert_eq!( - process_entries(&bank, &[entry_1_to_mint], false, None, None), + process_entries(&bank, &mut [entry_1_to_mint], false, None, None), Err(TransactionError::AccountInUse) ); @@ -2863,7 +2870,7 @@ pub mod tests { let mut hash = bank.last_blockhash(); let mut root: Option> = None; loop { - let entries: Vec<_> = (0..NUM_TRANSFERS) + let mut entries: Vec<_> = (0..NUM_TRANSFERS) .step_by(NUM_TRANSFERS_PER_ENTRY) .map(|i| { next_entry_mut(&mut hash, 0, { @@ -2891,9 +2898,9 @@ pub mod tests { }) .collect(); info!("paying iteration {}", i); - process_entries(&bank, &entries, true, None, None).expect("paying failed"); + process_entries(&bank, &mut entries, true, None, None).expect("paying failed"); - let entries: Vec<_> = (0..NUM_TRANSFERS) + let mut entries: Vec<_> = (0..NUM_TRANSFERS) .step_by(NUM_TRANSFERS_PER_ENTRY) .map(|i| { next_entry_mut( @@ -2914,12 +2921,12 @@ pub mod tests { .collect(); info!("refunding iteration {}", i); - process_entries(&bank, &entries, true, None, None).expect("refunding failed"); + process_entries(&bank, &mut entries, true, None, None).expect("refunding failed"); // advance to next block process_entries( &bank, - &(0..bank.ticks_per_slot()) + &mut (0..bank.ticks_per_slot()) .map(|_| next_entry_mut(&mut hash, 1, vec![])) .collect::>(), true, @@ -2969,7 +2976,7 @@ pub mod tests { process_entries_with_callback( &bank0, - &entries, + &mut entries, true, None, None, @@ -3049,12 +3056,8 @@ pub mod tests { bank.last_blockhash(), ); account_loaded_twice.message.account_keys[1] = mint_keypair.pubkey(); - let transactions = [account_loaded_twice, account_not_found_tx]; - - // Use inverted iteration_order - let iteration_order: Vec = vec![1, 0]; - - let batch = bank.prepare_batch(&transactions, Some(iteration_order)); + let transactions = [account_not_found_tx, account_loaded_twice]; + let batch = bank.prepare_batch(&transactions); let ( TransactionResults { fee_collection_results, @@ -3150,7 +3153,7 @@ pub mod tests { .collect(); let entry = next_entry(&bank_1_blockhash, 1, vote_txs); let (replay_vote_sender, replay_vote_receiver) = unbounded(); - let _ = process_entries(&bank1, &[entry], true, None, Some(&replay_vote_sender)); + let _ = process_entries(&bank1, &mut [entry], true, None, Some(&replay_vote_sender)); let successes: BTreeSet = replay_vote_receiver .try_iter() .map(|(vote_pubkey, _, _)| vote_pubkey) diff --git a/program-test/src/lib.rs b/program-test/src/lib.rs index cf3ba46c8..0522a5dab 100644 --- a/program-test/src/lib.rs +++ b/program-test/src/lib.rs @@ -375,12 +375,11 @@ fn setup_fee_calculator(bank: Bank) -> Bank { // initialized with a non-zero fee. assert_eq!(bank.signature_count(), 0); bank.commit_transactions( - &[], - None, - &mut [], - &[], - 0, - 1, + &[], // transactions + &mut [], // loaded accounts + &[], // transaction execution results + 0, // tx count + 1, // signature count &mut ExecuteTimings::default(), ); assert_eq!(bank.signature_count(), 1); diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 87f1dabfa..2d291721a 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -269,7 +269,7 @@ fn process_transaction_and_record_inner( ) -> (Result<(), TransactionError>, Vec>) { let signature = tx.signatures.get(0).unwrap().clone(); let txs = vec![tx]; - let tx_batch = bank.prepare_batch(&txs, None); + let tx_batch = bank.prepare_batch(&txs); let (mut results, _, mut inner, _transaction_logs) = bank.load_execute_and_commit_transactions( &tx_batch, MAX_PROCESSING_AGE, @@ -294,7 +294,7 @@ fn process_transaction_and_record_inner( } fn execute_transactions(bank: &Bank, txs: &[Transaction]) -> Vec { - let batch = bank.prepare_batch(txs, None); + let batch = bank.prepare_batch(txs); let mut timings = ExecuteTimings::default(); let mut mint_decimals = HashMap::new(); let tx_pre_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals); diff --git a/runtime/benches/transaction_utils.rs b/runtime/benches/transaction_utils.rs deleted file mode 100644 index 7c45718fa..000000000 --- a/runtime/benches/transaction_utils.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(test)] - -extern crate test; - -use rand::{seq::SliceRandom, thread_rng}; -use solana_runtime::transaction_utils::OrderedIterator; -use test::Bencher; - -#[bench] -fn bench_ordered_iterator_with_order_shuffling(bencher: &mut Bencher) { - let vec: Vec = (0..100_usize).collect(); - bencher.iter(|| { - let mut order: Vec = (0..100_usize).collect(); - order.shuffle(&mut thread_rng()); - let _ordered_iterator_resp: Vec<(usize, &usize)> = - OrderedIterator::new(&vec, Some(&order)).collect(); - }); -} diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 9bc03db43..4b3e6308b 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -7,7 +7,6 @@ use crate::{ blockhash_queue::BlockhashQueue, rent_collector::RentCollector, system_instruction_processor::{get_system_account_kind, SystemAccountKind}, - transaction_utils::OrderedIterator, }; use dashmap::{ mapref::entry::Entry::{Occupied, Vacant}, @@ -391,7 +390,6 @@ impl Accounts { &self, ancestors: &Ancestors, txs: &[Transaction], - txs_iteration_order: Option<&[usize]>, lock_results: Vec, hash_queue: &BlockhashQueue, error_counters: &mut ErrorCounters, @@ -402,10 +400,10 @@ impl Accounts { secp256k1_program_enabled: feature_set .is_active(&feature_set::secp256k1_program_enabled::id()), }; - OrderedIterator::new(txs, txs_iteration_order) - .zip(lock_results.into_iter()) + txs.iter() + .zip(lock_results) .map(|etx| match etx { - ((_, tx), (Ok(()), nonce_rollback)) => { + (tx, (Ok(()), nonce_rollback)) => { let fee_calculator = nonce_rollback .as_ref() .map(|nonce_rollback| nonce_rollback.fee_calculator()) @@ -804,12 +802,12 @@ impl Accounts { pub fn lock_accounts( &self, txs: &[Transaction], - txs_iteration_order: Option<&[usize]>, demote_sysvar_write_locks: bool, ) -> Vec> { use solana_sdk::sanitize::Sanitize; - let keys: Vec> = OrderedIterator::new(txs, txs_iteration_order) - .map(|(_, tx)| { + let keys: Vec> = txs + .iter() + .map(|tx| { tx.sanitize().map_err(TransactionError::from)?; if Self::has_duplicates(&tx.message.account_keys) { @@ -836,18 +834,19 @@ impl Accounts { pub fn unlock_accounts( &self, txs: &[Transaction], - txs_iteration_order: Option<&[usize]>, results: &[Result<()>], demote_sysvar_write_locks: bool, ) { let mut account_locks = self.account_locks.lock().unwrap(); debug!("bank unlock accounts"); - - OrderedIterator::new(txs, txs_iteration_order) - .zip(results.iter()) - .for_each(|((_, tx), result)| { - self.unlock_account(tx, result, &mut account_locks, demote_sysvar_write_locks) - }); + for (tx, lock_result) in txs.iter().zip(results) { + self.unlock_account( + tx, + lock_result, + &mut account_locks, + demote_sysvar_write_locks, + ); + } } /// Store the accounts into the DB @@ -857,7 +856,6 @@ impl Accounts { &self, slot: Slot, txs: &[Transaction], - txs_iteration_order: Option<&[usize]>, res: &[TransactionExecutionResult], loaded: &mut [TransactionLoadResult], rent_collector: &RentCollector, @@ -867,7 +865,6 @@ impl Accounts { ) { let accounts_to_store = self.collect_accounts_to_store( txs, - txs_iteration_order, res, loaded, rent_collector, @@ -892,7 +889,6 @@ impl Accounts { fn collect_accounts_to_store<'a>( &self, txs: &'a [Transaction], - txs_iteration_order: Option<&'a [usize]>, res: &'a [TransactionExecutionResult], loaded: &'a mut [TransactionLoadResult], rent_collector: &RentCollector, @@ -901,11 +897,7 @@ impl Accounts { demote_sysvar_write_locks: bool, ) -> Vec<(&'a Pubkey, &'a AccountSharedData)> { let mut accounts = Vec::with_capacity(loaded.len()); - for (i, ((raccs, _nonce_rollback), (_, tx))) in loaded - .iter_mut() - .zip(OrderedIterator::new(txs, txs_iteration_order)) - .enumerate() - { + for (i, ((raccs, _nonce_rollback), tx)) in loaded.iter_mut().zip(txs).enumerate() { if raccs.is_err() { continue; } @@ -1086,7 +1078,6 @@ mod tests { accounts.load_accounts( &ancestors, &[tx], - None, vec![(Ok(()), None)], &hash_queue, error_counters, @@ -1689,7 +1680,6 @@ mod tests { let tx = Transaction::new(&[&keypair0], message, Hash::default()); let results0 = accounts.lock_accounts( &[tx.clone()], - None, // txs_iteration_order true, // demote_sysvar_write_locks ); @@ -1727,8 +1717,7 @@ mod tests { let tx1 = Transaction::new(&[&keypair1], message, Hash::default()); let txs = vec![tx0, tx1]; let results1 = accounts.lock_accounts( - &txs, None, // txs_iteration_order - true, // demote_sysvar_write_locks + &txs, true, // demote_sysvar_write_locks ); assert!(results1[0].is_ok()); // Read-only account (keypair1) can be referenced multiple times @@ -1746,13 +1735,11 @@ mod tests { accounts.unlock_accounts( &[tx], - None, // txs_iteration_order &results0, true, // demote_sysvar_write_locks ); accounts.unlock_accounts( - &txs, None, // txs_iteration_order - &results1, true, // demote_sysvar_write_locks + &txs, &results1, true, // demote_sysvar_write_locks ); let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])]; let message = Message::new_with_compiled_instructions( @@ -1766,7 +1753,6 @@ mod tests { let tx = Transaction::new(&[&keypair1], message, Hash::default()); let results2 = accounts.lock_accounts( &[tx], - None, // txs_iteration_order true, // demote_sysvar_write_locks ); assert!(results2[0].is_ok()); // Now keypair1 account can be locked as writable @@ -1833,8 +1819,7 @@ mod tests { loop { let txs = vec![writable_tx.clone()]; let results = accounts_clone.clone().lock_accounts( - &txs, None, // txs_iteration_order - true, // demote_sysvar_write_locks + &txs, true, // demote_sysvar_write_locks ); for result in results.iter() { if result.is_ok() { @@ -1842,8 +1827,7 @@ mod tests { } } accounts_clone.unlock_accounts( - &txs, None, // txs_iteration_order - &results, true, // demote_sysvar_write_locks + &txs, &results, true, // demote_sysvar_write_locks ); if exit_clone.clone().load(Ordering::Relaxed) { break; @@ -1854,8 +1838,7 @@ mod tests { for _ in 0..5 { let txs = vec![readonly_tx.clone()]; let results = accounts_arc.clone().lock_accounts( - &txs, None, // txs_iteration_order - true, // demote_sysvar_write_locks + &txs, true, // demote_sysvar_write_locks ); if results[0].is_ok() { let counter_value = counter_clone.clone().load(Ordering::SeqCst); @@ -1863,8 +1846,7 @@ mod tests { assert_eq!(counter_value, counter_clone.clone().load(Ordering::SeqCst)); } accounts_arc.unlock_accounts( - &txs, None, // txs_iteration_order - &results, true, // demote_sysvar_write_locks + &txs, &results, true, // demote_sysvar_write_locks ); thread::sleep(time::Duration::from_millis(50)); } @@ -1947,7 +1929,6 @@ mod tests { } let collected_accounts = accounts.collect_accounts_to_store( &txs, - None, &loaders, loaded.as_mut_slice(), &rent_collector, @@ -2017,7 +1998,6 @@ mod tests { accounts.load_accounts( &ancestors, &[tx], - None, vec![(Ok(()), None)], &hash_queue, &mut error_counters, @@ -2313,7 +2293,6 @@ mod tests { Accounts::new_with_config(Vec::new(), &ClusterType::Development, HashSet::new(), false); let collected_accounts = accounts.collect_accounts_to_store( &txs, - None, &loaders, loaded.as_mut_slice(), &rent_collector, @@ -2425,7 +2404,6 @@ mod tests { Accounts::new_with_config(Vec::new(), &ClusterType::Development, HashSet::new(), false); let collected_accounts = accounts.collect_accounts_to_store( &txs, - None, &loaders, loaded.as_mut_slice(), &rent_collector, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 19a8d2b0c..54048c149 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -21,7 +21,6 @@ use crate::{ status_cache::{SlotDelta, StatusCache}, system_instruction_processor::{get_system_account_kind, SystemAccountKind}, transaction_batch::TransactionBatch, - transaction_utils::OrderedIterator, vote_account::ArcVoteAccount, }; use byteorder::{ByteOrder, LittleEndian}; @@ -2347,15 +2346,10 @@ impl Bank { } } - fn update_transaction_statuses( - &self, - txs: &[Transaction], - iteration_order: Option<&[usize]>, - res: &[TransactionExecutionResult], - ) { + fn update_transaction_statuses(&self, txs: &[Transaction], res: &[TransactionExecutionResult]) { let mut status_cache = self.src.status_cache.write().unwrap(); - for (i, (_, tx)) in OrderedIterator::new(txs, iteration_order).enumerate() { - let (res, _nonce_rollback) = &res[i]; + assert_eq!(txs.len(), res.len()); + for (tx, (res, _nonce_rollback)) in txs.iter().zip(res) { if Self::can_commit(res) && !tx.signatures.is_empty() { status_cache.insert( &tx.message().recent_blockhash, @@ -2416,17 +2410,12 @@ impl Bank { .is_active(&feature_set::demote_sysvar_write_locks::id()) } - pub fn prepare_batch<'a, 'b>( - &'a self, - txs: &'b [Transaction], - iteration_order: Option>, - ) -> TransactionBatch<'a, 'b> { - let results = self.rc.accounts.lock_accounts( - txs, - iteration_order.as_deref(), - self.demote_sysvar_write_locks(), - ); - TransactionBatch::new(results, &self, txs, iteration_order) + pub fn prepare_batch<'a, 'b>(&'a self, txs: &'b [Transaction]) -> TransactionBatch<'a, 'b> { + let lock_results = self + .rc + .accounts + .lock_accounts(txs, self.demote_sysvar_write_locks()); + TransactionBatch::new(lock_results, &self, txs) } pub fn prepare_simulation_batch<'a, 'b>( @@ -2437,7 +2426,7 @@ impl Bank { .iter() .map(|tx| tx.sanitize().map_err(|e| e.into())) .collect(); - let mut batch = TransactionBatch::new(lock_results, &self, txs, None); + let mut batch = TransactionBatch::new(lock_results, &self, txs); batch.needs_unlock = false; batch } @@ -2488,7 +2477,6 @@ impl Bank { batch.needs_unlock = false; self.rc.accounts.unlock_accounts( batch.transactions(), - batch.iteration_order(), batch.lock_results(), self.demote_sysvar_write_locks(), ) @@ -2506,15 +2494,14 @@ impl Bank { fn check_age( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, lock_results: Vec>, max_age: usize, error_counters: &mut ErrorCounters, ) -> Vec { let hash_queue = self.blockhash_queue.read().unwrap(); - OrderedIterator::new(txs, iteration_order) - .zip(lock_results.into_iter()) - .map(|((_, tx), lock_res)| match lock_res { + txs.iter() + .zip(lock_results) + .map(|(tx, lock_res)| match lock_res { Ok(()) => { let message = tx.message(); let hash_age = hash_queue.check_hash_age(&message.recent_blockhash, max_age); @@ -2538,14 +2525,13 @@ impl Bank { fn check_signatures( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, lock_results: Vec, error_counters: &mut ErrorCounters, ) -> Vec { let rcache = self.src.status_cache.read().unwrap(); - OrderedIterator::new(txs, iteration_order) - .zip(lock_results.into_iter()) - .map(|((_, tx), lock_res)| { + txs.iter() + .zip(lock_results) + .map(|(tx, lock_res)| { if tx.signatures.is_empty() { return lock_res; } @@ -2572,13 +2558,12 @@ impl Bank { fn filter_by_vote_transactions( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, lock_results: Vec, error_counters: &mut ErrorCounters, ) -> Vec { - OrderedIterator::new(txs, iteration_order) - .zip(lock_results.into_iter()) - .map(|((_, tx), lock_res)| { + txs.iter() + .zip(lock_results) + .map(|(tx, lock_res)| { if lock_res.0.is_ok() { if is_simple_vote_transaction(tx) { return lock_res; @@ -2627,28 +2612,15 @@ impl Bank { pub fn check_transactions( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, lock_results: &[Result<()>], max_age: usize, mut error_counters: &mut ErrorCounters, ) -> Vec { - let age_results = self.check_age( - txs, - iteration_order, - lock_results.to_vec(), - max_age, - &mut error_counters, - ); - let sigcheck_results = - self.check_signatures(txs, iteration_order, age_results, &mut error_counters); + let age_results = self.check_age(txs, lock_results.to_vec(), max_age, &mut error_counters); + let sigcheck_results = self.check_signatures(txs, age_results, &mut error_counters); if self.upgrade_epoch() { // Reject all non-vote transactions - self.filter_by_vote_transactions( - txs, - iteration_order, - sigcheck_results, - &mut error_counters, - ) + self.filter_by_vote_transactions(txs, sigcheck_results, &mut error_counters) } else { sigcheck_results } @@ -2656,8 +2628,7 @@ impl Bank { pub fn collect_balances(&self, batch: &TransactionBatch) -> TransactionBalances { let mut balances: TransactionBalances = vec![]; - for (_, transaction) in OrderedIterator::new(batch.transactions(), batch.iteration_order()) - { + for transaction in batch.transactions() { let mut transaction_balances: Vec = vec![]; for account_key in transaction.message.account_keys.iter() { transaction_balances.push(self.get_balance(account_key)); @@ -2882,30 +2853,25 @@ impl Bank { let mut error_counters = ErrorCounters::default(); let mut load_time = Measure::start("accounts_load"); - let retryable_txs: Vec<_> = - OrderedIterator::new(batch.lock_results(), batch.iteration_order()) - .enumerate() - .filter_map(|(index, (_, res))| match res { - Err(TransactionError::AccountInUse) => { - error_counters.account_in_use += 1; - Some(index) - } - Ok(_) => None, - Err(_) => None, - }) - .collect(); + let retryable_txs: Vec<_> = batch + .lock_results() + .iter() + .enumerate() + .filter_map(|(index, res)| match res { + Err(TransactionError::AccountInUse) => { + error_counters.account_in_use += 1; + Some(index) + } + Err(_) => None, + Ok(_) => None, + }) + .collect(); - let sig_results = self.check_transactions( - txs, - batch.iteration_order(), - batch.lock_results(), - max_age, - &mut error_counters, - ); + let sig_results = + self.check_transactions(txs, batch.lock_results(), max_age, &mut error_counters); let mut loaded_accounts = self.rc.accounts.load_accounts( &self.ancestors, txs, - batch.iteration_order(), sig_results, &self.blockhash_queue.read().unwrap(), &mut error_counters, @@ -2925,8 +2891,8 @@ impl Bank { let executed: Vec = loaded_accounts .iter_mut() - .zip(OrderedIterator::new(txs, batch.iteration_order())) - .map(|(accs, (_, tx))| match accs { + .zip(txs) + .map(|(accs, tx)| match accs { (Err(e), _nonce_rollback) => (Err(e.clone()), None), (Ok(loaded_transaction), nonce_rollback) => { signature_count += u64::from(tx.message().header.num_required_signatures); @@ -3025,11 +2991,7 @@ impl Bank { let transaction_log_collector_config = self.transaction_log_collector_config.read().unwrap(); - for (i, ((r, _nonce_rollback), (_, tx))) in executed - .iter() - .zip(OrderedIterator::new(txs, batch.iteration_order())) - .enumerate() - { + for (i, ((r, _nonce_rollback), tx)) in executed.iter().zip(txs).enumerate() { if let Some(debug_keys) = &self.transaction_debug_keys { for key in &tx.message.account_keys { if debug_keys.contains(key) { @@ -3112,7 +3074,6 @@ impl Bank { fn filter_program_errors_and_collect_fee( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, executed: &[TransactionExecutionResult], ) -> Vec> { let hash_queue = self.blockhash_queue.read().unwrap(); @@ -3122,9 +3083,10 @@ impl Bank { secp256k1_program_enabled: self.secp256k1_program_enabled(), }; - let results = OrderedIterator::new(txs, iteration_order) - .zip(executed.iter()) - .map(|((_, tx), (res, nonce_rollback))| { + let results = txs + .iter() + .zip(executed) + .map(|(tx, (res, nonce_rollback))| { let (fee_calculator, is_durable_nonce) = nonce_rollback .as_ref() .map(|nonce_rollback| nonce_rollback.fee_calculator()) @@ -3172,7 +3134,6 @@ impl Bank { pub fn commit_transactions( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, loaded_accounts: &mut [TransactionLoadResult], executed: &[TransactionExecutionResult], tx_count: u64, @@ -3211,7 +3172,6 @@ impl Bank { self.rc.accounts.store_cached( self.slot(), txs, - iteration_order, executed, loaded_accounts, &self.rent_collector, @@ -3221,16 +3181,14 @@ impl Bank { ); self.collect_rent(executed, loaded_accounts); - let overwritten_vote_accounts = - self.update_cached_accounts(txs, iteration_order, executed, loaded_accounts); + let overwritten_vote_accounts = self.update_cached_accounts(txs, executed, loaded_accounts); // once committed there is no way to unroll write_time.stop(); debug!("store: {}us txs_len={}", write_time.as_us(), txs.len(),); timings.store_us += write_time.as_us(); - self.update_transaction_statuses(txs, iteration_order, &executed); - let fee_collection_results = - self.filter_program_errors_and_collect_fee(txs, iteration_order, executed); + self.update_transaction_statuses(txs, &executed); + let fee_collection_results = self.filter_program_errors_and_collect_fee(txs, executed); TransactionResults { fee_collection_results, @@ -3830,7 +3788,6 @@ impl Bank { let results = self.commit_transactions( batch.transactions(), - batch.iteration_order(), &mut loaded_accounts, &executed, tx_count, @@ -3852,7 +3809,7 @@ impl Bank { #[must_use] pub fn process_transactions(&self, txs: &[Transaction]) -> Vec> { - let batch = self.prepare_batch(txs, None); + let batch = self.prepare_batch(txs); self.load_execute_and_commit_transactions( &batch, MAX_PROCESSING_AGE, @@ -4421,16 +4378,11 @@ impl Bank { fn update_cached_accounts( &self, txs: &[Transaction], - iteration_order: Option<&[usize]>, res: &[TransactionExecutionResult], loaded: &[TransactionLoadResult], ) -> Vec { let mut overwritten_vote_accounts = vec![]; - for (i, ((raccs, _load_nonce_rollback), (transaction_index, tx))) in loaded - .iter() - .zip(OrderedIterator::new(txs, iteration_order)) - .enumerate() - { + for (i, ((raccs, _load_nonce_rollback), tx)) in loaded.iter().zip(txs).enumerate() { let (res, _res_nonce_rollback) = &res[i]; if res.is_err() || raccs.is_err() { continue; @@ -4452,9 +4404,10 @@ impl Bank { self.stake_program_v2_enabled(), self.check_init_vote_data_enabled(), ) { + // TODO: one of the indices is redundant. overwritten_vote_accounts.push(OverwrittenVoteAccount { account: old_vote_account, - transaction_index, + transaction_index: i, transaction_result_index: i, }); } @@ -7600,7 +7553,7 @@ pub(crate) mod tests { ]; let initial_balance = bank.get_balance(&leader); - let results = bank.filter_program_errors_and_collect_fee(&[tx1, tx2], None, &results); + let results = bank.filter_program_errors_and_collect_fee(&[tx1, tx2], &results); bank.freeze(); assert_eq!( bank.get_balance(&leader), @@ -7726,7 +7679,7 @@ pub(crate) mod tests { system_transaction::transfer(&mint_keypair, &alice.pubkey(), 1, genesis_config.hash()); let pay_alice = vec![tx1]; - let lock_result = bank.prepare_batch(&pay_alice, None); + let lock_result = bank.prepare_batch(&pay_alice); let results_alice = bank .load_execute_and_commit_transactions( &lock_result, @@ -7779,7 +7732,7 @@ pub(crate) mod tests { let tx = Transaction::new(&[&key0], message, genesis_config.hash()); let txs = vec![tx]; - let batch0 = bank.prepare_batch(&txs, None); + let batch0 = bank.prepare_batch(&txs); assert!(batch0.lock_results()[0].is_ok()); // Try locking accounts, locking a previously read-only account as writable @@ -7797,7 +7750,7 @@ pub(crate) mod tests { let tx = Transaction::new(&[&key1], message, genesis_config.hash()); let txs = vec![tx]; - let batch1 = bank.prepare_batch(&txs, None); + let batch1 = bank.prepare_batch(&txs); assert!(batch1.lock_results()[0].is_err()); // Try locking a previously read-only account a 2nd time; should succeed @@ -7814,7 +7767,7 @@ pub(crate) mod tests { let tx = Transaction::new(&[&key2], message, genesis_config.hash()); let txs = vec![tx]; - let batch2 = bank.prepare_batch(&txs, None); + let batch2 = bank.prepare_batch(&txs); assert!(batch2.lock_results()[0].is_ok()); } @@ -9650,15 +9603,14 @@ pub(crate) mod tests { instructions, ); let txs = vec![tx0, tx1]; - let iteration_order: Vec = vec![0, 1]; - let batch = bank0.prepare_batch(&txs, Some(iteration_order)); + let batch = bank0.prepare_batch(&txs); let balances = bank0.collect_balances(&batch); assert_eq!(balances.len(), 2); assert_eq!(balances[0], vec![8, 11, 1]); assert_eq!(balances[1], vec![8, 0, 1]); - let iteration_order: Vec = vec![1, 0]; - let batch = bank0.prepare_batch(&txs, Some(iteration_order)); + let txs: Vec<_> = txs.iter().rev().cloned().collect(); + let batch = bank0.prepare_batch(&txs); let balances = bank0.collect_balances(&batch); assert_eq!(balances.len(), 2); assert_eq!(balances[0], vec![8, 0, 1]); @@ -9692,7 +9644,7 @@ pub(crate) mod tests { let tx2 = system_transaction::transfer(&keypair1, &pubkey2, 12, blockhash); let txs = vec![tx0, tx1, tx2]; - let lock_result = bank0.prepare_batch(&txs, None); + let lock_result = bank0.prepare_batch(&txs); let (transaction_results, transaction_balances_set, inner_instructions, transaction_logs) = bank0.load_execute_and_commit_transactions( &lock_result, @@ -12126,10 +12078,8 @@ pub(crate) mod tests { let success_sig = tx0.signatures[0]; let tx1 = system_transaction::transfer(&sender1, &recipient1, 110, blockhash); // Should produce insufficient funds log let failure_sig = tx1.signatures[0]; - let txs = vec![tx0, tx1]; - - // Use non-sequential batch ordering - let batch = bank.prepare_batch(&txs, Some(vec![1, 0])); + let txs = vec![tx1, tx0]; + let batch = bank.prepare_batch(&txs); let log_results = bank .load_execute_and_commit_transactions( diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a8fa95918..9d8af25d7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -34,7 +34,6 @@ pub mod stakes; pub mod status_cache; mod system_instruction_processor; pub mod transaction_batch; -pub mod transaction_utils; pub mod vote_account; pub mod vote_sender_types; diff --git a/runtime/src/transaction_batch.rs b/runtime/src/transaction_batch.rs index 5002927dd..cc33ccd62 100644 --- a/runtime/src/transaction_batch.rs +++ b/runtime/src/transaction_batch.rs @@ -6,7 +6,6 @@ pub struct TransactionBatch<'a, 'b> { lock_results: Vec>, bank: &'a Bank, transactions: &'b [Transaction], - iteration_order: Option>, pub(crate) needs_unlock: bool, } @@ -15,17 +14,12 @@ impl<'a, 'b> TransactionBatch<'a, 'b> { lock_results: Vec>, bank: &'a Bank, transactions: &'b [Transaction], - iteration_order: Option>, ) -> Self { assert_eq!(lock_results.len(), transactions.len()); - if let Some(iteration_order) = &iteration_order { - assert_eq!(transactions.len(), iteration_order.len()); - } Self { lock_results, bank, transactions, - iteration_order, needs_unlock: true, } } @@ -38,14 +32,6 @@ impl<'a, 'b> TransactionBatch<'a, 'b> { self.transactions } - pub fn iteration_order(&self) -> Option<&[usize]> { - self.iteration_order.as_deref() - } - - pub fn iteration_order_vec(&self) -> Option> { - self.iteration_order.clone() - } - pub fn bank(&self) -> &Bank { self.bank } @@ -69,20 +55,20 @@ mod tests { let (bank, txs) = setup(); // Test getting locked accounts - let batch = bank.prepare_batch(&txs, None); + let batch = bank.prepare_batch(&txs); // Grab locks assert!(batch.lock_results().iter().all(|x| x.is_ok())); // Trying to grab locks again should fail - let batch2 = bank.prepare_batch(&txs, None); + let batch2 = bank.prepare_batch(&txs); assert!(batch2.lock_results().iter().all(|x| x.is_err())); // Drop the first set of locks drop(batch); // Now grabbing locks should work again - let batch2 = bank.prepare_batch(&txs, None); + let batch2 = bank.prepare_batch(&txs); assert!(batch2.lock_results().iter().all(|x| x.is_ok())); } @@ -95,7 +81,7 @@ mod tests { assert!(batch.lock_results().iter().all(|x| x.is_ok())); // Grab locks - let batch2 = bank.prepare_batch(&txs, None); + let batch2 = bank.prepare_batch(&txs); assert!(batch2.lock_results().iter().all(|x| x.is_ok())); // Prepare another batch without locks diff --git a/runtime/src/transaction_utils.rs b/runtime/src/transaction_utils.rs deleted file mode 100644 index 994163972..000000000 --- a/runtime/src/transaction_utils.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::ops::Index; - -/// OrderedIterator allows iterating with specific order specified -pub struct OrderedIterator<'a, T: 'a> { - element_order: Option<&'a [usize]>, - current: usize, - vec: &'a [T], -} - -impl<'a, T> OrderedIterator<'a, T> { - pub fn new(vec: &'a [T], element_order: Option<&'a [usize]>) -> OrderedIterator<'a, T> { - if let Some(custom_order) = element_order { - assert!(custom_order.len() == vec.len()); - } - OrderedIterator { - element_order, - current: 0, - vec, - } - } -} - -impl<'a, T> Iterator for OrderedIterator<'a, T> { - type Item = (usize, &'a T); - fn next(&mut self) -> Option { - if self.current >= self.vec.len() { - None - } else { - let index: usize; - if let Some(custom_order) = self.element_order { - index = custom_order[self.current]; - } else { - index = self.current; - } - self.current += 1; - Some((index, self.vec.index(index))) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type IteratorResponse<'a> = Vec<(((usize, &'a usize), &'a usize), usize)>; - - #[test] - fn test_ordered_iterator_custom_order() { - let vec: Vec = vec![1, 2, 3, 4]; - let custom_order: Vec = vec![3, 1, 0, 2]; - let custom_order_ = custom_order.clone(); - let ordered_iterator = OrderedIterator::new(&vec, Some(&custom_order)); - let expected_response: Vec = vec![4, 2, 1, 3]; - - let resp: IteratorResponse = ordered_iterator - .zip(expected_response.iter()) - .zip(custom_order_) - .filter(|(((index, actual_elem), expected_elem), expected_index)| { - *actual_elem == *expected_elem && index == expected_index - }) - .collect(); - - assert_eq!(resp.len(), custom_order.len()); - } - - #[test] - fn test_ordered_iterator_original_order() { - let vec: Vec = vec![1, 2, 3, 4]; - let ordered_iterator = OrderedIterator::new(&vec, None); - - let resp: IteratorResponse = ordered_iterator - .zip(vec.iter()) - .zip(0..=4) - .filter(|(((index, actual_elem), expected_elem), expected_index)| { - *actual_elem == *expected_elem && index == expected_index - }) - .collect(); - - assert_eq!(resp.len(), vec.len()); - } -} diff --git a/transaction-status/src/token_balances.rs b/transaction-status/src/token_balances.rs index 8368bdc92..087ae99ff 100644 --- a/transaction-status/src/token_balances.rs +++ b/transaction-status/src/token_balances.rs @@ -2,9 +2,7 @@ use crate::TransactionTokenBalance; use solana_account_decoder::parse_token::{ spl_token_id_v2_0, spl_token_v2_0_native_mint, token_amount_to_ui_amount, UiTokenAmount, }; -use solana_runtime::{ - bank::Bank, transaction_batch::TransactionBatch, transaction_utils::OrderedIterator, -}; +use solana_runtime::{bank::Bank, transaction_batch::TransactionBatch}; use solana_sdk::{account::ReadableAccount, pubkey::Pubkey}; use spl_token_v2_0::{ solana_program::program_pack::Pack, @@ -57,7 +55,7 @@ pub fn collect_token_balances( ) -> TransactionTokenBalances { let mut balances: TransactionTokenBalances = vec![]; - for (_, transaction) in OrderedIterator::new(batch.transactions(), batch.iteration_order()) { + for transaction in batch.transactions() { let account_keys = &transaction.message.account_keys; let has_token_program = account_keys.iter().any(|p| is_token_program(p));