Skip to content

Commit

Permalink
Simple Staking Payouts (#5406)
Browse files Browse the repository at this point in the history
* Simple Payouts

* explicit test for out of order claiming

* Add `payout_all` benchmark

* Fix merge

* add docs

* change event to controller

* Fix timestamp test warnings

* Revert "change event to controller"

This reverts commit 5d4a97832d47fe1273602d5410774d5421940c4e.

* Update Reward event doc

* Add "non-production" test

* add unlock chunk to test

* fix merge

* End payout early if no reward points

* payout_validator -> payout_stakers

* bring back payout nominator/validator, but limit their use to before migration era

* Add test for before migration

* New payout works for the era that we migrate

* Fix logic, check that migration era works

* Migrate Era tests (copypasta)

* Move comment

* Add mock back to external functions

* Fixes based on review from gui

* Update Cargo.lock

* Update Cargo.lock

* small docs update

Co-authored-by: joepetrowski <joe@parity.io>
  • Loading branch information
shawntabrizi and joepetrowski authored Apr 4, 2020
1 parent 7c0fa83 commit 6847f84
Show file tree
Hide file tree
Showing 6 changed files with 1,034 additions and 254 deletions.
1 change: 1 addition & 0 deletions substrate/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions substrate/frame/staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ rand_chacha = { version = "0.2", default-features = false, optional = true }

[dev-dependencies]
sp-core = { version = "2.0.0-alpha.5", path = "../../primitives/core" }
sp-storage = { version = "2.0.0-alpha.5", path = "../../primitives/storage" }
pallet-balances = { version = "2.0.0-alpha.5", path = "../balances" }
pallet-timestamp = { version = "2.0.0-alpha.5", path = "../timestamp" }
pallet-staking-reward-curve = { version = "2.0.0-alpha.5", path = "../staking/reward-curve" }
Expand Down
145 changes: 59 additions & 86 deletions substrate/frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use super::*;

use rand_chacha::{rand_core::{RngCore, SeedableRng}, ChaChaRng};

use sp_runtime::traits::One;
use sp_runtime::traits::{Dispatchable, One};
use sp_io::hashing::blake2_256;

use frame_system::RawOrigin;
Expand Down Expand Up @@ -147,61 +147,6 @@ pub fn create_validator_with_nominators<T: Trait>(n: u32, upper_bound: u32) -> R
Ok(v_controller)
}

// This function generates one nominator nominating v validators.
// It starts an era and creates pending payouts.
pub fn create_nominator_with_validators<T: Trait>(v: u32) -> Result<(T::AccountId, Vec<T::AccountId>), &'static str> {
let mut validators = Vec::new();
let mut points_total = 0;
let mut points_individual = Vec::new();

MinimumValidatorCount::put(0);

// Create v validators
let mut validator_lookups = Vec::new();
for i in 0 .. v {
let (v_stash, v_controller) = create_stash_controller::<T>(i)?;
let validator_prefs = ValidatorPrefs {
commission: Perbill::from_percent(50),
};
Staking::<T>::validate(RawOrigin::Signed(v_controller.clone()).into(), validator_prefs)?;
let stash_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(v_stash.clone());

points_total += 10;
points_individual.push((v_stash.clone(), 10));
validator_lookups.push(stash_lookup);
// Add to the list if it is less than the number we want the nominator to have
if validators.len() < v as usize {
validators.push(v_stash.clone())
}
}

// Create a nominator
let (_n_stash, n_controller) = create_stash_controller::<T>(u32::max_value())?;
Staking::<T>::nominate(RawOrigin::Signed(n_controller.clone()).into(), validator_lookups)?;

ValidatorCount::put(v);

// Start a new Era
let new_validators = Staking::<T>::new_era(SessionIndex::one()).unwrap();

assert!(new_validators.len() == v as usize);

// Give Era Points
let reward = EraRewardPoints::<T::AccountId> {
total: points_total,
individual: points_individual.into_iter().collect(),
};

let current_era = CurrentEra::get().unwrap();
ErasRewardPoints::<T>::insert(current_era, reward);

// Create reward pool
let total_payout = T::Currency::minimum_balance() * 1000.into();
<ErasValidatorReward<T>>::insert(current_era, total_payout);

Ok((n_controller, validators))
}

benchmarks! {
_{
// User account seed
Expand Down Expand Up @@ -306,18 +251,12 @@ benchmarks! {
let slash_indices: Vec<u32> = (0 .. s).collect();
}: _(RawOrigin::Root, era, slash_indices)

payout_validator {
payout_stakers {
let n in 1 .. MAX_NOMINATIONS as u32;
let validator = create_validator_with_nominators::<T>(n, MAX_NOMINATIONS as u32)?;
let current_era = CurrentEra::get().unwrap();
}: _(RawOrigin::Signed(validator), current_era)

payout_nominator {
let v in 1 .. MAX_NOMINATIONS as u32;
let (nominator, validators) = create_nominator_with_validators::<T>(v)?;
let current_era = CurrentEra::get().unwrap();
let find_nominator = validators.into_iter().map(|x| (x, 0)).collect();
}: _(RawOrigin::Signed(nominator), current_era, find_nominator)
let caller = account("caller", n, SEED);
}: _(RawOrigin::Signed(caller), validator, current_era)

rebond {
let l in 1 .. 1000;
Expand Down Expand Up @@ -386,6 +325,45 @@ benchmarks! {
&mut NegativeImbalanceOf::<T>::zero()
);
}

payout_all {
let v in 1 .. 10;
let n in 1 .. 100;
MinimumValidatorCount::put(0);
create_validators_with_nominators_for_era::<T>(v, n)?;
// Start a new Era
let new_validators = Staking::<T>::new_era(SessionIndex::one()).unwrap();
assert!(new_validators.len() == v as usize);

let current_era = CurrentEra::get().unwrap();
let mut points_total = 0;
let mut points_individual = Vec::new();
let mut payout_calls = Vec::new();

for validator in new_validators.iter() {
points_total += 10;
points_individual.push((validator.clone(), 10));
payout_calls.push(Call::<T>::payout_stakers(validator.clone(), current_era))
}

// Give Era Points
let reward = EraRewardPoints::<T::AccountId> {
total: points_total,
individual: points_individual.into_iter().collect(),
};

ErasRewardPoints::<T>::insert(current_era, reward);

// Create reward pool
let total_payout = T::Currency::minimum_balance() * 1000.into();
<ErasValidatorReward<T>>::insert(current_era, total_payout);

let caller: T::AccountId = account("caller", 0, SEED);
}: {
for call in payout_calls {
call.dispatch(RawOrigin::Signed(caller.clone()).into())?;
}
}
}

#[cfg(test)]
Expand All @@ -397,7 +375,7 @@ mod tests {
use crate::benchmarking::{
create_validators_with_nominators_for_era,
create_validator_with_nominators,
create_nominator_with_validators,
SelectedBenchmark,
};

#[test]
Expand Down Expand Up @@ -429,36 +407,31 @@ mod tests {
let current_era = CurrentEra::get().unwrap();
let controller = validator;
let ledger = Staking::ledger(&controller).unwrap();
let stash = &ledger.stash;
let stash = ledger.stash;

let original_free_balance = Balances::free_balance(stash);
assert_ok!(Staking::payout_validator(Origin::signed(controller), current_era));
let new_free_balance = Balances::free_balance(stash);
let original_free_balance = Balances::free_balance(&stash);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), stash, current_era));
let new_free_balance = Balances::free_balance(&stash);

assert!(original_free_balance < new_free_balance);
});
}

#[test]
fn create_nominator_with_validators_works() {
fn test_payout_all() {
ExtBuilder::default().has_stakers(false).build().execute_with(|| {
let v = 5;

let (nominator, validators) = create_nominator_with_validators::<Test>(v).unwrap();

let current_era = CurrentEra::get().unwrap();
let controller = nominator;
let ledger = Staking::ledger(&controller).unwrap();
let stash = &ledger.stash;

let find_nominator = validators.into_iter().map(|x| (x, 0)).collect();
let v = 10;
let n = 100;

let original_free_balance = Balances::free_balance(stash);
assert_ok!(Staking::payout_nominator(Origin::signed(controller), current_era, find_nominator));
let new_free_balance = Balances::free_balance(stash);
let selected_benchmark = SelectedBenchmark::payout_all;
let c = vec![(frame_benchmarking::BenchmarkParameter::v, v), (frame_benchmarking::BenchmarkParameter::n, n)];
let closure_to_benchmark =
<SelectedBenchmark as frame_benchmarking::BenchmarkingSetup<Test>>::instance(
&selected_benchmark,
&c
).unwrap();

assert!(original_free_balance < new_free_balance);
assert_ok!(closure_to_benchmark());
});
}

}
Loading

0 comments on commit 6847f84

Please sign in to comment.