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.
This commit is contained in:
behzad nouri
2021-03-31 23:59:19 +00:00
committed by GitHub
parent ad7f8e7f23
commit 3f63ed9a72
14 changed files with 161 additions and 352 deletions

View File

@ -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<usize> = (0..100_usize).collect();
bencher.iter(|| {
let mut order: Vec<usize> = (0..100_usize).collect();
order.shuffle(&mut thread_rng());
let _ordered_iterator_resp: Vec<(usize, &usize)> =
OrderedIterator::new(&vec, Some(&order)).collect();
});
}

View File

@ -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<TransactionCheckResult>,
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<Result<()>> {
use solana_sdk::sanitize::Sanitize;
let keys: Vec<Result<_>> = OrderedIterator::new(txs, txs_iteration_order)
.map(|(_, tx)| {
let keys: Vec<Result<_>> = 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,

View File

@ -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<Vec<usize>>,
) -> 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<Result<()>>,
max_age: usize,
error_counters: &mut ErrorCounters,
) -> Vec<TransactionCheckResult> {
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<TransactionCheckResult>,
error_counters: &mut ErrorCounters,
) -> Vec<TransactionCheckResult> {
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<TransactionCheckResult>,
error_counters: &mut ErrorCounters,
) -> Vec<TransactionCheckResult> {
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<TransactionCheckResult> {
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<u64> = 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<TransactionExecutionResult> = 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<Result<()>> {
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<Result<()>> {
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<OverwrittenVoteAccount> {
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<usize> = 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<usize> = 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(

View File

@ -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;

View File

@ -6,7 +6,6 @@ pub struct TransactionBatch<'a, 'b> {
lock_results: Vec<Result<()>>,
bank: &'a Bank,
transactions: &'b [Transaction],
iteration_order: Option<Vec<usize>>,
pub(crate) needs_unlock: bool,
}
@ -15,17 +14,12 @@ impl<'a, 'b> TransactionBatch<'a, 'b> {
lock_results: Vec<Result<()>>,
bank: &'a Bank,
transactions: &'b [Transaction],
iteration_order: Option<Vec<usize>>,
) -> 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<Vec<usize>> {
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

View File

@ -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<Self::Item> {
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<usize> = vec![1, 2, 3, 4];
let custom_order: Vec<usize> = vec![3, 1, 0, 2];
let custom_order_ = custom_order.clone();
let ordered_iterator = OrderedIterator::new(&vec, Some(&custom_order));
let expected_response: Vec<usize> = 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<usize> = 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());
}
}