fix epoch_stakes again (#5396)

This commit is contained in:
Rob Walker
2019-08-01 14:27:47 -07:00
committed by GitHub
parent 4298b1f595
commit f7d3f55566
4 changed files with 43 additions and 38 deletions

View File

@ -214,8 +214,7 @@ impl Tower {
} }
pub fn is_recent_epoch(&self, bank: &Bank) -> bool { pub fn is_recent_epoch(&self, bank: &Bank) -> bool {
let bank_epoch = bank.get_epoch_and_slot_index(bank.slot()).0; bank.epoch() >= self.epoch_stakes.epoch
bank_epoch >= self.epoch_stakes.epoch
} }
pub fn update_epoch(&mut self, bank: &Bank) { pub fn update_epoch(&mut self, bank: &Bank) {
@ -224,8 +223,7 @@ impl Tower {
bank.slot(), bank.slot(),
self.epoch_stakes.epoch self.epoch_stakes.epoch
); );
let bank_epoch = bank.get_epoch_and_slot_index(bank.slot()).0; if bank.epoch() != self.epoch_stakes.epoch {
if bank_epoch != self.epoch_stakes.epoch {
assert!( assert!(
self.is_recent_epoch(bank), self.is_recent_epoch(bank),
"epoch_stakes cannot move backwards" "epoch_stakes cannot move backwards"

View File

@ -150,23 +150,15 @@ pub(crate) mod tests {
// First epoch has the bootstrap leader // First epoch has the bootstrap leader
expected.insert(voting_keypair.pubkey(), leader_stake.stake(0)); expected.insert(voting_keypair.pubkey(), leader_stake.stake(0));
assert_eq!(
vote_account_stakes_at_epoch(&bank, 0), // henceforth, verify that we have snapshots of stake at epoch 0
Some(expected.clone()) let expected = Some(expected);
); assert_eq!(vote_account_stakes_at_epoch(&bank, 0), expected);
// Second epoch carries same information // Second epoch carries same information
let bank = new_from_parent(&Arc::new(bank), 1); let bank = new_from_parent(&Arc::new(bank), 1);
assert_eq!( assert_eq!(vote_account_stakes_at_epoch(&bank, 0), expected);
vote_account_stakes_at_epoch(&bank, 0), assert_eq!(vote_account_stakes_at_epoch(&bank, 1), expected);
Some(expected.clone())
);
expected.insert(voting_keypair.pubkey(), leader_stake.stake(1));
assert_eq!(
vote_account_stakes_at_epoch(&bank, 1),
Some(expected.clone())
);
} }
pub(crate) fn setup_vote_and_stake_accounts( pub(crate) fn setup_vote_and_stake_accounts(
@ -233,7 +225,7 @@ pub(crate) mod tests {
.. ..
} = create_genesis_block(10_000); } = create_genesis_block(10_000);
let mut bank = Bank::new(&genesis_block); let bank = Bank::new(&genesis_block);
let vote_pubkey = Pubkey::new_rand(); let vote_pubkey = Pubkey::new_rand();
// Give the validator some stake but don't setup a staking account // Give the validator some stake but don't setup a staking account
@ -252,23 +244,28 @@ pub(crate) mod tests {
stake, stake,
); );
// simulated stake
let other_stake = Stake { let other_stake = Stake {
stake, stake,
activated: bank.get_stakers_epoch(bank.slot()), activated: bank.epoch(),
..Stake::default() ..Stake::default()
}; };
let epoch = bank.get_stakers_epoch(bank.slot()); let epoch = bank.get_stakers_epoch(bank.slot());
// find the first slot in the next staker's epoch // find the first slot in the next staker's epoch
while bank.epoch() <= epoch { let mut slot = 1;
let slot = bank.slot() + 1; while bank.get_stakers_epoch(slot) <= epoch {
bank = new_from_parent(&Arc::new(bank), slot); slot += 1;
} }
let bank = new_from_parent(&Arc::new(bank), slot);
let epoch = bank.get_stakers_epoch(slot);
let result: Vec<_> = epoch_stakes_and_lockouts(&bank, 0); let result: Vec<_> = epoch_stakes_and_lockouts(&bank, 0);
assert_eq!(result, vec![(leader_stake.stake(0), None)]); assert_eq!(result, vec![(leader_stake.stake(0), None)]);
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, bank.epoch()); // epoch stakes and lockouts are saved off for the future epoch, should
// match current bank state
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, epoch);
result.sort(); result.sort();
let mut expected = vec![ let mut expected = vec![
(leader_stake.stake(bank.epoch()), None), (leader_stake.stake(bank.epoch()), None),

View File

@ -217,7 +217,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
new_stake, new_stake,
vote_account.unsigned_key(), vote_account.unsigned_key(),
&vote_account.state()?, &vote_account.state()?,
clock.stakers_epoch, clock.epoch,
); );
self.set_state(&StakeState::Stake(stake)) self.set_state(&StakeState::Stake(stake))
@ -231,7 +231,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
} }
if let StakeState::Stake(mut stake) = self.state()? { if let StakeState::Stake(mut stake) = self.state()? {
stake.deactivate(clock.stakers_epoch); stake.deactivate(clock.epoch);
self.set_state(&StakeState::Stake(stake)) self.set_state(&StakeState::Stake(stake))
} else { } else {
@ -291,7 +291,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
if stake.deactivated == std::u64::MAX { if stake.deactivated == std::u64::MAX {
return Err(InstructionError::InsufficientFunds); return Err(InstructionError::InsufficientFunds);
} }
let staked = if stake.stake(clock.stakers_epoch) == 0 { let staked = if stake.stake(clock.epoch) == 0 {
0 0
} else { } else {
// Assume full stake if the stake is under warmup/cooldown // Assume full stake if the stake is under warmup/cooldown
@ -358,7 +358,7 @@ mod tests {
#[test] #[test]
fn test_stake_delegate_stake() { fn test_stake_delegate_stake() {
let clock = sysvar::clock::Clock { let clock = sysvar::clock::Clock {
stakers_epoch: 1, epoch: 1,
..sysvar::clock::Clock::default() ..sysvar::clock::Clock::default()
}; };
@ -406,7 +406,7 @@ mod tests {
voter_pubkey: vote_keypair.pubkey(), voter_pubkey: vote_keypair.pubkey(),
credits_observed: vote_state.credits(), credits_observed: vote_state.credits(),
stake: stake_lamports, stake: stake_lamports,
activated: clock.stakers_epoch, activated: clock.epoch,
deactivated: std::u64::MAX, deactivated: std::u64::MAX,
}) })
); );
@ -464,7 +464,7 @@ mod tests {
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id()); Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
let clock = sysvar::clock::Clock { let clock = sysvar::clock::Clock {
stakers_epoch: 1, epoch: 1,
..sysvar::clock::Clock::default() ..sysvar::clock::Clock::default()
}; };
@ -548,7 +548,7 @@ mod tests {
// deactivate the stake before withdrawal // deactivate the stake before withdrawal
assert_eq!(stake_keyed_account.deactivate_stake(&clock), Ok(())); assert_eq!(stake_keyed_account.deactivate_stake(&clock), Ok(()));
// simulate time passing // simulate time passing
clock.stakers_epoch += STAKE_WARMUP_EPOCHS; clock.epoch += STAKE_WARMUP_EPOCHS;
// Try to withdraw more than what's available // Try to withdraw more than what's available
assert_eq!( assert_eq!(
@ -581,7 +581,7 @@ mod tests {
let clock = sysvar::clock::Clock::default(); let clock = sysvar::clock::Clock::default();
let mut future = sysvar::clock::Clock::default(); let mut future = sysvar::clock::Clock::default();
future.stakers_epoch += 16; future.epoch += 16;
let to = Pubkey::new_rand(); let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id()); let mut to_account = Account::new(1, 0, &system_program::id());

View File

@ -301,8 +301,7 @@ impl Bank {
{ {
let stakes = bank.stakes.read().unwrap(); let stakes = bank.stakes.read().unwrap();
for epoch in 0..=bank.get_stakers_epoch(bank.slot) { for epoch in 0..=bank.get_stakers_epoch(bank.slot) {
bank.epoch_stakes bank.epoch_stakes.insert(epoch, stakes.clone());
.insert(epoch, stakes.clone_with_epoch(epoch));
} }
} }
bank.update_clock(); bank.update_clock();
@ -372,7 +371,7 @@ impl Bank {
// if my parent didn't populate for this epoch, we've // if my parent didn't populate for this epoch, we've
// crossed a boundary // crossed a boundary
if epoch_stakes.get(&epoch).is_none() { if epoch_stakes.get(&epoch).is_none() {
epoch_stakes.insert(epoch, self.stakes.read().unwrap().clone_with_epoch(epoch)); epoch_stakes.insert(epoch, self.stakes.read().unwrap().clone());
} }
epoch_stakes epoch_stakes
}; };
@ -2488,8 +2487,10 @@ mod tests {
let vote_accounts = parent.epoch_vote_accounts(epoch); let vote_accounts = parent.epoch_vote_accounts(epoch);
assert!(vote_accounts.is_some()); assert!(vote_accounts.is_some());
// epoch_stakes are a snapshot at the stakers_slot_offset boundary
// in the prior epoch (0 in this case)
assert_eq!( assert_eq!(
leader_stake.stake(epoch), leader_stake.stake(0),
vote_accounts.unwrap().get(&leader_vote_account).unwrap().0 vote_accounts.unwrap().get(&leader_vote_account).unwrap().0
); );
@ -2505,7 +2506,7 @@ mod tests {
assert!(child.epoch_vote_accounts(epoch).is_some()); assert!(child.epoch_vote_accounts(epoch).is_some());
assert_eq!( assert_eq!(
leader_stake.stake(epoch), leader_stake.stake(child.epoch()),
child child
.epoch_vote_accounts(epoch) .epoch_vote_accounts(epoch)
.unwrap() .unwrap()
@ -2515,13 +2516,22 @@ mod tests {
); );
// child crosses epoch boundary but isn't the first slot in the epoch, still // child crosses epoch boundary but isn't the first slot in the epoch, still
// makes an epoch stakes // makes an epoch stakes snapshot at 1
let child = Bank::new_from_parent( let child = Bank::new_from_parent(
&parent, &parent,
&leader_pubkey, &leader_pubkey,
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH) + 1, SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH) + 1,
); );
assert!(child.epoch_vote_accounts(epoch).is_some()); assert!(child.epoch_vote_accounts(epoch).is_some());
assert_eq!(
leader_stake.stake(child.epoch()),
child
.epoch_vote_accounts(epoch)
.unwrap()
.get(&leader_vote_account)
.unwrap()
.0
);
} }
#[test] #[test]