Allow the same account to be passed multiple times to a single instruction (#7795)

This commit is contained in:
Jack May
2020-01-22 09:11:56 -08:00
committed by GitHub
parent d854e90c23
commit 023074650f
33 changed files with 1392 additions and 765 deletions

View File

@@ -5,7 +5,6 @@ use crate::accounts_index::AccountsIndex;
use crate::append_vec::StoredAccount;
use crate::bank::{HashAgeKind, TransactionProcessResult};
use crate::blockhash_queue::BlockhashQueue;
use crate::message_processor::has_duplicates;
use crate::nonce_utils::prepare_if_nonce_account;
use crate::rent_collector::RentCollector;
use crate::system_instruction_processor::{get_system_account_kind, SystemAccountKind};
@@ -87,6 +86,19 @@ impl Accounts {
.accounts_from_stream(stream, local_paths, append_vecs_path)
}
/// Return true if the slice has any duplicate elements
pub fn has_duplicates<T: PartialEq>(xs: &[T]) -> bool {
// Note: This is an O(n^2) algorithm, but requires no heap allocations. The benchmark
// `bench_has_duplicates` in benches/message_processor.rs shows that this implementation is
// ~50 times faster than using HashSet for very short slices.
for i in 1..xs.len() {
if xs[i..].contains(&xs[i - 1]) {
return true;
}
}
false
}
fn load_tx_accounts(
&self,
storage: &AccountStorage,
@@ -103,7 +115,7 @@ impl Accounts {
Err(TransactionError::MissingSignatureForFee)
} else {
// Check for unique account keys
if has_duplicates(&message.account_keys) {
if Self::has_duplicates(&message.account_keys) {
error_counters.account_loaded_twice += 1;
return Err(TransactionError::AccountLoadedTwice);
}
@@ -1634,4 +1646,10 @@ mod tests {
1
);
}
#[test]
fn test_has_duplicates() {
assert!(!Accounts::has_duplicates(&[1, 2]));
assert!(Accounts::has_duplicates(&[1, 2, 1]));
}
}