solana_accounts_db/
accounts.rs

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/// This structure handles synchronization for db
61#[derive(Debug)]
62pub struct Accounts {
63    /// Single global AccountsDb
64    pub accounts_db: Arc<AccountsDb>,
65
66    /// set of read-only and writable accounts which are currently
67    /// being processed by banking/replay threads
68    pub(crate) account_locks: Mutex<AccountLocks>,
69}
70
71pub enum AccountAddressFilter {
72    Exclude, // exclude all addresses matching the filter
73    Include, // only include addresses matching the filter
74}
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    /// Return loaded addresses and the deactivation slot.
85    /// If the table hasn't been deactivated, the deactivation slot is `u64::MAX`.
86    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    /// Fill `loaded_addresses` and return the deactivation slot.
103    /// If no tables are de-activating, the deactivation slot is `u64::MAX`.
104    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            // Load iterators for addresses.
123            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            // Reserve space in vectors to avoid reallocations.
135            // If `loaded_addresses` is pre-allocated, this only does a simple
136            // bounds check.
137            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            // Append to the loaded addresses.
145            // Check if **any** of the addresses are not available.
146            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    /// Slow because lock is held for 1 operation instead of many
163    /// This always returns None for zero-lamport accounts.
164    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    /// same as `load_with_fixed_root` except:
182    /// if the account is not already in the read cache, it is NOT put in the read cache on successful load
183    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    /// scans underlying accounts_db for this delta (slot) with a map function
204    ///   from LoadedAccount to B
205    /// returns only the latest/current version of B for this slot
206    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                // Cache only has one version per key, don't need to worry about versioning
215                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    /// Returns all the accounts from `slot`
236    ///
237    /// If `program_id` is `Some`, filter the results to those whose owner matches `program_id`
238    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    /// Only called from startup or test code.
302    #[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, /*capitalization*/ 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        // Don't ever load zero lamport accounts into runtime because
327        // the existence of zero-lamport accounts are never deterministic!!
328        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    /// Accumulate size of (pubkey + account) into sum.
408    /// Return true iff sum > 'byte_limit_for_scan'
409    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                            // total size of results exceeds size limit, so abort scan
466                            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            "", // disable logging of this. We now parallelize it and this results in multiple parallel logs
543            ancestors,
544            range,
545            &ScanConfig::default(),
546            |option| Self::load_with_slot(&mut collector, option),
547        );
548        collector
549    }
550
551    /// Slow because lock is held for 1 operation instead of many.
552    /// WARNING: This noncached version is only to be used for tests/benchmarking
553    /// as bypassing the cache in general is not supported
554    pub fn store_slow_uncached(&self, slot: Slot, pubkey: &Pubkey, account: &AccountSharedData) {
555        self.accounts_db.store_uncached(slot, &[(pubkey, account)]);
556    }
557
558    /// This function will prevent multiple threads from modifying the same account state at the
559    /// same time
560    #[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        // Validate the account locks, then get iterator if successful validation.
567        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        // Validate the account locks, then get iterator if successful validation.
584        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    /// Once accounts are unlocked, new transactions that modify that state can enter the pipeline
613    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    /// Store the accounts into the DB
632    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    /// Add a slot to root.  Root slots cannot be purged
646    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        // use bins * 2 to get the first half of the range within bin 0
706        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        // Load accounts owned by various programs into AccountsDb
869        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        // Allow up to MAX_TX_ACCOUNT_LOCKS
923        {
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        // Disallow over MAX_TX_ACCOUNT_LOCKS
945        {
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(()), // Read-only account (keypair1) can be referenced multiple times
1030                Err(TransactionError::AccountInUse), // Read-only account (keypair1) cannot also be locked as writable
1031            ],
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(())] // Now keypair1 account can be locked as writable
1055        );
1056
1057        // Check that read-only lock with zero references is deleted
1058        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, // All accounts marked as writable
1167            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        // Instruction program-id account demoted to readonly
1176        assert!(accounts
1177            .account_locks
1178            .lock()
1179            .unwrap()
1180            .is_locked_readonly(&native_loader::id()));
1181        // Non-program accounts remain writable
1182        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        /// callers used to call store_uncached. But, this is not allowed anymore.
1196        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        /// useful to adapt tests written prior to introduction of the write cache
1201        /// to use the write cache
1202        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(()), // Read-only account (keypair0) can be referenced multiple times
1275                Err(TransactionError::WouldExceedMaxBlockCostLimit), // is not locked due to !qos_results[1].is_ok()
1276                Ok(()), // Read-only account (keypair0) can be referenced multiple times
1277            ],
1278        );
1279
1280        // verify that keypair0 read-only locked
1281        assert!(accounts
1282            .account_locks
1283            .lock()
1284            .unwrap()
1285            .is_locked_readonly(&keypair0.pubkey()));
1286        // verify that keypair2 (for tx1) is not write-locked
1287        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        /* This test assumes pubkey0 < pubkey1 < pubkey2.
1324         * But the keys created with new_unique() does not guarantee this
1325         * order because of the endianness.  new_unique() calls add 1 at each
1326         * key generaration as the little endian integer.  A pubkey stores its
1327         * value in a 32-byte array bytes, and its eq-partial trait considers
1328         * the lower-address bytes more significant, which is the big-endian
1329         * order.
1330         * So, sort first to ensure the order assumption holds.
1331         */
1332        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        // num == 0 should always return empty set
1351        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        // list should be sorted by balance, then pubkey, descending
1380        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        // larger num should not affect results
1422        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        // AccountAddressFilter::Exclude should exclude entry
1437        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        // AccountAddressFilter::Include should limit entries
1479        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            // calling a second time should accumulate above the threshold
1576            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}