| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  | use log::*;
 | 
					
						
							|  |  |  | use rand::{thread_rng, Rng};
 | 
					
						
							|  |  |  | use rayon::prelude::*;
 | 
					
						
							| 
									
										
										
										
											2021-02-18 23:42:09 -08:00
										 |  |  | use solana_runtime::{accounts_db::AccountsDb, accounts_index::Ancestors};
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  | use solana_sdk::genesis_config::ClusterType;
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  | use solana_sdk::{account::AccountSharedData, clock::Slot, pubkey::Pubkey};
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  | 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 {
 | 
					
						
							| 
									
										
										
										
											2021-02-18 23:42:09 -08:00
										 |  |  |         let accounts = Arc::new(AccountsDb::new_single());
 | 
					
						
							| 
									
										
										
										
											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;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2021-01-11 17:00:23 -08:00
										 |  |  |             accounts_for_shrink.process_stale_slot_v1();
 | 
					
						
							| 
									
										
										
										
											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 15:06:07 -06:00
										 |  |  |                     AccountSharedData::new(thread_rng().gen_range(0, 50), 0, &owner),
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  |                 ));
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             alive_accounts.retain(|(_pubkey, account)| account.lamports >= 1);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (pubkey, account) in alive_accounts.iter_mut() {
 | 
					
						
							|  |  |  |                 account.lamports -= 1;
 | 
					
						
							| 
									
										
										
										
											2021-01-11 17:00:23 -08:00
										 |  |  |                 accounts.store_uncached(current_slot, &[(&pubkey, &account)]);
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  |             }
 | 
					
						
							|  |  |  |             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};
 | 
					
						
							| 
									
										
										
										
											2021-02-18 23:42:09 -08:00
										 |  |  |     let db = AccountsDb::new(Vec::new(), &ClusterType::Development);
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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);
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06: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 {
 | 
					
						
							|  |  |  |         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();
 | 
					
						
							| 
									
										
										
										
											2021-01-11 17:00:23 -08:00
										 |  |  |         db.store_uncached(some_slot, &account_refs);
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (key, account) in &account_refs {
 | 
					
						
							|  |  |  |             assert_eq!(
 | 
					
						
							|  |  |  |                 db.load_account_hash(&ancestors, &key),
 | 
					
						
							| 
									
										
										
										
											2021-02-18 23:42:09 -08:00
										 |  |  |                 AccountsDb::hash_account(some_slot, &account, &key, &ClusterType::Development)
 | 
					
						
							| 
									
										
										
										
											2020-12-30 08:25:45 -08:00
										 |  |  |             );
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         existing.clear();
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 |