Adds tests for EAH and snapshot interactions (#28304)

This commit is contained in:
Brooks Prumo 2022-10-10 10:16:13 -04:00 committed by GitHub
parent 2fc8e533a2
commit 27cd2c324e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 165 additions and 11 deletions

View File

@ -11,13 +11,18 @@ use {
AbsRequestHandlers, AbsRequestSender, AccountsBackgroundService, DroppedSlotsReceiver,
PrunedBanksRequestHandler, SnapshotRequestHandler,
},
accounts_db::AccountShrinkThreshold,
accounts_hash::CalcAccountsHashConfig,
accounts_index::AccountSecondaryIndexes,
bank::Bank,
bank_forks::BankForks,
epoch_accounts_hash::{self, EpochAccountsHash},
genesis_utils::{self, GenesisConfigInfo},
runtime_config::RuntimeConfig,
snapshot_archive_info::SnapshotArchiveInfoGetter,
snapshot_config::SnapshotConfig,
snapshot_package::{PendingAccountsPackage, PendingSnapshotPackage},
snapshot_utils,
},
solana_sdk::{
clock::Slot,
@ -39,6 +44,7 @@ use {
time::Duration,
},
tempfile::TempDir,
test_case::test_case,
};
struct TestEnvironment {
@ -49,7 +55,7 @@ struct TestEnvironment {
bank_forks: Arc<RwLock<BankForks>>,
background_services: BackgroundServices,
genesis_config_info: GenesisConfigInfo,
_snapshot_config: SnapshotConfig,
snapshot_config: SnapshotConfig,
_bank_snapshots_dir: TempDir,
_full_snapshot_archives_dir: TempDir,
_incremental_snapshot_archives_dir: TempDir,
@ -64,6 +70,24 @@ impl TestEnvironment {
#[must_use]
fn new() -> TestEnvironment {
Self::_new(SnapshotConfig::new_load_only())
}
#[must_use]
fn new_with_snapshots(
full_snapshot_archive_interval_slots: Slot,
incremental_snapshot_archive_interval_slots: Slot,
) -> TestEnvironment {
let snapshot_config = SnapshotConfig {
full_snapshot_archive_interval_slots,
incremental_snapshot_archive_interval_slots,
..SnapshotConfig::default()
};
Self::_new(snapshot_config)
}
#[must_use]
fn _new(snapshot_config: SnapshotConfig) -> TestEnvironment {
let bank_snapshots_dir = TempDir::new().unwrap();
let full_snapshot_archives_dir = TempDir::new().unwrap();
let incremental_snapshot_archives_dir = TempDir::new().unwrap();
@ -80,7 +104,7 @@ impl TestEnvironment {
.path()
.to_path_buf(),
bank_snapshots_dir: bank_snapshots_dir.path().to_path_buf(),
..SnapshotConfig::new_load_only()
..snapshot_config
};
let mut bank_forks =
@ -124,7 +148,7 @@ impl TestEnvironment {
_bank_snapshots_dir: bank_snapshots_dir,
_full_snapshot_archives_dir: full_snapshot_archives_dir,
_incremental_snapshot_archives_dir: incremental_snapshot_archives_dir,
_snapshot_config: snapshot_config,
snapshot_config,
background_services,
}
}
@ -222,20 +246,21 @@ impl Drop for BackgroundServices {
}
}
/// Run through a few epochs and ensure the Epoch Accounts Hash is calculated correctly
#[test]
fn test_epoch_accounts_hash() {
/// Ensure that EAHs are requested, calculated, and awaited correctly.
/// Test both with and without snapshots to make sure they don't interfere with EAH.
#[test_case(TestEnvironment::new() ; "without snapshots")]
#[test_case(TestEnvironment::new_with_snapshots(20, 10) ; "with snapshots")]
fn test_epoch_accounts_hash_basic(test_environment: TestEnvironment) {
solana_logger::setup();
const NUM_EPOCHS_TO_TEST: u64 = 2;
const SET_ROOT_INTERVAL: Slot = 3;
let test_config = TestEnvironment::new();
let bank_forks = &test_config.bank_forks;
let bank_forks = &test_environment.bank_forks;
let mut expected_epoch_accounts_hash = None;
let slots_per_epoch = test_config
let slots_per_epoch = test_environment
.genesis_config_info
.genesis_config
.epoch_schedule
@ -250,7 +275,7 @@ fn test_epoch_accounts_hash() {
));
let transaction = system_transaction::transfer(
&test_config.genesis_config_info.mint_keypair,
&test_environment.genesis_config_info.mint_keypair,
&Pubkey::new_unique(),
1,
bank.last_blockhash(),
@ -267,7 +292,7 @@ fn test_epoch_accounts_hash() {
trace!("rooting bank {}", bank.slot());
bank_forks.write().unwrap().set_root(
bank.slot(),
&test_config
&test_environment
.background_services
.accounts_background_request_sender,
None,
@ -322,3 +347,132 @@ fn test_epoch_accounts_hash() {
std::thread::yield_now();
}
}
/// Ensure that snapshots always have the expected EAH
///
/// Generate snapshots:
/// - Before EAH start
/// - After EAH start but before EAH stop
/// - After EAH stop
///
/// In Epoch 0, this will correspond to all three EAH states (invalid, in-flight, and valid). In
/// Epoch 1, this will correspond to a normal running cluster, where EAH will only be either
/// in-flight or valid.
#[test]
fn test_snapshots_have_expected_epoch_accounts_hash() {
solana_logger::setup();
const NUM_EPOCHS_TO_TEST: u64 = 2;
// Since slots-per-epoch is 100, EAH start will be slots 25 and 125, and EAH stop will be slots
// 75 and 175. Pick a full snapshot interval that triggers in the three scenarios outlined in
// the test's description.
const FULL_SNAPSHOT_INTERVAL: Slot = 20;
let test_environment =
TestEnvironment::new_with_snapshots(FULL_SNAPSHOT_INTERVAL, FULL_SNAPSHOT_INTERVAL);
let bank_forks = &test_environment.bank_forks;
let slots_per_epoch = test_environment
.genesis_config_info
.genesis_config
.epoch_schedule
.slots_per_epoch;
for _ in 0..slots_per_epoch * NUM_EPOCHS_TO_TEST {
let bank = {
let parent = bank_forks.read().unwrap().working_bank();
let bank = bank_forks.write().unwrap().insert(Bank::new_from_parent(
&parent,
&Pubkey::default(),
parent.slot() + 1,
));
let transaction = system_transaction::transfer(
&test_environment.genesis_config_info.mint_keypair,
&Pubkey::new_unique(),
1,
bank.last_blockhash(),
);
bank.process_transaction(&transaction).unwrap();
bank.fill_bank_with_ticks_for_tests();
bank
};
trace!("new bank {}", bank.slot());
// Root every bank. This is what a normal validator does as well.
// `set_root()` is also what requests snapshots and EAH calculations.
bank_forks.write().unwrap().set_root(
bank.slot(),
&test_environment
.background_services
.accounts_background_request_sender,
None,
);
// After submitting an EAH calculation request, wait until it gets handled by ABS so that
// subsequent snapshot requests are not swallowed.
if bank.slot() == epoch_accounts_hash::calculation_start(&bank) {
while dbg!(bank.epoch_accounts_hash()).is_none() {
std::thread::sleep(Duration::from_secs(1));
}
}
// After submitting a snapshot request...
// - Wait until the snapshot archive has been generated
// - Deserialize the bank from the snapshot archive
// - Ensure the EAHs match
if bank.slot() % FULL_SNAPSHOT_INTERVAL == 0 {
let snapshot_config = &test_environment.snapshot_config;
let full_snapshot_archive_info = loop {
if let Some(full_snapshot_archive_info) =
snapshot_utils::get_highest_full_snapshot_archive_info(
&snapshot_config.full_snapshot_archives_dir,
)
{
if full_snapshot_archive_info.slot() == bank.slot() {
break full_snapshot_archive_info;
}
}
_ = dbg!(snapshot_utils::get_full_snapshot_archives(
&snapshot_config.full_snapshot_archives_dir
));
std::thread::sleep(Duration::from_millis(1000));
};
let accounts_dir = TempDir::new().unwrap();
let deserialized_bank = snapshot_utils::bank_from_snapshot_archives(
&[accounts_dir.into_path()],
&snapshot_config.bank_snapshots_dir,
&full_snapshot_archive_info,
None,
&test_environment.genesis_config_info.genesis_config,
&RuntimeConfig::default(),
None,
None,
AccountSecondaryIndexes::default(),
false,
None,
AccountShrinkThreshold::default(),
true,
true,
true,
None,
None,
&Arc::new(AtomicBool::new(false)),
)
.unwrap()
.0;
assert_eq!(&deserialized_bank, bank.as_ref());
assert_eq!(
deserialized_bank.epoch_accounts_hash(),
bank.epoch_accounts_hash(),
);
}
// Give the background services a chance to run
std::thread::yield_now();
}
}