From 958cc7efeac185756044668f288cec6cffa684a0 Mon Sep 17 00:00:00 2001 From: Kian Peymani Date: Fri, 29 Mar 2019 20:00:15 +0430 Subject: [PATCH] Extended Balance Type for Staking's Election (#2134) * First draft of extended balance type * Test cleanup. * Update staking docs. * Add a good failing test case for quintill * Bring back saturating. * Some final fixes * A few more. * Update wasm; Bump spec; * Re-bump. * Custom lossy conversion from currency to vote * remove print * Fix reverse conversion issue. * void. Re-trigger ci. --- substrate/core/sr-primitives/src/lib.rs | 70 +--- substrate/core/sr-primitives/src/traits.rs | 29 ++ .../substrate_test_runtime.compact.wasm | Bin 60075 -> 60075 bytes substrate/node/runtime/src/lib.rs | 7 +- .../release/node_runtime.compact.wasm | Bin 952621 -> 968565 bytes substrate/srml/staking/src/lib.rs | 196 +++++---- substrate/srml/staking/src/mock.rs | 17 +- substrate/srml/staking/src/phragmen.rs | 123 +++--- substrate/srml/staking/src/tests.rs | 380 +++++++++--------- substrate/srml/support/src/lib.rs | 41 ++ 10 files changed, 474 insertions(+), 389 deletions(-) diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index cd83573cfc..5167e57072 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -254,82 +254,48 @@ impl From> for Perbill { } } -/// Perquintill is parts-per-quintillion. It stores a value between 0 and 1 in fixed point and +/// PerU128 is parts-per-u128-max-value. It stores a value between 0 and 1 in fixed point and /// provides a means to multiply some other value by that. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] -pub struct Perquintill(u64); +pub struct PerU128(u128); -const QUINTILLION: u64 = 1_000_000_000_000_000_000; +const U128: u128 = u128::max_value(); -impl Perquintill { +impl PerU128 { /// Nothing. pub fn zero() -> Self { Self(0) } /// Everything. - pub fn one() -> Self { Self(QUINTILLION) } + pub fn one() -> Self { Self(U128) } - /// Construct new instance where `x` is in quintillionths. Value equivalent to `x / 1,000,000,000,000,000,000`. - pub fn from_quintillionths(x: u64) -> Self { Self(x.min(QUINTILLION)) } - - /// Construct new instance where `x` is in billionths. Value equivalent to `x / 1,000,000,000`. - pub fn from_billionths(x: u64) -> Self { Self(x.min(1_000_000_000) * 1_000_000_000 ) } - - /// Construct new instance where `x` is in millionths. Value equivalent to `x / 1,000,000`. - pub fn from_millionths(x: u64) -> Self { Self(x.min(1_000_000) * 1000_000_000_000) } + /// Construct new instance where `x` is parts in u128::max_value. Equal to x/U128::max_value. + pub fn from_max_value(x: u128) -> Self { Self(x) } /// Construct new instance where `x` is denominator and the nominator is 1. - pub fn from_xth(x: u64) -> Self { Self(QUINTILLION / x.min(QUINTILLION)) } - - #[cfg(feature = "std")] - /// Construct new instance whose value is equal to `x` (between 0 and 1). - pub fn from_fraction(x: f64) -> Self { Self((x.max(0.0).min(1.0) * QUINTILLION as f64) as u64) } + pub fn from_xth(x: u128) -> Self { Self(U128/x.max(1)) } } -impl ::rstd::ops::Deref for Perquintill { - type Target = u64; +impl ::rstd::ops::Deref for PerU128 { + type Target = u128; - fn deref(&self) -> &u64 { + fn deref(&self) -> &u128 { &self.0 } } -impl ::rstd::ops::Mul for Perquintill -where - N: traits::As -{ - type Output = N; - fn mul(self, b: N) -> Self::Output { - >::sa(b.as_().saturating_mul(self.0) / QUINTILLION) - } -} - -#[cfg(feature = "std")] -impl From for Perquintill { - fn from(x: f64) -> Perquintill { - Perquintill::from_fraction(x) - } -} - -#[cfg(feature = "std")] -impl From for Perquintill { - fn from(x: f32) -> Perquintill { - Perquintill::from_fraction(x as f64) - } -} - -impl codec::CompactAs for Perquintill { - type As = u64; - fn encode_as(&self) -> &u64 { +impl codec::CompactAs for PerU128 { + type As = u128; + fn encode_as(&self) -> &u128 { &self.0 } - fn decode_from(x: u64) -> Perquintill { - Perquintill(x) + fn decode_from(x: u128) -> PerU128 { + Self(x) } } -impl From> for Perquintill { - fn from(x: codec::Compact) -> Perquintill { +impl From> for PerU128 { + fn from(x: codec::Compact) -> PerU128 { x.0 } } diff --git a/substrate/core/sr-primitives/src/traits.rs b/substrate/core/sr-primitives/src/traits.rs index 0454b74f6f..b62bc067b6 100644 --- a/substrate/core/sr-primitives/src/traits.rs +++ b/substrate/core/sr-primitives/src/traits.rs @@ -152,6 +152,35 @@ impl Convert for () { fn convert(_: A) -> B { Default::default() } } +/// A structure that converts the currency type into a lossy u64 +/// And back from u128 +pub struct CurrencyToVoteHandler; + +impl Convert for CurrencyToVoteHandler { + fn convert(x: u128) -> u64 { + if x >> 96 == 0 { + // Remove dust; divide by 2^32 + (x >> 32) as u64 + } else { + u64::max_value() + } + } +} + +impl Convert for CurrencyToVoteHandler { + fn convert(x: u128) -> u128 { + // if it practically fits in u64 + if x >> 64 == 0 { + // Add zero dust; multiply by 2^32 + x << 32 + } + else { + // 0000_0000_FFFF_FFFF_FFFF_FFFF_0000_0000 + (u64::max_value() << 32) as u128 + } + } +} + /// A structure that performs identity conversion. pub struct Identity; impl Convert for Identity { diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 956fa2bf2760c7123a7229dc288ab0da9eeeb8f8..9113d509fd7675b9d6cbd3537cd64650e05bd43f 100644 GIT binary patch delta 3298 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 IWqro~0QwKxXaE2J delta 3159 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 diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index c6e8397be6..d720681ebe 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -34,7 +34,7 @@ use client::{ use runtime_primitives::{ApplyResult, generic, create_runtime_str}; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::traits::{ - BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, + BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, CurrencyToVoteHandler }; use version::RuntimeVersion; use council::{motions as council_motions, voting as council_voting}; @@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 51, - impl_version: 51, + spec_version: 52, + impl_version: 52, apis: RUNTIME_API_VERSIONS, }; @@ -129,6 +129,7 @@ impl session::Trait for Runtime { impl staking::Trait for Runtime { type Currency = balances::Module; + type CurrencyToVote = CurrencyToVoteHandler; type OnRewardMinted = Treasury; type Event = Event; type Slash = (); diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 1514b0e607b2ded9e81cc4bcfda82624b16b3990..1ae0a286ed67cacff0b234677c5dd9ac481859bc 100644 GIT binary patch delta 119285 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
    ~GhXDZoj2BDTHLBR}6$9$sk(9N|~;mrQC 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. //! # Staking Module -//! //! -//! The staking module is the means by which a set of network maintainers (known as "authorities" in some contexts and "validators" in others) +//! +//! The staking module is the means by which a set of network maintainers (known as _authorities_ in some contexts and _validators_ in others) //! are chosen based upon those who voluntarily place funds under deposit. Under deposit, those funds are rewarded under -//! normal operation but are held at pain of "slash" (expropriation) should the staked maintainer be found not to be +//! normal operation but are held at pain of _slash_ (expropriation) should the staked maintainer be found not to be //! discharging their duties properly. +//! //! You can start using the Staking module by implementing the staking [`Trait`]. //! //! ## Overview @@ -34,12 +35,13 @@ //! - Stash account: The account holding an owner's funds used for staking. //! - Controller account: The account which controls an owner's funds for staking. //! - Era: A (whole) number of sessions, which is the period that the validator set (and each validator's active nominator set) is recalculated and where rewards are paid out. -//! - Slash: The punishment of a staker by reducing their funds ([reference](#references)). +//! - Slash: The punishment of a staker by reducing their funds. //! //! ### Goals //! //! //! The staking system in Substrate NPoS is designed to achieve three goals: +//! //! - It should be possible to stake funds that are controlled by a cold wallet. //! - It should be possible to withdraw some, or deposit more, funds without interrupting the role of an entity. //! - It should be possible to switch between roles (nominator, validator, idle) with minimal overhead. @@ -48,59 +50,62 @@ //! //! #### Staking //! -//! Almost any interaction with the staking module requires at least one account to become **bonded**, also known as -//! being a **staker**. For this, all that it is needed is a secondary _**stash account**_ which will hold the staked funds. -//! Henceforth, the former account that initiated the interest is called the **controller** and the latter, holding the -//! funds, is named the **stash**. Also, note that this implies that entering the staking process requires an _account -//! pair_, one to take the role of the controller and one to be the frozen stash account (any value locked in -//! stash cannot be used, hence called _frozen_). This process in the public API is mostly referred to as _bonding_ via -//! the `bond()` function. +//! Almost any interaction with the staking module requires a process of _**bonding**_ (also known as +//! being a _staker_). To become *bonded* a fund-holding account known as the _stash account_, which holds some of all of the +//! funds that become frozen in place as part of the staking process, is paired with an active **controller** account which issues +//! instructions on how they shall be used. //! -//! Any account pair successfully placed at stake can accept three possible roles, namely: `validate`, `nominate` or -//! simply `chill`. Note that during the process of accepting these roles, the _controller_ account is always responsible -//! for declaring interest and the _stash_ account stays untouched, without directly interacting in any operation. +//! An account pair can become bonded using the [`bond`](./enum.Call.html#variant.bond) call. +//! +//! Stash accounts can change their associated controller using the [`set_controller`](./enum.Call.html#variant.set_controller) call. +//! +//! There are three possible roles that any staked account pair can be in: `Validator`, `Nominator` and `Idle` (defined in [`StakerStatus`]). There are +//! three corresponding instructions to change between roles, namely: +//! [`validate`](./enum.Call.html#variant.validate), [`nominate`](./enum.Call.html#variant.nominate) and [`chill`](./enum.Call.html#variant.chill). //! //! #### Validating //! //! A **validator** takes the role of either validating blocks or ensuring their finality, maintaining the veracity of //! the network. A validator should avoid both any sort of malicious misbehavior and going offline. //! Bonded accounts that state interest in being a validator do NOT get immediately chosen as a validator. Instead, they -//! are declared as a _candidate_ and they _might_ get elected at the _next **era**_ as a validator. The result of the -//! election is determined by nominators and their votes. An account can become a validator via the `validate()` call. +//! are declared as a _candidate_ and they _might_ get elected at the _next era_ as a validator. The result of the +//! election is determined by nominators and their votes. +//! +//! An account can become a validator candidate via the [`validate`](./enum.Call.html#variant.validate) call. //! //! #### Nomination //! //! A **nominator** does not take any _direct_ role in maintaining the network, instead, it votes on a set of validators -//! to be elected. Once interest in nomination is stated by an account, it takes effect _immediately_, meaning that its -//! votes will be taken into account at the next election round. As mentioned above, a nominator must also place some -//! funds in a stash account, essentially indicating the _weight_ of its vote. In some sense, the nominator bets on the -//! honesty of a set of validators by voting for them, with the goal of having a share of the reward granted to them. -//! Any rewards given to a validator is shared among that validator and all of the nominators that voted for it. The -//! same logic applies to the slash of a validator; if a validator misbehaves all of its nominators also get slashed. +//! to be elected. Once interest in nomination is stated by an account, it takes effect at the next election round. The +//! funds in the nominator's stash account indicate the _weight_ of its vote. +//! Both the rewards and any punishment that a validator earns are shared between the validator and its nominators. //! This rule incentivizes the nominators to NOT vote for the misbehaving/offline validators as much as possible, simply -//! because the nominators will also lose funds if they vote poorly. An account can become a nominator via the -//! `nominate()` call. +//! because the nominators will also lose funds if they vote poorly. +//! +//! An account can become a nominator via the [`nominate`](enum.Call.html#variant.nominate) call. //! //! #### Rewards and Slash //! -//! The **reward and slashing** procedure are the core of the staking module, attempting to _embrace valid behavior_ -//! while _punishing any misbehavior or lack of availability_. Slashing can occur at any point in time, once -//! misbehavior is reported. One such misbehavior is a validator being detected as offline more than a certain number of -//! times. Once slashing is determined, a value is deducted from the balance of the validator and all the nominators who -//! voted for this validator. Same rules apply to the rewards in the sense of being shared among a validator and its -//! associated nominators. +//! The **reward and slashing** procedure is the core of the staking module, attempting to _embrace valid behavior_ +//! while _punishing any misbehavior or lack of availability_. +//! +//! Slashing can occur at any point in time, once misbehavior is reported. Once slashing is determined, a value is +//! deducted from the balance of the validator and all the nominators who voted for this validator (values are deducted from the _stash_ account of the slashed entity). +//! +//! Similar to slashing, rewards are also shared among a validator and its associated nominators. +//! Yet, the reward funds are not always transferred to the stash account and can be configured. See [Reward Calculation](#reward-calculation) +//! for more details. +//! +//! #### Chilling //! //! Finally, any of the roles above can choose to step back temporarily and just chill for a while. This means that if //! they are a nominator, they will not be considered as voters anymore and if they are validators, they will no longer -//! be a candidate for the next election (again, both effects apply at the beginning of the next era). An account can -//! step back via the `chill()` call. +//! be a candidate for the next election. +//! +//! An account can step back via the [`chill`](enum.Call.html#variant.chill) call. //! //! ## Interface //! -//! ### Types -//! -//! - `Currency`: Used as the measurement means of staking and funds management. -//! //! ### Dispatchable //! //! The Dispatchable functions of the staking module enable the steps needed for entities to accept and change their @@ -110,7 +115,7 @@ //! //! ### Public //! The staking module contains many public storage items and (im)mutable functions. Please refer to the [struct list](#structs) -//! below and the [`Module`](https://crates.parity.io/srml_staking/struct.Module.html) struct definition for more details. +//! below and the [`Module`] struct definition for more details. //! //! ## Usage //! @@ -134,8 +139,6 @@ //! Staking::validate(Origin::signed(4), ValidatorPrefs::default()); //! ``` //! -//! Note that, as mentioned, the stash account is transparent in such calls and only the controller initiates the function calls. -//! //! Similarly, to state desire in nominating: //! //! ```rust,ignore @@ -149,59 +152,96 @@ //! Staking::chill(Origin::signed(4)); //! ``` //! +//! You can find the equivalent of the above calls in your [Substrate UI](https://substrate-ui.parity.io). +//! ### Snippet: Reporting Misbehavior +//! +//! ``` +//! use srml_support::{decl_module, dispatch::Result}; +//! use system::ensure_signed; +//! use srml_staking::{self as staking}; +//! +//! pub trait Trait: staking::Trait {} +//! +//! decl_module! { +//! pub struct Module for enum Call where origin: T::Origin { +//! /// Report whoever calls this function as offline once. +//! pub fn report_sender(origin) -> Result { +//! let reported = ensure_signed(origin)?; +//! >::on_offline_validator(reported, 1); +//! Ok(()) +//! } +//! } +//! } +//! # fn main() { } +//! ``` +//! //! ## Implementation Details //! //! ### Slot Stake //! -//! The term `slot_stake` will be used throughout this section. It refers to a value calculated at the end of each era, -//! containing the _minimum value at stake among all validators._ +//! The term [`SlotStake`] will be used throughout this section. It refers to a value calculated at the end of each era, +//! containing the _minimum value at stake among all validators._ Note that a validator's value at stake might be a combination of +//! The validator's own stake and the votes it received. See [`Exposure`] for more details. //! //! ### Reward Calculation //! -//! - Rewards are recorded **per-session** and paid **per-era**. The value of the reward for each session is calculated at -//! the end of the session based on the timeliness of the session, then accumulated to be paid later. The value of -//! the new _per-session-reward_ is calculated at the end of each era by multiplying `slot_stake` and a configuration -//! storage item named `SessionReward`. -//! - Once a new era is triggered, rewards are paid to the validators and the associated nominators. -//! - The validator can declare an amount, named `validator_payment`, that does not get shared with the nominators at -//! each reward payout through their `ValidatorPrefs`. This value gets deducted from the total reward that can be paid. -//! The remaining portion is split among the validator and all of the nominators who had a vote for this validator, -//! proportional to their staked value. -//! - All entities who receive a reward have the option to choose their reward destination, through the `Payee` storage item (see `set_payee()`), to be one of the following: -//! - Controller account. +//! Rewards are recorded **per-session** and paid **per-era**. The value of the reward for each session is calculated at +//! the end of the session based on the timeliness of the session, then accumulated to be paid later. The value of +//! the new _per-session-reward_ is calculated at the end of each era by multiplying [`SlotStake`] and [`SessionReward`] +//! (`SessionReward` is the multiplication factor, represented by a number between 0 and 1). +//! Once a new era is triggered, rewards are paid to the validators and the associated nominators. +//! +//! The validator can declare an amount, named [`validator_payment`](./struct.ValidatorPrefs.html#structfield.validator_payment), that does not get shared with the nominators at +//! each reward payout through their [`ValidatorPrefs`]. This value gets deducted from the total reward that can be paid. +//! The remaining portion is split among the validator and all of the nominators that nominated the validator, +//! proportional to the value staked behind this validator +//! (_i.e._ dividing the [`own`](./struct.Exposure.html#structfield.own) or [`others`](./struct.Exposure.html#structfield.others) by [`total`](./struct.Exposure.html#structfield.total) in [`Exposure`]). +//! +//! All entities who receive a reward have the option to choose their reward destination, +//! through the [`Payee`] storage item (see [`set_payee`](enum.Call.html#variant.set_payee)), to be one of the following: +//! +//! - Controller account, (obviously) not increasing the staked value. //! - Stash account, not increasing the staked value. //! - Stash account, also increasing the staked value. //! //! ### Slashing details //! -//! - A validator can be _reported_ to be offline at any point via `on_offline_validator` public function. -//! - Each validator declares how many times it can be _reported_ before it actually gets slashed via the -//! `unstake_threshold` in `ValidatorPrefs`. On top of this, the module also introduces an `OfflineSlashGrace`, -//! which applies to all validators and prevents them from getting immediately slashed. -//! - Similar to the reward value, the slash value is updated at the end of each era by multiplying `slot_stake` and a -//! configuration storage item, `OfflineSlash`. -//! - Once a validator has been reported a sufficient number of times, the actual value that gets deducted from that -//! validator, and every single nominator that voted for it is calculated by multiplying the result of the above point -//! by `2.pow(unstake_threshold)`. -//! - If the previous overflows, then `slot_stake` is used. -//! - If the previous is more than what the validator/nominator has in stake, all of its stake is slashed (`.max(total_stake)`). +//! A validator can be _reported_ to be offline at any point via [`on_offline_validator`](enum.Call.html#variant.on_offline_validator) public function. +//! Each validator declares how many times it can be _reported_ before it actually gets slashed via their +//! `unstake_threshold` in [`ValidatorPrefs`]. +//! +//! On top of this, staking module also introduces an [`OfflineSlashGrace`], which applies to all validators and prevents +//! them from getting immediately slashed. +//! +//! Essentially, a validator gets slashed once they have been reported more than [`OfflineSlashGrace`] + [`unstake_threshold`](./struct.ValidatorPrefs.html#structfield.unstake_threshold) times. +//! Getting slashed due to offline report always leads to being _unstaked_ (_i.e._ removed as a validator candidate) as the consequence. +//! +//! The base slash value is computed _per slash-event_ by multiplying [`OfflineSlash`] and the `total` [`Exposure`]. This value +//! is then multiplied by `2.pow(unstake_threshold)` to obtain the final slash value. +//! All individual accounts' punishments are capped at their total stake (NOTE: This cap should never come into force in a correctly implemented, non-corrupted, well-configured system). //! //! ### Additional Fund Management Operations //! //! Any funds already placed into stash can be the target of the following operations: //! -//! - The controller account can free a portion (or all) of the funds using the `unbond()` call. Note that the funds -//! are not immediately accessible, instead, a duration denoted by `BondingDuration` (in number of eras) must pass until the funds can actually be removed. -//! - To actually remove the funds, once the bonding duration is over, `withdraw_unbonded()` can be used. -//! - As opposed to the above, additional funds can be added to the stash account via the `bond_extra()` transaction call. +//! The controller account can free a portion (or all) of the funds using the [`unbond`](enum.Call.html#variant.unbond) call. +//! Note that the funds are not immediately accessible. Instead, a duration denoted by [`BondingDuration`] (in number of eras) +//! must pass until the funds can actually be removed. Once the [`BondingDuration`] is over the [`withdraw_unbonded`]((enum.Call.html#variant.withdraw_unbonded)) call can be used +//! to actually withdraw the funds. //! -//! ### Election algorithm details. +//!### Election Algorithm +//! +//! The current election algorithm is implemented based on Phragmén. +//! The reference implementation can be found [here](https://github.com/w3f/consensus/tree/master/NPoS). +//! +//! The election algorithm, aside from electing the validators with the most stake value and votes, tries to divide the nominator votes +//! among candidates in an equal manner. To further assure this, an optional post-processing can be applied that iteratively normalizes the nominator staked values +//! until the total difference among votes of a particular nominator are less than a threshold. //! -//! The current election algorithm is implemented based on Phragmén. The reference implementation can be found [here](https://github.com/w3f/consensus/tree/master/NPoS). //! //! ## GenesisConfig //! -//! See the [`GensisConfig`] for a list of attributes that can be provided. +//! See the [`GenesisConfig`] for a list of attributes that can be provided. //! //! ## Related Modules //! @@ -209,10 +249,6 @@ //! - [**Sessions**](https://crates.parity.io/srml_session/index.html): Used to manage sessions. Also, a list of new validators is also stored in the sessions module's `Validators` at the end of each era. //! - [**System**](https://crates.parity.io/srml_system/index.html): Used to obtain block number and time, among other details. //! -//! # References -//! -//! 1. This document is written as a more verbose version of the original [Staking.md](../Staking.md) file. Some sections, are taken directly from the aforementioned document. - #![cfg_attr(not(feature = "std"), no_std)] @@ -224,11 +260,11 @@ use srml_support::{StorageValue, StorageMap, EnumerableStorageMap, dispatch::Res use srml_support::{decl_module, decl_event, decl_storage, ensure}; use srml_support::traits::{ Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency, WithdrawReasons, - OnUnbalanced, Imbalance + OnUnbalanced, Imbalance, }; use session::OnSessionChange; use primitives::Perbill; -use primitives::traits::{Zero, One, As, StaticLookup, CheckedSub, Saturating, Bounded}; +use primitives::traits::{Convert, Zero, One, As, StaticLookup, CheckedSub, Saturating, Bounded}; #[cfg(feature = "std")] use primitives::{Serialize, Deserialize}; use system::ensure_signed; @@ -249,7 +285,7 @@ const MAX_UNSTAKE_THRESHOLD: u32 = 10; pub enum StakerStatus { /// Chilling. Idle, - /// Declared state in validating or already participating in it. + /// Declared desire in validating or already participating in it. Validator, /// Nominating for a group of other stakers. Nominator(Vec), @@ -381,6 +417,10 @@ pub trait Trait: system::Trait + session::Trait { Currency + LockableCurrency; + /// Convert a balance into a number used for election calculation. + /// This must fit into a `u64` but is allowed to be sensibly lossy. + type CurrencyToVote: Convert, u64> + Convert>; + /// Some tokens minted. type OnRewardMinted: OnDilution>; @@ -520,7 +560,7 @@ decl_module! { /// Take the origin account as a stash and lock up `value` of its balance. `controller` will be the /// account that controls it. /// - /// The dispatch origin for this call must be _Signed_. + /// The dispatch origin for this call must be _Signed_ by the stash account. fn bond(origin, controller: ::Source, #[compact] value: BalanceOf, payee: RewardDestination) { let stash = ensure_signed(origin)?; diff --git a/substrate/srml/staking/src/mock.rs b/substrate/srml/staking/src/mock.rs index 5871306f49..17723cb362 100644 --- a/substrate/srml/staking/src/mock.rs +++ b/substrate/srml/staking/src/mock.rs @@ -18,16 +18,27 @@ #![cfg(test)] -use primitives::{traits::IdentityLookup, BuildStorage, Perbill}; +use primitives::{traits::{IdentityLookup, Convert}, BuildStorage, Perbill}; use primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, ConvertUintAuthorityId}; use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; use srml_support::impl_outer_origin; use crate::{GenesisConfig, Module, Trait, StakerStatus}; -// The AccountId alias in this test module. +/// The AccountId alias in this test module. pub type AccountIdType = u64; +/// Simple structure that exposes how u64 currency can be represented as... u64. +pub struct CurrencyToVoteHandler; +impl Convert for CurrencyToVoteHandler { + fn convert(x: u64) -> u64 { x } +} +impl Convert for CurrencyToVoteHandler { + fn convert(x: u128) -> u64 { + x as u64 + } +} + impl_outer_origin!{ pub enum Origin for Test {} } @@ -73,6 +84,7 @@ impl timestamp::Trait for Test { } impl Trait for Test { type Currency = balances::Module; + type CurrencyToVote = CurrencyToVoteHandler; type OnRewardMinted = (); type Event = (); type Slash = (); @@ -131,7 +143,6 @@ impl ExtBuilder { self } pub fn nominate(mut self, nominate: bool) -> Self { - // NOTE: this only sets a dummy nominator for tests that want 10 and 20 (default validators) to be chosen by default. self.nominate = nominate; self } diff --git a/substrate/srml/staking/src/phragmen.rs b/substrate/srml/staking/src/phragmen.rs index 8d59562f69..bb939baa79 100644 --- a/substrate/srml/staking/src/phragmen.rs +++ b/substrate/srml/staking/src/phragmen.rs @@ -17,11 +17,13 @@ //! Rust implementation of the Phragmén election algorithm. use rstd::prelude::*; -use primitives::Perquintill; -use primitives::traits::{Zero, As, Bounded, CheckedMul, Saturating}; +use primitives::PerU128; +use primitives::traits::{Zero, Saturating, Convert}; use parity_codec::{HasCompact, Encode, Decode}; use crate::{Exposure, BalanceOf, Trait, ValidatorPrefs, IndividualExposure}; +type Fraction = PerU128; +type ExtendedBalance = u128; /// Configure the behavior of the Phragmen election. /// Might be deprecated. @@ -43,39 +45,39 @@ pub struct Candidate { /// Exposure struct, holding info about the value that the validator has in stake. pub exposure: Exposure, /// Intermediary value used to sort candidates. - pub score: Perquintill, + pub score: Fraction, /// Accumulator of the stake of this candidate based on received votes. - approval_stake: Balance, + approval_stake: ExtendedBalance, /// Flag for being elected. elected: bool, /// This is most often equal to `Exposure.total` but not always. Needed for [`equalize`] - backing_stake: Balance + backing_stake: ExtendedBalance } /// Wrapper around the nomination info of a single nominator for a group of validators. #[derive(Clone, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct Nominator { +pub struct Nominator { /// The nominator's account. who: AccountId, /// List of validators proposed by this nominator. - edges: Vec>, + edges: Vec>, /// the stake amount proposed by the nominator as a part of the vote. - budget: Balance, + budget: ExtendedBalance, /// Incremented each time a nominee that this nominator voted for has been elected. - load: Perquintill, + load: Fraction, } /// Wrapper around a nominator vote and the load of that vote. #[derive(Clone, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct Edge { +pub struct Edge { /// Account being voted for who: AccountId, /// Load of this vote. - load: Perquintill, + load: Fraction, /// Final backing stake of this vote. - backing_stake: Balance, + backing_stake: ExtendedBalance, /// Index of the candidate stored in the 'candidates' vector candidate_index: usize, /// Index of the candidate stored in the 'elected_candidates' vector. Used only with equalize. @@ -107,6 +109,8 @@ pub fn elect( >>, for <'r> FS: Fn(&'r T::AccountId) -> BalanceOf, { + let expand = |b: BalanceOf| , u64>>::convert(b) as ExtendedBalance; + let shrink = |b: ExtendedBalance| >>::convert(b); let rounds = get_rounds(); let mut elected_candidates; @@ -121,14 +125,14 @@ pub fn elect( }).collect::>>>(); // 1.1- Add phantom votes. - let mut nominators: Vec>> = Vec::with_capacity(candidates.len()); + let mut nominators: Vec> = Vec::with_capacity(candidates.len()); candidates.iter_mut().enumerate().for_each(|(idx, c)| { - c.approval_stake += c.exposure.total; + c.approval_stake += expand(c.exposure.total); nominators.push(Nominator { who: c.who.clone(), edges: vec![ Edge { who: c.who.clone(), candidate_index: idx, ..Default::default() }], - budget: c.exposure.total, - load: Perquintill::zero(), + budget: expand(c.exposure.total), + load: Fraction::zero(), }) }); @@ -136,10 +140,11 @@ pub fn elect( // Also collect approval stake along the way. nominators.extend(get_nominators().map(|(who, nominees)| { let nominator_stake = stash_of(&who); - let mut edges: Vec>> = Vec::with_capacity(nominees.len()); + let mut edges: Vec> = Vec::with_capacity(nominees.len()); for n in &nominees { if let Some(idx) = candidates.iter_mut().position(|i| i.who == *n) { - candidates[idx].approval_stake = candidates[idx].approval_stake.saturating_add(nominator_stake); + candidates[idx].approval_stake = candidates[idx].approval_stake + .saturating_add(expand(nominator_stake)); edges.push(Edge { who: n.clone(), candidate_index: idx, ..Default::default() }); } } @@ -147,15 +152,15 @@ pub fn elect( Nominator { who, edges: edges, - budget: nominator_stake, - load: Perquintill::zero(), + budget: expand(nominator_stake), + load: Fraction::zero(), } })); // 3- optimization: // Candidates who have 0 stake => have no votes or all null-votes. Kick them out not. - let mut candidates = candidates.into_iter().filter(|c| c.approval_stake > BalanceOf::::zero()) + let mut candidates = candidates.into_iter().filter(|c| c.approval_stake > 0) .collect::>>>(); // 4- If we have more candidates then needed, run Phragmén. @@ -166,7 +171,7 @@ pub fn elect( // Loop 1: initialize score for c in &mut candidates { if !c.elected { - c.score = Perquintill::from_xth(c.approval_stake.as_()); + c.score = Fraction::from_xth(c.approval_stake); } } // Loop 2: increment score. @@ -174,10 +179,8 @@ pub fn elect( for e in &n.edges { let c = &mut candidates[e.candidate_index]; if !c.elected { - // Note: This seems to never overflow, ok to be safe though - let temp = n.budget.as_().saturating_mul(*n.load) / c.approval_stake.as_(); - // Note: This seems to never overflow, ok to be safe though - c.score = Perquintill::from_quintillionths((*c.score).saturating_add(temp)); + let temp = n.budget.saturating_mul(*n.load) / c.approval_stake; + c.score = Fraction::from_max_value((*c.score).saturating_add(temp)); } } } @@ -194,7 +197,7 @@ pub fn elect( for n in &mut nominators { for e in &mut n.edges { if e.who == winner.who { - e.load = Perquintill::from_quintillionths(*winner.score - *n.load); + e.load = Fraction::from_max_value(*winner.score - *n.load); n.load = winner.score; } } @@ -209,14 +212,14 @@ pub fn elect( // if the target of this vote is among the winners, otherwise let go. if let Some(c) = elected_candidates.iter_mut().find(|c| c.who == e.who) { e.elected = true; - // NOTE: always divide last to avoid collapse to zero. - e.backing_stake = >::sa(n.budget.as_().saturating_mul(*e.load) / *n.load); + // NOTE: for now, always divide last to avoid collapse to zero. + e.backing_stake = n.budget.saturating_mul(*e.load) / *n.load; c.backing_stake = c.backing_stake.saturating_add(e.backing_stake); if c.who != n.who { // Only update the exposure if this vote is from some other account. - c.exposure.total = c.exposure.total.saturating_add(e.backing_stake); + c.exposure.total = c.exposure.total.saturating_add(shrink(e.backing_stake)); c.exposure.others.push( - IndividualExposure { who: n.who.clone(), value: e.backing_stake } + IndividualExposure { who: n.who.clone(), value: shrink(e.backing_stake) } ); } } @@ -250,7 +253,6 @@ pub fn elect( } } } - } else { if candidates.len() > minimum_validator_count { // if we don't have enough candidates, just choose all that have some vote. @@ -259,9 +261,9 @@ pub fn elect( let nominator = n.who.clone(); for e in &mut n.edges { if let Some(c) = elected_candidates.iter_mut().find(|c| c.who == e.who && c.who != nominator) { - c.exposure.total = c.exposure.total.saturating_add(n.budget); + c.exposure.total = c.exposure.total.saturating_add(shrink(n.budget)); c.exposure.others.push( - IndividualExposure { who: n.who.clone(), value: n.budget } + IndividualExposure { who: n.who.clone(), value: shrink(n.budget) } ); } } @@ -274,29 +276,40 @@ pub fn elect( Some(elected_candidates) } +/// Performs equalize post-processing to the output of the election algorithm +/// This function mutates the input parameters, most noticeably it updates the exposure of +/// the elected candidates. +/// The return value is to tolerance at which the function has stopped. pub fn equalize( - nominator: &mut Nominator>, + nominator: &mut Nominator, elected_candidates: &mut Vec>>, - tolerance: BalanceOf + _tolerance: BalanceOf ) -> BalanceOf { + let expand = |b: BalanceOf| , u64>>::convert(b) as ExtendedBalance; + let shrink = |b: ExtendedBalance| >>::convert(b); + let tolerance = expand(_tolerance); let mut elected_edges = nominator.edges .iter_mut() .filter(|e| e.elected) - .collect::>>>(); - if elected_edges.len() == 0 { return >::zero(); } + .collect::>>(); + + if elected_edges.len() == 0 { + return >::zero(); + } + let stake_used = elected_edges .iter() - .fold(>::zero(), |s, e| s.saturating_add(e.backing_stake)); + .fold(0, |s, e| s.saturating_add(e.backing_stake)); let backed_stakes = elected_edges .iter() .map(|e| elected_candidates[e.elected_idx].backing_stake) - .collect::>>(); + .collect::>(); let backing_backed_stake = elected_edges .iter() - .filter(|e| e.backing_stake > >::zero()) + .filter(|e| e.backing_stake > 0) .map(|e| elected_candidates[e.elected_idx].backing_stake) - .collect::>>(); + .collect::>(); let mut difference; if backing_backed_stake.len() > 0 { @@ -311,7 +324,7 @@ pub fn equalize( difference = max_stake.saturating_sub(min_stake); difference = difference.saturating_add(nominator.budget.saturating_sub(stake_used)); if difference < tolerance { - return difference; + return shrink(difference); } } else { difference = nominator.budget; @@ -322,18 +335,19 @@ pub fn equalize( // NOTE: no assertions in the runtime, but this should nonetheless be indicative. //assert_eq!(elected_candidates[e.elected_idx].who, e.who); elected_candidates[e.elected_idx].backing_stake -= e.backing_stake; - elected_candidates[e.elected_idx].exposure.total -= e.backing_stake; - e.backing_stake = >::zero(); + elected_candidates[e.elected_idx].exposure.total -= shrink(e.backing_stake); + e.backing_stake = 0; }); elected_edges.sort_unstable_by_key(|e| elected_candidates[e.elected_idx].backing_stake); - let mut cumulative_stake = >::zero(); + let mut cumulative_stake: ExtendedBalance = 0; let mut last_index = elected_edges.len() - 1; let budget = nominator.budget; elected_edges.iter_mut().enumerate().for_each(|(idx, e)| { let stake = elected_candidates[e.elected_idx].backing_stake; - let stake_mul = stake.checked_mul(&>::sa(idx as u64)).unwrap_or(>::max_value()); + + let stake_mul = stake.saturating_mul(idx as ExtendedBalance); let stake_sub = stake_mul.saturating_sub(cumulative_stake); if stake_sub > budget { last_index = idx.checked_sub(1).unwrap_or(0); @@ -346,19 +360,18 @@ pub fn equalize( let split_ways = last_index + 1; let excess = nominator.budget .saturating_add(cumulative_stake) - .saturating_sub( - last_stake.checked_mul(&>::sa(split_ways as u64)) - .unwrap_or(>::max_value()) - ); + .saturating_sub(last_stake.saturating_mul(split_ways as ExtendedBalance)); let nominator_address = nominator.who.clone(); elected_edges.iter_mut().take(split_ways).for_each(|e| { let c = &mut elected_candidates[e.elected_idx]; - e.backing_stake = (excess / >::sa(split_ways as u64)).saturating_add(last_stake) - c.backing_stake; - c.exposure.total = c.exposure.total.saturating_add(e.backing_stake); + e.backing_stake = (excess / split_ways as ExtendedBalance) + .saturating_add(last_stake) + .saturating_sub(c.backing_stake); + c.exposure.total = c.exposure.total.saturating_add(shrink(e.backing_stake)); c.backing_stake = c.backing_stake.saturating_add(e.backing_stake); if let Some(i_expo) = c.exposure.others.iter_mut().find(|i| i.who == nominator_address) { - i_expo.value = e.backing_stake; + i_expo.value = shrink(e.backing_stake); } }); - difference + shrink(difference) } diff --git a/substrate/srml/staking/src/tests.rs b/substrate/srml/staking/src/tests.rs index 6f3d504c06..2d6ce5aa7a 100644 --- a/substrate/srml/staking/src/tests.rs +++ b/substrate/srml/staking/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use runtime_io::with_externalities; use phragmen; -use primitives::Perquintill; -use srml_support::{assert_ok, assert_noop, EnumerableStorageMap}; +use primitives::PerU128; +use srml_support::{assert_ok, assert_noop, assert_eq_uvec, EnumerableStorageMap}; use mock::{Balances, Session, Staking, System, Timestamp, Test, ExtBuilder, Origin}; use srml_support::traits::{Currency, ReservableCurrency}; @@ -54,7 +54,7 @@ fn basic_setup_works() { assert_eq!(Staking::nominators(101), vec![11, 21]); // Account 10 is exposed by 1000 * balance_factor from their own stash in account 11 + the default nominator vote - assert_eq!(Staking::stakers(11), Exposure { total: 1125, own: 1000, others: vec![ IndividualExposure { who: 101, value: 125 }] }); + assert_eq!(Staking::stakers(11), Exposure { total: 1124, own: 1000, others: vec![ IndividualExposure { who: 101, value: 124 }] }); // Account 20 is exposed by 1000 * balance_factor from their own stash in account 21 + the default nominator vote assert_eq!(Staking::stakers(21), Exposure { total: 1375, own: 1000, others: vec![ IndividualExposure { who: 101, value: 375 }] }); @@ -69,8 +69,7 @@ fn basic_setup_works() { assert_eq!(Staking::current_session_reward(), 10); // initial slot_stake - assert_eq!(Staking::slot_stake(), 1125); // Naive - // assert_eq!(Staking::slot_stake(), 1250); // Post-process + assert_eq!(Staking::slot_stake(), 1124); // Naive // initial slash_count of validators assert_eq!(Staking::slash_count(&11), 0); @@ -173,7 +172,7 @@ fn offline_grace_should_delay_slashing() { assert_ok!(Staking::set_offline_slash_grace(offline_slash_grace)); assert_eq!(Staking::offline_slash_grace(), 1); - // Check unstaked_threshold is 3 (default) + // Check unstake_threshold is 3 (default) let default_unstake_threshold = 3; assert_eq!(Staking::validators(&11), ValidatorPrefs { unstake_threshold: default_unstake_threshold, validator_payment: 0 }); @@ -192,7 +191,7 @@ fn offline_grace_should_delay_slashing() { Staking::on_offline_validator(10, 1); assert_eq!(Staking::slash_count(&11), 5); // User gets slashed - assert_eq!(Balances::free_balance(&11), 0); + assert!(Balances::free_balance(&11) < 70); // New era is forced assert!(Staking::forcing_new_era().is_some()); }); @@ -440,7 +439,7 @@ fn staking_should_work() { .build(), || { // remember + compare this along with the test. - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); assert_ok!(Staking::set_bonding_duration(2)); assert_eq!(Staking::bonding_duration(), 2); @@ -458,7 +457,7 @@ fn staking_should_work() { assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); // No effects will be seen so far. - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // --- Block 2: System::set_block_number(2); @@ -466,7 +465,7 @@ fn staking_should_work() { assert_eq!(Staking::current_era(), 0); // No effects will be seen so far. Era has not been yet triggered. - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // --- Block 3: the validators will now change. @@ -475,7 +474,7 @@ fn staking_should_work() { // 2 only voted for 4 and 20 assert_eq!(Session::validators().len(), 2); - assert_eq!(Session::validators(), vec![20, 4]); + assert_eq_uvec!(Session::validators(), vec![20, 4]); assert_eq!(Staking::current_era(), 1); @@ -487,14 +486,14 @@ fn staking_should_work() { Staking::chill(Origin::signed(4)).unwrap(); // nothing should be changed so far. - assert_eq!(Session::validators(), vec![20, 4]); + assert_eq_uvec!(Session::validators(), vec![20, 4]); assert_eq!(Staking::current_era(), 1); // --- Block 5: nothing. 4 is still there. System::set_block_number(5); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![20, 4]); + assert_eq_uvec!(Session::validators(), vec![20, 4]); assert_eq!(Staking::current_era(), 1); @@ -503,7 +502,7 @@ fn staking_should_work() { Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 2); assert_eq!(Session::validators().contains(&4), false); - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // Note: the stashed value of 4 is still lock assert_eq!(Staking::ledger(&4), Some(StakingLedger { stash: 3, total: 1500, active: 1500, unlocking: vec![] })); @@ -528,7 +527,7 @@ fn less_than_needed_candidates_works() { assert_eq!(Staking::minimum_validator_count(), 1); // initial validators - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // 10 and 20 are now valid candidates. // trigger era @@ -537,7 +536,7 @@ fn less_than_needed_candidates_works() { assert_eq!(Staking::current_era(), 1); // both validators will be chosen again. NO election algorithm is even executed. - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // But the exposure is updated in a simple way. No external votes exists. This is purely self-vote. assert_eq!(Staking::stakers(10).others.iter().map(|e| e.who).collect::>>(), vec![]); @@ -560,7 +559,7 @@ fn no_candidate_emergency_condition() { assert_eq!(Staking::validator_count(), 15); // initial validators - assert_eq!(Session::validators(), vec![10, 20, 30, 40]); + assert_eq_uvec!(Session::validators(), vec![10, 20, 30, 40]); // trigger era System::set_block_number(1); @@ -568,15 +567,12 @@ fn no_candidate_emergency_condition() { assert_eq!(Staking::current_era(), 1); // No one nominates => no one has a proper vote => no change - assert_eq!(Session::validators(), vec![10, 20, 30, 40]); + assert_eq_uvec!(Session::validators(), vec![10, 20, 30, 40]); }); } #[test] fn nominating_and_rewards_should_work() { - // For now it tests a functionality which somehow overlaps with other tests: - // the fact that the nominator is rewarded properly. - // // PHRAGMEN OUTPUT: running this test with the reference impl gives: // // Votes [('10', 1000, ['10']), ('20', 1000, ['20']), ('30', 1000, ['30']), ('40', 1000, ['40']), ('2', 1000, ['10', '20', '30']), ('4', 1000, ['10', '20', '40'])] @@ -620,7 +616,7 @@ fn nominating_and_rewards_should_work() { .build(), || { // initial validators -- everyone is actually even. - assert_eq!(Session::validators(), vec![40, 30]); + assert_eq_uvec!(Session::validators(), vec![40, 30]); // Set payee to controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -638,9 +634,6 @@ fn nominating_and_rewards_should_work() { let _ = Balances::make_free_balance_be(i, initial_balance); } - // record their balances. - for i in 1..5 { assert_eq!(Balances::total_balance(&i), initial_balance); } - // bond two account pairs and state interest in nomination. // 2 will nominate for 10, 20, 30 assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); @@ -654,7 +647,7 @@ fn nominating_and_rewards_should_work() { assert_eq!(Staking::current_era(), 1); // 10 and 20 have more votes, they will be chosen by phragmen. - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // OLD validators must have already received some rewards. assert_eq!(Balances::total_balance(&40), 1 + session_reward); @@ -664,9 +657,9 @@ fn nominating_and_rewards_should_work() { // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. assert_eq!(Staking::stakers(11).own, 1000); - assert_eq!(Staking::stakers(11).total, 1000 + 800); + assert_eq!(Staking::stakers(11).total, 1000 + 798); // 2 and 4 supported 10, each with stake 600, according to phragmen. - assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), vec![400, 400]); + assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), vec![399, 399]); assert_eq!(Staking::stakers(11).others.iter().map(|e| e.who).collect::>>(), vec![3, 1]); // total expo of 20, with 500 coming from nominators (externals), according to phragmen. assert_eq!(Staking::stakers(21).own, 1000); @@ -687,13 +680,13 @@ fn nominating_and_rewards_should_work() { // nothing else will happen, era ends and rewards are paid again, // it is expected that nominators will also be paid. See below - // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 + // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 assert_eq!(Balances::total_balance(&2), initial_balance + (2*new_session_reward/9 + 3*new_session_reward/11)); // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 assert_eq!(Balances::total_balance(&4), initial_balance + (2*new_session_reward/9 + 3*new_session_reward/11)); // 10 got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 - assert_eq!(Balances::total_balance(&10), initial_balance + 5*new_session_reward/9) ; + assert_eq!(Balances::total_balance(&10), initial_balance + 5*new_session_reward/9 + 2) ; // 10 got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 assert_eq!(Balances::total_balance(&20), initial_balance + 5*new_session_reward/11); }); @@ -710,7 +703,7 @@ fn nominators_also_get_slashed() { // Account 10 has not been reported offline assert_eq!(Staking::slash_count(&10), 0); // initial validators - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); >::put(Perbill::from_percent(12)); // Set payee to controller @@ -753,8 +746,7 @@ fn nominators_also_get_slashed() { #[test] fn double_staking_should_fail() { // should test (in the same order): - // * an account already bonded as controller CAN be reused as the controller of another account. - // * an account already bonded as stash cannot be the controller of another account. + // * an account already bonded as stash cannot be be stashed again. // * an account already bonded as stash cannot nominate. // * an account already bonded as controller can nominate. with_externalities(&mut ExtBuilder::default() @@ -762,7 +754,6 @@ fn double_staking_should_fail() { .build(), || { let arbitrary_value = 5; - System::set_block_number(1); // 2 = controller, 1 stashed => ok assert_ok!(Staking::bond(Origin::signed(1), 2, arbitrary_value, RewardDestination::default())); // 4 = not used so far, 1 stashed => not allowed. @@ -777,16 +768,12 @@ fn double_staking_should_fail() { #[test] fn double_controlling_should_fail() { // should test (in the same order): - // * an account already bonded as controller CAN be reused as the controller of another account. - // * an account already bonded as stash cannot be the controller of another account. - // * an account already bonded as stash cannot nominate. - // * an account already bonded as controller can nominate. + // * an account already bonded as controller CANNOT be reused as the controller of another account. with_externalities(&mut ExtBuilder::default() .sessions_per_era(2) .build(), || { let arbitrary_value = 5; - System::set_block_number(1); // 2 = controller, 1 stashed => ok assert_ok!(Staking::bond(Origin::signed(1), 2, arbitrary_value, RewardDestination::default())); // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op @@ -888,7 +875,7 @@ fn cannot_transfer_staked_balance() { #[test] fn cannot_transfer_staked_balance_2() { // Tests that a stash account cannot transfer funds - // Same test as above but with 20 + // Same test as above but with 20, and more accurate. // 21 has 2000 free balance but 1000 at stake with_externalities(&mut ExtBuilder::default() .nominate(false) @@ -916,7 +903,7 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 has some free balance assert_eq!(Balances::free_balance(&11), 1000); // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::stakers(&11).total, 1125); + assert_eq!(Staking::stakers(&11).own, 1000); // Confirm account 11 cannot transfer as a result assert_noop!(Balances::reserve(&11, 1), "account liquidity restrictions prevent withdrawal"); @@ -931,20 +918,16 @@ fn cannot_reserve_staked_balance() { fn reward_destination_works() { // Rewards go to the correct destination as determined in Payee with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { - // Check that account 11 is a validator - assert!(>::exists(11)); // Check that account 11 is a validator assert!(Staking::current_elected().contains(&11)); // Check the balance of the validator account assert_eq!(Balances::free_balance(&10), 1); // Check the balance of the stash account assert_eq!(Balances::free_balance(&11), 1000); - // Check these two accounts are bonded - assert_eq!(Staking::bonded(&11), Some(10)); // Check how much is at stake assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); - // Track current session reward - let mut current_session_reward = Staking::current_session_reward(); + // Check current session reward is 10 + let session_reward0 = Staking::current_session_reward(); // 10 // Move forward the system for payment System::set_block_number(1); @@ -953,14 +936,12 @@ fn reward_destination_works() { // Check that RewardDestination is Staked (default) assert_eq!(Staking::payee(&11), RewardDestination::Staked); - // Check current session reward is 10 - assert_eq!(current_session_reward, 10); // Check that reward went to the stash account of validator - assert_eq!(Balances::free_balance(&11), 1000 + current_session_reward); + assert_eq!(Balances::free_balance(&11), 1000 + session_reward0); // Check that amount at stake increased accordingly - assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 10, active: 1000 + 10, unlocking: vec![] })); + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + session_reward0, active: 1000 + session_reward0, unlocking: vec![] })); // Update current session reward - current_session_reward = Staking::current_session_reward(); // 1010 (1* slot_stake) + let session_reward1 = Staking::current_session_reward(); // 1010 (1* slot_stake) //Change RewardDestination to Stash >::insert(&11, RewardDestination::Stash); @@ -973,12 +954,11 @@ fn reward_destination_works() { // Check that RewardDestination is Stash assert_eq!(Staking::payee(&11), RewardDestination::Stash); // Check that reward went to the stash account - assert_eq!(Balances::free_balance(&11), 1000 + 10 + current_session_reward); + assert_eq!(Balances::free_balance(&11), 1000 + session_reward0 + session_reward1); // Record this value - let recorded_stash_balance = 1000 + 10 + current_session_reward; - + let recorded_stash_balance = 1000 + session_reward0 + session_reward1; // Check that amount at stake is NOT increased - assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 10, active: 1000 + 10, unlocking: vec![] })); + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + session_reward0, active: 1000 + session_reward0, unlocking: vec![] })); // Change RewardDestination to Controller >::insert(&11, RewardDestination::Controller); @@ -990,13 +970,14 @@ fn reward_destination_works() { System::set_block_number(3); Timestamp::set_timestamp(15); Session::check_rotate_session(System::block_number()); + let session_reward2 = Staking::current_session_reward(); // 1010 (1* slot_stake) // Check that RewardDestination is Controller assert_eq!(Staking::payee(&11), RewardDestination::Controller); // Check that reward went to the controller account - assert_eq!(Balances::free_balance(&10), 1 + 1010); + assert_eq!(Balances::free_balance(&10), 1 + session_reward2); // Check that amount at stake is NOT increased - assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 10, active: 1000 + 10, unlocking: vec![] })); + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + session_reward0, active: 1000 + session_reward0, unlocking: vec![] })); // Check that amount in staked account is NOT increased. assert_eq!(Balances::free_balance(&11), recorded_stash_balance); }); @@ -1012,27 +993,20 @@ fn validator_payment_prefs_work() { .sessions_per_era(3) .build(), || { + // Initial config let session_reward = 10; let validator_cut = 5; - let validator_initial_balance = Balances::total_balance(&11); - // Initial config should be correct - assert_eq!(Staking::era_length(), 9); - assert_eq!(Staking::sessions_per_era(), 3); - assert_eq!(Staking::last_era_length_change(), 0); - assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::current_index(), 0); - + let stash_initial_balance = Balances::total_balance(&11); assert_eq!(Staking::current_session_reward(), session_reward); // check the balance of a validator accounts. assert_eq!(Balances::total_balance(&10), 1); // check the balance of a validator's stash accounts. - assert_eq!(Balances::total_balance(&11), validator_initial_balance); + assert_eq!(Balances::total_balance(&11), stash_initial_balance); // and the nominator (to-be) let _ = Balances::make_free_balance_be(&2, 500); // add a dummy nominator. - // NOTE: this nominator is being added 'manually', use '.nominate()' to do it realistically. >::insert(&11, Exposure { own: 500, // equal division indicates that the reward will be equally divided among validator and nominator. total: 1000, @@ -1045,10 +1019,9 @@ fn validator_payment_prefs_work() { }); // ------------ Fast forward - let mut block = 3; // Block 3 => Session 1 => Era 0 + let mut block = 3; System::set_block_number(block); - Timestamp::set_timestamp(block*5); // on time. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 1); @@ -1059,7 +1032,6 @@ fn validator_payment_prefs_work() { block = 6; // Block 6 => Session 2 => Era 0 System::set_block_number(block); - Timestamp::set_timestamp(block*5); // a little late. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 2); @@ -1069,7 +1041,6 @@ fn validator_payment_prefs_work() { block = 9; // Block 9 => Session 3 => Era 1 System::set_block_number(block); - Timestamp::set_timestamp(block*5); Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); assert_eq!(Session::current_index(), 3); @@ -1077,7 +1048,7 @@ fn validator_payment_prefs_work() { // whats left to be shared is the sum of 3 rounds minus the validator's cut. let shared_cut = 3 * session_reward - validator_cut; // Validator's payee is Staked account, 11, reward will be paid here. - assert_eq!(Balances::total_balance(&11), validator_initial_balance + shared_cut/2 + validator_cut); + assert_eq!(Balances::total_balance(&11), stash_initial_balance + shared_cut/2 + validator_cut); // Controller account will not get any reward. assert_eq!(Balances::total_balance(&10), 1); // Rest of the reward will be shared and paid to the nominator in stake. @@ -1112,7 +1083,6 @@ fn bond_extra_works() { assert_ok!(Staking::bond_extra(Origin::signed(11), u64::max_value())); // The full amount of the funds should now be in the total and active assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000000, active: 1000000, unlocking: vec![] })); - }); } @@ -1147,14 +1117,7 @@ fn bond_extra_and_withdraw_unbonded_works() { // confirm that 10 is a normal validator and gets paid at the end of the era. System::set_block_number(1); - Timestamp::set_timestamp(5); Session::check_rotate_session(System::block_number()); - assert_eq!(Staking::current_era(), 1); - assert_eq!(Session::current_index(), 1); - - // NOTE: despite having .nominate() in extBuilder, 20 doesn't have a share since - // rewards are paid before election in new_era() - assert_eq!(Balances::total_balance(&10), 1 + 10); // Initial state of 10 assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); @@ -1176,13 +1139,12 @@ fn bond_extra_and_withdraw_unbonded_works() { assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] })); // Exposure is now updated. assert_eq!(Staking::stakers(&11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }); - // Note that by this point 10 also have received more rewards, but we don't care now. - // assert_eq!(Balances::total_balance(&10), 1 + 10 + MORE_REWARD); // Unbond almost all of the funds in stash. Staking::unbond(Origin::signed(10), 1000).unwrap(); assert_eq!(Staking::ledger(&10), Some(StakingLedger { - stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] })); + stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] }) + ); // Attempting to free the balances now will fail. 2 eras need to pass. Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); @@ -1190,7 +1152,9 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] })); // trigger next era. - System::set_block_number(3);Timestamp::set_timestamp(15);Session::check_rotate_session(System::block_number()); + System::set_block_number(3); + Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 3); assert_eq!(Session::current_index(), 3); @@ -1200,7 +1164,8 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] })); // trigger next era. - System::set_block_number(4);Timestamp::set_timestamp(20);Session::check_rotate_session(System::block_number()); + System::set_block_number(4); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 4); assert_eq!(Session::current_index(), 4); @@ -1212,17 +1177,14 @@ fn bond_extra_and_withdraw_unbonded_works() { } #[test] -fn slot_stake_is_least_staked_validator_and_limits_maximum_punishment() { +fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() { // Test that slot_stake is determined by the least staked validator // Test that slot_stake is the maximum punishment that can happen to a validator - // Note that rewardDestination is the stash account by default - // Note that unlike reward slash will affect free_balance, not the stash account. with_externalities(&mut ExtBuilder::default() .nominate(false) .fare(false) .build(), || { - // Give the man some money. // Confirm validator count is 2 assert_eq!(Staking::validator_count(), 2); // Confirm account 10 and 20 are validators @@ -1245,26 +1207,21 @@ fn slot_stake_is_least_staked_validator_and_limits_maximum_punishment() { // New era --> rewards are paid --> stakes are changed System::set_block_number(1); - Timestamp::set_timestamp(5); Session::check_rotate_session(System::block_number()); - assert_eq!(Staking::current_era(), 1); + // -- new balances + reward assert_eq!(Staking::stakers(&11).total, 1000 + 10); assert_eq!(Staking::stakers(&21).total, 69 + 10); - // -- Note that rewards are going directly to stash, not as free balance. - assert_eq!(Balances::free_balance(&10), 1000); - assert_eq!(Balances::free_balance(&20), 1000); - // -- slot stake should also be updated. assert_eq!(Staking::slot_stake(), 79); - // // If 10 gets slashed now, despite having +1000 in stash, it will be slashed byt 79, which is the slot stake + // If 10 gets slashed now, it will be slashed by 5% of exposure.total * 2.pow(unstake_thresh) Staking::on_offline_validator(10, 4); - // // Confirm user has been reported + // Confirm user has been reported assert_eq!(Staking::slash_count(&11), 4); - // // check the balance of 10 (slash will be deducted from free balance.) + // check the balance of 10 (slash will be deducted from free balance.) assert_eq!(Balances::free_balance(&11), 1000 + 10 - 50 /*5% of 1000*/ * 8 /*2**3*/); }); } @@ -1277,8 +1234,6 @@ fn on_free_balance_zero_stash_removes_validator() { .existential_deposit(10) .build(), || { - // Check that account 10 is a validator - assert!(>::exists(11)); // Check the balance of the validator account assert_eq!(Balances::free_balance(&10), 256); // Check the balance of the stash account @@ -1345,13 +1300,10 @@ fn on_free_balance_zero_stash_removes_nominator() { assert_eq!(Balances::free_balance(&10), 256); // Check the balance of the stash account assert_eq!(Balances::free_balance(&11), 256000); - // Check these two accounts are bonded - assert_eq!(Staking::bonded(&11), Some(10)); // Set payee information assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); - // Check storage items that should be cleaned up assert!(>::exists(&10)); assert!(>::exists(&11)); @@ -1442,13 +1394,9 @@ fn phragmen_poc_works() { .build(), || { // We don't really care about this. At this point everything is even. - // assert_eq!(Session::validators(), vec![40, 30]); - - assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); - assert_eq!(Staking::ledger(&20), Some(StakingLedger { stash: 21, total: 1000, active: 1000, unlocking: vec![] })); - assert_eq!(Staking::ledger(&30), Some(StakingLedger { stash: 31, total: 1000, active: 1000, unlocking: vec![] })); - assert_eq!(Staking::ledger(&40), Some(StakingLedger { stash: 41, total: 1000, active: 1000, unlocking: vec![] })); + assert_eq_uvec!(Session::validators(), vec![40, 30]); + // Set payees to Controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); @@ -1471,7 +1419,7 @@ fn phragmen_poc_works() { System::set_block_number(1); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // with stake 1666 and 1333 respectively assert_eq!(Staking::stakers(11).own, 1000); @@ -1491,22 +1439,55 @@ fn phragmen_poc_works() { } #[test] -fn phragmen_election_works_example_2() { +fn phragmen_election_works_with_post_processing() { // tests the encapsulated phragmen::elect function. + // Votes [ + // ('10', 1000, ['10']), + // ('20', 1000, ['20']), + // ('30', 1000, ['30']), + // ('2', 50, ['10', '20']), + // ('4', 1000, ['10', '30']) + // ] + // Sequential Phragmén gives + // 10 is elected with stake 1705.7377049180327 and score 0.0004878048780487805 + // 30 is elected with stake 1344.2622950819673 and score 0.0007439024390243903 + + // 10 has load 0.0004878048780487805 and supported + // 10 with stake 1000.0 + // 20 has load 0 and supported + // 20 with stake 0 + // 30 has load 0.0007439024390243903 and supported + // 30 with stake 1000.0 + // 2 has load 0.0004878048780487805 and supported + // 10 with stake 50.0 20 with stake 0.0 + // 4 has load 0.0007439024390243903 and supported + // 10 with stake 655.7377049180328 30 with stake 344.26229508196724 + + // Sequential Phragmén with post processing gives + // 10 is elected with stake 1525.0 and score 0.0004878048780487805 + // 30 is elected with stake 1525.0 and score 0.0007439024390243903 + + // 10 has load 0.0004878048780487805 and supported + // 10 with stake 1000.0 + // 20 has load 0 and supported + // 20 with stake 0 + // 30 has load 0.0007439024390243903 and supported + // 30 with stake 1000.0 + // 2 has load 0.0004878048780487805 and supported + // 10 with stake 50.0 20 with stake 0.0 + // 4 has load 0.0007439024390243903 and supported + // 10 with stake 475.0 30 with stake 525.0 with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { // initial setup of 10 and 20, both validators - assert_eq!(Session::validators(), vec![20, 10]); - - // no one is a nominator - assert_eq!(>::enumerate().count(), 0 as usize); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // Bond [30, 31] as the third validator assert_ok!(Staking::bond(Origin::signed(31), 30, 1000, RewardDestination::default())); assert_ok!(Staking::validate(Origin::signed(30), ValidatorPrefs::default())); // bond [2,1](A), [4,3](B), as 2 nominators - // Give all of them some balance to be able to bond properly. for i in &[1, 3] { let _ = Balances::deposit_creating(i, 2000); } + assert_ok!(Staking::bond(Origin::signed(1), 2, 50, RewardDestination::default())); assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21])); @@ -1539,62 +1520,21 @@ fn phragmen_election_works_example_2() { let winner_10 = winners.iter().filter(|w| w.who == 11).nth(0).unwrap(); let winner_30 = winners.iter().filter(|w| w.who == 31).nth(0).unwrap(); - // python implementation output: - /* - Votes [ - ('10', 1000, ['10']), - ('20', 1000, ['20']), - ('30', 1000, ['30']), - ('2', 50, ['10', '20']), - ('4', 1000, ['10', '30']) - ] - Sequential Phragmén gives - 10 is elected with stake 1705.7377049180327 and score 0.0004878048780487805 - 30 is elected with stake 1344.2622950819673 and score 0.0007439024390243903 - - 10 has load 0.0004878048780487805 and supported - 10 with stake 1000.0 - 20 has load 0 and supported - 20 with stake 0 - 30 has load 0.0007439024390243903 and supported - 30 with stake 1000.0 - 2 has load 0.0004878048780487805 and supported - 10 with stake 50.0 20 with stake 0.0 - 4 has load 0.0007439024390243903 and supported - 10 with stake 655.7377049180328 30 with stake 344.26229508196724 - - Sequential Phragmén with post processing gives - 10 is elected with stake 1525.0 and score 0.0004878048780487805 - 30 is elected with stake 1525.0 and score 0.0007439024390243903 - - 10 has load 0.0004878048780487805 and supported - 10 with stake 1000.0 - 20 has load 0 and supported - 20 with stake 0 - 30 has load 0.0007439024390243903 and supported - 30 with stake 1000.0 - 2 has load 0.0004878048780487805 and supported - 10 with stake 50.0 20 with stake 0.0 - 4 has load 0.0007439024390243903 and supported - 10 with stake 475.0 30 with stake 525.0 - - - */ - + // Check exposures assert_eq!(winner_10.exposure.total, 1000 + 525); - assert_eq!(winner_10.score, Perquintill::from_quintillionths(487804878048780)); + assert_eq!(winner_10.score, PerU128::from_max_value(165991398498018762665060784113057664)); assert_eq!(winner_10.exposure.others[0].value, 475); assert_eq!(winner_10.exposure.others[1].value, 50); assert_eq!(winner_30.exposure.total, 1000 + 525); - assert_eq!(winner_30.score, Perquintill::from_quintillionths(743902439024390)); + assert_eq!(winner_30.score, PerU128::from_max_value(253136882709478613064217695772412937)); assert_eq!(winner_30.exposure.others[0].value, 525); }) } #[test] fn switching_roles() { - // Show: It should be possible to switch between roles (nominator, validator, idle) with minimal overhead. + // Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead. with_externalities(&mut ExtBuilder::default() .nominate(false) .sessions_per_era(3) @@ -1603,7 +1543,7 @@ fn switching_roles() { // Reset reward destination for i in &[10, 20] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); } - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // put some money in account that we'll use. for i in 1..7 { let _ = Balances::deposit_creating(&i, 5000); } @@ -1624,42 +1564,43 @@ fn switching_roles() { Session::check_rotate_session(System::block_number()); // no change - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // new block System::set_block_number(2); Session::check_rotate_session(System::block_number()); // no change - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // new block --> ne era --> new validators System::set_block_number(3); Session::check_rotate_session(System::block_number()); // with current nominators 10 and 5 have the most stake - assert_eq!(Session::validators(), vec![6, 10]); + assert_eq_uvec!(Session::validators(), vec![6, 10]); // 2 decides to be a validator. Consequences: + assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); // new stakes: // 10: 1000 self vote - // 6: 1000 self vote // 20: 1000 self vote + 500 vote - // 2: 2000 self vote + 500 vote. - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + // 6 : 1000 self vote + // 2 : 2000 self vote + 500 vote. + // Winners: 20 and 2 System::set_block_number(4); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![6, 10]); + assert_eq_uvec!(Session::validators(), vec![6, 10]); System::set_block_number(5); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![6, 10]); + assert_eq_uvec!(Session::validators(), vec![6, 10]); // ne era System::set_block_number(6); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![2, 20]); + assert_eq_uvec!(Session::validators(), vec![2, 20]); }); } @@ -1670,7 +1611,7 @@ fn wrong_vote_is_null() { .validator_pool(true) .build(), || { - assert_eq!(Session::validators(), vec![40, 30]); + assert_eq_uvec!(Session::validators(), vec![40, 30]); // put some money in account that we'll use. for i in 1..3 { let _ = Balances::deposit_creating(&i, 5000); } @@ -1686,7 +1627,7 @@ fn wrong_vote_is_null() { System::set_block_number(1); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); }); } @@ -1701,13 +1642,12 @@ fn bond_with_no_staked_value() { .build(), || { // setup assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); let _ = Balances::deposit_creating(&3, 1000); let initial_balance_2 = Balances::free_balance(&2); let initial_balance_4 = Balances::free_balance(&4); // initial validators - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // Stingy validator. assert_ok!(Staking::bond(Origin::signed(1), 2, 0, RewardDestination::Controller)); @@ -1717,7 +1657,7 @@ fn bond_with_no_staked_value() { Session::check_rotate_session(System::block_number()); // Not elected even though we want 3. - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // min of 10 and 20. assert_eq!(Staking::slot_stake(), 1000); @@ -1726,17 +1666,17 @@ fn bond_with_no_staked_value() { assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); - assert_eq!(Staking::ledger(4), Some(StakingLedger { stash: 3, active: 500, total: 500, unlocking: vec![]})); - + // no rewards paid to 2 and 4 yet assert_eq!(Balances::free_balance(&2), initial_balance_2); assert_eq!(Balances::free_balance(&4), initial_balance_4); System::set_block_number(2); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![20, 10, 2]); + // Stingy one is selected + assert_eq_uvec!(Session::validators(), vec![20, 10, 2]); assert_eq!(Staking::stakers(1), Exposure { own: 0, total: 500, others: vec![IndividualExposure { who: 3, value: 500}]}); - + // New slot stake. assert_eq!(Staking::slot_stake(), 500); // no rewards paid to 2 and 4 yet @@ -1750,13 +1690,12 @@ fn bond_with_no_staked_value() { // 2 will not get any reward // 4 will get all the reward share assert_eq!(Balances::free_balance(&2), initial_balance_2); - // assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward); assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward); }); } #[test] -fn bond_with_little_staked_value() { +fn bond_with_little_staked_value_bounded_by_slot_stake() { // Behavior when someone bonds with little staked value. // Particularly when she votes and the candidate is elected. with_externalities(&mut ExtBuilder::default() @@ -1767,11 +1706,11 @@ fn bond_with_little_staked_value() { || { // setup assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); let initial_balance_2 = Balances::free_balance(&2); + let initial_balance_10 = Balances::free_balance(&10); // initial validators - assert_eq!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(Session::validators(), vec![20, 10]); // Stingy validator. assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); @@ -1782,24 +1721,25 @@ fn bond_with_little_staked_value() { // 2 is elected. // and fucks up the slot stake. - assert_eq!(Session::validators(), vec![20, 10, 2]); + assert_eq_uvec!(Session::validators(), vec![20, 10, 2]); assert_eq!(Staking::slot_stake(), 1); // Old ones are rewarded. - assert_eq!(Balances::free_balance(&10), 1 + 10); - assert_eq!(Balances::free_balance(&20), 1 + 10); + assert_eq!(Balances::free_balance(&10), initial_balance_10 + 10); // no rewards paid to 2. This was initial election. assert_eq!(Balances::free_balance(&2), initial_balance_2); System::set_block_number(2); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![20, 10, 2]); + assert_eq_uvec!(Session::validators(), vec![20, 10, 2]); assert_eq!(Staking::slot_stake(), 1); let reward = Staking::current_session_reward(); // 2 will not get the full reward, practically 1 assert_eq!(Balances::free_balance(&2), initial_balance_2 + reward.max(1)); + // same for 10 + assert_eq!(Balances::free_balance(&10), initial_balance_10 + 10 + reward.max(1)); }); } @@ -1838,13 +1778,13 @@ fn phragmen_linear_worse_case_equalize() { bond_nominator(112, 1000, vec![51, 61]); bond_nominator(114, 1000, vec![61, 71]); - assert_eq!(Session::validators(), vec![40, 30]); + assert_eq_uvec!(Session::validators(), vec![40, 30]); assert_ok!(Staking::set_validator_count(7)); System::set_block_number(1); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![10, 60, 40, 20, 50, 30, 70]); + assert_eq_uvec!(Session::validators(), vec![10, 60, 40, 20, 50, 30, 70]); // Sequential Phragmén with post processing gives // 10 is elected with stake 3000.0 and score 0.00025 @@ -1866,7 +1806,7 @@ fn phragmen_linear_worse_case_equalize() { } #[test] -fn phragmen_chooses_correct_validators() { +fn phragmen_chooses_correct_number_of_validators() { with_externalities(&mut ExtBuilder::default() .nominate(true) .validator_pool(true) @@ -1874,8 +1814,6 @@ fn phragmen_chooses_correct_validators() { .validator_count(1) .build(), || { - // 4 validator candidates - // self vote + default account 100 is nominator. assert_eq!(Staking::validator_count(), 1); assert_eq!(Session::validators().len(), 1); @@ -1886,6 +1824,34 @@ fn phragmen_chooses_correct_validators() { }) } + +#[test] +fn phragmen_score_should_be_accurate_on_large_stakes() { + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .build() + , || { + let bond_validator = |a, b| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default())); + }; + + for i in 1..=8 { + let _ = Balances::make_free_balance_be(&i, u64::max_value()); + } + + bond_validator(2, u64::max_value()); + bond_validator(4, u64::max_value()); + bond_validator(6, u64::max_value()-1); + bond_validator(8, u64::max_value()-2); + + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![4, 2]); + }) +} + #[test] fn phragmen_should_not_overflow_validators() { with_externalities(&mut ExtBuilder::default() @@ -1900,6 +1866,10 @@ fn phragmen_should_not_overflow_validators() { assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(a), v)); }; + let check_exposure = |a| { + let expo = Staking::stakers(&a); + assert_eq!(expo.total, expo.own + expo.others.iter().map(|e| e.value).sum::()); + }; for i in 1..=8 { let _ = Balances::make_free_balance_be(&i, u64::max_value()); @@ -1917,7 +1887,9 @@ fn phragmen_should_not_overflow_validators() { System::set_block_number(2); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![4, 2]); + assert_eq_uvec!(Session::validators(), vec![4, 2]); + check_exposure(4); + check_exposure(2); }) } @@ -1935,6 +1907,10 @@ fn phragmen_should_not_overflow_nominators() { assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(a), v)); }; + let check_exposure = |a| { + let expo = Staking::stakers(&a); + assert_eq!(expo.total, expo.own + expo.others.iter().map(|e| e.value).sum::()); + }; let _ = Staking::chill(Origin::signed(10)); let _ = Staking::chill(Origin::signed(20)); @@ -1952,7 +1928,9 @@ fn phragmen_should_not_overflow_nominators() { System::set_block_number(2); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![4, 2]); + assert_eq_uvec!(Session::validators(), vec![4, 2]); + check_exposure(4); + check_exposure(2); }) } @@ -1970,6 +1948,10 @@ fn phragmen_should_not_overflow_ultimate() { assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(a), v)); }; + let check_exposure = |a| { + let expo = Staking::stakers(&a); + assert_eq!(expo.total, expo.own + expo.others.iter().map(|e| e.value).sum::()); + }; for i in 1..=8 { let _ = Balances::make_free_balance_be(&i, u64::max_value()); @@ -1984,6 +1966,8 @@ fn phragmen_should_not_overflow_ultimate() { System::set_block_number(2); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![4, 2]); + assert_eq_uvec!(Session::validators(), vec![4, 2]); + check_exposure(4); + check_exposure(2); }) -} \ No newline at end of file +} diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index d20af28f5b..d99db6ddb8 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -110,6 +110,47 @@ macro_rules! assert_ok { } } +/// Panic when the vectors are different, without taking the order into account. +/// +/// # Examples +/// +/// ```rust +/// #[macro_use] +/// # extern crate srml_support; +/// # use srml_support::{assert_eq_uvec}; +/// # fn main() { +/// assert_eq_uvec!(vec![1,2], vec![2,1]); +/// # } +/// ``` +/// +/// ```rust,should_panic +/// #[macro_use] +/// # extern crate srml_support; +/// # use srml_support::{assert_eq_uvec}; +/// # fn main() { +/// assert_eq_uvec!(vec![1,2,3], vec![2,1]); +/// # } +/// ``` +#[macro_export] +#[cfg(feature = "std")] +macro_rules! assert_eq_uvec { + ( $x:expr, $y:expr ) => { + $crate::__assert_eq_uvec!($x, $y); + $crate::__assert_eq_uvec!($y, $x); + } +} + +#[macro_export] +#[doc(hidden)] +#[cfg(feature = "std")] +macro_rules! __assert_eq_uvec { + ( $x:expr, $y:expr ) => { + $x.iter().for_each(|e| { + if !$y.contains(e) { panic!(format!("vectors not equal: {:?} != {:?}", $x, $y)); } + }); + } +} + /// The void type - it cannot exist. // Oh rust, you crack me up... #[derive(Clone, Eq, PartialEq)]