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:
@ -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]
|
||||
|
Reference in New Issue
Block a user