Move filter_executable_program_accounts to bank.rs (#34004)
This commit is contained in:
parent
9f25f67e60
commit
59eb55990c
|
@ -59,10 +59,7 @@ use {
|
||||||
solana_system_program::{get_system_account_kind, SystemAccountKind},
|
solana_system_program::{get_system_account_kind, SystemAccountKind},
|
||||||
std::{
|
std::{
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
collections::{
|
collections::{hash_map, BinaryHeap, HashMap, HashSet},
|
||||||
hash_map::{self, Entry},
|
|
||||||
BinaryHeap, HashMap, HashSet,
|
|
||||||
},
|
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::RangeBounds,
|
ops::RangeBounds,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
@ -638,59 +635,6 @@ impl Accounts {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a hash map of executable program accounts (program accounts that are not writable
|
|
||||||
/// in the given transactions), and their owners, for the transactions with a valid
|
|
||||||
/// blockhash or nonce.
|
|
||||||
pub fn filter_executable_program_accounts<'a>(
|
|
||||||
&self,
|
|
||||||
ancestors: &Ancestors,
|
|
||||||
txs: &[SanitizedTransaction],
|
|
||||||
lock_results: &mut [TransactionCheckResult],
|
|
||||||
program_owners: &'a [Pubkey],
|
|
||||||
hash_queue: &BlockhashQueue,
|
|
||||||
) -> HashMap<Pubkey, (&'a Pubkey, u64)> {
|
|
||||||
let mut result: HashMap<Pubkey, (&'a Pubkey, u64)> = HashMap::new();
|
|
||||||
lock_results.iter_mut().zip(txs).for_each(|etx| {
|
|
||||||
if let ((Ok(()), nonce), tx) = etx {
|
|
||||||
if nonce
|
|
||||||
.as_ref()
|
|
||||||
.map(|nonce| nonce.lamports_per_signature())
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
hash_queue.get_lamports_per_signature(tx.message().recent_blockhash())
|
|
||||||
})
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
tx.message()
|
|
||||||
.account_keys()
|
|
||||||
.iter()
|
|
||||||
.for_each(|key| match result.entry(*key) {
|
|
||||||
Entry::Occupied(mut entry) => {
|
|
||||||
let (_, count) = entry.get_mut();
|
|
||||||
saturating_add_assign!(*count, 1);
|
|
||||||
}
|
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
if let Ok(index) = self.accounts_db.account_matches_owners(
|
|
||||||
ancestors,
|
|
||||||
key,
|
|
||||||
program_owners,
|
|
||||||
) {
|
|
||||||
program_owners
|
|
||||||
.get(index)
|
|
||||||
.map(|owner| entry.insert((owner, 1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// If the transaction's nonce account was not valid, and blockhash is not found,
|
|
||||||
// the transaction will fail to process. Let's not load any programs from the
|
|
||||||
// transaction, and update the status of the transaction.
|
|
||||||
*etx.0 = (Err(TransactionError::BlockhashNotFound), None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn load_accounts(
|
pub fn load_accounts(
|
||||||
&self,
|
&self,
|
||||||
|
@ -2000,220 +1944,6 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_filter_executable_program_accounts() {
|
|
||||||
let mut tx_accounts: Vec<TransactionAccount> = Vec::new();
|
|
||||||
|
|
||||||
let keypair1 = Keypair::new();
|
|
||||||
let keypair2 = Keypair::new();
|
|
||||||
|
|
||||||
let non_program_pubkey1 = Pubkey::new_unique();
|
|
||||||
let non_program_pubkey2 = Pubkey::new_unique();
|
|
||||||
let program1_pubkey = Pubkey::new_unique();
|
|
||||||
let program2_pubkey = Pubkey::new_unique();
|
|
||||||
let account1_pubkey = Pubkey::new_unique();
|
|
||||||
let account2_pubkey = Pubkey::new_unique();
|
|
||||||
let account3_pubkey = Pubkey::new_unique();
|
|
||||||
let account4_pubkey = Pubkey::new_unique();
|
|
||||||
|
|
||||||
let account5_pubkey = Pubkey::new_unique();
|
|
||||||
|
|
||||||
tx_accounts.push((
|
|
||||||
non_program_pubkey1,
|
|
||||||
AccountSharedData::new(1, 10, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
non_program_pubkey2,
|
|
||||||
AccountSharedData::new(1, 10, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
program1_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
program2_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account1_pubkey,
|
|
||||||
AccountSharedData::new(1, 10, &non_program_pubkey1),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account2_pubkey,
|
|
||||||
AccountSharedData::new(1, 10, &non_program_pubkey2),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account3_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &program1_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account4_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &program2_pubkey),
|
|
||||||
));
|
|
||||||
|
|
||||||
let accounts = Accounts::new_with_config_for_tests(
|
|
||||||
Vec::new(),
|
|
||||||
&ClusterType::Development,
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
);
|
|
||||||
for tx_account in tx_accounts.iter() {
|
|
||||||
accounts.store_for_tests(0, &tx_account.0, &tx_account.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut hash_queue = BlockhashQueue::new(100);
|
|
||||||
|
|
||||||
let tx1 = Transaction::new_with_compiled_instructions(
|
|
||||||
&[&keypair1],
|
|
||||||
&[non_program_pubkey1],
|
|
||||||
Hash::new_unique(),
|
|
||||||
vec![account1_pubkey, account2_pubkey, account3_pubkey],
|
|
||||||
vec![CompiledInstruction::new(1, &(), vec![0])],
|
|
||||||
);
|
|
||||||
hash_queue.register_hash(&tx1.message().recent_blockhash, 0);
|
|
||||||
let sanitized_tx1 = SanitizedTransaction::from_transaction_for_tests(tx1);
|
|
||||||
|
|
||||||
let tx2 = Transaction::new_with_compiled_instructions(
|
|
||||||
&[&keypair2],
|
|
||||||
&[non_program_pubkey2],
|
|
||||||
Hash::new_unique(),
|
|
||||||
vec![account4_pubkey, account3_pubkey, account2_pubkey],
|
|
||||||
vec![CompiledInstruction::new(1, &(), vec![0])],
|
|
||||||
);
|
|
||||||
hash_queue.register_hash(&tx2.message().recent_blockhash, 0);
|
|
||||||
let sanitized_tx2 = SanitizedTransaction::from_transaction_for_tests(tx2);
|
|
||||||
|
|
||||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
|
||||||
let owners = &[program1_pubkey, program2_pubkey];
|
|
||||||
let programs = accounts.filter_executable_program_accounts(
|
|
||||||
&ancestors,
|
|
||||||
&[sanitized_tx1, sanitized_tx2],
|
|
||||||
&mut [(Ok(()), None), (Ok(()), None)],
|
|
||||||
owners,
|
|
||||||
&hash_queue,
|
|
||||||
);
|
|
||||||
|
|
||||||
// The result should contain only account3_pubkey, and account4_pubkey as the program accounts
|
|
||||||
assert_eq!(programs.len(), 2);
|
|
||||||
assert_eq!(
|
|
||||||
programs
|
|
||||||
.get(&account3_pubkey)
|
|
||||||
.expect("failed to find the program account"),
|
|
||||||
&(&program1_pubkey, 2)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
programs
|
|
||||||
.get(&account4_pubkey)
|
|
||||||
.expect("failed to find the program account"),
|
|
||||||
&(&program2_pubkey, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_filter_executable_program_accounts_invalid_blockhash() {
|
|
||||||
let mut tx_accounts: Vec<TransactionAccount> = Vec::new();
|
|
||||||
|
|
||||||
let keypair1 = Keypair::new();
|
|
||||||
let keypair2 = Keypair::new();
|
|
||||||
|
|
||||||
let non_program_pubkey1 = Pubkey::new_unique();
|
|
||||||
let non_program_pubkey2 = Pubkey::new_unique();
|
|
||||||
let program1_pubkey = Pubkey::new_unique();
|
|
||||||
let program2_pubkey = Pubkey::new_unique();
|
|
||||||
let account1_pubkey = Pubkey::new_unique();
|
|
||||||
let account2_pubkey = Pubkey::new_unique();
|
|
||||||
let account3_pubkey = Pubkey::new_unique();
|
|
||||||
let account4_pubkey = Pubkey::new_unique();
|
|
||||||
|
|
||||||
let account5_pubkey = Pubkey::new_unique();
|
|
||||||
|
|
||||||
tx_accounts.push((
|
|
||||||
non_program_pubkey1,
|
|
||||||
AccountSharedData::new(1, 10, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
non_program_pubkey2,
|
|
||||||
AccountSharedData::new(1, 10, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
program1_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
program2_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &account5_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account1_pubkey,
|
|
||||||
AccountSharedData::new(1, 10, &non_program_pubkey1),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account2_pubkey,
|
|
||||||
AccountSharedData::new(1, 10, &non_program_pubkey2),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account3_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &program1_pubkey),
|
|
||||||
));
|
|
||||||
tx_accounts.push((
|
|
||||||
account4_pubkey,
|
|
||||||
AccountSharedData::new(40, 1, &program2_pubkey),
|
|
||||||
));
|
|
||||||
|
|
||||||
let accounts = Accounts::new_with_config_for_tests(
|
|
||||||
Vec::new(),
|
|
||||||
&ClusterType::Development,
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
);
|
|
||||||
for tx_account in tx_accounts.iter() {
|
|
||||||
accounts.store_for_tests(0, &tx_account.0, &tx_account.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut hash_queue = BlockhashQueue::new(100);
|
|
||||||
|
|
||||||
let tx1 = Transaction::new_with_compiled_instructions(
|
|
||||||
&[&keypair1],
|
|
||||||
&[non_program_pubkey1],
|
|
||||||
Hash::new_unique(),
|
|
||||||
vec![account1_pubkey, account2_pubkey, account3_pubkey],
|
|
||||||
vec![CompiledInstruction::new(1, &(), vec![0])],
|
|
||||||
);
|
|
||||||
hash_queue.register_hash(&tx1.message().recent_blockhash, 0);
|
|
||||||
let sanitized_tx1 = SanitizedTransaction::from_transaction_for_tests(tx1);
|
|
||||||
|
|
||||||
let tx2 = Transaction::new_with_compiled_instructions(
|
|
||||||
&[&keypair2],
|
|
||||||
&[non_program_pubkey2],
|
|
||||||
Hash::new_unique(),
|
|
||||||
vec![account4_pubkey, account3_pubkey, account2_pubkey],
|
|
||||||
vec![CompiledInstruction::new(1, &(), vec![0])],
|
|
||||||
);
|
|
||||||
// Let's not register blockhash from tx2. This should cause the tx2 to fail
|
|
||||||
let sanitized_tx2 = SanitizedTransaction::from_transaction_for_tests(tx2);
|
|
||||||
|
|
||||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
|
||||||
let owners = &[program1_pubkey, program2_pubkey];
|
|
||||||
let mut lock_results = vec![(Ok(()), None), (Ok(()), None)];
|
|
||||||
let programs = accounts.filter_executable_program_accounts(
|
|
||||||
&ancestors,
|
|
||||||
&[sanitized_tx1, sanitized_tx2],
|
|
||||||
&mut lock_results,
|
|
||||||
owners,
|
|
||||||
&hash_queue,
|
|
||||||
);
|
|
||||||
|
|
||||||
// The result should contain only account3_pubkey as the program accounts
|
|
||||||
assert_eq!(programs.len(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
programs
|
|
||||||
.get(&account3_pubkey)
|
|
||||||
.expect("failed to find the program account"),
|
|
||||||
&(&program1_pubkey, 1)
|
|
||||||
);
|
|
||||||
assert_eq!(lock_results[1].0, Err(TransactionError::BlockhashNotFound));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_accounts_multiple_loaders() {
|
fn test_load_accounts_multiple_loaders() {
|
||||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||||
|
|
|
@ -184,7 +184,7 @@ use {
|
||||||
std::{
|
std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashMap, HashSet},
|
collections::{hash_map::Entry, HashMap, HashSet},
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
fmt, mem,
|
fmt, mem,
|
||||||
ops::{AddAssign, RangeInclusive},
|
ops::{AddAssign, RangeInclusive},
|
||||||
|
@ -5116,6 +5116,60 @@ impl Bank {
|
||||||
loaded_programs_for_txs
|
loaded_programs_for_txs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a hash map of executable program accounts (program accounts that are not writable
|
||||||
|
/// in the given transactions), and their owners, for the transactions with a valid
|
||||||
|
/// blockhash or nonce.
|
||||||
|
fn filter_executable_program_accounts<'a>(
|
||||||
|
&self,
|
||||||
|
ancestors: &Ancestors,
|
||||||
|
txs: &[SanitizedTransaction],
|
||||||
|
lock_results: &mut [TransactionCheckResult],
|
||||||
|
program_owners: &'a [Pubkey],
|
||||||
|
hash_queue: &BlockhashQueue,
|
||||||
|
) -> HashMap<Pubkey, (&'a Pubkey, u64)> {
|
||||||
|
let mut result: HashMap<Pubkey, (&'a Pubkey, u64)> = HashMap::new();
|
||||||
|
lock_results.iter_mut().zip(txs).for_each(|etx| {
|
||||||
|
if let ((Ok(()), nonce), tx) = etx {
|
||||||
|
if nonce
|
||||||
|
.as_ref()
|
||||||
|
.map(|nonce| nonce.lamports_per_signature())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
hash_queue.get_lamports_per_signature(tx.message().recent_blockhash())
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
tx.message()
|
||||||
|
.account_keys()
|
||||||
|
.iter()
|
||||||
|
.for_each(|key| match result.entry(*key) {
|
||||||
|
Entry::Occupied(mut entry) => {
|
||||||
|
let (_, count) = entry.get_mut();
|
||||||
|
saturating_add_assign!(*count, 1);
|
||||||
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
if let Ok(index) = self
|
||||||
|
.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.account_matches_owners(ancestors, key, program_owners)
|
||||||
|
{
|
||||||
|
program_owners
|
||||||
|
.get(index)
|
||||||
|
.map(|owner| entry.insert((owner, 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If the transaction's nonce account was not valid, and blockhash is not found,
|
||||||
|
// the transaction will fail to process. Let's not load any programs from the
|
||||||
|
// transaction, and update the status of the transaction.
|
||||||
|
*etx.0 = (Err(TransactionError::BlockhashNotFound), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn load_and_execute_transactions(
|
pub fn load_and_execute_transactions(
|
||||||
&self,
|
&self,
|
||||||
|
@ -5183,7 +5237,7 @@ impl Bank {
|
||||||
bpf_loader_deprecated::id(),
|
bpf_loader_deprecated::id(),
|
||||||
loader_v4::id(),
|
loader_v4::id(),
|
||||||
];
|
];
|
||||||
let mut program_accounts_map = self.rc.accounts.filter_executable_program_accounts(
|
let mut program_accounts_map = self.filter_executable_program_accounts(
|
||||||
&self.ancestors,
|
&self.ancestors,
|
||||||
sanitized_txs,
|
sanitized_txs,
|
||||||
&mut check_results,
|
&mut check_results,
|
||||||
|
|
|
@ -13536,3 +13536,197 @@ fn test_last_restart_slot() {
|
||||||
assert!(!last_restart_slot_dirty(&bank7));
|
assert!(!last_restart_slot_dirty(&bank7));
|
||||||
assert_eq!(get_last_restart_slot(&bank7), Some(6));
|
assert_eq!(get_last_restart_slot(&bank7), Some(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_filter_executable_program_accounts() {
|
||||||
|
let keypair1 = Keypair::new();
|
||||||
|
let keypair2 = Keypair::new();
|
||||||
|
|
||||||
|
let non_program_pubkey1 = Pubkey::new_unique();
|
||||||
|
let non_program_pubkey2 = Pubkey::new_unique();
|
||||||
|
let program1_pubkey = Pubkey::new_unique();
|
||||||
|
let program2_pubkey = Pubkey::new_unique();
|
||||||
|
let account1_pubkey = Pubkey::new_unique();
|
||||||
|
let account2_pubkey = Pubkey::new_unique();
|
||||||
|
let account3_pubkey = Pubkey::new_unique();
|
||||||
|
let account4_pubkey = Pubkey::new_unique();
|
||||||
|
|
||||||
|
let account5_pubkey = Pubkey::new_unique();
|
||||||
|
|
||||||
|
let (genesis_config, _mint_keypair) = create_genesis_config(10);
|
||||||
|
let bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
bank.store_account(
|
||||||
|
&non_program_pubkey1,
|
||||||
|
&AccountSharedData::new(1, 10, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&non_program_pubkey2,
|
||||||
|
&AccountSharedData::new(1, 10, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&program1_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&program2_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account1_pubkey,
|
||||||
|
&AccountSharedData::new(1, 10, &non_program_pubkey1),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account2_pubkey,
|
||||||
|
&AccountSharedData::new(1, 10, &non_program_pubkey2),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account3_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &program1_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account4_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &program2_pubkey),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut hash_queue = BlockhashQueue::new(100);
|
||||||
|
|
||||||
|
let tx1 = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&keypair1],
|
||||||
|
&[non_program_pubkey1],
|
||||||
|
Hash::new_unique(),
|
||||||
|
vec![account1_pubkey, account2_pubkey, account3_pubkey],
|
||||||
|
vec![CompiledInstruction::new(1, &(), vec![0])],
|
||||||
|
);
|
||||||
|
hash_queue.register_hash(&tx1.message().recent_blockhash, 0);
|
||||||
|
let sanitized_tx1 = SanitizedTransaction::from_transaction_for_tests(tx1);
|
||||||
|
|
||||||
|
let tx2 = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&keypair2],
|
||||||
|
&[non_program_pubkey2],
|
||||||
|
Hash::new_unique(),
|
||||||
|
vec![account4_pubkey, account3_pubkey, account2_pubkey],
|
||||||
|
vec![CompiledInstruction::new(1, &(), vec![0])],
|
||||||
|
);
|
||||||
|
hash_queue.register_hash(&tx2.message().recent_blockhash, 0);
|
||||||
|
let sanitized_tx2 = SanitizedTransaction::from_transaction_for_tests(tx2);
|
||||||
|
|
||||||
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||||
|
let owners = &[program1_pubkey, program2_pubkey];
|
||||||
|
let programs = bank.filter_executable_program_accounts(
|
||||||
|
&ancestors,
|
||||||
|
&[sanitized_tx1, sanitized_tx2],
|
||||||
|
&mut [(Ok(()), None), (Ok(()), None)],
|
||||||
|
owners,
|
||||||
|
&hash_queue,
|
||||||
|
);
|
||||||
|
|
||||||
|
// The result should contain only account3_pubkey, and account4_pubkey as the program accounts
|
||||||
|
assert_eq!(programs.len(), 2);
|
||||||
|
assert_eq!(
|
||||||
|
programs
|
||||||
|
.get(&account3_pubkey)
|
||||||
|
.expect("failed to find the program account"),
|
||||||
|
&(&program1_pubkey, 2)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
programs
|
||||||
|
.get(&account4_pubkey)
|
||||||
|
.expect("failed to find the program account"),
|
||||||
|
&(&program2_pubkey, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_filter_executable_program_accounts_invalid_blockhash() {
|
||||||
|
let keypair1 = Keypair::new();
|
||||||
|
let keypair2 = Keypair::new();
|
||||||
|
|
||||||
|
let non_program_pubkey1 = Pubkey::new_unique();
|
||||||
|
let non_program_pubkey2 = Pubkey::new_unique();
|
||||||
|
let program1_pubkey = Pubkey::new_unique();
|
||||||
|
let program2_pubkey = Pubkey::new_unique();
|
||||||
|
let account1_pubkey = Pubkey::new_unique();
|
||||||
|
let account2_pubkey = Pubkey::new_unique();
|
||||||
|
let account3_pubkey = Pubkey::new_unique();
|
||||||
|
let account4_pubkey = Pubkey::new_unique();
|
||||||
|
|
||||||
|
let account5_pubkey = Pubkey::new_unique();
|
||||||
|
|
||||||
|
let (genesis_config, _mint_keypair) = create_genesis_config(10);
|
||||||
|
let bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
bank.store_account(
|
||||||
|
&non_program_pubkey1,
|
||||||
|
&AccountSharedData::new(1, 10, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&non_program_pubkey2,
|
||||||
|
&AccountSharedData::new(1, 10, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&program1_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&program2_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &account5_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account1_pubkey,
|
||||||
|
&AccountSharedData::new(1, 10, &non_program_pubkey1),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account2_pubkey,
|
||||||
|
&AccountSharedData::new(1, 10, &non_program_pubkey2),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account3_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &program1_pubkey),
|
||||||
|
);
|
||||||
|
bank.store_account(
|
||||||
|
&account4_pubkey,
|
||||||
|
&AccountSharedData::new(40, 1, &program2_pubkey),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut hash_queue = BlockhashQueue::new(100);
|
||||||
|
|
||||||
|
let tx1 = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&keypair1],
|
||||||
|
&[non_program_pubkey1],
|
||||||
|
Hash::new_unique(),
|
||||||
|
vec![account1_pubkey, account2_pubkey, account3_pubkey],
|
||||||
|
vec![CompiledInstruction::new(1, &(), vec![0])],
|
||||||
|
);
|
||||||
|
hash_queue.register_hash(&tx1.message().recent_blockhash, 0);
|
||||||
|
let sanitized_tx1 = SanitizedTransaction::from_transaction_for_tests(tx1);
|
||||||
|
|
||||||
|
let tx2 = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&keypair2],
|
||||||
|
&[non_program_pubkey2],
|
||||||
|
Hash::new_unique(),
|
||||||
|
vec![account4_pubkey, account3_pubkey, account2_pubkey],
|
||||||
|
vec![CompiledInstruction::new(1, &(), vec![0])],
|
||||||
|
);
|
||||||
|
// Let's not register blockhash from tx2. This should cause the tx2 to fail
|
||||||
|
let sanitized_tx2 = SanitizedTransaction::from_transaction_for_tests(tx2);
|
||||||
|
|
||||||
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||||
|
let owners = &[program1_pubkey, program2_pubkey];
|
||||||
|
let mut lock_results = vec![(Ok(()), None), (Ok(()), None)];
|
||||||
|
let programs = bank.filter_executable_program_accounts(
|
||||||
|
&ancestors,
|
||||||
|
&[sanitized_tx1, sanitized_tx2],
|
||||||
|
&mut lock_results,
|
||||||
|
owners,
|
||||||
|
&hash_queue,
|
||||||
|
);
|
||||||
|
|
||||||
|
// The result should contain only account3_pubkey as the program accounts
|
||||||
|
assert_eq!(programs.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
programs
|
||||||
|
.get(&account3_pubkey)
|
||||||
|
.expect("failed to find the program account"),
|
||||||
|
&(&program1_pubkey, 1)
|
||||||
|
);
|
||||||
|
assert_eq!(lock_results[1].0, Err(TransactionError::BlockhashNotFound));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue