stake: Advance credits_observed on activation epoch (#19309)

* stake: Advance `credits_observed` on activation epoch

* Add test for merging stakes just after activation
This commit is contained in:
Jon Cinque
2021-09-03 23:20:56 +02:00
committed by GitHub
parent 5e25ee5ebe
commit 2c3bdedea3
4 changed files with 290 additions and 59 deletions

View File

@ -156,11 +156,13 @@ pub struct PointValue {
}
fn redeem_stake_rewards(
rewarded_epoch: Epoch,
stake: &mut Stake,
point_value: &PointValue,
vote_state: &VoteState,
stake_history: Option<&StakeHistory>,
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
fix_activating_credits_observed: bool,
) -> Option<(u64, u64)> {
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved(
@ -169,11 +171,13 @@ fn redeem_stake_rewards(
));
}
calculate_stake_rewards(
rewarded_epoch,
stake,
point_value,
vote_state,
stake_history,
inflation_point_calc_tracer,
fix_activating_credits_observed,
)
.map(|(stakers_reward, voters_reward, credits_observed)| {
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
@ -270,11 +274,13 @@ fn calculate_stake_points_and_credits(
/// * new value for credits_observed in the stake
/// returns None if there's no payout or if any deserved payout is < 1 lamport
fn calculate_stake_rewards(
rewarded_epoch: Epoch,
stake: &Stake,
point_value: &PointValue,
vote_state: &VoteState,
stake_history: Option<&StakeHistory>,
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
fix_activating_credits_observed: bool,
) -> Option<(u64, u64, u64)> {
let (points, credits_observed) = calculate_stake_points_and_credits(
stake,
@ -284,7 +290,10 @@ fn calculate_stake_rewards(
);
// Drive credits_observed forward unconditionally when rewards are disabled
if point_value.rewards == 0 {
// or when this is the stake's activation epoch
if point_value.rewards == 0
|| (fix_activating_credits_observed && stake.delegation.activation_epoch == rewarded_epoch)
{
return Some((0, 0, credits_observed));
}
@ -1098,6 +1107,7 @@ pub fn redeem_rewards(
point_value: &PointValue,
stake_history: Option<&StakeHistory>,
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
fix_activating_credits_observed: bool,
) -> Result<(u64, u64), InstructionError> {
if let StakeState::Stake(meta, mut stake) = stake_account.state()? {
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
@ -1115,11 +1125,13 @@ pub fn redeem_rewards(
}
if let Some((stakers_reward, voters_reward)) = redeem_stake_rewards(
rewarded_epoch,
&mut stake,
point_value,
vote_state,
stake_history,
inflation_point_calc_tracer,
fix_activating_credits_observed,
) {
stake_account.checked_add_lamports(stakers_reward)?;
vote_account.checked_add_lamports(voters_reward)?;
@ -3379,6 +3391,7 @@ mod tests {
assert_eq!(
None,
redeem_stake_rewards(
0,
&mut stake,
&PointValue {
rewards: 1_000_000_000,
@ -3387,6 +3400,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3398,6 +3412,7 @@ mod tests {
assert_eq!(
Some((stake_lamports * 2, 0)),
redeem_stake_rewards(
0,
&mut stake,
&PointValue {
rewards: 1,
@ -3406,6 +3421,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3434,6 +3450,7 @@ mod tests {
assert_eq!(
None,
calculate_stake_rewards(
0,
&stake,
&PointValue {
rewards: 1_000_000_000,
@ -3442,6 +3459,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3476,6 +3494,7 @@ mod tests {
assert_eq!(
None,
calculate_stake_rewards(
0,
&stake,
&PointValue {
rewards: 1_000_000_000,
@ -3484,6 +3503,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3495,6 +3515,7 @@ mod tests {
assert_eq!(
Some((stake.delegation.stake * 2, 0, 2)),
calculate_stake_rewards(
0,
&stake,
&PointValue {
rewards: 2,
@ -3503,6 +3524,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3511,6 +3533,7 @@ mod tests {
assert_eq!(
Some((stake.delegation.stake, 0, 2)),
calculate_stake_rewards(
0,
&stake,
&PointValue {
rewards: 1,
@ -3519,6 +3542,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3530,6 +3554,7 @@ mod tests {
assert_eq!(
Some((stake.delegation.stake, 0, 3)),
calculate_stake_rewards(
1,
&stake,
&PointValue {
rewards: 2,
@ -3538,6 +3563,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3547,6 +3573,7 @@ mod tests {
assert_eq!(
Some((stake.delegation.stake * 2, 0, 4)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 2,
@ -3555,6 +3582,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3570,6 +3598,7 @@ mod tests {
4
)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 4,
@ -3578,6 +3607,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3587,6 +3617,7 @@ mod tests {
assert_eq!(
None, // would be Some((0, 2 * 1 + 1 * 2, 4)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 4,
@ -3595,12 +3626,14 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
vote_state.commission = 99;
assert_eq!(
None, // would be Some((0, 2 * 1 + 1 * 2, 4)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 4,
@ -3609,6 +3642,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3618,6 +3652,7 @@ mod tests {
assert_eq!(
Some((0, 0, 4)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 0,
@ -3626,6 +3661,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3635,6 +3671,7 @@ mod tests {
assert_eq!(
Some((0, 0, 4)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 0,
@ -3643,6 +3680,7 @@ mod tests {
&vote_state,
None,
&mut null_tracer(),
true,
)
);
@ -3651,6 +3689,50 @@ mod tests {
(0, 4),
calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer())
);
// get rewards and credits observed when not the activation epoch
vote_state.commission = 0;
stake.credits_observed = 3;
stake.delegation.activation_epoch = 1;
assert_eq!(
Some((
stake.delegation.stake, // epoch 2
0,
4
)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 1,
points: 1
},
&vote_state,
None,
&mut null_tracer(),
true,
)
);
// credits_observed is moved forward for the stake's activation epoch,
// and no rewards are perceived
stake.delegation.activation_epoch = 2;
stake.credits_observed = 3;
assert_eq!(
Some((0, 0, 4)),
calculate_stake_rewards(
2,
&stake,
&PointValue {
rewards: 1,
points: 1
},
&vote_state,
None,
&mut null_tracer(),
true,
)
);
}
#[test]