Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

staking: Fix Reward usage #10887

Merged
merged 9 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,13 @@ impl<T: Config> Pallet<T> {

Self::deposit_event(Event::<T>::PayoutStarted(era, ledger.stash.clone()));

let mut total_imbalance = PositiveImbalanceOf::<T>::zero();
// We can now make total validator payout:
if let Some(imbalance) =
Self::make_payout(&ledger.stash, validator_staking_payout + validator_commission_payout)
{
Self::deposit_event(Event::<T>::Rewarded(ledger.stash, imbalance.peek()));
total_imbalance.subsume(imbalance);
}

// Track the number of payout ops to nominators. Note:
Expand All @@ -191,9 +193,11 @@ impl<T: Config> Pallet<T> {
nominator_payout_count += 1;
let e = Event::<T>::Rewarded(nominator.who.clone(), imbalance.peek());
Self::deposit_event(e);
total_imbalance.subsume(imbalance);
}
}

T::Reward::on_unbalanced(total_imbalance);
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get());
Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into())
}
Expand Down
28 changes: 23 additions & 5 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3315,26 +3315,41 @@ fn set_history_depth_works() {

#[test]
fn test_payout_stakers() {
// Here we will test validator can set `max_nominators_payout` and it works.
// We also test that `payout_extra_nominators` works.
// Test that payout_stakers work in general, including that only the top
// `T::MaxNominatorRewardedPerValidator` nominators are rewarded.
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
let balance = 1000;
// Track the exposure of the validator and all nominators.
let mut total_exposure = balance;
// Track the exposure of the validator and the nominators that will get paid out.
let mut payout_exposure = balance;
// Create a validator:
bond_validator(11, 10, balance); // Default(64)
assert_eq!(Validators::<Test>::count(), 1);

// Create nominators, targeting stash of validators
for i in 0..100 {
bond_nominator(1000 + i, 100 + i, balance + i as Balance, vec![11]);
let bond_amount = balance + i as Balance;
bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]);
total_exposure += bond_amount;
if i >= 36 {
payout_exposure += bond_amount;
};
}
let payout_exposure_part = Perbill::from_rational(payout_exposure, total_exposure);

mock::start_active_era(1);
Staking::reward_by_ids(vec![(11, 1)]);

// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
let payout = current_total_payout_for_duration(reward_time_per_era());
let actual_paid_out = payout_exposure_part.mul_ceil(payout);

mock::start_active_era(2);

let pre_payout_total_issuance = Balances::total_issuance();
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));
assert_eq!(Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out);

// Top 64 nominators of validator 11 automatically paid out, including the validator
// Validator payout goes to controller.
Expand Down Expand Up @@ -3363,10 +3378,13 @@ fn test_payout_stakers() {
Staking::reward_by_ids(vec![(11, 1)]);

// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
let payout = current_total_payout_for_duration(reward_time_per_era());
let actual_paid_out = payout_exposure_part.mul_ceil(payout);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why only .mul_ceil worked here; .mul ends up being 1 less which I don't understand because we use normal multiplication here:

let nominator_reward: BalanceOf<T> =
nominator_exposure_part * validator_leftover_payout;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel we should figure this out before we merge :/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let pre_payout_total_issuance = Balances::total_issuance();

mock::start_active_era(i);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1));
assert_eq!(Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out);
}

// We track rewards in `claimed_rewards` vec
Expand Down