Move bank dependent tests out of serde_snapshot/tests.rs (#32571)
This commit is contained in:
parent
261007bb43
commit
faff34403c
|
@ -209,6 +209,7 @@ struct VerifyAccountsHashConfig {
|
||||||
mod address_lookup_table;
|
mod address_lookup_table;
|
||||||
mod builtin_programs;
|
mod builtin_programs;
|
||||||
mod metrics;
|
mod metrics;
|
||||||
|
mod serde_snapshot;
|
||||||
mod sysvar_cache;
|
mod sysvar_cache;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
|
@ -0,0 +1,644 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
account_storage::{AccountStorageMap, AccountStorageReference},
|
||||||
|
accounts_db::{
|
||||||
|
get_temp_accounts_paths, AccountShrinkThreshold, AccountStorageEntry, AccountsDb,
|
||||||
|
AtomicAppendVecId,
|
||||||
|
},
|
||||||
|
accounts_file::{AccountsFile, AccountsFileError},
|
||||||
|
accounts_hash::{AccountsDeltaHash, AccountsHash},
|
||||||
|
accounts_index::AccountSecondaryIndexes,
|
||||||
|
bank::{Bank, BankTestConfig, EpochRewardStatus, StartBlockHeightAndRewards},
|
||||||
|
epoch_accounts_hash::{self, EpochAccountsHash},
|
||||||
|
genesis_utils::{activate_all_features, activate_feature},
|
||||||
|
runtime_config::RuntimeConfig,
|
||||||
|
serde_snapshot::{
|
||||||
|
reserialize_bank_with_new_accounts_hash, BankIncrementalSnapshotPersistence,
|
||||||
|
SerdeAccountsHash, SerdeIncrementalAccountsHash, SerdeStyle, SnapshotStreams,
|
||||||
|
},
|
||||||
|
snapshot_utils::{
|
||||||
|
self, create_tmp_accounts_dir_for_tests, get_storages_to_serialize, ArchiveFormat,
|
||||||
|
StorageAndNextAppendVecId, BANK_SNAPSHOT_PRE_FILENAME_EXTENSION,
|
||||||
|
},
|
||||||
|
stake_rewards::StakeReward,
|
||||||
|
status_cache::StatusCache,
|
||||||
|
},
|
||||||
|
solana_sdk::{
|
||||||
|
epoch_schedule::EpochSchedule,
|
||||||
|
feature_set,
|
||||||
|
genesis_config::create_genesis_config,
|
||||||
|
hash::Hash,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
signature::{Keypair, Signer},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
io::{Cursor, Read, Write},
|
||||||
|
num::NonZeroUsize,
|
||||||
|
ops::RangeFull,
|
||||||
|
path::Path,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
},
|
||||||
|
tempfile::TempDir,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Simulates the unpacking & storage reconstruction done during snapshot unpacking
|
||||||
|
fn copy_append_vecs<P: AsRef<Path>>(
|
||||||
|
accounts_db: &AccountsDb,
|
||||||
|
output_dir: P,
|
||||||
|
) -> Result<StorageAndNextAppendVecId, AccountsFileError> {
|
||||||
|
let storage_entries = accounts_db.get_snapshot_storages(RangeFull).0;
|
||||||
|
let storage: AccountStorageMap = AccountStorageMap::with_capacity(storage_entries.len());
|
||||||
|
let mut next_append_vec_id = 0;
|
||||||
|
for storage_entry in storage_entries.into_iter() {
|
||||||
|
// Copy file to new directory
|
||||||
|
let storage_path = storage_entry.get_path();
|
||||||
|
let file_name =
|
||||||
|
AccountsFile::file_name(storage_entry.slot(), storage_entry.append_vec_id());
|
||||||
|
let output_path = output_dir.as_ref().join(file_name);
|
||||||
|
std::fs::copy(storage_path, &output_path)?;
|
||||||
|
|
||||||
|
// Read new file into append-vec and build new entry
|
||||||
|
let (accounts_file, num_accounts) =
|
||||||
|
AccountsFile::new_from_file(output_path, storage_entry.accounts.len())?;
|
||||||
|
let new_storage_entry = AccountStorageEntry::new_existing(
|
||||||
|
storage_entry.slot(),
|
||||||
|
storage_entry.append_vec_id(),
|
||||||
|
accounts_file,
|
||||||
|
num_accounts,
|
||||||
|
);
|
||||||
|
next_append_vec_id = next_append_vec_id.max(new_storage_entry.append_vec_id());
|
||||||
|
storage.insert(
|
||||||
|
new_storage_entry.slot(),
|
||||||
|
AccountStorageReference {
|
||||||
|
id: new_storage_entry.append_vec_id(),
|
||||||
|
storage: Arc::new(new_storage_entry),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(StorageAndNextAppendVecId {
|
||||||
|
storage,
|
||||||
|
next_append_vec_id: AtomicAppendVecId::new(next_append_vec_id + 1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_bank_serialize_style(
|
||||||
|
serde_style: SerdeStyle,
|
||||||
|
reserialize_accounts_hash: bool,
|
||||||
|
update_accounts_hash: bool,
|
||||||
|
incremental_snapshot_persistence: bool,
|
||||||
|
initial_epoch_accounts_hash: bool,
|
||||||
|
) {
|
||||||
|
solana_logger::setup();
|
||||||
|
let (mut genesis_config, _) = create_genesis_config(500);
|
||||||
|
activate_feature(&mut genesis_config, feature_set::epoch_accounts_hash::id());
|
||||||
|
genesis_config.epoch_schedule = EpochSchedule::custom(400, 400, false);
|
||||||
|
let bank0 = Arc::new(Bank::new_for_tests(&genesis_config));
|
||||||
|
let eah_start_slot = epoch_accounts_hash::calculation_start(&bank0);
|
||||||
|
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).unwrap();
|
||||||
|
|
||||||
|
// If setting an initial EAH, then the bank being snapshotted must be in the EAH calculation
|
||||||
|
// window. Otherwise `bank_to_stream()` below will *not* include the EAH in the bank snapshot,
|
||||||
|
// and the later-deserialized bank's EAH will not match the expected EAH.
|
||||||
|
let bank2_slot = if initial_epoch_accounts_hash {
|
||||||
|
eah_start_slot
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
} + 2;
|
||||||
|
let bank2 = Bank::new_from_parent(&bank0, &Pubkey::default(), bank2_slot);
|
||||||
|
|
||||||
|
// Test new account
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
bank2.deposit(&key2.pubkey(), 10).unwrap();
|
||||||
|
assert_eq!(bank2.get_balance(&key2.pubkey()), 10);
|
||||||
|
|
||||||
|
let key3 = Keypair::new();
|
||||||
|
bank2.deposit(&key3.pubkey(), 0).unwrap();
|
||||||
|
|
||||||
|
bank2.freeze();
|
||||||
|
bank2.squash();
|
||||||
|
bank2.force_flush_accounts_cache();
|
||||||
|
bank2
|
||||||
|
.accounts()
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_hash_for_tests(bank2.slot(), AccountsHash(Hash::new(&[0; 32])));
|
||||||
|
|
||||||
|
let snapshot_storages = bank2.get_snapshot_storages(None);
|
||||||
|
let mut buf = vec![];
|
||||||
|
let mut writer = Cursor::new(&mut buf);
|
||||||
|
|
||||||
|
let mut expected_epoch_accounts_hash = None;
|
||||||
|
|
||||||
|
if initial_epoch_accounts_hash {
|
||||||
|
expected_epoch_accounts_hash = Some(Hash::new(&[7; 32]));
|
||||||
|
bank2
|
||||||
|
.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.epoch_accounts_hash_manager
|
||||||
|
.set_valid(
|
||||||
|
EpochAccountsHash::new(expected_epoch_accounts_hash.unwrap()),
|
||||||
|
eah_start_slot,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::serde_snapshot::bank_to_stream(
|
||||||
|
serde_style,
|
||||||
|
&mut std::io::BufWriter::new(&mut writer),
|
||||||
|
&bank2,
|
||||||
|
&get_storages_to_serialize(&snapshot_storages),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if update_accounts_hash {
|
||||||
|
bank2
|
||||||
|
.accounts()
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_hash_for_tests(bank2.slot(), AccountsHash(Hash::new(&[1; 32])));
|
||||||
|
}
|
||||||
|
let accounts_hash = bank2.get_accounts_hash().unwrap();
|
||||||
|
|
||||||
|
let slot = bank2.slot();
|
||||||
|
let incremental =
|
||||||
|
incremental_snapshot_persistence.then(|| BankIncrementalSnapshotPersistence {
|
||||||
|
full_slot: slot - 1,
|
||||||
|
full_hash: SerdeAccountsHash(Hash::new(&[1; 32])),
|
||||||
|
full_capitalization: 31,
|
||||||
|
incremental_hash: SerdeIncrementalAccountsHash(Hash::new(&[2; 32])),
|
||||||
|
incremental_capitalization: 32,
|
||||||
|
});
|
||||||
|
|
||||||
|
if reserialize_accounts_hash || incremental_snapshot_persistence {
|
||||||
|
let temp_dir = TempDir::new().unwrap();
|
||||||
|
let slot_dir = snapshot_utils::get_bank_snapshot_dir(&temp_dir, slot);
|
||||||
|
let post_path = slot_dir.join(slot.to_string());
|
||||||
|
let pre_path = post_path.with_extension(BANK_SNAPSHOT_PRE_FILENAME_EXTENSION);
|
||||||
|
std::fs::create_dir(&slot_dir).unwrap();
|
||||||
|
{
|
||||||
|
let mut f = std::fs::File::create(pre_path).unwrap();
|
||||||
|
f.write_all(&buf).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(reserialize_bank_with_new_accounts_hash(
|
||||||
|
slot_dir,
|
||||||
|
slot,
|
||||||
|
&accounts_hash,
|
||||||
|
incremental.as_ref(),
|
||||||
|
));
|
||||||
|
let mut buf_reserialized;
|
||||||
|
{
|
||||||
|
let previous_len = buf.len();
|
||||||
|
let expected = previous_len
|
||||||
|
+ if incremental_snapshot_persistence {
|
||||||
|
// previously saved a none (size = sizeof_None), now added a Some
|
||||||
|
let sizeof_none = std::mem::size_of::<u64>();
|
||||||
|
let sizeof_incremental_snapshot_persistence =
|
||||||
|
std::mem::size_of::<Option<BankIncrementalSnapshotPersistence>>();
|
||||||
|
sizeof_incremental_snapshot_persistence - sizeof_none
|
||||||
|
} else {
|
||||||
|
// no change
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
// +1: larger buffer than expected to make sure the file isn't larger than expected
|
||||||
|
buf_reserialized = vec![0; expected + 1];
|
||||||
|
let mut f = std::fs::File::open(post_path).unwrap();
|
||||||
|
let size = f.read(&mut buf_reserialized).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
size,
|
||||||
|
expected,
|
||||||
|
"(reserialize_accounts_hash, incremental_snapshot_persistence, update_accounts_hash, initial_epoch_accounts_hash): {:?}, previous_len: {previous_len}",
|
||||||
|
(
|
||||||
|
reserialize_accounts_hash,
|
||||||
|
incremental_snapshot_persistence,
|
||||||
|
update_accounts_hash,
|
||||||
|
initial_epoch_accounts_hash,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
buf_reserialized.truncate(size);
|
||||||
|
}
|
||||||
|
if update_accounts_hash {
|
||||||
|
// We cannot guarantee buffer contents are exactly the same if hash is the same.
|
||||||
|
// Things like hashsets/maps have randomness in their in-mem representations.
|
||||||
|
// This makes serialized bytes not deterministic.
|
||||||
|
// But, we can guarantee that the buffer is different if we change the hash!
|
||||||
|
assert_ne!(buf, buf_reserialized);
|
||||||
|
}
|
||||||
|
if update_accounts_hash || incremental_snapshot_persistence {
|
||||||
|
buf = buf_reserialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 mut status_cache = StatusCache::default();
|
||||||
|
status_cache.add_root(2);
|
||||||
|
// Create a directory to simulate AppendVecs unpackaged from a snapshot tar
|
||||||
|
let copied_accounts = TempDir::new().unwrap();
|
||||||
|
let storage_and_next_append_vec_id =
|
||||||
|
copy_append_vecs(&bank2.rc.accounts.accounts_db, copied_accounts.path()).unwrap();
|
||||||
|
let mut snapshot_streams = SnapshotStreams {
|
||||||
|
full_snapshot_stream: &mut reader,
|
||||||
|
incremental_snapshot_stream: None,
|
||||||
|
};
|
||||||
|
let mut dbank = crate::serde_snapshot::bank_from_streams(
|
||||||
|
serde_style,
|
||||||
|
&mut snapshot_streams,
|
||||||
|
&dbank_paths,
|
||||||
|
storage_and_next_append_vec_id,
|
||||||
|
&genesis_config,
|
||||||
|
&RuntimeConfig::default(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
AccountSecondaryIndexes::default(),
|
||||||
|
None,
|
||||||
|
AccountShrinkThreshold::default(),
|
||||||
|
false,
|
||||||
|
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
||||||
|
None,
|
||||||
|
Arc::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
dbank.status_cache = Arc::new(RwLock::new(status_cache));
|
||||||
|
assert_eq!(dbank.get_balance(&key1.pubkey()), 0);
|
||||||
|
assert_eq!(dbank.get_balance(&key2.pubkey()), 10);
|
||||||
|
assert_eq!(dbank.get_balance(&key3.pubkey()), 0);
|
||||||
|
if let Some(incremental_snapshot_persistence) = incremental.clone() {
|
||||||
|
assert_eq!(dbank.get_accounts_hash(), None,);
|
||||||
|
assert_eq!(
|
||||||
|
dbank.get_incremental_accounts_hash(),
|
||||||
|
Some(incremental_snapshot_persistence.incremental_hash.into()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(dbank.get_accounts_hash(), Some(accounts_hash));
|
||||||
|
assert_eq!(dbank.get_incremental_accounts_hash(), None);
|
||||||
|
}
|
||||||
|
assert!(bank2 == dbank);
|
||||||
|
assert_eq!(dbank.incremental_snapshot_persistence, incremental);
|
||||||
|
assert_eq!(dbank.get_epoch_accounts_hash_to_serialize().map(|epoch_accounts_hash| *epoch_accounts_hash.as_ref()), expected_epoch_accounts_hash,
|
||||||
|
"(reserialize_accounts_hash, incremental_snapshot_persistence, update_accounts_hash, initial_epoch_accounts_hash): {:?}",
|
||||||
|
(
|
||||||
|
reserialize_accounts_hash,
|
||||||
|
incremental_snapshot_persistence,
|
||||||
|
update_accounts_hash,
|
||||||
|
initial_epoch_accounts_hash,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bank_serialize_newer() {
|
||||||
|
for (reserialize_accounts_hash, update_accounts_hash) in
|
||||||
|
[(false, false), (true, false), (true, true)]
|
||||||
|
{
|
||||||
|
let parameters = if reserialize_accounts_hash {
|
||||||
|
[false, true].to_vec()
|
||||||
|
} else {
|
||||||
|
[false].to_vec()
|
||||||
|
};
|
||||||
|
for incremental_snapshot_persistence in parameters.clone() {
|
||||||
|
for initial_epoch_accounts_hash in [false, true] {
|
||||||
|
test_bank_serialize_style(
|
||||||
|
SerdeStyle::Newer,
|
||||||
|
reserialize_accounts_hash,
|
||||||
|
update_accounts_hash,
|
||||||
|
incremental_snapshot_persistence,
|
||||||
|
initial_epoch_accounts_hash,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_root_and_flush_write_cache(bank: &Bank) {
|
||||||
|
bank.rc.accounts.add_root(bank.slot());
|
||||||
|
bank.flush_accounts_cache_slot_for_tests()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extra_fields_eof() {
|
||||||
|
solana_logger::setup();
|
||||||
|
let sample_rewards = (0..2)
|
||||||
|
.map(|_| StakeReward::new_random())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for epoch_reward_status_active in [None, Some(vec![]), Some(vec![sample_rewards])] {
|
||||||
|
let (genesis_config, _) = create_genesis_config(500);
|
||||||
|
|
||||||
|
let bank0 = Arc::new(Bank::new_for_tests_with_config(
|
||||||
|
&genesis_config,
|
||||||
|
BankTestConfig::default(),
|
||||||
|
));
|
||||||
|
bank0.squash();
|
||||||
|
let mut bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||||
|
|
||||||
|
add_root_and_flush_write_cache(&bank0);
|
||||||
|
bank.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_delta_hash_for_tests(
|
||||||
|
bank.slot(),
|
||||||
|
AccountsDeltaHash(Hash::new_unique()),
|
||||||
|
);
|
||||||
|
bank.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_hash_for_tests(bank.slot(), AccountsHash(Hash::new_unique()));
|
||||||
|
|
||||||
|
// Set extra fields
|
||||||
|
bank.fee_rate_governor.lamports_per_signature = 7000;
|
||||||
|
|
||||||
|
if let Some(rewards) = epoch_reward_status_active.as_ref() {
|
||||||
|
assert_eq!(bank.block_height(), 1);
|
||||||
|
bank.set_epoch_reward_status_active(rewards.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize
|
||||||
|
let snapshot_storages = bank.get_snapshot_storages(None);
|
||||||
|
let mut buf = vec![];
|
||||||
|
let mut writer = Cursor::new(&mut buf);
|
||||||
|
|
||||||
|
crate::serde_snapshot::bank_to_stream(
|
||||||
|
SerdeStyle::Newer,
|
||||||
|
&mut std::io::BufWriter::new(&mut writer),
|
||||||
|
&bank,
|
||||||
|
&get_storages_to_serialize(&snapshot_storages),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Deserialize
|
||||||
|
let rdr = Cursor::new(&buf[..]);
|
||||||
|
let mut reader = std::io::BufReader::new(&buf[rdr.position() as usize..]);
|
||||||
|
let mut snapshot_streams = SnapshotStreams {
|
||||||
|
full_snapshot_stream: &mut reader,
|
||||||
|
incremental_snapshot_stream: None,
|
||||||
|
};
|
||||||
|
let (_accounts_dir, dbank_paths) = get_temp_accounts_paths(4).unwrap();
|
||||||
|
let copied_accounts = TempDir::new().unwrap();
|
||||||
|
let storage_and_next_append_vec_id =
|
||||||
|
copy_append_vecs(&bank.rc.accounts.accounts_db, copied_accounts.path()).unwrap();
|
||||||
|
let dbank = crate::serde_snapshot::bank_from_streams(
|
||||||
|
SerdeStyle::Newer,
|
||||||
|
&mut snapshot_streams,
|
||||||
|
&dbank_paths,
|
||||||
|
storage_and_next_append_vec_id,
|
||||||
|
&genesis_config,
|
||||||
|
&RuntimeConfig::default(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
AccountSecondaryIndexes::default(),
|
||||||
|
None,
|
||||||
|
AccountShrinkThreshold::default(),
|
||||||
|
false,
|
||||||
|
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
||||||
|
None,
|
||||||
|
Arc::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
bank.fee_rate_governor.lamports_per_signature,
|
||||||
|
dbank.fee_rate_governor.lamports_per_signature
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert epoch_reward_status is the same as the set epoch reward status
|
||||||
|
let epoch_reward_status = bank
|
||||||
|
.get_epoch_reward_status_to_serialize()
|
||||||
|
.unwrap_or(&EpochRewardStatus::Inactive);
|
||||||
|
if let Some(rewards) = epoch_reward_status_active {
|
||||||
|
assert!(matches!(epoch_reward_status, EpochRewardStatus::Active(_)));
|
||||||
|
if let EpochRewardStatus::Active(StartBlockHeightAndRewards {
|
||||||
|
start_block_height,
|
||||||
|
ref stake_rewards_by_partition,
|
||||||
|
}) = epoch_reward_status
|
||||||
|
{
|
||||||
|
assert_eq!(*start_block_height, 1);
|
||||||
|
assert_eq!(&rewards[..], &stake_rewards_by_partition[..]);
|
||||||
|
} else {
|
||||||
|
unreachable!("Epoch reward status should NOT be inactive.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(matches!(epoch_reward_status, EpochRewardStatus::Inactive));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extra_fields_full_snapshot_archive() {
|
||||||
|
solana_logger::setup();
|
||||||
|
|
||||||
|
let sample_rewards = (0..2)
|
||||||
|
.map(|_| StakeReward::new_random())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for epoch_reward_status_active in [None, Some(vec![]), Some(vec![sample_rewards])] {
|
||||||
|
let (mut genesis_config, _) = create_genesis_config(500);
|
||||||
|
activate_all_features(&mut genesis_config);
|
||||||
|
|
||||||
|
let bank0 = Arc::new(Bank::new_for_tests(&genesis_config));
|
||||||
|
let mut bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||||
|
while !bank.is_complete() {
|
||||||
|
bank.fill_bank_with_ticks_for_tests();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set extra field
|
||||||
|
bank.fee_rate_governor.lamports_per_signature = 7000;
|
||||||
|
|
||||||
|
if let Some(rewards) = epoch_reward_status_active.as_ref() {
|
||||||
|
assert_eq!(bank.block_height(), 1);
|
||||||
|
bank.set_epoch_reward_status_active(rewards.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
|
||||||
|
let bank_snapshots_dir = TempDir::new().unwrap();
|
||||||
|
let full_snapshot_archives_dir = TempDir::new().unwrap();
|
||||||
|
let incremental_snapshot_archives_dir = TempDir::new().unwrap();
|
||||||
|
|
||||||
|
// Serialize
|
||||||
|
let snapshot_archive_info = snapshot_utils::bank_to_full_snapshot_archive(
|
||||||
|
&bank_snapshots_dir,
|
||||||
|
&bank,
|
||||||
|
None,
|
||||||
|
full_snapshot_archives_dir.path(),
|
||||||
|
incremental_snapshot_archives_dir.path(),
|
||||||
|
ArchiveFormat::TarBzip2,
|
||||||
|
NonZeroUsize::new(1).unwrap(),
|
||||||
|
NonZeroUsize::new(1).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Deserialize
|
||||||
|
let (dbank, _) = snapshot_utils::bank_from_snapshot_archives(
|
||||||
|
&[accounts_dir],
|
||||||
|
bank_snapshots_dir.path(),
|
||||||
|
&snapshot_archive_info,
|
||||||
|
None,
|
||||||
|
&genesis_config,
|
||||||
|
&RuntimeConfig::default(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
AccountSecondaryIndexes::default(),
|
||||||
|
None,
|
||||||
|
AccountShrinkThreshold::default(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
||||||
|
None,
|
||||||
|
Arc::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
bank.fee_rate_governor.lamports_per_signature,
|
||||||
|
dbank.fee_rate_governor.lamports_per_signature
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert epoch_reward_status is the same as the set epoch reward status
|
||||||
|
let epoch_reward_status = bank
|
||||||
|
.get_epoch_reward_status_to_serialize()
|
||||||
|
.unwrap_or(&EpochRewardStatus::Inactive);
|
||||||
|
if let Some(rewards) = epoch_reward_status_active {
|
||||||
|
assert!(matches!(epoch_reward_status, EpochRewardStatus::Active(_)));
|
||||||
|
if let EpochRewardStatus::Active(StartBlockHeightAndRewards {
|
||||||
|
start_block_height,
|
||||||
|
ref stake_rewards_by_partition,
|
||||||
|
}) = epoch_reward_status
|
||||||
|
{
|
||||||
|
assert_eq!(*start_block_height, 1);
|
||||||
|
assert_eq!(&rewards[..], &stake_rewards_by_partition[..]);
|
||||||
|
} else {
|
||||||
|
unreachable!("Epoch reward status should NOT be inactive.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(matches!(epoch_reward_status, EpochRewardStatus::Inactive));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blank_extra_fields() {
|
||||||
|
solana_logger::setup();
|
||||||
|
let (genesis_config, _) = create_genesis_config(500);
|
||||||
|
|
||||||
|
let bank0 = Arc::new(Bank::new_for_tests_with_config(
|
||||||
|
&genesis_config,
|
||||||
|
BankTestConfig::default(),
|
||||||
|
));
|
||||||
|
bank0.squash();
|
||||||
|
let mut bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||||
|
add_root_and_flush_write_cache(&bank0);
|
||||||
|
bank.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_delta_hash_for_tests(bank.slot(), AccountsDeltaHash(Hash::new_unique()));
|
||||||
|
bank.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_hash_for_tests(bank.slot(), AccountsHash(Hash::new_unique()));
|
||||||
|
|
||||||
|
// Set extra fields
|
||||||
|
bank.fee_rate_governor.lamports_per_signature = 7000;
|
||||||
|
|
||||||
|
// Serialize, but don't serialize the extra fields
|
||||||
|
let snapshot_storages = bank.get_snapshot_storages(None);
|
||||||
|
let mut buf = vec![];
|
||||||
|
let mut writer = Cursor::new(&mut buf);
|
||||||
|
|
||||||
|
crate::serde_snapshot::bank_to_stream_no_extra_fields(
|
||||||
|
SerdeStyle::Newer,
|
||||||
|
&mut std::io::BufWriter::new(&mut writer),
|
||||||
|
&bank,
|
||||||
|
&get_storages_to_serialize(&snapshot_storages),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Deserialize
|
||||||
|
let rdr = Cursor::new(&buf[..]);
|
||||||
|
let mut reader = std::io::BufReader::new(&buf[rdr.position() as usize..]);
|
||||||
|
let mut snapshot_streams = SnapshotStreams {
|
||||||
|
full_snapshot_stream: &mut reader,
|
||||||
|
incremental_snapshot_stream: None,
|
||||||
|
};
|
||||||
|
let (_accounts_dir, dbank_paths) = get_temp_accounts_paths(4).unwrap();
|
||||||
|
let copied_accounts = TempDir::new().unwrap();
|
||||||
|
let storage_and_next_append_vec_id =
|
||||||
|
copy_append_vecs(&bank.rc.accounts.accounts_db, copied_accounts.path()).unwrap();
|
||||||
|
let dbank = crate::serde_snapshot::bank_from_streams(
|
||||||
|
SerdeStyle::Newer,
|
||||||
|
&mut snapshot_streams,
|
||||||
|
&dbank_paths,
|
||||||
|
storage_and_next_append_vec_id,
|
||||||
|
&genesis_config,
|
||||||
|
&RuntimeConfig::default(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
AccountSecondaryIndexes::default(),
|
||||||
|
None,
|
||||||
|
AccountShrinkThreshold::default(),
|
||||||
|
false,
|
||||||
|
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
||||||
|
None,
|
||||||
|
Arc::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Defaults to 0
|
||||||
|
assert_eq!(0, dbank.fee_rate_governor.lamports_per_signature);
|
||||||
|
|
||||||
|
// epoch_reward status should default to `Inactive`
|
||||||
|
let epoch_reward_status = bank
|
||||||
|
.get_epoch_reward_status_to_serialize()
|
||||||
|
.unwrap_or(&EpochRewardStatus::Inactive);
|
||||||
|
assert!(matches!(epoch_reward_status, EpochRewardStatus::Inactive));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
||||||
|
mod test_bank_serialize {
|
||||||
|
use {super::*, crate::serde_snapshot::serialize_test_bank_and_storage};
|
||||||
|
|
||||||
|
// This some what long test harness is required to freeze the ABI of
|
||||||
|
// Bank's serialization due to versioned nature
|
||||||
|
#[frozen_abi(digest = "A99zFXvqYm88n6EbtEFbroDbuFNnhw4K7AmqMh2wjJmh")]
|
||||||
|
#[derive(Serialize, AbiExample)]
|
||||||
|
pub struct BankAbiTestWrapperNewer {
|
||||||
|
#[serde(serialize_with = "wrapper_newer")]
|
||||||
|
bank: Bank,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrapper_newer<S>(bank: &Bank, s: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
bank.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_delta_hash_for_tests(
|
||||||
|
bank.slot(),
|
||||||
|
AccountsDeltaHash(Hash::new_unique()),
|
||||||
|
);
|
||||||
|
bank.rc
|
||||||
|
.accounts
|
||||||
|
.accounts_db
|
||||||
|
.set_accounts_hash_for_tests(bank.slot(), AccountsHash(Hash::new_unique()));
|
||||||
|
let snapshot_storages = bank.rc.accounts.accounts_db.get_snapshot_storages(..=0).0;
|
||||||
|
// ensure there is a single snapshot storage example for ABI digesting
|
||||||
|
assert_eq!(snapshot_storages.len(), 1);
|
||||||
|
|
||||||
|
serialize_test_bank_and_storage::<S>(
|
||||||
|
bank,
|
||||||
|
&get_storages_to_serialize(&snapshot_storages),
|
||||||
|
s,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -504,6 +504,23 @@ impl<'a, C: TypeContext<'a>> Serialize for SerializableBankAndStorage<'a, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn serialize_test_bank_and_storage<S>(
|
||||||
|
bank: &Bank,
|
||||||
|
storage: &[Vec<Arc<AccountStorageEntry>>],
|
||||||
|
s: S,
|
||||||
|
) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
(SerializableBankAndStorage::<newer::Context> {
|
||||||
|
bank,
|
||||||
|
snapshot_storages: storage,
|
||||||
|
phantom: std::marker::PhantomData::default(),
|
||||||
|
})
|
||||||
|
.serialize(s)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
struct SerializableBankAndStorageNoExtra<'a, C> {
|
struct SerializableBankAndStorageNoExtra<'a, C> {
|
||||||
bank: &'a Bank,
|
bank: &'a Bank,
|
||||||
|
|
|
@ -9,33 +9,23 @@ use {
|
||||||
get_temp_accounts_paths, test_utils::create_test_accounts, AccountShrinkThreshold,
|
get_temp_accounts_paths, test_utils::create_test_accounts, AccountShrinkThreshold,
|
||||||
},
|
},
|
||||||
accounts_file::{AccountsFile, AccountsFileError},
|
accounts_file::{AccountsFile, AccountsFileError},
|
||||||
accounts_hash::{AccountsDeltaHash, AccountsHash},
|
accounts_hash::AccountsHash,
|
||||||
bank::{Bank, BankTestConfig, EpochRewardStatus, StartBlockHeightAndRewards},
|
snapshot_utils::get_storages_to_serialize,
|
||||||
epoch_accounts_hash,
|
|
||||||
genesis_utils::{activate_all_features, activate_feature},
|
|
||||||
snapshot_utils::{
|
|
||||||
create_tmp_accounts_dir_for_tests, get_storages_to_serialize, ArchiveFormat,
|
|
||||||
},
|
|
||||||
stake_rewards::StakeReward,
|
|
||||||
status_cache::StatusCache,
|
|
||||||
},
|
},
|
||||||
bincode::serialize_into,
|
bincode::serialize_into,
|
||||||
rand::{thread_rng, Rng},
|
rand::{thread_rng, Rng},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{AccountSharedData, ReadableAccount},
|
account::{AccountSharedData, ReadableAccount},
|
||||||
clock::Slot,
|
clock::Slot,
|
||||||
feature_set,
|
genesis_config::ClusterType,
|
||||||
genesis_config::{create_genesis_config, ClusterType},
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
io::{BufReader, Cursor},
|
io::{BufReader, Cursor},
|
||||||
num::NonZeroUsize,
|
|
||||||
ops::RangeFull,
|
ops::RangeFull,
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{Arc, RwLock},
|
sync::Arc,
|
||||||
},
|
},
|
||||||
tempfile::TempDir,
|
tempfile::TempDir,
|
||||||
};
|
};
|
||||||
|
@ -228,219 +218,6 @@ fn test_accounts_serialize_style(serde_style: SerdeStyle) {
|
||||||
assert_eq!(accounts_hash, daccounts_hash);
|
assert_eq!(accounts_hash, daccounts_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_bank_serialize_style(
|
|
||||||
serde_style: SerdeStyle,
|
|
||||||
reserialize_accounts_hash: bool,
|
|
||||||
update_accounts_hash: bool,
|
|
||||||
incremental_snapshot_persistence: bool,
|
|
||||||
initial_epoch_accounts_hash: bool,
|
|
||||||
) {
|
|
||||||
solana_logger::setup();
|
|
||||||
let (mut genesis_config, _) = create_genesis_config(500);
|
|
||||||
activate_feature(&mut genesis_config, feature_set::epoch_accounts_hash::id());
|
|
||||||
genesis_config.epoch_schedule = EpochSchedule::custom(400, 400, false);
|
|
||||||
let bank0 = Arc::new(Bank::new_for_tests(&genesis_config));
|
|
||||||
let eah_start_slot = epoch_accounts_hash::calculation_start(&bank0);
|
|
||||||
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).unwrap();
|
|
||||||
|
|
||||||
// If setting an initial EAH, then the bank being snapshotted must be in the EAH calculation
|
|
||||||
// window. Otherwise `bank_to_stream()` below will *not* include the EAH in the bank snapshot,
|
|
||||||
// and the later-deserialized bank's EAH will not match the expected EAH.
|
|
||||||
let bank2_slot = if initial_epoch_accounts_hash {
|
|
||||||
eah_start_slot
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
} + 2;
|
|
||||||
let bank2 = Bank::new_from_parent(&bank0, &Pubkey::default(), bank2_slot);
|
|
||||||
|
|
||||||
// Test new account
|
|
||||||
let key2 = Keypair::new();
|
|
||||||
bank2.deposit(&key2.pubkey(), 10).unwrap();
|
|
||||||
assert_eq!(bank2.get_balance(&key2.pubkey()), 10);
|
|
||||||
|
|
||||||
let key3 = Keypair::new();
|
|
||||||
bank2.deposit(&key3.pubkey(), 0).unwrap();
|
|
||||||
|
|
||||||
bank2.freeze();
|
|
||||||
bank2.squash();
|
|
||||||
bank2.force_flush_accounts_cache();
|
|
||||||
bank2
|
|
||||||
.accounts()
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_hash_for_tests(bank2.slot(), AccountsHash(Hash::new(&[0; 32])));
|
|
||||||
|
|
||||||
let snapshot_storages = bank2.get_snapshot_storages(None);
|
|
||||||
let mut buf = vec![];
|
|
||||||
let mut writer = Cursor::new(&mut buf);
|
|
||||||
|
|
||||||
let mut expected_epoch_accounts_hash = None;
|
|
||||||
|
|
||||||
if initial_epoch_accounts_hash {
|
|
||||||
expected_epoch_accounts_hash = Some(Hash::new(&[7; 32]));
|
|
||||||
bank2
|
|
||||||
.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.epoch_accounts_hash_manager
|
|
||||||
.set_valid(
|
|
||||||
EpochAccountsHash::new(expected_epoch_accounts_hash.unwrap()),
|
|
||||||
eah_start_slot,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::serde_snapshot::bank_to_stream(
|
|
||||||
serde_style,
|
|
||||||
&mut std::io::BufWriter::new(&mut writer),
|
|
||||||
&bank2,
|
|
||||||
&get_storages_to_serialize(&snapshot_storages),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if update_accounts_hash {
|
|
||||||
bank2
|
|
||||||
.accounts()
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_hash_for_tests(bank2.slot(), AccountsHash(Hash::new(&[1; 32])));
|
|
||||||
}
|
|
||||||
let accounts_hash = bank2.get_accounts_hash().unwrap();
|
|
||||||
|
|
||||||
let slot = bank2.slot();
|
|
||||||
let incremental =
|
|
||||||
incremental_snapshot_persistence.then(|| BankIncrementalSnapshotPersistence {
|
|
||||||
full_slot: slot - 1,
|
|
||||||
full_hash: SerdeAccountsHash(Hash::new(&[1; 32])),
|
|
||||||
full_capitalization: 31,
|
|
||||||
incremental_hash: SerdeIncrementalAccountsHash(Hash::new(&[2; 32])),
|
|
||||||
incremental_capitalization: 32,
|
|
||||||
});
|
|
||||||
|
|
||||||
if reserialize_accounts_hash || incremental_snapshot_persistence {
|
|
||||||
let temp_dir = TempDir::new().unwrap();
|
|
||||||
let slot_dir = snapshot_utils::get_bank_snapshot_dir(&temp_dir, slot);
|
|
||||||
let post_path = slot_dir.join(slot.to_string());
|
|
||||||
let pre_path = post_path.with_extension(BANK_SNAPSHOT_PRE_FILENAME_EXTENSION);
|
|
||||||
std::fs::create_dir(&slot_dir).unwrap();
|
|
||||||
{
|
|
||||||
let mut f = std::fs::File::create(pre_path).unwrap();
|
|
||||||
f.write_all(&buf).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(reserialize_bank_with_new_accounts_hash(
|
|
||||||
slot_dir,
|
|
||||||
slot,
|
|
||||||
&accounts_hash,
|
|
||||||
incremental.as_ref(),
|
|
||||||
));
|
|
||||||
let mut buf_reserialized;
|
|
||||||
{
|
|
||||||
let previous_len = buf.len();
|
|
||||||
let expected = previous_len
|
|
||||||
+ if incremental_snapshot_persistence {
|
|
||||||
// previously saved a none (size = sizeof_None), now added a Some
|
|
||||||
let sizeof_none = std::mem::size_of::<u64>();
|
|
||||||
let sizeof_incremental_snapshot_persistence =
|
|
||||||
std::mem::size_of::<Option<BankIncrementalSnapshotPersistence>>();
|
|
||||||
sizeof_incremental_snapshot_persistence - sizeof_none
|
|
||||||
} else {
|
|
||||||
// no change
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
// +1: larger buffer than expected to make sure the file isn't larger than expected
|
|
||||||
buf_reserialized = vec![0; expected + 1];
|
|
||||||
let mut f = std::fs::File::open(post_path).unwrap();
|
|
||||||
let size = f.read(&mut buf_reserialized).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
size,
|
|
||||||
expected,
|
|
||||||
"(reserialize_accounts_hash, incremental_snapshot_persistence, update_accounts_hash, initial_epoch_accounts_hash): {:?}, previous_len: {previous_len}",
|
|
||||||
(
|
|
||||||
reserialize_accounts_hash,
|
|
||||||
incremental_snapshot_persistence,
|
|
||||||
update_accounts_hash,
|
|
||||||
initial_epoch_accounts_hash,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
buf_reserialized.truncate(size);
|
|
||||||
}
|
|
||||||
if update_accounts_hash {
|
|
||||||
// We cannot guarantee buffer contents are exactly the same if hash is the same.
|
|
||||||
// Things like hashsets/maps have randomness in their in-mem representations.
|
|
||||||
// This makes serialized bytes not deterministic.
|
|
||||||
// But, we can guarantee that the buffer is different if we change the hash!
|
|
||||||
assert_ne!(buf, buf_reserialized);
|
|
||||||
}
|
|
||||||
if update_accounts_hash || incremental_snapshot_persistence {
|
|
||||||
buf = buf_reserialized;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 mut status_cache = StatusCache::default();
|
|
||||||
status_cache.add_root(2);
|
|
||||||
// Create a directory to simulate AppendVecs unpackaged from a snapshot tar
|
|
||||||
let copied_accounts = TempDir::new().unwrap();
|
|
||||||
let storage_and_next_append_vec_id =
|
|
||||||
copy_append_vecs(&bank2.rc.accounts.accounts_db, copied_accounts.path()).unwrap();
|
|
||||||
let mut snapshot_streams = SnapshotStreams {
|
|
||||||
full_snapshot_stream: &mut reader,
|
|
||||||
incremental_snapshot_stream: None,
|
|
||||||
};
|
|
||||||
let mut dbank = crate::serde_snapshot::bank_from_streams(
|
|
||||||
serde_style,
|
|
||||||
&mut snapshot_streams,
|
|
||||||
&dbank_paths,
|
|
||||||
storage_and_next_append_vec_id,
|
|
||||||
&genesis_config,
|
|
||||||
&RuntimeConfig::default(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
None,
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
false,
|
|
||||||
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
|
||||||
None,
|
|
||||||
Arc::default(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
dbank.status_cache = Arc::new(RwLock::new(status_cache));
|
|
||||||
assert_eq!(dbank.get_balance(&key1.pubkey()), 0);
|
|
||||||
assert_eq!(dbank.get_balance(&key2.pubkey()), 10);
|
|
||||||
assert_eq!(dbank.get_balance(&key3.pubkey()), 0);
|
|
||||||
if let Some(incremental_snapshot_persistence) = incremental.clone() {
|
|
||||||
assert_eq!(dbank.get_accounts_hash(), None,);
|
|
||||||
assert_eq!(
|
|
||||||
dbank.get_incremental_accounts_hash(),
|
|
||||||
Some(incremental_snapshot_persistence.incremental_hash.into()),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
assert_eq!(dbank.get_accounts_hash(), Some(accounts_hash));
|
|
||||||
assert_eq!(dbank.get_incremental_accounts_hash(), None);
|
|
||||||
}
|
|
||||||
assert!(bank2 == dbank);
|
|
||||||
assert_eq!(dbank.incremental_snapshot_persistence, incremental);
|
|
||||||
assert_eq!(dbank.get_epoch_accounts_hash_to_serialize().map(|epoch_accounts_hash| *epoch_accounts_hash.as_ref()), expected_epoch_accounts_hash,
|
|
||||||
"(reserialize_accounts_hash, incremental_snapshot_persistence, update_accounts_hash, initial_epoch_accounts_hash): {:?}",
|
|
||||||
(
|
|
||||||
reserialize_accounts_hash,
|
|
||||||
incremental_snapshot_persistence,
|
|
||||||
update_accounts_hash,
|
|
||||||
initial_epoch_accounts_hash,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn reconstruct_accounts_db_via_serialization(
|
pub(crate) fn reconstruct_accounts_db_via_serialization(
|
||||||
accounts: &AccountsDb,
|
accounts: &AccountsDb,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
|
@ -486,343 +263,3 @@ pub(crate) fn reconstruct_accounts_db_via_serialization(
|
||||||
fn test_accounts_serialize_newer() {
|
fn test_accounts_serialize_newer() {
|
||||||
test_accounts_serialize_style(SerdeStyle::Newer)
|
test_accounts_serialize_style(SerdeStyle::Newer)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bank_serialize_newer() {
|
|
||||||
for (reserialize_accounts_hash, update_accounts_hash) in
|
|
||||||
[(false, false), (true, false), (true, true)]
|
|
||||||
{
|
|
||||||
let parameters = if reserialize_accounts_hash {
|
|
||||||
[false, true].to_vec()
|
|
||||||
} else {
|
|
||||||
[false].to_vec()
|
|
||||||
};
|
|
||||||
for incremental_snapshot_persistence in parameters.clone() {
|
|
||||||
for initial_epoch_accounts_hash in [false, true] {
|
|
||||||
test_bank_serialize_style(
|
|
||||||
SerdeStyle::Newer,
|
|
||||||
reserialize_accounts_hash,
|
|
||||||
update_accounts_hash,
|
|
||||||
incremental_snapshot_persistence,
|
|
||||||
initial_epoch_accounts_hash,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_root_and_flush_write_cache(bank: &Bank) {
|
|
||||||
bank.rc.accounts.add_root(bank.slot());
|
|
||||||
bank.flush_accounts_cache_slot_for_tests()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extra_fields_eof() {
|
|
||||||
solana_logger::setup();
|
|
||||||
let sample_rewards = (0..2)
|
|
||||||
.map(|_| StakeReward::new_random())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for epoch_reward_status_active in [None, Some(vec![]), Some(vec![sample_rewards])] {
|
|
||||||
let (genesis_config, _) = create_genesis_config(500);
|
|
||||||
|
|
||||||
let bank0 = Arc::new(Bank::new_for_tests_with_config(
|
|
||||||
&genesis_config,
|
|
||||||
BankTestConfig::default(),
|
|
||||||
));
|
|
||||||
bank0.squash();
|
|
||||||
let mut bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
||||||
|
|
||||||
add_root_and_flush_write_cache(&bank0);
|
|
||||||
bank.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_delta_hash_for_tests(bank.slot(), AccountsDeltaHash(Hash::new_unique()));
|
|
||||||
bank.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_hash_for_tests(bank.slot(), AccountsHash(Hash::new_unique()));
|
|
||||||
|
|
||||||
// Set extra fields
|
|
||||||
bank.fee_rate_governor.lamports_per_signature = 7000;
|
|
||||||
|
|
||||||
if let Some(rewards) = epoch_reward_status_active.as_ref() {
|
|
||||||
assert_eq!(bank.block_height(), 1);
|
|
||||||
bank.set_epoch_reward_status_active(rewards.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize
|
|
||||||
let snapshot_storages = bank.get_snapshot_storages(None);
|
|
||||||
let mut buf = vec![];
|
|
||||||
let mut writer = Cursor::new(&mut buf);
|
|
||||||
|
|
||||||
crate::serde_snapshot::bank_to_stream(
|
|
||||||
SerdeStyle::Newer,
|
|
||||||
&mut std::io::BufWriter::new(&mut writer),
|
|
||||||
&bank,
|
|
||||||
&get_storages_to_serialize(&snapshot_storages),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Deserialize
|
|
||||||
let rdr = Cursor::new(&buf[..]);
|
|
||||||
let mut reader = std::io::BufReader::new(&buf[rdr.position() as usize..]);
|
|
||||||
let mut snapshot_streams = SnapshotStreams {
|
|
||||||
full_snapshot_stream: &mut reader,
|
|
||||||
incremental_snapshot_stream: None,
|
|
||||||
};
|
|
||||||
let (_accounts_dir, dbank_paths) = get_temp_accounts_paths(4).unwrap();
|
|
||||||
let copied_accounts = TempDir::new().unwrap();
|
|
||||||
let storage_and_next_append_vec_id =
|
|
||||||
copy_append_vecs(&bank.rc.accounts.accounts_db, copied_accounts.path()).unwrap();
|
|
||||||
let dbank = crate::serde_snapshot::bank_from_streams(
|
|
||||||
SerdeStyle::Newer,
|
|
||||||
&mut snapshot_streams,
|
|
||||||
&dbank_paths,
|
|
||||||
storage_and_next_append_vec_id,
|
|
||||||
&genesis_config,
|
|
||||||
&RuntimeConfig::default(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
None,
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
false,
|
|
||||||
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
|
||||||
None,
|
|
||||||
Arc::default(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
bank.fee_rate_governor.lamports_per_signature,
|
|
||||||
dbank.fee_rate_governor.lamports_per_signature
|
|
||||||
);
|
|
||||||
|
|
||||||
// assert epoch_reward_status is the same as the set epoch reward status
|
|
||||||
let epoch_reward_status = bank
|
|
||||||
.get_epoch_reward_status_to_serialize()
|
|
||||||
.unwrap_or(&EpochRewardStatus::Inactive);
|
|
||||||
if let Some(rewards) = epoch_reward_status_active {
|
|
||||||
assert!(matches!(epoch_reward_status, EpochRewardStatus::Active(_)));
|
|
||||||
if let EpochRewardStatus::Active(StartBlockHeightAndRewards {
|
|
||||||
start_block_height,
|
|
||||||
ref stake_rewards_by_partition,
|
|
||||||
}) = epoch_reward_status
|
|
||||||
{
|
|
||||||
assert_eq!(*start_block_height, 1);
|
|
||||||
assert_eq!(&rewards[..], &stake_rewards_by_partition[..]);
|
|
||||||
} else {
|
|
||||||
unreachable!("Epoch reward status should NOT be inactive.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert!(matches!(epoch_reward_status, EpochRewardStatus::Inactive));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extra_fields_full_snapshot_archive() {
|
|
||||||
solana_logger::setup();
|
|
||||||
|
|
||||||
let sample_rewards = (0..2)
|
|
||||||
.map(|_| StakeReward::new_random())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for epoch_reward_status_active in [None, Some(vec![]), Some(vec![sample_rewards])] {
|
|
||||||
let (mut genesis_config, _) = create_genesis_config(500);
|
|
||||||
activate_all_features(&mut genesis_config);
|
|
||||||
|
|
||||||
let bank0 = Arc::new(Bank::new_for_tests(&genesis_config));
|
|
||||||
let mut bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
||||||
while !bank.is_complete() {
|
|
||||||
bank.fill_bank_with_ticks_for_tests();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set extra field
|
|
||||||
bank.fee_rate_governor.lamports_per_signature = 7000;
|
|
||||||
|
|
||||||
if let Some(rewards) = epoch_reward_status_active.as_ref() {
|
|
||||||
assert_eq!(bank.block_height(), 1);
|
|
||||||
bank.set_epoch_reward_status_active(rewards.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
|
|
||||||
let bank_snapshots_dir = TempDir::new().unwrap();
|
|
||||||
let full_snapshot_archives_dir = TempDir::new().unwrap();
|
|
||||||
let incremental_snapshot_archives_dir = TempDir::new().unwrap();
|
|
||||||
|
|
||||||
// Serialize
|
|
||||||
let snapshot_archive_info = snapshot_utils::bank_to_full_snapshot_archive(
|
|
||||||
&bank_snapshots_dir,
|
|
||||||
&bank,
|
|
||||||
None,
|
|
||||||
full_snapshot_archives_dir.path(),
|
|
||||||
incremental_snapshot_archives_dir.path(),
|
|
||||||
ArchiveFormat::TarBzip2,
|
|
||||||
NonZeroUsize::new(1).unwrap(),
|
|
||||||
NonZeroUsize::new(1).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Deserialize
|
|
||||||
let (dbank, _) = snapshot_utils::bank_from_snapshot_archives(
|
|
||||||
&[accounts_dir],
|
|
||||||
bank_snapshots_dir.path(),
|
|
||||||
&snapshot_archive_info,
|
|
||||||
None,
|
|
||||||
&genesis_config,
|
|
||||||
&RuntimeConfig::default(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
None,
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
|
||||||
None,
|
|
||||||
Arc::default(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
bank.fee_rate_governor.lamports_per_signature,
|
|
||||||
dbank.fee_rate_governor.lamports_per_signature
|
|
||||||
);
|
|
||||||
|
|
||||||
// assert epoch_reward_status is the same as the set epoch reward status
|
|
||||||
let epoch_reward_status = bank
|
|
||||||
.get_epoch_reward_status_to_serialize()
|
|
||||||
.unwrap_or(&EpochRewardStatus::Inactive);
|
|
||||||
if let Some(rewards) = epoch_reward_status_active {
|
|
||||||
assert!(matches!(epoch_reward_status, EpochRewardStatus::Active(_)));
|
|
||||||
if let EpochRewardStatus::Active(StartBlockHeightAndRewards {
|
|
||||||
start_block_height,
|
|
||||||
ref stake_rewards_by_partition,
|
|
||||||
}) = epoch_reward_status
|
|
||||||
{
|
|
||||||
assert_eq!(*start_block_height, 1);
|
|
||||||
assert_eq!(&rewards[..], &stake_rewards_by_partition[..]);
|
|
||||||
} else {
|
|
||||||
unreachable!("Epoch reward status should NOT be inactive.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert!(matches!(epoch_reward_status, EpochRewardStatus::Inactive));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_blank_extra_fields() {
|
|
||||||
solana_logger::setup();
|
|
||||||
let (genesis_config, _) = create_genesis_config(500);
|
|
||||||
|
|
||||||
let bank0 = Arc::new(Bank::new_for_tests_with_config(
|
|
||||||
&genesis_config,
|
|
||||||
BankTestConfig::default(),
|
|
||||||
));
|
|
||||||
bank0.squash();
|
|
||||||
let mut bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
||||||
add_root_and_flush_write_cache(&bank0);
|
|
||||||
bank.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_delta_hash_for_tests(bank.slot(), AccountsDeltaHash(Hash::new_unique()));
|
|
||||||
bank.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_hash_for_tests(bank.slot(), AccountsHash(Hash::new_unique()));
|
|
||||||
|
|
||||||
// Set extra fields
|
|
||||||
bank.fee_rate_governor.lamports_per_signature = 7000;
|
|
||||||
|
|
||||||
// Serialize, but don't serialize the extra fields
|
|
||||||
let snapshot_storages = bank.get_snapshot_storages(None);
|
|
||||||
let mut buf = vec![];
|
|
||||||
let mut writer = Cursor::new(&mut buf);
|
|
||||||
|
|
||||||
crate::serde_snapshot::bank_to_stream_no_extra_fields(
|
|
||||||
SerdeStyle::Newer,
|
|
||||||
&mut std::io::BufWriter::new(&mut writer),
|
|
||||||
&bank,
|
|
||||||
&get_storages_to_serialize(&snapshot_storages),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Deserialize
|
|
||||||
let rdr = Cursor::new(&buf[..]);
|
|
||||||
let mut reader = std::io::BufReader::new(&buf[rdr.position() as usize..]);
|
|
||||||
let mut snapshot_streams = SnapshotStreams {
|
|
||||||
full_snapshot_stream: &mut reader,
|
|
||||||
incremental_snapshot_stream: None,
|
|
||||||
};
|
|
||||||
let (_accounts_dir, dbank_paths) = get_temp_accounts_paths(4).unwrap();
|
|
||||||
let copied_accounts = TempDir::new().unwrap();
|
|
||||||
let storage_and_next_append_vec_id =
|
|
||||||
copy_append_vecs(&bank.rc.accounts.accounts_db, copied_accounts.path()).unwrap();
|
|
||||||
let dbank = crate::serde_snapshot::bank_from_streams(
|
|
||||||
SerdeStyle::Newer,
|
|
||||||
&mut snapshot_streams,
|
|
||||||
&dbank_paths,
|
|
||||||
storage_and_next_append_vec_id,
|
|
||||||
&genesis_config,
|
|
||||||
&RuntimeConfig::default(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
None,
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
false,
|
|
||||||
Some(crate::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING),
|
|
||||||
None,
|
|
||||||
Arc::default(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Defaults to 0
|
|
||||||
assert_eq!(0, dbank.fee_rate_governor.lamports_per_signature);
|
|
||||||
|
|
||||||
// epoch_reward status should default to `Inactive`
|
|
||||||
let epoch_reward_status = bank
|
|
||||||
.get_epoch_reward_status_to_serialize()
|
|
||||||
.unwrap_or(&EpochRewardStatus::Inactive);
|
|
||||||
assert!(matches!(epoch_reward_status, EpochRewardStatus::Inactive));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
|
||||||
mod test_bank_serialize {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
// This some what long test harness is required to freeze the ABI of
|
|
||||||
// Bank's serialization due to versioned nature
|
|
||||||
#[frozen_abi(digest = "A99zFXvqYm88n6EbtEFbroDbuFNnhw4K7AmqMh2wjJmh")]
|
|
||||||
#[derive(Serialize, AbiExample)]
|
|
||||||
pub struct BankAbiTestWrapperNewer {
|
|
||||||
#[serde(serialize_with = "wrapper_newer")]
|
|
||||||
bank: Bank,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wrapper_newer<S>(bank: &Bank, s: S) -> std::result::Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
bank.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_delta_hash_for_tests(bank.slot(), AccountsDeltaHash(Hash::new_unique()));
|
|
||||||
bank.rc
|
|
||||||
.accounts
|
|
||||||
.accounts_db
|
|
||||||
.set_accounts_hash_for_tests(bank.slot(), AccountsHash(Hash::new_unique()));
|
|
||||||
let snapshot_storages = bank.rc.accounts.accounts_db.get_snapshot_storages(..=0).0;
|
|
||||||
// ensure there is a single snapshot storage example for ABI digesting
|
|
||||||
assert_eq!(snapshot_storages.len(), 1);
|
|
||||||
|
|
||||||
(SerializableBankAndStorage::<newer::Context> {
|
|
||||||
bank,
|
|
||||||
snapshot_storages: &get_storages_to_serialize(&snapshot_storages),
|
|
||||||
phantom: std::marker::PhantomData::default(),
|
|
||||||
})
|
|
||||||
.serialize(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue