2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
log::*,
|
|
|
|
rand::{thread_rng, Rng},
|
|
|
|
rayon::prelude::*,
|
|
|
|
solana_runtime::{
|
2022-10-18 08:03:37 -07:00
|
|
|
accounts_db::{AccountsDb, LoadHint, INCLUDE_SLOT_IN_HASH_TESTS},
|
2021-12-03 09:00:31 -08:00
|
|
|
ancestors::Ancestors,
|
|
|
|
},
|
|
|
|
solana_sdk::{
|
|
|
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
|
|
|
clock::Slot,
|
|
|
|
genesis_config::ClusterType,
|
|
|
|
pubkey::Pubkey,
|
2023-05-10 08:05:31 -07:00
|
|
|
sysvar::epoch_schedule::EpochSchedule,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
std::{
|
|
|
|
collections::HashSet,
|
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc,
|
|
|
|
},
|
|
|
|
time::Instant,
|
|
|
|
},
|
2021-04-16 08:23:32 -07:00
|
|
|
};
|
2020-12-30 08:25:45 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_shrink_and_clean() {
|
|
|
|
solana_logger::setup();
|
|
|
|
|
|
|
|
// repeat the whole test scenario
|
|
|
|
for _ in 0..5 {
|
2021-08-04 09:47:11 -07:00
|
|
|
let accounts = Arc::new(AccountsDb::new_single_for_tests());
|
2020-12-30 08:25:45 -08:00
|
|
|
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;
|
|
|
|
}
|
2023-05-10 08:05:31 -07:00
|
|
|
accounts_for_shrink.shrink_all_slots(false, None, &EpochSchedule::default());
|
2020-12-30 08:25:45 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
let mut alive_accounts = vec![];
|
|
|
|
let owner = Pubkey::default();
|
|
|
|
|
2021-02-18 23:42:09 -08:00
|
|
|
// populate the AccountsDb with plenty of food for slot shrinking
|
2020-12-30 08:25:45 -08:00
|
|
|
// 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(),
|
2021-03-09 13:06:07 -08:00
|
|
|
AccountSharedData::new(thread_rng().gen_range(0, 50), 0, &owner),
|
2020-12-30 08:25:45 -08:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2021-05-03 08:45:54 -07:00
|
|
|
alive_accounts.retain(|(_pubkey, account)| account.lamports() >= 1);
|
2020-12-30 08:25:45 -08:00
|
|
|
|
|
|
|
for (pubkey, account) in alive_accounts.iter_mut() {
|
2021-04-27 07:12:48 -07:00
|
|
|
account.checked_sub_lamports(1).unwrap();
|
2022-12-13 16:32:24 -08:00
|
|
|
|
|
|
|
accounts.store_cached(
|
|
|
|
(
|
|
|
|
current_slot,
|
|
|
|
&[(&*pubkey, &*account)][..],
|
|
|
|
INCLUDE_SLOT_IN_HASH_TESTS,
|
|
|
|
),
|
|
|
|
None,
|
|
|
|
);
|
2020-12-30 08:25:45 -08:00
|
|
|
}
|
|
|
|
accounts.add_root(current_slot);
|
2022-12-13 16:32:24 -08:00
|
|
|
accounts.flush_accounts_cache(true, Some(current_slot));
|
2020-12-30 08:25:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// let's dance.
|
|
|
|
for _ in 0..10 {
|
2022-08-17 15:45:59 -07:00
|
|
|
accounts.clean_accounts_for_tests();
|
2020-12-30 08:25:45 -08:00
|
|
|
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();
|
2021-08-06 10:36:42 -07:00
|
|
|
let db = AccountsDb::new_for_tests(Vec::new(), &ClusterType::Development);
|
2020-12-30 08:25:45 -08:00
|
|
|
|
|
|
|
let some_slot: Slot = 0;
|
|
|
|
let max_accounts = 200;
|
|
|
|
let mut accounts_keys: Vec<_> = (0..max_accounts)
|
|
|
|
.into_par_iter()
|
|
|
|
.map(|_| {
|
2022-09-10 13:56:45 -07:00
|
|
|
let key = solana_sdk::pubkey::new_rand();
|
2020-12-30 08:25:45 -08:00
|
|
|
let lamports = thread_rng().gen_range(0, 100);
|
|
|
|
let some_data_len = thread_rng().gen_range(0, 1000);
|
2021-03-09 13:06:07 -08:00
|
|
|
let account = AccountSharedData::new(lamports, some_data_len, &key);
|
2020-12-30 08:25:45 -08:00
|
|
|
(key, account)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let mut existing = HashSet::new();
|
|
|
|
let mut last_print = Instant::now();
|
|
|
|
for i in 0..5_000 {
|
2023-01-09 08:10:28 -08:00
|
|
|
let some_slot = some_slot + i;
|
|
|
|
let ancestors = Ancestors::from(vec![some_slot]);
|
|
|
|
|
2020-12-30 08:25:45 -08:00
|
|
|
if last_print.elapsed().as_millis() > 5000 {
|
|
|
|
info!("i: {}", i);
|
|
|
|
last_print = Instant::now();
|
|
|
|
}
|
|
|
|
let num_accounts = thread_rng().gen_range(0, 100);
|
2023-01-05 10:05:32 -08:00
|
|
|
(0..num_accounts).for_each(|_| {
|
2020-12-30 08:25:45 -08:00
|
|
|
let mut idx;
|
|
|
|
loop {
|
|
|
|
idx = thread_rng().gen_range(0, max_accounts);
|
|
|
|
if existing.contains(&idx) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
existing.insert(idx);
|
|
|
|
break;
|
|
|
|
}
|
2021-04-30 14:17:05 -07:00
|
|
|
accounts_keys[idx]
|
|
|
|
.1
|
|
|
|
.set_lamports(thread_rng().gen_range(0, 1000));
|
2020-12-30 08:25:45 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
let account_refs: Vec<_> = existing
|
|
|
|
.iter()
|
|
|
|
.map(|idx| (&accounts_keys[*idx].0, &accounts_keys[*idx].1))
|
|
|
|
.collect();
|
2023-01-09 08:10:28 -08:00
|
|
|
db.store_cached(
|
|
|
|
(some_slot, &account_refs[..], INCLUDE_SLOT_IN_HASH_TESTS),
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
for pass in 0..2 {
|
|
|
|
for (key, account) in &account_refs {
|
|
|
|
assert_eq!(
|
|
|
|
db.load_account_hash(&ancestors, key, Some(some_slot), LoadHint::Unspecified)
|
|
|
|
.unwrap(),
|
|
|
|
AccountsDb::hash_account(some_slot, *account, key, INCLUDE_SLOT_IN_HASH_TESTS)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if pass == 0 {
|
|
|
|
// flush the write cache so we're reading from append vecs on the next iteration
|
|
|
|
db.add_root(some_slot);
|
|
|
|
db.flush_accounts_cache(true, Some(some_slot));
|
|
|
|
}
|
2020-12-30 08:25:45 -08:00
|
|
|
}
|
|
|
|
existing.clear();
|
|
|
|
}
|
|
|
|
}
|