Skip to content

Commit

Permalink
staking: Fix Reward usage (paritytech#10887)
Browse files Browse the repository at this point in the history
* staking: Fix `Reward` usage

* Some small fixes

* Check on_unbalanced was called

* Improve tests

* Add not for Reward; FMT

* 🤦

Co-authored-by: parity-processbot <>
  • Loading branch information
emostov authored and godcodehunter committed Jun 22, 2022
1 parent 4a9411c commit 383baf3
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 6 deletions.
10 changes: 9 additions & 1 deletion frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] =
parameter_types! {
pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS;
pub static MaxNominations: u32 = 16;
pub static RewardOnUnbalanceWasCalled: bool = false;
}

impl pallet_bags_list::Config for Test {
Expand All @@ -255,6 +256,13 @@ impl onchain::Config for OnChainSeqPhragmen {
type WeightInfo = ();
}

pub struct MockReward {}
impl OnUnbalanced<PositiveImbalanceOf<Test>> for MockReward {
fn on_unbalanced(_: PositiveImbalanceOf<Test>) {
RewardOnUnbalanceWasCalled::set(true);
}
}

impl crate::pallet::pallet::Config for Test {
type MaxNominations = MaxNominations;
type Currency = Balances;
Expand All @@ -263,7 +271,7 @@ impl crate::pallet::pallet::Config for Test {
type RewardRemainder = RewardRemainderMock;
type Event = Event;
type Slash = ();
type Reward = ();
type Reward = MockReward;
type SessionsPerEra = SessionsPerEra;
type SlashDeferDuration = SlashDeferDuration;
type SlashCancelOrigin = frame_system::EnsureRoot<Self::AccountId>;
Expand Down
4 changes: 4 additions & 0 deletions frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,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 @@ -199,9 +201,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);
debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get());
Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into())
}
Expand Down
2 changes: 2 additions & 0 deletions frame/staking/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ pub mod pallet {
type Slash: OnUnbalanced<NegativeImbalanceOf<Self>>;

/// Handler for the unbalanced increment when rewarding a staker.
/// NOTE: in most cases, the implementation of `OnUnbalanced` should modify the total
/// issuance.
type Reward: OnUnbalanced<PositiveImbalanceOf<Self>>;

/// Number of sessions per era.
Expand Down
40 changes: 35 additions & 5 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3370,26 +3370,47 @@ 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 * payout;

mock::start_active_era(2);

let pre_payout_total_issuance = Balances::total_issuance();
RewardOnUnbalanceWasCalled::set(false);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));
assert_eq_error_rate!(
Balances::total_issuance(),
pre_payout_total_issuance + actual_paid_out,
1
);
assert!(RewardOnUnbalanceWasCalled::get());

// Top 64 nominators of validator 11 automatically paid out, including the validator
// Validator payout goes to controller.
Expand Down Expand Up @@ -3418,10 +3439,19 @@ 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 * payout;
let pre_payout_total_issuance = Balances::total_issuance();

mock::start_active_era(i);
RewardOnUnbalanceWasCalled::set(false);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1));
assert_eq_error_rate!(
Balances::total_issuance(),
pre_payout_total_issuance + actual_paid_out,
1
);
assert!(RewardOnUnbalanceWasCalled::get());
}

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

0 comments on commit 383baf3

Please sign in to comment.