1use {
2 crate::{
3 account_locks::{validate_account_locks, AccountLocks},
4 accounts_db::{
5 AccountStorageEntry, AccountsAddRootTiming, AccountsDb, LoadHint, LoadedAccount,
6 ScanAccountStorageData, ScanStorageResult, VerifyAccountsHashAndLamportsConfig,
7 },
8 accounts_index::{IndexKey, ScanConfig, ScanError, ScanResult},
9 ancestors::Ancestors,
10 storable_accounts::StorableAccounts,
11 },
12 dashmap::DashMap,
13 log::*,
14 solana_sdk::{
15 account::{AccountSharedData, ReadableAccount},
16 address_lookup_table::{self, error::AddressLookupError, state::AddressLookupTable},
17 clock::{BankId, Slot},
18 message::v0::LoadedAddresses,
19 pubkey::Pubkey,
20 slot_hashes::SlotHashes,
21 transaction::{Result, SanitizedTransaction},
22 transaction_context::TransactionAccount,
23 },
24 solana_svm_transaction::{
25 message_address_table_lookup::SVMMessageAddressTableLookup, svm_message::SVMMessage,
26 },
27 std::{
28 cmp::Reverse,
29 collections::{BinaryHeap, HashSet},
30 ops::RangeBounds,
31 sync::{
32 atomic::{AtomicUsize, Ordering},
33 Arc, Mutex,
34 },
35 },
36};
37
38pub type PubkeyAccountSlot = (Pubkey, AccountSharedData, Slot);
39
40struct TransactionAccountLocksIterator<'a, T: SVMMessage> {
41 transaction: &'a T,
42}
43
44impl<'a, T: SVMMessage> TransactionAccountLocksIterator<'a, T> {
45 pub(crate) fn new(transaction: &'a T) -> Self {
46 Self { transaction }
47 }
48
49 pub(crate) fn accounts_with_is_writable(
50 &self,
51 ) -> impl Iterator<Item = (&'a Pubkey, bool)> + Clone {
52 self.transaction
53 .account_keys()
54 .iter()
55 .enumerate()
56 .map(|(index, key)| (key, self.transaction.is_writable(index)))
57 }
58}
59
60#[derive(Debug)]
62pub struct Accounts {
63 pub accounts_db: Arc<AccountsDb>,
65
66 pub(crate) account_locks: Mutex<AccountLocks>,
69}
70
71pub enum AccountAddressFilter {
72 Exclude, Include, }
75
76impl Accounts {
77 pub fn new(accounts_db: Arc<AccountsDb>) -> Self {
78 Self {
79 accounts_db,
80 account_locks: Mutex::new(AccountLocks::default()),
81 }
82 }
83
84 pub fn load_lookup_table_addresses(
87 &self,
88 ancestors: &Ancestors,
89 address_table_lookup: SVMMessageAddressTableLookup,
90 slot_hashes: &SlotHashes,
91 ) -> std::result::Result<(LoadedAddresses, Slot), AddressLookupError> {
92 let mut loaded_addresses = LoadedAddresses::default();
93 self.load_lookup_table_addresses_into(
94 ancestors,
95 address_table_lookup,
96 slot_hashes,
97 &mut loaded_addresses,
98 )
99 .map(|deactivation_slot| (loaded_addresses, deactivation_slot))
100 }
101
102 pub fn load_lookup_table_addresses_into(
105 &self,
106 ancestors: &Ancestors,
107 address_table_lookup: SVMMessageAddressTableLookup,
108 slot_hashes: &SlotHashes,
109 loaded_addresses: &mut LoadedAddresses,
110 ) -> std::result::Result<Slot, AddressLookupError> {
111 let table_account = self
112 .accounts_db
113 .load_with_fixed_root(ancestors, address_table_lookup.account_key)
114 .map(|(account, _rent)| account)
115 .ok_or(AddressLookupError::LookupTableAccountNotFound)?;
116
117 if table_account.owner() == &address_lookup_table::program::id() {
118 let current_slot = ancestors.max_slot();
119 let lookup_table = AddressLookupTable::deserialize(table_account.data())
120 .map_err(|_ix_err| AddressLookupError::InvalidAccountData)?;
121
122 let writable_addresses = lookup_table.lookup_iter(
124 current_slot,
125 address_table_lookup.writable_indexes,
126 slot_hashes,
127 )?;
128 let readonly_addresses = lookup_table.lookup_iter(
129 current_slot,
130 address_table_lookup.readonly_indexes,
131 slot_hashes,
132 )?;
133
134 loaded_addresses
138 .writable
139 .reserve(address_table_lookup.writable_indexes.len());
140 loaded_addresses
141 .readonly
142 .reserve(address_table_lookup.readonly_indexes.len());
143
144 for address in writable_addresses {
147 loaded_addresses
148 .writable
149 .push(address.ok_or(AddressLookupError::InvalidLookupIndex)?);
150 }
151 for address in readonly_addresses {
152 loaded_addresses
153 .readonly
154 .push(address.ok_or(AddressLookupError::InvalidLookupIndex)?);
155 }
156
157 Ok(lookup_table.meta.deactivation_slot)
158 } else {
159 Err(AddressLookupError::InvalidAccountOwner)
160 }
161 }
162 fn load_slow(
165 &self,
166 ancestors: &Ancestors,
167 pubkey: &Pubkey,
168 load_hint: LoadHint,
169 ) -> Option<(AccountSharedData, Slot)> {
170 self.accounts_db.load(ancestors, pubkey, load_hint)
171 }
172
173 pub fn load_with_fixed_root(
174 &self,
175 ancestors: &Ancestors,
176 pubkey: &Pubkey,
177 ) -> Option<(AccountSharedData, Slot)> {
178 self.load_slow(ancestors, pubkey, LoadHint::FixedMaxRoot)
179 }
180
181 pub fn load_with_fixed_root_do_not_populate_read_cache(
184 &self,
185 ancestors: &Ancestors,
186 pubkey: &Pubkey,
187 ) -> Option<(AccountSharedData, Slot)> {
188 self.load_slow(
189 ancestors,
190 pubkey,
191 LoadHint::FixedMaxRootDoNotPopulateReadCache,
192 )
193 }
194
195 pub fn load_without_fixed_root(
196 &self,
197 ancestors: &Ancestors,
198 pubkey: &Pubkey,
199 ) -> Option<(AccountSharedData, Slot)> {
200 self.load_slow(ancestors, pubkey, LoadHint::Unspecified)
201 }
202
203 pub fn scan_slot<F, B>(&self, slot: Slot, func: F) -> Vec<B>
207 where
208 F: Fn(&LoadedAccount) -> Option<B> + Send + Sync,
209 B: Sync + Send + Default + std::cmp::Eq,
210 {
211 let scan_result = self.accounts_db.scan_account_storage(
212 slot,
213 |loaded_account: &LoadedAccount| {
214 func(loaded_account)
216 },
217 |accum: &DashMap<Pubkey, B>, loaded_account: &LoadedAccount, _data| {
218 let loaded_account_pubkey = *loaded_account.pubkey();
219 if let Some(val) = func(loaded_account) {
220 accum.insert(loaded_account_pubkey, val);
221 }
222 },
223 ScanAccountStorageData::NoData,
224 );
225
226 match scan_result {
227 ScanStorageResult::Cached(cached_result) => cached_result,
228 ScanStorageResult::Stored(stored_result) => stored_result
229 .into_iter()
230 .map(|(_pubkey, val)| val)
231 .collect(),
232 }
233 }
234
235 pub fn load_by_program_slot(
239 &self,
240 slot: Slot,
241 program_id: Option<&Pubkey>,
242 ) -> Vec<TransactionAccount> {
243 self.scan_slot(slot, |stored_account| {
244 program_id
245 .map(|program_id| program_id == stored_account.owner())
246 .unwrap_or(true)
247 .then(|| (*stored_account.pubkey(), stored_account.take_account()))
248 })
249 }
250
251 pub fn load_largest_accounts(
252 &self,
253 ancestors: &Ancestors,
254 bank_id: BankId,
255 num: usize,
256 filter_by_address: &HashSet<Pubkey>,
257 filter: AccountAddressFilter,
258 sort_results: bool,
259 ) -> ScanResult<Vec<(Pubkey, u64)>> {
260 if num == 0 {
261 return Ok(vec![]);
262 }
263 let mut account_balances = BinaryHeap::new();
264 self.accounts_db.scan_accounts(
265 ancestors,
266 bank_id,
267 |option| {
268 if let Some((pubkey, account, _slot)) = option {
269 if account.lamports() == 0 {
270 return;
271 }
272 let contains_address = filter_by_address.contains(pubkey);
273 let collect = match filter {
274 AccountAddressFilter::Exclude => !contains_address,
275 AccountAddressFilter::Include => contains_address,
276 };
277 if !collect {
278 return;
279 }
280 if account_balances.len() == num {
281 let Reverse(entry) = account_balances
282 .peek()
283 .expect("BinaryHeap::peek should succeed when len > 0");
284 if *entry >= (account.lamports(), *pubkey) {
285 return;
286 }
287 account_balances.pop();
288 }
289 account_balances.push(Reverse((account.lamports(), *pubkey)));
290 }
291 },
292 &ScanConfig::new(!sort_results),
293 )?;
294 Ok(account_balances
295 .into_sorted_vec()
296 .into_iter()
297 .map(|Reverse((balance, pubkey))| (pubkey, balance))
298 .collect())
299 }
300
301 #[must_use]
303 pub fn verify_accounts_hash_and_lamports(
304 &self,
305 snapshot_storages_and_slots: (&[Arc<AccountStorageEntry>], &[Slot]),
306 slot: Slot,
307 total_lamports: u64,
308 base: Option<(Slot, u64)>,
309 config: VerifyAccountsHashAndLamportsConfig,
310 ) -> bool {
311 if let Err(err) = self.accounts_db.verify_accounts_hash_and_lamports(
312 snapshot_storages_and_slots,
313 slot,
314 total_lamports,
315 base,
316 config,
317 ) {
318 warn!("verify_accounts_hash failed: {err:?}, slot: {slot}");
319 false
320 } else {
321 true
322 }
323 }
324
325 pub fn is_loadable(lamports: u64) -> bool {
326 lamports > 0
329 }
330
331 fn load_while_filtering<F: Fn(&AccountSharedData) -> bool>(
332 collector: &mut Vec<TransactionAccount>,
333 some_account_tuple: Option<(&Pubkey, AccountSharedData, Slot)>,
334 filter: F,
335 ) {
336 if let Some(mapped_account_tuple) = some_account_tuple
337 .filter(|(_, account, _)| Self::is_loadable(account.lamports()) && filter(account))
338 .map(|(pubkey, account, _slot)| (*pubkey, account))
339 {
340 collector.push(mapped_account_tuple)
341 }
342 }
343
344 fn load_with_slot(
345 collector: &mut Vec<PubkeyAccountSlot>,
346 some_account_tuple: Option<(&Pubkey, AccountSharedData, Slot)>,
347 ) {
348 if let Some(mapped_account_tuple) = some_account_tuple
349 .filter(|(_, account, _)| Self::is_loadable(account.lamports()))
350 .map(|(pubkey, account, slot)| (*pubkey, account, slot))
351 {
352 collector.push(mapped_account_tuple)
353 }
354 }
355
356 pub fn load_by_program(
357 &self,
358 ancestors: &Ancestors,
359 bank_id: BankId,
360 program_id: &Pubkey,
361 config: &ScanConfig,
362 ) -> ScanResult<Vec<TransactionAccount>> {
363 let mut collector = Vec::new();
364 self.accounts_db
365 .scan_accounts(
366 ancestors,
367 bank_id,
368 |some_account_tuple| {
369 Self::load_while_filtering(&mut collector, some_account_tuple, |account| {
370 account.owner() == program_id
371 })
372 },
373 config,
374 )
375 .map(|_| collector)
376 }
377
378 pub fn load_by_program_with_filter<F: Fn(&AccountSharedData) -> bool>(
379 &self,
380 ancestors: &Ancestors,
381 bank_id: BankId,
382 program_id: &Pubkey,
383 filter: F,
384 config: &ScanConfig,
385 ) -> ScanResult<Vec<TransactionAccount>> {
386 let mut collector = Vec::new();
387 self.accounts_db
388 .scan_accounts(
389 ancestors,
390 bank_id,
391 |some_account_tuple| {
392 Self::load_while_filtering(&mut collector, some_account_tuple, |account| {
393 account.owner() == program_id && filter(account)
394 })
395 },
396 config,
397 )
398 .map(|_| collector)
399 }
400
401 fn calc_scan_result_size(account: &AccountSharedData) -> usize {
402 account.data().len()
403 + std::mem::size_of::<AccountSharedData>()
404 + std::mem::size_of::<Pubkey>()
405 }
406
407 fn accumulate_and_check_scan_result_size(
410 sum: &AtomicUsize,
411 account: &AccountSharedData,
412 byte_limit_for_scan: &Option<usize>,
413 ) -> bool {
414 if let Some(byte_limit_for_scan) = byte_limit_for_scan.as_ref() {
415 let added = Self::calc_scan_result_size(account);
416 sum.fetch_add(added, Ordering::Relaxed)
417 .saturating_add(added)
418 > *byte_limit_for_scan
419 } else {
420 false
421 }
422 }
423
424 fn maybe_abort_scan(
425 result: ScanResult<Vec<TransactionAccount>>,
426 config: &ScanConfig,
427 ) -> ScanResult<Vec<TransactionAccount>> {
428 if config.is_aborted() {
429 ScanResult::Err(ScanError::Aborted(
430 "The accumulated scan results exceeded the limit".to_string(),
431 ))
432 } else {
433 result
434 }
435 }
436
437 pub fn load_by_index_key_with_filter<F: Fn(&AccountSharedData) -> bool>(
438 &self,
439 ancestors: &Ancestors,
440 bank_id: BankId,
441 index_key: &IndexKey,
442 filter: F,
443 config: &ScanConfig,
444 byte_limit_for_scan: Option<usize>,
445 ) -> ScanResult<Vec<TransactionAccount>> {
446 let sum = AtomicUsize::default();
447 let config = config.recreate_with_abort();
448 let mut collector = Vec::new();
449 let result = self
450 .accounts_db
451 .index_scan_accounts(
452 ancestors,
453 bank_id,
454 *index_key,
455 |some_account_tuple| {
456 Self::load_while_filtering(&mut collector, some_account_tuple, |account| {
457 let use_account = filter(account);
458 if use_account
459 && Self::accumulate_and_check_scan_result_size(
460 &sum,
461 account,
462 &byte_limit_for_scan,
463 )
464 {
465 config.abort();
467 }
468 use_account
469 });
470 },
471 &config,
472 )
473 .map(|_| collector);
474 Self::maybe_abort_scan(result, &config)
475 }
476
477 pub fn account_indexes_include_key(&self, key: &Pubkey) -> bool {
478 self.accounts_db.account_indexes.include_key(key)
479 }
480
481 pub fn load_all(
482 &self,
483 ancestors: &Ancestors,
484 bank_id: BankId,
485 sort_results: bool,
486 ) -> ScanResult<Vec<PubkeyAccountSlot>> {
487 let mut collector = Vec::new();
488 self.accounts_db
489 .scan_accounts(
490 ancestors,
491 bank_id,
492 |some_account_tuple| {
493 if let Some((pubkey, account, slot)) = some_account_tuple
494 .filter(|(_, account, _)| Self::is_loadable(account.lamports()))
495 {
496 collector.push((*pubkey, account, slot))
497 }
498 },
499 &ScanConfig::new(!sort_results),
500 )
501 .map(|_| collector)
502 }
503
504 pub fn scan_all<F>(
505 &self,
506 ancestors: &Ancestors,
507 bank_id: BankId,
508 scan_func: F,
509 sort_results: bool,
510 ) -> ScanResult<()>
511 where
512 F: FnMut(Option<(&Pubkey, AccountSharedData, Slot)>),
513 {
514 self.accounts_db.scan_accounts(
515 ancestors,
516 bank_id,
517 scan_func,
518 &ScanConfig::new(!sort_results),
519 )
520 }
521
522 pub fn hold_range_in_memory<R>(
523 &self,
524 range: &R,
525 start_holding: bool,
526 thread_pool: &rayon::ThreadPool,
527 ) where
528 R: RangeBounds<Pubkey> + std::fmt::Debug + Sync,
529 {
530 self.accounts_db
531 .accounts_index
532 .hold_range_in_memory(range, start_holding, thread_pool)
533 }
534
535 pub fn load_to_collect_rent_eagerly<R: RangeBounds<Pubkey> + std::fmt::Debug>(
536 &self,
537 ancestors: &Ancestors,
538 range: R,
539 ) -> Vec<PubkeyAccountSlot> {
540 let mut collector = Vec::new();
541 self.accounts_db.range_scan_accounts(
542 "", ancestors,
544 range,
545 &ScanConfig::default(),
546 |option| Self::load_with_slot(&mut collector, option),
547 );
548 collector
549 }
550
551 pub fn store_slow_uncached(&self, slot: Slot, pubkey: &Pubkey, account: &AccountSharedData) {
555 self.accounts_db.store_uncached(slot, &[(pubkey, account)]);
556 }
557
558 #[must_use]
561 pub fn lock_accounts<'a, Tx: SVMMessage + 'a>(
562 &self,
563 txs: impl Iterator<Item = &'a Tx>,
564 tx_account_lock_limit: usize,
565 ) -> Vec<Result<()>> {
566 let tx_account_locks_results: Vec<Result<_>> = txs
568 .map(|tx| {
569 validate_account_locks(tx.account_keys(), tx_account_lock_limit)
570 .map(|_| TransactionAccountLocksIterator::new(tx))
571 })
572 .collect();
573 self.lock_accounts_inner(tx_account_locks_results)
574 }
575
576 #[must_use]
577 pub fn lock_accounts_with_results<'a>(
578 &self,
579 txs: impl Iterator<Item = &'a (impl SVMMessage + 'a)>,
580 results: impl Iterator<Item = Result<()>>,
581 tx_account_lock_limit: usize,
582 ) -> Vec<Result<()>> {
583 let tx_account_locks_results: Vec<Result<_>> = txs
585 .zip(results)
586 .map(|(tx, result)| match result {
587 Ok(()) => validate_account_locks(tx.account_keys(), tx_account_lock_limit)
588 .map(|_| TransactionAccountLocksIterator::new(tx)),
589 Err(err) => Err(err),
590 })
591 .collect();
592 self.lock_accounts_inner(tx_account_locks_results)
593 }
594
595 #[must_use]
596 fn lock_accounts_inner(
597 &self,
598 tx_account_locks_results: Vec<Result<TransactionAccountLocksIterator<impl SVMMessage>>>,
599 ) -> Vec<Result<()>> {
600 let account_locks = &mut self.account_locks.lock().unwrap();
601 tx_account_locks_results
602 .into_iter()
603 .map(|tx_account_locks_result| match tx_account_locks_result {
604 Ok(tx_account_locks) => {
605 account_locks.try_lock_accounts(tx_account_locks.accounts_with_is_writable())
606 }
607 Err(err) => Err(err),
608 })
609 .collect()
610 }
611
612 pub fn unlock_accounts<'a, Tx: SVMMessage + 'a>(
614 &self,
615 txs_and_results: impl Iterator<Item = (&'a Tx, &'a Result<()>)> + Clone,
616 ) {
617 if !txs_and_results.clone().any(|(_, res)| res.is_ok()) {
618 return;
619 }
620
621 let mut account_locks = self.account_locks.lock().unwrap();
622 debug!("bank unlock accounts");
623 for (tx, res) in txs_and_results {
624 if res.is_ok() {
625 let tx_account_locks = TransactionAccountLocksIterator::new(tx);
626 account_locks.unlock_accounts(tx_account_locks.accounts_with_is_writable());
627 }
628 }
629 }
630
631 pub fn store_cached<'a>(
633 &self,
634 accounts: impl StorableAccounts<'a>,
635 transactions: Option<&'a [&'a SanitizedTransaction]>,
636 ) {
637 self.accounts_db
638 .store_cached_inline_update_index(accounts, transactions);
639 }
640
641 pub fn store_accounts_cached<'a>(&self, accounts: impl StorableAccounts<'a>) {
642 self.accounts_db.store_cached(accounts, None)
643 }
644
645 pub fn add_root(&self, slot: Slot) -> AccountsAddRootTiming {
647 self.accounts_db.add_root(slot)
648 }
649}
650
651#[cfg(test)]
652mod tests {
653 use {
654 super::*,
655 solana_sdk::{
656 account::{AccountSharedData, WritableAccount},
657 address_lookup_table::state::LookupTableMeta,
658 hash::Hash,
659 instruction::CompiledInstruction,
660 message::{v0::MessageAddressTableLookup, Message, MessageHeader},
661 native_loader,
662 signature::{signers::Signers, Keypair, Signer},
663 transaction::{Transaction, TransactionError, MAX_TX_ACCOUNT_LOCKS},
664 },
665 std::{
666 borrow::Cow,
667 iter,
668 sync::atomic::{AtomicBool, AtomicU64, Ordering},
669 thread, time,
670 },
671 };
672
673 fn new_sanitized_tx<T: Signers>(
674 from_keypairs: &T,
675 message: Message,
676 recent_blockhash: Hash,
677 ) -> SanitizedTransaction {
678 SanitizedTransaction::from_transaction_for_tests(Transaction::new(
679 from_keypairs,
680 message,
681 recent_blockhash,
682 ))
683 }
684
685 #[test]
686 fn test_hold_range_in_memory() {
687 let accounts_db = AccountsDb::default_for_tests();
688 let accts = Accounts::new(Arc::new(accounts_db));
689 let range = Pubkey::from([0; 32])..=Pubkey::from([0xff; 32]);
690 accts.hold_range_in_memory(&range, true, &test_thread_pool());
691 accts.hold_range_in_memory(&range, false, &test_thread_pool());
692 accts.hold_range_in_memory(&range, true, &test_thread_pool());
693 accts.hold_range_in_memory(&range, true, &test_thread_pool());
694 accts.hold_range_in_memory(&range, false, &test_thread_pool());
695 accts.hold_range_in_memory(&range, false, &test_thread_pool());
696 }
697
698 #[test]
699 fn test_hold_range_in_memory2() {
700 let accounts_db = AccountsDb::default_for_tests();
701 let accts = Accounts::new(Arc::new(accounts_db));
702 let range = Pubkey::from([0; 32])..=Pubkey::from([0xff; 32]);
703 let idx = &accts.accounts_db.accounts_index;
704 let bins = idx.account_maps.len();
705 let bins_2 = bins * 2;
707 let binner = crate::pubkey_bins::PubkeyBinCalculator24::new(bins_2);
708 let range2 =
709 binner.lowest_pubkey_from_bin(0, bins_2)..binner.lowest_pubkey_from_bin(1, bins_2);
710 let range2_inclusive = range2.start..=range2.end;
711 assert_eq!(0, idx.bin_calculator.bin_from_pubkey(&range2.start));
712 assert_eq!(0, idx.bin_calculator.bin_from_pubkey(&range2.end));
713 accts.hold_range_in_memory(&range, true, &test_thread_pool());
714 idx.account_maps.iter().for_each(|map| {
715 assert_eq!(
716 map.cache_ranges_held.read().unwrap().to_vec(),
717 vec![range.clone()]
718 );
719 });
720 accts.hold_range_in_memory(&range2, true, &test_thread_pool());
721 idx.account_maps.iter().enumerate().for_each(|(bin, map)| {
722 let expected = if bin == 0 {
723 vec![range.clone(), range2_inclusive.clone()]
724 } else {
725 vec![range.clone()]
726 };
727 assert_eq!(
728 map.cache_ranges_held.read().unwrap().to_vec(),
729 expected,
730 "bin: {bin}"
731 );
732 });
733 accts.hold_range_in_memory(&range, false, &test_thread_pool());
734 accts.hold_range_in_memory(&range2, false, &test_thread_pool());
735 }
736
737 fn test_thread_pool() -> rayon::ThreadPool {
738 crate::accounts_db::make_min_priority_thread_pool()
739 }
740
741 #[test]
742 fn test_load_lookup_table_addresses_account_not_found() {
743 let ancestors = vec![(0, 0)].into_iter().collect();
744 let accounts_db = AccountsDb::new_single_for_tests();
745 let accounts = Accounts::new(Arc::new(accounts_db));
746
747 let invalid_table_key = Pubkey::new_unique();
748 let address_table_lookup = MessageAddressTableLookup {
749 account_key: invalid_table_key,
750 writable_indexes: vec![],
751 readonly_indexes: vec![],
752 };
753
754 assert_eq!(
755 accounts.load_lookup_table_addresses(
756 &ancestors,
757 SVMMessageAddressTableLookup::from(&address_table_lookup),
758 &SlotHashes::default(),
759 ),
760 Err(AddressLookupError::LookupTableAccountNotFound),
761 );
762 }
763
764 #[test]
765 fn test_load_lookup_table_addresses_invalid_account_owner() {
766 let ancestors = vec![(0, 0)].into_iter().collect();
767 let accounts_db = AccountsDb::new_single_for_tests();
768 let accounts = Accounts::new(Arc::new(accounts_db));
769
770 let invalid_table_key = Pubkey::new_unique();
771 let mut invalid_table_account = AccountSharedData::default();
772 invalid_table_account.set_lamports(1);
773 accounts.store_slow_uncached(0, &invalid_table_key, &invalid_table_account);
774
775 let address_table_lookup = MessageAddressTableLookup {
776 account_key: invalid_table_key,
777 writable_indexes: vec![],
778 readonly_indexes: vec![],
779 };
780
781 assert_eq!(
782 accounts.load_lookup_table_addresses(
783 &ancestors,
784 SVMMessageAddressTableLookup::from(&address_table_lookup),
785 &SlotHashes::default(),
786 ),
787 Err(AddressLookupError::InvalidAccountOwner),
788 );
789 }
790
791 #[test]
792 fn test_load_lookup_table_addresses_invalid_account_data() {
793 let ancestors = vec![(0, 0)].into_iter().collect();
794 let accounts_db = AccountsDb::new_single_for_tests();
795 let accounts = Accounts::new(Arc::new(accounts_db));
796
797 let invalid_table_key = Pubkey::new_unique();
798 let invalid_table_account =
799 AccountSharedData::new(1, 0, &address_lookup_table::program::id());
800 accounts.store_slow_uncached(0, &invalid_table_key, &invalid_table_account);
801
802 let address_table_lookup = MessageAddressTableLookup {
803 account_key: invalid_table_key,
804 writable_indexes: vec![],
805 readonly_indexes: vec![],
806 };
807
808 assert_eq!(
809 accounts.load_lookup_table_addresses(
810 &ancestors,
811 SVMMessageAddressTableLookup::from(&address_table_lookup),
812 &SlotHashes::default(),
813 ),
814 Err(AddressLookupError::InvalidAccountData),
815 );
816 }
817
818 #[test]
819 fn test_load_lookup_table_addresses() {
820 let ancestors = vec![(1, 1), (0, 0)].into_iter().collect();
821 let accounts_db = AccountsDb::new_single_for_tests();
822 let accounts = Accounts::new(Arc::new(accounts_db));
823
824 let table_key = Pubkey::new_unique();
825 let table_addresses = vec![Pubkey::new_unique(), Pubkey::new_unique()];
826 let table_account = {
827 let table_state = AddressLookupTable {
828 meta: LookupTableMeta::default(),
829 addresses: Cow::Owned(table_addresses.clone()),
830 };
831 AccountSharedData::create(
832 1,
833 table_state.serialize_for_tests().unwrap(),
834 address_lookup_table::program::id(),
835 false,
836 0,
837 )
838 };
839 accounts.store_slow_uncached(0, &table_key, &table_account);
840
841 let address_table_lookup = MessageAddressTableLookup {
842 account_key: table_key,
843 writable_indexes: vec![0],
844 readonly_indexes: vec![1],
845 };
846
847 assert_eq!(
848 accounts.load_lookup_table_addresses(
849 &ancestors,
850 SVMMessageAddressTableLookup::from(&address_table_lookup),
851 &SlotHashes::default(),
852 ),
853 Ok((
854 LoadedAddresses {
855 writable: vec![table_addresses[0]],
856 readonly: vec![table_addresses[1]],
857 },
858 u64::MAX
859 )),
860 );
861 }
862
863 #[test]
864 fn test_load_by_program_slot() {
865 let accounts_db = AccountsDb::new_single_for_tests();
866 let accounts = Accounts::new(Arc::new(accounts_db));
867
868 let pubkey0 = solana_sdk::pubkey::new_rand();
870 let account0 = AccountSharedData::new(1, 0, &Pubkey::from([2; 32]));
871 accounts.store_slow_uncached(0, &pubkey0, &account0);
872 let pubkey1 = solana_sdk::pubkey::new_rand();
873 let account1 = AccountSharedData::new(1, 0, &Pubkey::from([2; 32]));
874 accounts.store_slow_uncached(0, &pubkey1, &account1);
875 let pubkey2 = solana_sdk::pubkey::new_rand();
876 let account2 = AccountSharedData::new(1, 0, &Pubkey::from([3; 32]));
877 accounts.store_slow_uncached(0, &pubkey2, &account2);
878
879 let loaded = accounts.load_by_program_slot(0, Some(&Pubkey::from([2; 32])));
880 assert_eq!(loaded.len(), 2);
881 let loaded = accounts.load_by_program_slot(0, Some(&Pubkey::from([3; 32])));
882 assert_eq!(loaded, vec![(pubkey2, account2)]);
883 let loaded = accounts.load_by_program_slot(0, Some(&Pubkey::from([4; 32])));
884 assert_eq!(loaded, vec![]);
885 }
886
887 #[test]
888 fn test_accounts_empty_bank_hash_stats() {
889 let accounts_db = AccountsDb::new_single_for_tests();
890 let accounts = Accounts::new(Arc::new(accounts_db));
891 assert!(accounts.accounts_db.get_bank_hash_stats(0).is_some());
892 assert!(accounts.accounts_db.get_bank_hash_stats(1).is_none());
893 }
894
895 #[test]
896 fn test_lock_accounts_with_duplicates() {
897 let accounts_db = AccountsDb::new_single_for_tests();
898 let accounts = Accounts::new(Arc::new(accounts_db));
899
900 let keypair = Keypair::new();
901 let message = Message {
902 header: MessageHeader {
903 num_required_signatures: 1,
904 ..MessageHeader::default()
905 },
906 account_keys: vec![keypair.pubkey(), keypair.pubkey()],
907 ..Message::default()
908 };
909
910 let tx = new_sanitized_tx(&[&keypair], message, Hash::default());
911 let results = accounts.lock_accounts([tx].iter(), MAX_TX_ACCOUNT_LOCKS);
912 assert_eq!(results[0], Err(TransactionError::AccountLoadedTwice));
913 }
914
915 #[test]
916 fn test_lock_accounts_with_too_many_accounts() {
917 let accounts_db = AccountsDb::new_single_for_tests();
918 let accounts = Accounts::new(Arc::new(accounts_db));
919
920 let keypair = Keypair::new();
921
922 {
924 let num_account_keys = MAX_TX_ACCOUNT_LOCKS;
925 let mut account_keys: Vec<_> = (0..num_account_keys)
926 .map(|_| Pubkey::new_unique())
927 .collect();
928 account_keys[0] = keypair.pubkey();
929 let message = Message {
930 header: MessageHeader {
931 num_required_signatures: 1,
932 ..MessageHeader::default()
933 },
934 account_keys,
935 ..Message::default()
936 };
937
938 let txs = vec![new_sanitized_tx(&[&keypair], message, Hash::default())];
939 let results = accounts.lock_accounts(txs.iter(), MAX_TX_ACCOUNT_LOCKS);
940 assert_eq!(results, vec![Ok(())]);
941 accounts.unlock_accounts(txs.iter().zip(&results));
942 }
943
944 {
946 let num_account_keys = MAX_TX_ACCOUNT_LOCKS + 1;
947 let mut account_keys: Vec<_> = (0..num_account_keys)
948 .map(|_| Pubkey::new_unique())
949 .collect();
950 account_keys[0] = keypair.pubkey();
951 let message = Message {
952 header: MessageHeader {
953 num_required_signatures: 1,
954 ..MessageHeader::default()
955 },
956 account_keys,
957 ..Message::default()
958 };
959
960 let txs = vec![new_sanitized_tx(&[&keypair], message, Hash::default())];
961 let results = accounts.lock_accounts(txs.iter(), MAX_TX_ACCOUNT_LOCKS);
962 assert_eq!(results[0], Err(TransactionError::TooManyAccountLocks));
963 }
964 }
965
966 #[test]
967 fn test_accounts_locks() {
968 let keypair0 = Keypair::new();
969 let keypair1 = Keypair::new();
970 let keypair2 = Keypair::new();
971 let keypair3 = Keypair::new();
972
973 let account0 = AccountSharedData::new(1, 0, &Pubkey::default());
974 let account1 = AccountSharedData::new(2, 0, &Pubkey::default());
975 let account2 = AccountSharedData::new(3, 0, &Pubkey::default());
976 let account3 = AccountSharedData::new(4, 0, &Pubkey::default());
977
978 let accounts_db = AccountsDb::new_single_for_tests();
979 let accounts = Accounts::new(Arc::new(accounts_db));
980 accounts.store_for_tests(0, &keypair0.pubkey(), &account0);
981 accounts.store_for_tests(0, &keypair1.pubkey(), &account1);
982 accounts.store_for_tests(0, &keypair2.pubkey(), &account2);
983 accounts.store_for_tests(0, &keypair3.pubkey(), &account3);
984
985 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
986 let message = Message::new_with_compiled_instructions(
987 1,
988 0,
989 2,
990 vec![keypair0.pubkey(), keypair1.pubkey(), native_loader::id()],
991 Hash::default(),
992 instructions,
993 );
994 let tx = new_sanitized_tx(&[&keypair0], message, Hash::default());
995 let results0 = accounts.lock_accounts([tx.clone()].iter(), MAX_TX_ACCOUNT_LOCKS);
996
997 assert_eq!(results0, vec![Ok(())]);
998 assert!(accounts
999 .account_locks
1000 .lock()
1001 .unwrap()
1002 .is_locked_readonly(&keypair1.pubkey()));
1003
1004 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1005 let message = Message::new_with_compiled_instructions(
1006 1,
1007 0,
1008 2,
1009 vec![keypair2.pubkey(), keypair1.pubkey(), native_loader::id()],
1010 Hash::default(),
1011 instructions,
1012 );
1013 let tx0 = new_sanitized_tx(&[&keypair2], message, Hash::default());
1014 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1015 let message = Message::new_with_compiled_instructions(
1016 1,
1017 0,
1018 2,
1019 vec![keypair1.pubkey(), keypair3.pubkey(), native_loader::id()],
1020 Hash::default(),
1021 instructions,
1022 );
1023 let tx1 = new_sanitized_tx(&[&keypair1], message, Hash::default());
1024 let txs = vec![tx0, tx1];
1025 let results1 = accounts.lock_accounts(txs.iter(), MAX_TX_ACCOUNT_LOCKS);
1026 assert_eq!(
1027 results1,
1028 vec![
1029 Ok(()), Err(TransactionError::AccountInUse), ],
1032 );
1033 assert!(accounts
1034 .account_locks
1035 .lock()
1036 .unwrap()
1037 .is_locked_readonly(&keypair1.pubkey()));
1038
1039 accounts.unlock_accounts(iter::once(&tx).zip(&results0));
1040 accounts.unlock_accounts(txs.iter().zip(&results1));
1041 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1042 let message = Message::new_with_compiled_instructions(
1043 1,
1044 0,
1045 2,
1046 vec![keypair1.pubkey(), keypair3.pubkey(), native_loader::id()],
1047 Hash::default(),
1048 instructions,
1049 );
1050 let tx = new_sanitized_tx(&[&keypair1], message, Hash::default());
1051 let results2 = accounts.lock_accounts([tx].iter(), MAX_TX_ACCOUNT_LOCKS);
1052 assert_eq!(
1053 results2,
1054 vec![Ok(())] );
1056
1057 assert!(!accounts
1059 .account_locks
1060 .lock()
1061 .unwrap()
1062 .is_locked_readonly(&keypair1.pubkey()));
1063 }
1064
1065 #[test]
1066 fn test_accounts_locks_multithreaded() {
1067 let counter = Arc::new(AtomicU64::new(0));
1068 let exit = Arc::new(AtomicBool::new(false));
1069
1070 let keypair0 = Keypair::new();
1071 let keypair1 = Keypair::new();
1072 let keypair2 = Keypair::new();
1073
1074 let account0 = AccountSharedData::new(1, 0, &Pubkey::default());
1075 let account1 = AccountSharedData::new(2, 0, &Pubkey::default());
1076 let account2 = AccountSharedData::new(3, 0, &Pubkey::default());
1077
1078 let accounts_db = AccountsDb::new_single_for_tests();
1079 let accounts = Accounts::new(Arc::new(accounts_db));
1080 accounts.store_for_tests(0, &keypair0.pubkey(), &account0);
1081 accounts.store_for_tests(0, &keypair1.pubkey(), &account1);
1082 accounts.store_for_tests(0, &keypair2.pubkey(), &account2);
1083
1084 let accounts_arc = Arc::new(accounts);
1085
1086 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1087 let readonly_message = Message::new_with_compiled_instructions(
1088 1,
1089 0,
1090 2,
1091 vec![keypair0.pubkey(), keypair1.pubkey(), native_loader::id()],
1092 Hash::default(),
1093 instructions,
1094 );
1095 let readonly_tx = new_sanitized_tx(&[&keypair0], readonly_message, Hash::default());
1096
1097 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1098 let writable_message = Message::new_with_compiled_instructions(
1099 1,
1100 0,
1101 2,
1102 vec![keypair1.pubkey(), keypair2.pubkey(), native_loader::id()],
1103 Hash::default(),
1104 instructions,
1105 );
1106 let writable_tx = new_sanitized_tx(&[&keypair1], writable_message, Hash::default());
1107
1108 let counter_clone = counter.clone();
1109 let accounts_clone = accounts_arc.clone();
1110 let exit_clone = exit.clone();
1111 thread::spawn(move || loop {
1112 let txs = vec![writable_tx.clone()];
1113 let results = accounts_clone
1114 .clone()
1115 .lock_accounts(txs.iter(), MAX_TX_ACCOUNT_LOCKS);
1116 for result in results.iter() {
1117 if result.is_ok() {
1118 counter_clone.clone().fetch_add(1, Ordering::SeqCst);
1119 }
1120 }
1121 accounts_clone.unlock_accounts(txs.iter().zip(&results));
1122 if exit_clone.clone().load(Ordering::Relaxed) {
1123 break;
1124 }
1125 });
1126 let counter_clone = counter;
1127 for _ in 0..5 {
1128 let txs = vec![readonly_tx.clone()];
1129 let results = accounts_arc
1130 .clone()
1131 .lock_accounts(txs.iter(), MAX_TX_ACCOUNT_LOCKS);
1132 if results[0].is_ok() {
1133 let counter_value = counter_clone.clone().load(Ordering::SeqCst);
1134 thread::sleep(time::Duration::from_millis(50));
1135 assert_eq!(counter_value, counter_clone.clone().load(Ordering::SeqCst));
1136 }
1137 accounts_arc.unlock_accounts(txs.iter().zip(&results));
1138 thread::sleep(time::Duration::from_millis(50));
1139 }
1140 exit.store(true, Ordering::Relaxed);
1141 }
1142
1143 #[test]
1144 fn test_demote_program_write_locks() {
1145 let keypair0 = Keypair::new();
1146 let keypair1 = Keypair::new();
1147 let keypair2 = Keypair::new();
1148 let keypair3 = Keypair::new();
1149
1150 let account0 = AccountSharedData::new(1, 0, &Pubkey::default());
1151 let account1 = AccountSharedData::new(2, 0, &Pubkey::default());
1152 let account2 = AccountSharedData::new(3, 0, &Pubkey::default());
1153 let account3 = AccountSharedData::new(4, 0, &Pubkey::default());
1154
1155 let accounts_db = AccountsDb::new_single_for_tests();
1156 let accounts = Accounts::new(Arc::new(accounts_db));
1157 accounts.store_for_tests(0, &keypair0.pubkey(), &account0);
1158 accounts.store_for_tests(0, &keypair1.pubkey(), &account1);
1159 accounts.store_for_tests(0, &keypair2.pubkey(), &account2);
1160 accounts.store_for_tests(0, &keypair3.pubkey(), &account3);
1161
1162 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1163 let message = Message::new_with_compiled_instructions(
1164 1,
1165 0,
1166 0, vec![keypair0.pubkey(), keypair1.pubkey(), native_loader::id()],
1168 Hash::default(),
1169 instructions,
1170 );
1171 let tx = new_sanitized_tx(&[&keypair0], message, Hash::default());
1172 let results0 = accounts.lock_accounts([tx].iter(), MAX_TX_ACCOUNT_LOCKS);
1173
1174 assert!(results0[0].is_ok());
1175 assert!(accounts
1177 .account_locks
1178 .lock()
1179 .unwrap()
1180 .is_locked_readonly(&native_loader::id()));
1181 assert!(accounts
1183 .account_locks
1184 .lock()
1185 .unwrap()
1186 .is_locked_write(&keypair0.pubkey()));
1187 assert!(accounts
1188 .account_locks
1189 .lock()
1190 .unwrap()
1191 .is_locked_write(&keypair1.pubkey()));
1192 }
1193
1194 impl Accounts {
1195 pub fn store_for_tests(&self, slot: Slot, pubkey: &Pubkey, account: &AccountSharedData) {
1197 self.accounts_db.store_for_tests(slot, &[(pubkey, account)])
1198 }
1199
1200 pub fn add_root_and_flush_write_cache(&self, slot: Slot) {
1203 self.add_root(slot);
1204 self.accounts_db.flush_accounts_cache_slot_for_tests(slot);
1205 }
1206 }
1207
1208 #[test]
1209 fn test_accounts_locks_with_results() {
1210 let keypair0 = Keypair::new();
1211 let keypair1 = Keypair::new();
1212 let keypair2 = Keypair::new();
1213 let keypair3 = Keypair::new();
1214
1215 let account0 = AccountSharedData::new(1, 0, &Pubkey::default());
1216 let account1 = AccountSharedData::new(2, 0, &Pubkey::default());
1217 let account2 = AccountSharedData::new(3, 0, &Pubkey::default());
1218 let account3 = AccountSharedData::new(4, 0, &Pubkey::default());
1219
1220 let accounts_db = AccountsDb::new_single_for_tests();
1221 let accounts = Accounts::new(Arc::new(accounts_db));
1222 accounts.store_for_tests(0, &keypair0.pubkey(), &account0);
1223 accounts.store_for_tests(0, &keypair1.pubkey(), &account1);
1224 accounts.store_for_tests(0, &keypair2.pubkey(), &account2);
1225 accounts.store_for_tests(0, &keypair3.pubkey(), &account3);
1226
1227 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1228 let message = Message::new_with_compiled_instructions(
1229 1,
1230 0,
1231 2,
1232 vec![keypair1.pubkey(), keypair0.pubkey(), native_loader::id()],
1233 Hash::default(),
1234 instructions,
1235 );
1236 let tx0 = new_sanitized_tx(&[&keypair1], message, Hash::default());
1237 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1238 let message = Message::new_with_compiled_instructions(
1239 1,
1240 0,
1241 2,
1242 vec![keypair2.pubkey(), keypair0.pubkey(), native_loader::id()],
1243 Hash::default(),
1244 instructions,
1245 );
1246 let tx1 = new_sanitized_tx(&[&keypair2], message, Hash::default());
1247 let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1248 let message = Message::new_with_compiled_instructions(
1249 1,
1250 0,
1251 2,
1252 vec![keypair3.pubkey(), keypair0.pubkey(), native_loader::id()],
1253 Hash::default(),
1254 instructions,
1255 );
1256 let tx2 = new_sanitized_tx(&[&keypair3], message, Hash::default());
1257 let txs = vec![tx0, tx1, tx2];
1258
1259 let qos_results = vec![
1260 Ok(()),
1261 Err(TransactionError::WouldExceedMaxBlockCostLimit),
1262 Ok(()),
1263 ];
1264
1265 let results = accounts.lock_accounts_with_results(
1266 txs.iter(),
1267 qos_results.into_iter(),
1268 MAX_TX_ACCOUNT_LOCKS,
1269 );
1270
1271 assert_eq!(
1272 results,
1273 vec![
1274 Ok(()), Err(TransactionError::WouldExceedMaxBlockCostLimit), Ok(()), ],
1278 );
1279
1280 assert!(accounts
1282 .account_locks
1283 .lock()
1284 .unwrap()
1285 .is_locked_readonly(&keypair0.pubkey()));
1286 assert!(!accounts
1288 .account_locks
1289 .lock()
1290 .unwrap()
1291 .is_locked_write(&keypair2.pubkey()));
1292 }
1293
1294 #[test]
1295 fn huge_clean() {
1296 solana_logger::setup();
1297 let accounts_db = AccountsDb::new_single_for_tests();
1298 let accounts = Accounts::new(Arc::new(accounts_db));
1299 let mut old_pubkey = Pubkey::default();
1300 let zero_account = AccountSharedData::new(0, 0, AccountSharedData::default().owner());
1301 info!("storing..");
1302 for i in 0..2_000 {
1303 let pubkey = solana_sdk::pubkey::new_rand();
1304 let account = AccountSharedData::new(i + 1, 0, AccountSharedData::default().owner());
1305 accounts.store_for_tests(i, &pubkey, &account);
1306 accounts.store_for_tests(i, &old_pubkey, &zero_account);
1307 old_pubkey = pubkey;
1308 accounts.add_root_and_flush_write_cache(i);
1309
1310 if i % 1_000 == 0 {
1311 info!(" store {}", i);
1312 }
1313 }
1314 info!("done..cleaning..");
1315 accounts.accounts_db.clean_accounts_for_tests();
1316 }
1317
1318 #[test]
1319 fn test_load_largest_accounts() {
1320 let accounts_db = AccountsDb::new_single_for_tests();
1321 let accounts = Accounts::new(Arc::new(accounts_db));
1322
1323 let mut keys = vec![];
1333 for _idx in 0..3 {
1334 keys.push(Pubkey::new_unique());
1335 }
1336 keys.sort();
1337 let pubkey2 = keys.pop().unwrap();
1338 let pubkey1 = keys.pop().unwrap();
1339 let pubkey0 = keys.pop().unwrap();
1340 let account0 = AccountSharedData::new(42, 0, &Pubkey::default());
1341 accounts.store_for_tests(0, &pubkey0, &account0);
1342 let account1 = AccountSharedData::new(42, 0, &Pubkey::default());
1343 accounts.store_for_tests(0, &pubkey1, &account1);
1344 let account2 = AccountSharedData::new(41, 0, &Pubkey::default());
1345 accounts.store_for_tests(0, &pubkey2, &account2);
1346
1347 let ancestors = vec![(0, 0)].into_iter().collect();
1348 let all_pubkeys: HashSet<_> = vec![pubkey0, pubkey1, pubkey2].into_iter().collect();
1349
1350 let bank_id = 0;
1352 assert_eq!(
1353 accounts
1354 .load_largest_accounts(
1355 &ancestors,
1356 bank_id,
1357 0,
1358 &HashSet::new(),
1359 AccountAddressFilter::Exclude,
1360 false
1361 )
1362 .unwrap(),
1363 vec![]
1364 );
1365 assert_eq!(
1366 accounts
1367 .load_largest_accounts(
1368 &ancestors,
1369 bank_id,
1370 0,
1371 &all_pubkeys,
1372 AccountAddressFilter::Include,
1373 false
1374 )
1375 .unwrap(),
1376 vec![]
1377 );
1378
1379 assert!(pubkey1 > pubkey0);
1381 assert_eq!(
1382 accounts
1383 .load_largest_accounts(
1384 &ancestors,
1385 bank_id,
1386 1,
1387 &HashSet::new(),
1388 AccountAddressFilter::Exclude,
1389 false
1390 )
1391 .unwrap(),
1392 vec![(pubkey1, 42)]
1393 );
1394 assert_eq!(
1395 accounts
1396 .load_largest_accounts(
1397 &ancestors,
1398 bank_id,
1399 2,
1400 &HashSet::new(),
1401 AccountAddressFilter::Exclude,
1402 false
1403 )
1404 .unwrap(),
1405 vec![(pubkey1, 42), (pubkey0, 42)]
1406 );
1407 assert_eq!(
1408 accounts
1409 .load_largest_accounts(
1410 &ancestors,
1411 bank_id,
1412 3,
1413 &HashSet::new(),
1414 AccountAddressFilter::Exclude,
1415 false
1416 )
1417 .unwrap(),
1418 vec![(pubkey1, 42), (pubkey0, 42), (pubkey2, 41)]
1419 );
1420
1421 assert_eq!(
1423 accounts
1424 .load_largest_accounts(
1425 &ancestors,
1426 bank_id,
1427 6,
1428 &HashSet::new(),
1429 AccountAddressFilter::Exclude,
1430 false
1431 )
1432 .unwrap(),
1433 vec![(pubkey1, 42), (pubkey0, 42), (pubkey2, 41)]
1434 );
1435
1436 let exclude1: HashSet<_> = vec![pubkey1].into_iter().collect();
1438 assert_eq!(
1439 accounts
1440 .load_largest_accounts(
1441 &ancestors,
1442 bank_id,
1443 1,
1444 &exclude1,
1445 AccountAddressFilter::Exclude,
1446 false
1447 )
1448 .unwrap(),
1449 vec![(pubkey0, 42)]
1450 );
1451 assert_eq!(
1452 accounts
1453 .load_largest_accounts(
1454 &ancestors,
1455 bank_id,
1456 2,
1457 &exclude1,
1458 AccountAddressFilter::Exclude,
1459 false
1460 )
1461 .unwrap(),
1462 vec![(pubkey0, 42), (pubkey2, 41)]
1463 );
1464 assert_eq!(
1465 accounts
1466 .load_largest_accounts(
1467 &ancestors,
1468 bank_id,
1469 3,
1470 &exclude1,
1471 AccountAddressFilter::Exclude,
1472 false
1473 )
1474 .unwrap(),
1475 vec![(pubkey0, 42), (pubkey2, 41)]
1476 );
1477
1478 let include1_2: HashSet<_> = vec![pubkey1, pubkey2].into_iter().collect();
1480 assert_eq!(
1481 accounts
1482 .load_largest_accounts(
1483 &ancestors,
1484 bank_id,
1485 1,
1486 &include1_2,
1487 AccountAddressFilter::Include,
1488 false
1489 )
1490 .unwrap(),
1491 vec![(pubkey1, 42)]
1492 );
1493 assert_eq!(
1494 accounts
1495 .load_largest_accounts(
1496 &ancestors,
1497 bank_id,
1498 2,
1499 &include1_2,
1500 AccountAddressFilter::Include,
1501 false
1502 )
1503 .unwrap(),
1504 vec![(pubkey1, 42), (pubkey2, 41)]
1505 );
1506 assert_eq!(
1507 accounts
1508 .load_largest_accounts(
1509 &ancestors,
1510 bank_id,
1511 3,
1512 &include1_2,
1513 AccountAddressFilter::Include,
1514 false
1515 )
1516 .unwrap(),
1517 vec![(pubkey1, 42), (pubkey2, 41)]
1518 );
1519 }
1520
1521 fn zero_len_account_size() -> usize {
1522 std::mem::size_of::<AccountSharedData>() + std::mem::size_of::<Pubkey>()
1523 }
1524
1525 #[test]
1526 fn test_calc_scan_result_size() {
1527 for len in 0..3 {
1528 assert_eq!(
1529 Accounts::calc_scan_result_size(&AccountSharedData::new(
1530 0,
1531 len,
1532 &Pubkey::default()
1533 )),
1534 zero_len_account_size() + len
1535 );
1536 }
1537 }
1538
1539 #[test]
1540 fn test_maybe_abort_scan() {
1541 assert!(Accounts::maybe_abort_scan(ScanResult::Ok(vec![]), &ScanConfig::default()).is_ok());
1542 assert!(
1543 Accounts::maybe_abort_scan(ScanResult::Ok(vec![]), &ScanConfig::new(false)).is_ok()
1544 );
1545 let config = ScanConfig::new(false).recreate_with_abort();
1546 assert!(Accounts::maybe_abort_scan(ScanResult::Ok(vec![]), &config).is_ok());
1547 config.abort();
1548 assert!(Accounts::maybe_abort_scan(ScanResult::Ok(vec![]), &config).is_err());
1549 }
1550
1551 #[test]
1552 fn test_accumulate_and_check_scan_result_size() {
1553 for (account, byte_limit_for_scan, result) in [
1554 (AccountSharedData::default(), zero_len_account_size(), false),
1555 (
1556 AccountSharedData::new(0, 1, &Pubkey::default()),
1557 zero_len_account_size(),
1558 true,
1559 ),
1560 (
1561 AccountSharedData::new(0, 2, &Pubkey::default()),
1562 zero_len_account_size() + 3,
1563 false,
1564 ),
1565 ] {
1566 let sum = AtomicUsize::default();
1567 assert_eq!(
1568 result,
1569 Accounts::accumulate_and_check_scan_result_size(
1570 &sum,
1571 &account,
1572 &Some(byte_limit_for_scan)
1573 )
1574 );
1575 assert!(Accounts::accumulate_and_check_scan_result_size(
1577 &sum,
1578 &account,
1579 &Some(byte_limit_for_scan)
1580 ));
1581 assert!(!Accounts::accumulate_and_check_scan_result_size(
1582 &sum, &account, &None
1583 ));
1584 }
1585 }
1586}