Add struct and convenience methods to track stake activation status (#20392)

* Add struct and convenience methods to track stake activation status

* fix nits

* rename
This commit is contained in:
Justin Starry
2021-10-04 18:59:11 -04:00
committed by GitHub
parent 2b967202f3
commit 0ddb34a0b4
7 changed files with 139 additions and 98 deletions

View File

@ -875,12 +875,11 @@ impl MergeKind {
StakeState::Stake(meta, stake) => {
// stake must not be in a transient state. Transient here meaning
// activating or deactivating with non-zero effective stake.
match stake
let status = stake
.delegation
.stake_activating_and_deactivating(clock.epoch, Some(stake_history))
{
/*
(e, a, d): e - effective, a - activating, d - deactivating */
.stake_activating_and_deactivating(clock.epoch, Some(stake_history));
match (status.effective, status.activating, status.deactivating) {
(0, 0, 0) => Ok(Self::Inactive(meta, stake_keyed_account.lamports()?)),
(0, _, _) => Ok(Self::ActivationEpoch(meta, stake)),
(_, 0, 0) => Ok(Self::FullyActive(meta, stake)),
@ -1192,20 +1191,9 @@ pub fn new_stake_history_entry<'a, I>(
where
I: Iterator<Item = &'a Delegation>,
{
// whatever the stake says they had for the epoch
// and whatever the were still waiting for
fn add(a: (u64, u64, u64), b: (u64, u64, u64)) -> (u64, u64, u64) {
(a.0 + b.0, a.1 + b.1, a.2 + b.2)
}
let (effective, activating, deactivating) = stakes.fold((0, 0, 0), |sum, stake| {
add(sum, stake.stake_activating_and_deactivating(epoch, history))
});
StakeHistoryEntry {
effective,
activating,
deactivating,
}
stakes.fold(StakeHistoryEntry::default(), |sum, stake| {
sum + stake.stake_activating_and_deactivating(epoch, history)
})
}
// genesis investor accounts
@ -1769,19 +1757,19 @@ mod tests {
// assert that this stake follows step function if there's no history
assert_eq!(
stake.stake_activating_and_deactivating(stake.activation_epoch, Some(&stake_history),),
(0, stake.stake, 0)
StakeActivationStatus::with_effective_and_activating(0, stake.stake),
);
for epoch in stake.activation_epoch + 1..stake.deactivation_epoch {
assert_eq!(
stake.stake_activating_and_deactivating(epoch, Some(&stake_history)),
(stake.stake, 0, 0)
StakeActivationStatus::with_effective(stake.stake),
);
}
// assert that this stake is full deactivating
assert_eq!(
stake
.stake_activating_and_deactivating(stake.deactivation_epoch, Some(&stake_history),),
(stake.stake, 0, stake.stake)
StakeActivationStatus::with_deactivating(stake.stake),
);
// assert that this stake is fully deactivated if there's no history
assert_eq!(
@ -1789,21 +1777,20 @@ mod tests {
stake.deactivation_epoch + 1,
Some(&stake_history),
),
(0, 0, 0)
StakeActivationStatus::default(),
);
stake_history.add(
0u64, // entry for zero doesn't have my activating amount
StakeHistoryEntry {
effective: 1_000,
activating: 0,
..StakeHistoryEntry::default()
},
);
// assert that this stake is broken, because above setup is broken
assert_eq!(
stake.stake_activating_and_deactivating(1, Some(&stake_history)),
(0, stake.stake, 0)
StakeActivationStatus::with_effective_and_activating(0, stake.stake),
);
stake_history.add(
@ -1818,7 +1805,10 @@ mod tests {
// assert that this stake is broken, because above setup is broken
assert_eq!(
stake.stake_activating_and_deactivating(2, Some(&stake_history)),
(increment, stake.stake - increment, 0)
StakeActivationStatus::with_effective_and_activating(
increment,
stake.stake - increment
),
);
// start over, test deactivation edge cases
@ -1828,7 +1818,6 @@ mod tests {
stake.deactivation_epoch, // entry for zero doesn't have my de-activating amount
StakeHistoryEntry {
effective: 1_000,
activating: 0,
..StakeHistoryEntry::default()
},
);
@ -1838,7 +1827,7 @@ mod tests {
stake.deactivation_epoch + 1,
Some(&stake_history),
),
(stake.stake, 0, stake.stake) // says "I'm still waiting for deactivation"
StakeActivationStatus::with_deactivating(stake.stake),
);
// put in my initial deactivating amount, but don't put in an entry for next
@ -1856,7 +1845,8 @@ mod tests {
stake.deactivation_epoch + 2,
Some(&stake_history),
),
(stake.stake - increment, 0, stake.stake - increment) // hung, should be lower
// hung, should be lower
StakeActivationStatus::with_deactivating(stake.stake - increment),
);
}
@ -1868,7 +1858,10 @@ mod tests {
Slow,
}
fn do_test(old_behavior: OldDeactivationBehavior, expected_stakes: &[(u64, u64, u64)]) {
fn do_test(
old_behavior: OldDeactivationBehavior,
expected_stakes: &[StakeActivationStatus],
) {
let cluster_stake = 1_000;
let activating_stake = 10_000;
let some_stake = 700;
@ -1931,13 +1924,13 @@ mod tests {
do_test(
OldDeactivationBehavior::Slow,
&[
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
],
);
}
@ -1950,13 +1943,13 @@ mod tests {
do_test(
OldDeactivationBehavior::Stuck,
&[
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
(0, 0, 0),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
StakeActivationStatus::default(),
],
);
}
@ -2049,37 +2042,34 @@ mod tests {
})
.collect::<Vec<_>>()
};
let adjust_staking_status = |rate: f64, status: &Vec<_>| {
let adjust_staking_status = |rate: f64, status: &[StakeActivationStatus]| {
status
.clone()
.into_iter()
.map(|(a, b, c)| {
(
(a as f64 * rate) as u64,
(b as f64 * rate) as u64,
(c as f64 * rate) as u64,
)
.iter()
.map(|entry| StakeActivationStatus {
effective: (entry.effective as f64 * rate) as u64,
activating: (entry.activating as f64 * rate) as u64,
deactivating: (entry.deactivating as f64 * rate) as u64,
})
.collect::<Vec<_>>()
};
let expected_staking_status_transition = vec![
(0, 700, 0),
(250, 450, 0),
(562, 138, 0),
(700, 0, 0),
(700, 0, 700),
(275, 0, 275),
(0, 0, 0),
StakeActivationStatus::with_effective_and_activating(0, 700),
StakeActivationStatus::with_effective_and_activating(250, 450),
StakeActivationStatus::with_effective_and_activating(562, 138),
StakeActivationStatus::with_effective(700),
StakeActivationStatus::with_deactivating(700),
StakeActivationStatus::with_deactivating(275),
StakeActivationStatus::default(),
];
let expected_staking_status_transition_base = vec![
(0, 700, 0),
(250, 450, 0),
(562, 138 + 1, 0), // +1 is needed for rounding
(700, 0, 0),
(700, 0, 700),
(275 + 1, 0, 275 + 1), // +1 is needed for rounding
(0, 0, 0),
StakeActivationStatus::with_effective_and_activating(0, 700),
StakeActivationStatus::with_effective_and_activating(250, 450),
StakeActivationStatus::with_effective_and_activating(562, 138 + 1), // +1 is needed for rounding
StakeActivationStatus::with_effective(700),
StakeActivationStatus::with_deactivating(700),
StakeActivationStatus::with_deactivating(275 + 1), // +1 is needed for rounding
StakeActivationStatus::default(),
];
// normal stake activating and deactivating transition test, just in case
@ -2170,7 +2160,11 @@ mod tests {
};
assert_eq!(
stake.stake_activating_and_deactivating(epoch, Some(&stake_history)),
(expected_stake, expected_activating, expected_deactivating)
StakeActivationStatus {
effective: expected_stake,
activating: expected_activating,
deactivating: expected_deactivating,
},
);
}
}