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:
@ -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,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user