diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index 793fe3d298..6a299bbd27 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -590,7 +590,6 @@ impl AccountsDB { self.file_size } - #[cfg(test)] pub fn new_single() -> Self { AccountsDB { min_num_stores: 0, @@ -1466,8 +1465,7 @@ impl AccountsDB { }) } - #[cfg(test)] - fn load_account_hash(&self, ancestors: &Ancestors, pubkey: &Pubkey) -> Hash { + pub fn load_account_hash(&self, ancestors: &Ancestors, pubkey: &Pubkey) -> Hash { let (slot, store_id, offset) = { let (lock, index) = self .accounts_index @@ -4894,64 +4892,6 @@ pub mod tests { ); } - #[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(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(); - } - } - #[test] fn test_storage_finder() { solana_logger::setup(); @@ -5512,60 +5452,6 @@ pub mod tests { } } - #[test] - #[ignore] - 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(); - }); - - 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..1000 { - 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(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_account_balance_for_capitalization_normal() { // system accounts diff --git a/runtime/tests/accounts.rs b/runtime/tests/accounts.rs new file mode 100644 index 0000000000..2ee328d07c --- /dev/null +++ b/runtime/tests/accounts.rs @@ -0,0 +1,121 @@ +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(); + }); + + 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(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(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(); + } +}