add test_stake_account_consistency_with_rent_epoch_max_feature (#29915)

* add test_stake_account_consistency_with_rent_epoch_max_feature

* create_stake_account takes id

* use test_case

* reformat panic message
This commit is contained in:
Jeff Washington (jwash) 2023-01-27 13:50:33 -06:00 committed by GitHub
parent 6f4fe37bd2
commit 5e35823b66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 140 additions and 16 deletions

View File

@ -423,6 +423,7 @@ pub const ACCOUNTS_DB_CONFIG_FOR_TESTING: AccountsDbConfig = AccountsDbConfig {
ancient_append_vec_offset: None,
skip_initial_hash_calc: false,
exhaustively_verify_refcounts: false,
assert_stakes_cache_consistency: true,
};
pub const ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS: AccountsDbConfig = AccountsDbConfig {
index: Some(ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS),
@ -432,6 +433,7 @@ pub const ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS: AccountsDbConfig = AccountsDbConfig
ancient_append_vec_offset: None,
skip_initial_hash_calc: false,
exhaustively_verify_refcounts: false,
assert_stakes_cache_consistency: false,
};
pub type BinnedHashData = Vec<Vec<CalculateHashIntermediate>>;
@ -489,6 +491,8 @@ pub struct AccountsDbConfig {
pub ancient_append_vec_offset: Option<i64>,
pub skip_initial_hash_calc: bool,
pub exhaustively_verify_refcounts: bool,
/// when stakes cache consistency check occurs, assert that cached accounts match accounts db
pub assert_stakes_cache_consistency: bool,
}
#[cfg(not(test))]
@ -1275,6 +1279,8 @@ pub struct AccountsDb {
pub(crate) storage: AccountStorage,
pub(crate) assert_stakes_cache_consistency: bool,
pub accounts_cache: AccountsCache,
write_cache_limit_bytes: Option<u64>,
@ -2291,6 +2297,7 @@ impl AccountsDb {
const ACCOUNTS_STACK_SIZE: usize = 8 * 1024 * 1024;
AccountsDb {
assert_stakes_cache_consistency: false,
verify_accounts_hash_in_bg: VerifyAccountsHashInBackground::default(),
filler_accounts_per_slot: AtomicU64::default(),
filler_account_slots_remaining: AtomicU64::default(),
@ -2409,6 +2416,11 @@ impl AccountsDb {
.map(|config| config.exhaustively_verify_refcounts)
.unwrap_or_default();
let assert_stakes_cache_consistency = accounts_db_config
.as_ref()
.map(|config| config.assert_stakes_cache_consistency)
.unwrap_or_default();
let filler_account_suffix = if filler_accounts_config.count > 0 {
Some(solana_sdk::pubkey::new_rand())
} else {
@ -2425,6 +2437,7 @@ impl AccountsDb {
accounts_update_notifier,
filler_accounts_config,
filler_account_suffix,
assert_stakes_cache_consistency,
write_cache_limit_bytes: accounts_db_config
.as_ref()
.and_then(|x| x.write_cache_limit_bytes),

View File

@ -2494,6 +2494,11 @@ impl Bank {
}
};
if cached_stake_account.account() != &stake_account {
if self.rc.accounts.accounts_db.assert_stakes_cache_consistency {
panic!(
"stakes cache accounts mismatch {cached_stake_account:?} {stake_account:?}"
);
}
invalid_cached_stake_accounts.fetch_add(1, Relaxed);
let cached_stake_account = cached_stake_account.account();
if cached_stake_account.lamports() == stake_account.lamports()
@ -7916,6 +7921,7 @@ pub(crate) mod tests {
genesis_sysvar_and_builtin_program_lamports, GenesisConfigInfo,
ValidatorVoteKeypairs,
},
rent_collector::RENT_EXEMPT_RENT_EPOCH,
rent_paying_accounts_by_partition::RentPayingAccountsByPartition,
status_cache::MAX_CACHE_ENTRIES,
},
@ -7969,6 +7975,7 @@ pub(crate) mod tests {
fs::File, io::Read, result, str::FromStr, sync::atomic::Ordering::Release,
thread::Builder, time::Duration,
},
test_case::test_case,
test_utils::goto_end_of_slot,
};
@ -10236,8 +10243,10 @@ pub(crate) mod tests {
let vote_id = solana_sdk::pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_id, &solana_sdk::pubkey::new_rand(), 0, 100);
let (stake_id1, stake_account1) = crate::stakes::tests::create_stake_account(123, &vote_id);
let (stake_id2, stake_account2) = crate::stakes::tests::create_stake_account(456, &vote_id);
let stake_id1 = solana_sdk::pubkey::new_rand();
let stake_account1 = crate::stakes::tests::create_stake_account(123, &vote_id, &stake_id1);
let stake_id2 = solana_sdk::pubkey::new_rand();
let stake_account2 = crate::stakes::tests::create_stake_account(456, &vote_id, &stake_id2);
// set up accounts
bank.store_account_and_update_capitalization(&stake_id1, &stake_account1);
@ -17423,7 +17432,23 @@ pub(crate) mod tests {
&validator_keypairs,
vec![LAMPORTS_PER_SOL; 2],
);
let bank = Arc::new(Bank::new_for_tests(&genesis_config));
let bank = Arc::new(Bank::new_with_paths(
&genesis_config,
Arc::<RuntimeConfig>::default(),
Vec::new(),
None,
None,
AccountSecondaryIndexes::default(),
AccountShrinkThreshold::default(),
false,
Some(AccountsDbConfig {
// at least one tests hit this assert, so disable it
assert_stakes_cache_consistency: false,
..ACCOUNTS_DB_CONFIG_FOR_TESTING
}),
None,
&Arc::default(),
));
let vote_and_stake_accounts =
load_vote_and_stake_accounts(&bank).vote_with_stake_delegations_map;
assert_eq!(vote_and_stake_accounts.len(), 2);
@ -20151,4 +20176,87 @@ pub(crate) mod tests {
bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false);
assert_eq!(bank.hashes_per_tick, Some(DEFAULT_HASHES_PER_TICK));
}
#[test_case(true)]
#[test_case(false)]
fn test_stake_account_consistency_with_rent_epoch_max_feature(
rent_epoch_max_enabled_initially: bool,
) {
// this test can be removed once set_exempt_rent_epoch_max gets activated
solana_logger::setup();
let (mut genesis_config, _mint_keypair) = create_genesis_config(100 * LAMPORTS_PER_SOL);
genesis_config.rent = Rent::default();
let mut bank = Bank::new_for_tests(&genesis_config);
let expected_initial_rent_epoch = if rent_epoch_max_enabled_initially {
bank.activate_feature(&solana_sdk::feature_set::set_exempt_rent_epoch_max::id());
RENT_EXEMPT_RENT_EPOCH
} else {
Epoch::default()
};
assert!(bank.rc.accounts.accounts_db.assert_stakes_cache_consistency);
let mut pubkey_bytes_early = [0u8; 32];
pubkey_bytes_early[31] = 2;
let stake_id1 = Pubkey::from(pubkey_bytes_early);
let vote_id = solana_sdk::pubkey::new_rand();
let stake_account1 =
crate::stakes::tests::create_stake_account(12300000, &vote_id, &stake_id1);
// set up accounts
bank.store_account_and_update_capitalization(&stake_id1, &stake_account1);
// create banks at a few slots
assert_eq!(
bank.load_slow(&bank.ancestors, &stake_id1)
.unwrap()
.0
.rent_epoch(),
0 // manually created, so default is 0
);
let slot = 1;
let slots_per_epoch = bank.epoch_schedule().get_slots_in_epoch(0);
let mut bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default(), slot);
if !rent_epoch_max_enabled_initially {
bank.activate_feature(&solana_sdk::feature_set::set_exempt_rent_epoch_max::id());
}
let bank = Arc::new(bank);
let slot = slots_per_epoch - 1;
assert_eq!(
bank.load_slow(&bank.ancestors, &stake_id1)
.unwrap()
.0
.rent_epoch(),
// rent has been collected, so if rent epoch is max is activated, this will be max by now
expected_initial_rent_epoch
);
let mut bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::default(), slot));
let last_slot_in_epoch = bank.epoch_schedule().get_last_slot_in_epoch(1);
let slot = last_slot_in_epoch - 2;
assert_eq!(
bank.load_slow(&bank.ancestors, &stake_id1)
.unwrap()
.0
.rent_epoch(),
expected_initial_rent_epoch
);
bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::default(), slot));
assert_eq!(
bank.load_slow(&bank.ancestors, &stake_id1)
.unwrap()
.0
.rent_epoch(),
expected_initial_rent_epoch
);
let slot = last_slot_in_epoch - 1;
bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::default(), slot));
assert_eq!(
bank.load_slow(&bank.ancestors, &stake_id1)
.unwrap()
.0
.rent_epoch(),
RENT_EXEMPT_RENT_EPOCH
);
}
}

View File

@ -521,9 +521,13 @@ pub(crate) mod tests {
let vote_pubkey = solana_sdk::pubkey::new_rand();
let vote_account =
vote_state::create_account(&vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1);
let stake_pubkey = solana_sdk::pubkey::new_rand();
(
(vote_pubkey, vote_account),
create_stake_account(stake, &vote_pubkey),
(
stake_pubkey,
create_stake_account(stake, &vote_pubkey, &stake_pubkey),
),
)
}
@ -531,17 +535,14 @@ pub(crate) mod tests {
pub(crate) fn create_stake_account(
stake: u64,
vote_pubkey: &Pubkey,
) -> (Pubkey, AccountSharedData) {
let stake_pubkey = solana_sdk::pubkey::new_rand();
(
stake_pubkey: &Pubkey,
) -> AccountSharedData {
stake_state::create_account(
stake_pubkey,
stake_state::create_account(
&stake_pubkey,
vote_pubkey,
&vote_state::create_account(vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1),
&Rent::free(),
stake,
),
vote_pubkey,
&vote_state::create_account(vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1),
&Rent::free(),
stake,
)
}
@ -615,7 +616,8 @@ pub(crate) mod tests {
}
// activate more
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
let mut stake_account =
create_stake_account(42, &vote_pubkey, &solana_sdk::pubkey::new_rand());
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
let stake = stake_state::stake_from(&stake_account).unwrap();
{
@ -799,7 +801,8 @@ pub(crate) mod tests {
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
create_staked_node_accounts(10);
let (stake_pubkey2, stake_account2) = create_stake_account(10, &vote_pubkey);
let stake_pubkey2 = solana_sdk::pubkey::new_rand();
let stake_account2 = create_stake_account(10, &vote_pubkey, &stake_pubkey2);
stakes_cache.check_and_store(&vote_pubkey, &vote_account);