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

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