#[cfg(test)] use { super::*, crate::{ accounts::{create_test_accounts, Accounts}, accounts_db::get_temp_accounts_paths, bank::{Bank, StatusCacheRc}, }, bincode::serialize_into, rand::{thread_rng, Rng}, solana_sdk::{ account::Account, clock::Slot, genesis_config::{create_genesis_config, ClusterType}, pubkey::Pubkey, signature::{Keypair, Signer}, }, std::io::{BufReader, Cursor}, tempfile::TempDir, }; #[cfg(test)] fn copy_append_vecs>( accounts_db: &AccountsDB, output_dir: P, ) -> std::io::Result<()> { let storage_entries = accounts_db.get_snapshot_storages(Slot::max_value()); for storage in storage_entries.iter().flatten() { let storage_path = storage.get_path(); let output_path = output_dir.as_ref().join( storage_path .file_name() .expect("Invalid AppendVec file path"), ); std::fs::copy(storage_path, output_path)?; } Ok(()) } #[cfg(test)] fn check_accounts(accounts: &Accounts, pubkeys: &[Pubkey], num: usize) { for _ in 1..num { let idx = thread_rng().gen_range(0, num - 1); let ancestors = vec![(0, 0)].into_iter().collect(); let account = accounts.load_slow(&ancestors, &pubkeys[idx]); let account1 = Some(( Account::new((idx + 1) as u64, 0, &Account::default().owner), 0, )); assert_eq!(account, account1); } } #[cfg(test)] fn context_accountsdb_from_stream<'a, C, R, P>( stream: &mut BufReader, account_paths: &[PathBuf], stream_append_vecs_path: P, ) -> Result where C: TypeContext<'a>, R: Read, P: AsRef, { // read and deserialise the accounts database directly from the stream reconstruct_accountsdb_from_fields( C::deserialize_accounts_db_fields(stream)?, account_paths, stream_append_vecs_path, &ClusterType::Development, ) } #[cfg(test)] fn accountsdb_from_stream( serde_style: SerdeStyle, stream: &mut BufReader, account_paths: &[PathBuf], stream_append_vecs_path: P, ) -> Result where R: Read, P: AsRef, { match serde_style { SerdeStyle::NEWER => context_accountsdb_from_stream::( stream, account_paths, stream_append_vecs_path, ), } } #[cfg(test)] fn accountsdb_to_stream( serde_style: SerdeStyle, stream: &mut W, accounts_db: &AccountsDB, slot: Slot, account_storage_entries: &[SnapshotStorage], ) -> Result<(), Error> where W: Write, { match serde_style { SerdeStyle::NEWER => serialize_into( stream, &SerializableAccountsDB:: { accounts_db, slot, account_storage_entries, phantom: std::marker::PhantomData::default(), }, ), } } #[cfg(test)] fn test_accounts_serialize_style(serde_style: SerdeStyle) { solana_logger::setup(); let (_accounts_dir, paths) = get_temp_accounts_paths(4).unwrap(); let accounts = Accounts::new(paths, &ClusterType::Development); let mut pubkeys: Vec = vec![]; create_test_accounts(&accounts, &mut pubkeys, 100, 0); check_accounts(&accounts, &pubkeys, 100); accounts.add_root(0); let mut writer = Cursor::new(vec![]); accountsdb_to_stream( serde_style, &mut writer, &*accounts.accounts_db, 0, &accounts.accounts_db.get_snapshot_storages(0), ) .unwrap(); let copied_accounts = TempDir::new().unwrap(); // Simulate obtaining a copy of the AppendVecs from a tarball copy_append_vecs(&accounts.accounts_db, copied_accounts.path()).unwrap(); let buf = writer.into_inner(); let mut reader = BufReader::new(&buf[..]); let (_accounts_dir, daccounts_paths) = get_temp_accounts_paths(2).unwrap(); let daccounts = Accounts::new_empty( accountsdb_from_stream( serde_style, &mut reader, &daccounts_paths, copied_accounts.path(), ) .unwrap(), ); check_accounts(&daccounts, &pubkeys, 100); assert_eq!(accounts.bank_hash_at(0), daccounts.bank_hash_at(0)); } #[cfg(test)] fn test_bank_serialize_style(serde_style: SerdeStyle) { solana_logger::setup(); let (genesis_config, _) = create_genesis_config(500); let bank0 = Arc::new(Bank::new(&genesis_config)); let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1); bank0.squash(); // Create an account on a non-root fork let key1 = Keypair::new(); bank1.deposit(&key1.pubkey(), 5); let bank2 = Bank::new_from_parent(&bank0, &Pubkey::default(), 2); // Test new account let key2 = Keypair::new(); bank2.deposit(&key2.pubkey(), 10); assert_eq!(bank2.get_balance(&key2.pubkey()), 10); let key3 = Keypair::new(); bank2.deposit(&key3.pubkey(), 0); bank2.squash(); let snapshot_storages = bank2.get_snapshot_storages(); let mut buf = vec![]; let mut writer = Cursor::new(&mut buf); crate::serde_snapshot::bank_to_stream( serde_style, &mut std::io::BufWriter::new(&mut writer), &bank2, &snapshot_storages, ) .unwrap(); let rdr = Cursor::new(&buf[..]); let mut reader = std::io::BufReader::new(&buf[rdr.position() as usize..]); // Create a new set of directories for this bank's accounts let (_accounts_dir, dbank_paths) = get_temp_accounts_paths(4).unwrap(); let ref_sc = StatusCacheRc::default(); ref_sc.status_cache.write().unwrap().add_root(2); // Create a directory to simulate AppendVecs unpackaged from a snapshot tar let copied_accounts = TempDir::new().unwrap(); copy_append_vecs(&bank2.rc.accounts.accounts_db, copied_accounts.path()).unwrap(); let mut dbank = crate::serde_snapshot::bank_from_stream( serde_style, &mut reader, copied_accounts.path(), &dbank_paths, &genesis_config, &[], None, None, ) .unwrap(); dbank.src = ref_sc; assert_eq!(dbank.get_balance(&key1.pubkey()), 0); assert_eq!(dbank.get_balance(&key2.pubkey()), 10); assert_eq!(dbank.get_balance(&key3.pubkey()), 0); assert!(bank2 == dbank); } #[cfg(test)] pub(crate) fn reconstruct_accounts_db_via_serialization( accounts: &AccountsDB, slot: Slot, ) -> AccountsDB { let mut writer = Cursor::new(vec![]); let snapshot_storages = accounts.get_snapshot_storages(slot); accountsdb_to_stream( SerdeStyle::NEWER, &mut writer, &accounts, slot, &snapshot_storages, ) .unwrap(); let buf = writer.into_inner(); let mut reader = BufReader::new(&buf[..]); let copied_accounts = TempDir::new().unwrap(); // Simulate obtaining a copy of the AppendVecs from a tarball copy_append_vecs(&accounts, copied_accounts.path()).unwrap(); accountsdb_from_stream(SerdeStyle::NEWER, &mut reader, &[], copied_accounts.path()).unwrap() } #[test] fn test_accounts_serialize_newer() { test_accounts_serialize_style(SerdeStyle::NEWER) } #[test] fn test_bank_serialize_newer() { test_bank_serialize_style(SerdeStyle::NEWER) } #[cfg(all(test, RUSTC_WITH_SPECIALIZATION))] mod test_bank_serialize { use super::*; // These some what long test harness is required to freeze the ABI of // Bank's serialization due to versioned nature #[frozen_abi(digest = "ULV2jDndxR3JB677ayyjaamtAcZ24q75tCkHS2bKVoy")] #[derive(Serialize, AbiExample)] pub struct BankAbiTestWrapperFuture { #[serde(serialize_with = "wrapper_future")] bank: Bank, } pub fn wrapper_future(bank: &Bank, s: S) -> std::result::Result where S: serde::Serializer, { let snapshot_storages = bank.rc.accounts.accounts_db.get_snapshot_storages(0); // ensure there is a single snapshot storage example for ABI digesting assert_eq!(snapshot_storages.len(), 1); (SerializableBankAndStorage:: { bank, snapshot_storages: &snapshot_storages, phantom: std::marker::PhantomData::default(), }) .serialize(s) } }