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

Staking Payout Creates Controller #6496

Merged
merged 7 commits into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from all 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: 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 @@ -2393,7 +2395,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);
})
}