use log::*; use rand::{thread_rng, Rng}; use rayon::prelude::*; use solana_runtime::{accounts_db::AccountsDb, accounts_index::Ancestors}; use solana_sdk::genesis_config::ClusterType; use solana_sdk::{account::Account, clock::Slot, pubkey::Pubkey}; use std::collections::HashSet; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Instant; #[test] fn test_shrink_and_clean() { solana_logger::setup(); // repeat the whole test scenario for _ in 0..5 { let accounts = Arc::new(AccountsDb::new_single()); let accounts_for_shrink = accounts.clone(); // spawn the slot shrinking background thread let exit = Arc::new(AtomicBool::default()); let exit_for_shrink = exit.clone(); let shrink_thread = std::thread::spawn(move || loop { if exit_for_shrink.load(Ordering::Relaxed) { break; } accounts_for_shrink.process_stale_slot_v1(); }); let mut alive_accounts = vec![]; let owner = Pubkey::default(); // populate the AccountsDb with plenty of food for slot shrinking // also this simulates realistic some heavy spike account updates in the wild for current_slot in 0..100 { while alive_accounts.len() <= 10 { alive_accounts.push(( solana_sdk::pubkey::new_rand(), Account::new(thread_rng().gen_range(0, 50), 0, &owner), )); } alive_accounts.retain(|(_pubkey, account)| account.lamports >= 1); for (pubkey, account) in alive_accounts.iter_mut() { account.lamports -= 1; accounts.store_uncached(current_slot, &[(&pubkey, &account)]); } accounts.add_root(current_slot); } // let's dance. for _ in 0..10 { accounts.clean_accounts(None); std::thread::sleep(std::time::Duration::from_millis(100)); } // cleanup exit.store(true, Ordering::Relaxed); shrink_thread.join().unwrap(); } } #[test] fn test_bad_bank_hash() { solana_logger::setup(); use solana_sdk::signature::{Keypair, Signer}; let db = AccountsDb::new(Vec::new(), &ClusterType::Development); let some_slot: Slot = 0; let ancestors: Ancestors = [(some_slot, 0)].iter().copied().collect(); let max_accounts = 200; let mut accounts_keys: Vec<_> = (0..max_accounts) .into_par_iter() .map(|_| { let key = Keypair::new().pubkey(); let lamports = thread_rng().gen_range(0, 100); let some_data_len = thread_rng().gen_range(0, 1000); let account = Account::new(lamports, some_data_len, &key); (key, account) }) .collect(); let mut existing = HashSet::new(); let mut last_print = Instant::now(); for i in 0..5_000 { if last_print.elapsed().as_millis() > 5000 { info!("i: {}", i); last_print = Instant::now(); } let num_accounts = thread_rng().gen_range(0, 100); (0..num_accounts).into_iter().for_each(|_| { let mut idx; loop { idx = thread_rng().gen_range(0, max_accounts); if existing.contains(&idx) { continue; } existing.insert(idx); break; } accounts_keys[idx].1.lamports = thread_rng().gen_range(0, 1000); }); let account_refs: Vec<_> = existing .iter() .map(|idx| (&accounts_keys[*idx].0, &accounts_keys[*idx].1)) .collect(); db.store_uncached(some_slot, &account_refs); for (key, account) in &account_refs { assert_eq!( db.load_account_hash(&ancestors, &key), AccountsDb::hash_account(some_slot, &account, &key, &ClusterType::Development) ); } existing.clear(); } }