Fixes NPoS reward, along with tests, cleanups & docs corrections (#3595)

* Minor cleanups and tests

* Add another test

* fix

* Fix tests

* Fix tests

* Update srml/staking/src/tests.rs

Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
Gavin Wood
2019-09-11 15:11:08 +02:00
committed by GitHub
parent ccc73da289
commit d908f32c30
6 changed files with 161 additions and 115 deletions
+22 -18
View File
@@ -292,24 +292,27 @@ const STAKING_ID: LockIdentifier = *b"staking ";
/// Counter for the number of eras that have passed.
pub type EraIndex = u32;
/// Counter for the number of "reward" points earned by a given validator.
pub type Points = u32;
/// Reward points of an era. Used to split era total payout between validators.
#[derive(Encode, Decode, Default)]
pub struct EraRewards {
pub struct EraPoints {
/// Total number of points. Equals the sum of reward points for each validator.
total: u32,
/// Reward at one index correspond to reward for validator in current_elected of this index.
/// Thus this reward vec is only valid for one elected set.
rewards: Vec<u32>,
total: Points,
/// The reward points earned by a given validator. The index of this vec corresponds to the
/// index into the current validator set.
individual: Vec<Points>,
}
impl EraRewards {
impl EraPoints {
/// Add the reward to the validator at the given index. Index must be valid
/// (i.e. `index < current_elected.len()`).
fn add_points_to_index(&mut self, index: u32, points: u32) {
if let Some(new_total) = self.total.checked_add(points) {
self.total = new_total;
self.rewards.resize((index as usize + 1).max(self.rewards.len()), 0);
self.rewards[index as usize] += points; // Addition is less than total
self.individual.resize((index as usize + 1).max(self.individual.len()), 0);
self.individual[index as usize] += points; // Addition is less than total
}
}
}
@@ -590,7 +593,7 @@ decl_storage! {
pub CurrentEraStartSessionIndex get(current_era_start_session_index): SessionIndex;
/// Rewards for the current era. Using indices of current elected set.
CurrentEraRewards get(current_era_reward): EraRewards;
CurrentEraPointsEarned get(current_era_reward): EraPoints;
/// The amount of balance actively at stake for each validator slot, currently.
///
@@ -1161,7 +1164,7 @@ impl<T: Trait> Module<T> {
/// get a chance to set their session keys.
fn new_era(start_session_index: SessionIndex) -> Option<Vec<T::AccountId>> {
// Payout
let rewards = CurrentEraRewards::take();
let points = CurrentEraPointsEarned::take();
let now = T::Time::now();
let previous_era_start = <CurrentEraStart<T>>::mutate(|v| {
rstd::mem::replace(v, now)
@@ -1176,21 +1179,22 @@ impl<T: Trait> Module<T> {
let total_payout = inflation::compute_total_payout(
total_rewarded_stake.clone(),
T::Currency::total_issuance(),
// Era of duration more than u32::MAX is rewarded as u32::MAX.
<BalanceOf<T>>::from(era_duration.saturated_into::<u32>()),
// Duration of era; more than u64::MAX is rewarded as u64::MAX.
era_duration.saturated_into::<u64>(),
);
let mut total_imbalance = <PositiveImbalanceOf<T>>::zero();
let total_points = rewards.total;
for (v, points) in validators.iter().zip(rewards.rewards.into_iter()) {
if points != 0 {
let reward = multiply_by_rational(total_payout, points, total_points);
for (v, p) in validators.iter().zip(points.individual.into_iter()) {
if p != 0 {
let reward = multiply_by_rational(total_payout, p, points.total);
total_imbalance.subsume(Self::reward_validator(v, reward));
}
}
let total_reward = total_imbalance.peek();
// assert!(total_reward <= total_payout)
Self::deposit_event(RawEvent::Reward(total_reward));
T::Reward::on_unbalanced(total_imbalance);
T::OnRewardMinted::on_dilution(total_reward, total_rewarded_stake);
@@ -1376,7 +1380,7 @@ impl<T: Trait> Module<T> {
/// COMPLEXITY: Complexity is `number_of_validator_to_reward x current_elected_len`.
/// If you need to reward lots of validator consider using `reward_by_indices`.
pub fn reward_by_ids(validators_points: impl IntoIterator<Item = (T::AccountId, u32)>) {
CurrentEraRewards::mutate(|rewards| {
CurrentEraPointsEarned::mutate(|rewards| {
let current_elected = <Module<T>>::current_elected();
for (validator, points) in validators_points.into_iter() {
if let Some(index) = current_elected.iter()
@@ -1396,7 +1400,7 @@ impl<T: Trait> Module<T> {
// TODO: This can be optimised once #3302 is implemented.
let current_elected_len = <Module<T>>::current_elected().len() as u32;
CurrentEraRewards::mutate(|rewards| {
CurrentEraPointsEarned::mutate(|rewards| {
for (validator_index, points) in validators_points.into_iter() {
if validator_index < current_elected_len {
rewards.add_points_to_index(validator_index, points);