Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
aa83f22
initial doc for the staking module
kianenigma Mar 9, 2019
b9d09bb
Remove md style links.
kianenigma Mar 9, 2019
7df2b19
Remove todos.
kianenigma Mar 9, 2019
28b959b
Add rust code types
kianenigma Mar 9, 2019
91be68b
Rename and fix review notes.
kianenigma Mar 11, 2019
5912ff5
Add new md file
kianenigma Mar 11, 2019
64ca546
Final touches.
kianenigma Mar 11, 2019
a8ba78e
Migrate compleatly to rustdoc
kianenigma Mar 11, 2019
982d7e8
Update link
kianenigma Mar 11, 2019
4a572a2
Fix heading
kianenigma Mar 11, 2019
ea5ae00
Merge branch 'master' into kiz-document-staking
kianenigma Mar 12, 2019
89682a6
Final touches wrt the new template.
kianenigma Mar 12, 2019
956ec96
Remove empty prereq.
kianenigma Mar 12, 2019
2879e1d
Fix more reviews
kianenigma Mar 12, 2019
105723b
Some final nits.
kianenigma Mar 12, 2019
531ae73
Merge branch 'master' of github.com:paritytech/substrate into kiz-doc…
kianenigma Mar 14, 2019
5567859
Fix some side issues.
kianenigma Mar 14, 2019
e739361
Fix another set of reviews
kianenigma Mar 15, 2019
4eb568c
Fix + stabilize leftover reivews.
kianenigma Mar 15, 2019
9b026cc
Remove unused test parameters
kianenigma Mar 15, 2019
a8075c7
Fix typo.
kianenigma Mar 15, 2019
a33205b
Merge redundant loops
kianenigma Mar 15, 2019
07f9710
Merge branch 'kiz-document-staking' into kiz-staking-enhance
kianenigma Mar 15, 2019
cfb39b9
Adds phantom self-vote
kianenigma Mar 16, 2019
a4c298c
Fix broken tests.
kianenigma Mar 17, 2019
5eb6f24
Refactor some names to match the reference.
kianenigma Mar 17, 2019
c4bdb81
Remove redundant inner loops from election round.
kianenigma Mar 18, 2019
03d7583
Introduce phragmen post-processing.
kianenigma Mar 19, 2019
bf8212f
Some fixes and todos.
kianenigma Mar 19, 2019
85f1294
Fix some tests with new phragmen params
kianenigma Mar 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix another set of reviews
  • Loading branch information
kianenigma committed Mar 15, 2019
commit e739361fccf59f4119b4c41e1336e8f482a845b0
101 changes: 75 additions & 26 deletions srml/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
//! # Staking Module
//!
//! <!-- Original author of paragraph: @gavofyork -->
//! 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 they be found not to bee discharging their duties properly.
//! 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
//! discharging their duties properly.
//! You can start using the Staking module by implementing the staking [`Trait`].
//!
//! ## Overview
//!
Expand All @@ -30,8 +34,8 @@
//! - Validating: The process of running a node to actively maintain the network, either by producing blocks or guaranteeing finality of the chain.
//! - Nominating: The process of placing staked funds behind one or more validators in order to share in any reward, and punishment, they take.
//! - Stash account: The account holding an owner's funds used for staking.
//! - Controller account: The account which controls am 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.
//! - 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)).
//!
//! ### Goals
Expand All @@ -46,23 +50,52 @@
//!
//! #### 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 of which 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 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.
//!
//! 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.
//! 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.
//!
//! #### Validating
//!
//! A **validator** takes the role of either validating blocks or ensuring their finality, maintaining the veracity of the network in other words. 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 election is determined by nominators and their votes. An account can become a validator via the `validate()` call.
//! 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.
//!
//! #### 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 their votes will be taken into account at the next election round. As mentioned above, a nominator must also place some fund in a stash account, essentially indicating the _weight_ of their 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. 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.
//! 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.
//! 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.
//!
//! #### 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 a misbehavior is reported. One such misbehavior is a validator to be detected as offline more than a certain number of times. Once slashing is determined, a value is deducted from the balance of validator and all the nominators who voted for this validator. Same rules apply to the rewards in the sense of being shared among validator and its associated nominators.
//! 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.
//!
//! Finally, any of the roles above can choose to temporarily step back 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.
//! 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.
//!
//! ## Interface
//!
Expand All @@ -72,12 +105,14 @@
//!
//! ### Dispatchable
//!
//! The Dispatchable functions of the staking module enable the steps needed for entities to accept and change their role, alongside some helper functions to get/set the metadata of the module.
//! The Dispatchable functions of the staking module enable the steps needed for entities to accept and change their
//! role, alongside some helper functions to get/set the metadata of the module.
//!
//! Please refer to the [`Call`] enum and its associated variants for a detailed list of dispatchable functions.
//!
//! ### 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.
//! 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.
//!
//! ## Usage
//!
Expand All @@ -94,7 +129,7 @@
//! Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller);
//! ```
//!
//! To state desire in becoming a validator:
//! To state desire to become a validator:
//!
//! ```rust,ignore
//! // controller account 4 states desire for validation with the given preferences.
Expand All @@ -120,42 +155,55 @@
//!
//! ### 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 `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._
//!
//! ### Reward Calculation
//!
//! - Rewards are recorded **per-session** and paid **per-era**. The value of 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 named `SessionReward`.
//! - 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 (see `set_payee()`), to be one of the following:
//! - 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.
//! - 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 they can be _reported_ before it actually gets slashed via the `unstake_threshold` in `ValidatorPrefs`. On top of this, the module also introduces a `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 amount 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 overflow, then `slot_stake` is used.
//! - If the previous is more than what the validator/nominator has in stake, all of their stake is slashed (`.max(total_stake)` in other words).
//! - 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)`).
//!
//! ### Additional Fund Management Operations
//!
//! Any funds already placed into stash can be the target of the following operations:
//!
//! - The controller account can free an portion (or all) of the funds using the `unbond()` call. Note that the funds are not immediately accessible, instead, a duration denoted by `BondingDuration` number of eras must pass until the funds can be actually removed.
//! - To actually remove the funds, once the bonding duration is over, the `withdraw_unbonded()` can be used.
//! - 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.
//!
//! ### Election algorithm details.
//!
//! 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 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 attributed that can be provided.
//! See the [`GensisConfig`] for a list of attributes that can be provided.
//!
//! ## Related Modules
//!
Expand Down Expand Up @@ -460,6 +508,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_.
fn bond(origin, controller: <T::Lookup as StaticLookup>::Source, #[compact] value: BalanceOf<T>, payee: RewardDestination) {
let stash = ensure_signed(origin)?;
Expand Down Expand Up @@ -811,7 +860,7 @@ impl<T: Trait> Module<T> {

/// Select a new validator set from the assembled stakers and their role preferences.
///
/// returns the new SlotStake value.
/// Returns the new SlotStake value.
fn select_validators() -> BalanceOf<T> {
// Map of (would-be) validator account to amount of stake backing it.

Expand Down
2 changes: 1 addition & 1 deletion srml/staking/src/phragmen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub struct Vote<AccountId, Balance: HasCompact> {
///
/// Reference implementation: https://github.com/w3f/consensus
///
/// returns a vector of elected candidates
/// Returns a vector of elected candidates
pub fn elect<T: Trait + 'static, FR, FN, FV, FS>(
get_rounds: FR,
get_validators: FV,
Expand Down