137 lines
4.2 KiB
Rust
137 lines
4.2 KiB
Rust
use {
|
|
log::*,
|
|
rand::{thread_rng, Rng},
|
|
rayon::prelude::*,
|
|
solana_runtime::{
|
|
accounts_db::{AccountsDb, LoadHint, INCLUDE_SLOT_IN_HASH_TESTS},
|
|
ancestors::Ancestors,
|
|
},
|
|
solana_sdk::{
|
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
|
clock::Slot,
|
|
genesis_config::ClusterType,
|
|
pubkey::Pubkey,
|
|
},
|
|
std::{
|
|
collections::HashSet,
|
|
sync::{
|
|
atomic::{AtomicBool, Ordering},
|
|
Arc,
|
|
},
|
|
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_for_tests());
|
|
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(),
|
|
AccountSharedData::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.checked_sub_lamports(1).unwrap();
|
|
accounts.store_uncached(current_slot, &[(pubkey, account)]);
|
|
}
|
|
accounts.add_root(current_slot);
|
|
}
|
|
|
|
// let's dance.
|
|
for _ in 0..10 {
|
|
accounts.clean_accounts_for_tests();
|
|
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();
|
|
let db = AccountsDb::new_for_tests(Vec::new(), &ClusterType::Development);
|
|
|
|
let some_slot: Slot = 0;
|
|
let ancestors = Ancestors::from(vec![some_slot]);
|
|
|
|
let max_accounts = 200;
|
|
let mut accounts_keys: Vec<_> = (0..max_accounts)
|
|
.into_par_iter()
|
|
.map(|_| {
|
|
let key = solana_sdk::pubkey::new_rand();
|
|
let lamports = thread_rng().gen_range(0, 100);
|
|
let some_data_len = thread_rng().gen_range(0, 1000);
|
|
let account = AccountSharedData::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
|
|
.set_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, None, LoadHint::Unspecified)
|
|
.unwrap(),
|
|
AccountsDb::hash_account(some_slot, *account, key, INCLUDE_SLOT_IN_HASH_TESTS)
|
|
);
|
|
}
|
|
existing.clear();
|
|
}
|
|
}
|