Skip to content

Commit

Permalink
Staking Payout Creates Controller (paritytech#6496)
Browse files Browse the repository at this point in the history
* payout creates controller

* update benchmarks

* oops

* fix session benchmarks

* Update weights

* fix line width
  • Loading branch information
shawntabrizi authored Jun 25, 2020
1 parent 4101443 commit a2a2776
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 8 deletions.
4 changes: 2 additions & 2 deletions frame/session/benchmarking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ benchmarks! {

set_keys {
let n in 1 .. MAX_NOMINATIONS as u32;
let v_stash = create_validator_with_nominators::<T>(n, MAX_NOMINATIONS as u32)?;
let v_stash = create_validator_with_nominators::<T>(n, MAX_NOMINATIONS as u32, false)?;
let v_controller = pallet_staking::Module::<T>::bonded(&v_stash).ok_or("not stash")?;
let keys = T::Keys::default();
let proof: Vec<u8> = vec![0,1,2,3];
}: _(RawOrigin::Signed(v_controller), keys, proof)

purge_keys {
let n in 1 .. MAX_NOMINATIONS as u32;
let v_stash = create_validator_with_nominators::<T>(n, MAX_NOMINATIONS as u32)?;
let v_stash = create_validator_with_nominators::<T>(n, MAX_NOMINATIONS as u32, false)?;
let v_controller = pallet_staking::Module::<T>::bonded(&v_stash).ok_or("not stash")?;
let keys = T::Keys::default();
let proof: Vec<u8> = vec![0,1,2,3];
Expand Down
32 changes: 29 additions & 3 deletions frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ fn add_slashing_spans<T: Trait>(who: &T::AccountId, spans: u32) {

// This function generates one validator being nominated by n nominators, and returns the validator
// stash account. It also starts an era and creates pending payouts.
pub fn create_validator_with_nominators<T: Trait>(n: u32, upper_bound: u32) -> Result<T::AccountId, &'static str> {
pub fn create_validator_with_nominators<T: Trait>(
n: u32,
upper_bound: u32,
dead: bool,
) -> Result<T::AccountId, &'static str> {
let mut points_total = 0;
let mut points_individual = Vec::new();

Expand All @@ -65,7 +69,11 @@ pub fn create_validator_with_nominators<T: Trait>(n: u32, upper_bound: u32) -> R

// Give the validator n nominators, but keep total users in the system the same.
for i in 0 .. upper_bound {
let (_n_stash, n_controller) = create_stash_controller::<T>(u32::max_value() - i, 100)?;
let (_n_stash, n_controller) = if !dead {
create_stash_controller::<T>(u32::max_value() - i, 100)?
} else {
create_stash_and_dead_controller::<T>(u32::max_value() - i, 100)?
};
if i < n {
Staking::<T>::nominate(RawOrigin::Signed(n_controller.clone()).into(), vec![stash_lookup.clone()])?;
}
Expand Down Expand Up @@ -271,7 +279,8 @@ benchmarks! {

payout_stakers {
let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32;
let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32)?;
let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32, true)?;

let current_era = CurrentEra::get().unwrap();
let caller = account("caller", 0, SEED);
let balance_before = T::Currency::free_balance(&validator);
Expand All @@ -282,6 +291,20 @@ benchmarks! {
assert!(balance_before < balance_after);
}

payout_stakers_alive_controller {
let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32;
let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32, false)?;

let current_era = CurrentEra::get().unwrap();
let caller = account("caller", 0, SEED);
let balance_before = T::Currency::free_balance(&validator);
}: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era)
verify {
// Validator has been paid!
let balance_after = T::Currency::free_balance(&validator);
assert!(balance_before < balance_after);
}

rebond {
let l in 1 .. MAX_UNLOCKING_CHUNKS as u32;
let (_, controller) = create_stash_controller::<T>(u, 100)?;
Expand Down Expand Up @@ -630,6 +653,7 @@ mod tests {
let validator_stash = create_validator_with_nominators::<Test>(
n,
<Test as Trait>::MaxNominatorRewardedPerValidator::get() as u32,
false,
).unwrap();

let current_era = CurrentEra::get().unwrap();
Expand All @@ -650,6 +674,7 @@ mod tests {
let validator_stash = create_validator_with_nominators::<Test>(
n,
<Test as Trait>::MaxNominatorRewardedPerValidator::get() as u32,
false,
).unwrap();

// Add 20 slashing spans
Expand Down Expand Up @@ -710,6 +735,7 @@ mod tests {
assert_ok!(test_benchmark_force_unstake::<Test>());
assert_ok!(test_benchmark_cancel_deferred_slash::<Test>());
assert_ok!(test_benchmark_payout_stakers::<Test>());
assert_ok!(test_benchmark_payout_stakers_alive_controller::<Test>());
assert_ok!(test_benchmark_rebond::<Test>());
assert_ok!(test_benchmark_set_history_depth::<Test>());
assert_ok!(test_benchmark_reap_stash::<Test>());
Expand Down
8 changes: 5 additions & 3 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1978,15 +1978,17 @@ decl_module! {
/// - Contains a limited number of reads and writes.
/// -----------
/// N is the Number of payouts for the validator (including the validator)
/// Base Weight: 110 + 54.2 * N µs (Median Slopes)
/// Base Weight:
/// - Reward Destination Staked: 110 + 54.2 * N µs (Median Slopes)
/// - Reward Destination Controller (Creating): 120 + 41.95 * N µs (Median Slopes)
/// DB Weight:
/// - Read: EraElectionStatus, CurrentEra, HistoryDepth, ErasValidatorReward,
/// ErasStakersClipped, ErasRewardPoints, ErasValidatorPrefs (8 items)
/// - Read Each: Bonded, Ledger, Payee, Locks, System Account (5 items)
/// - Write Each: System Account, Locks, Ledger (3 items)
/// # </weight>
#[weight =
110 * WEIGHT_PER_MICROS
120 * WEIGHT_PER_MICROS
+ 54 * WEIGHT_PER_MICROS * Weight::from(T::MaxNominatorRewardedPerValidator::get())
+ T::DbWeight::get().reads(7)
+ T::DbWeight::get().reads(5) * Weight::from(T::MaxNominatorRewardedPerValidator::get() + 1)
Expand Down Expand Up @@ -2395,7 +2397,7 @@ impl<T: Trait> Module<T> {
match dest {
RewardDestination::Controller => Self::bonded(stash)
.and_then(|controller|
T::Currency::deposit_into_existing(&controller, amount).ok()
Some(T::Currency::deposit_creating(&controller, amount))
),
RewardDestination::Stash =>
T::Currency::deposit_into_existing(stash, amount).ok(),
Expand Down
15 changes: 15 additions & 0 deletions frame/staking/src/testing_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ pub fn create_stash_controller<T: Trait>(n: u32, balance_factor: u32)
return Ok((stash, controller))
}

/// Create a stash and controller pair, where the controller is dead, and payouts go to controller.
/// This is used to test worst case payout scenarios.
pub fn create_stash_and_dead_controller<T: Trait>(n: u32, balance_factor: u32)
-> Result<(T::AccountId, T::AccountId), &'static str>
{
let stash = create_funded_user::<T>("stash", n, balance_factor);
// controller has no funds
let controller = create_funded_user::<T>("controller", n, 0);
let controller_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(controller.clone());
let reward_destination = RewardDestination::Controller;
let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into();
Staking::<T>::bond(RawOrigin::Signed(stash.clone()).into(), controller_lookup, amount, reward_destination)?;
return Ok((stash, controller))
}

/// create `max` validators.
pub fn create_validators<T: Trait>(
max: u32,
Expand Down
30 changes: 30 additions & 0 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4501,3 +4501,33 @@ fn on_initialize_weight_is_correct() {
assert_eq!(final_weight, Staking::on_initialize(System::block_number()));
});
}


#[test]
fn payout_creates_controller() {
// Here we will test validator can set `max_nominators_payout` and it works.
// We also test that `payout_extra_nominators` works.
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
let balance = 1000;
// Create three validators:
bond_validator(11, 10, balance); // Default(64)

// Create a stash/controller pair
bond_nominator(1234, 1337, 100, vec![11]);

// kill controller
assert_ok!(Balances::transfer(Origin::signed(1337), 1234, 100));
assert_eq!(Balances::free_balance(1337), 0);

mock::start_era(1);
Staking::reward_by_ids(vec![(11, 1)]);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(3 * 1000);
assert!(total_payout_0 > 100); // Test is meaningful if reward something
mock::start_era(2);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));

// Controller is created
assert!(Balances::free_balance(1337) > 0);
})
}

0 comments on commit a2a2776

Please sign in to comment.