Luke Schoen
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    The purpose of this documentation is to explain in plain english the contents and interactions of each module in the runtime module library to avoid incorrect assumptions or interpretations of the code by new users. It will be used to create tutorials. The target audiences are users wishing to implement a governance runtime module, and other documentation authors. ## Substrate Runtime Module Library (SRML) ### Council Module --- ### Introduction TODO > Note: There are different voting systems. The `vote` function in srml/council/src/motions.rs is for Council Motions that allow an arbitrary number of councillors (other than the councillor that proposed the motion) to vote and initiate a call and where the `origin` is the Council (not Root). Whereas the `vote` function in srml/council/src/voting.rs is for the Council Voting as a body regarding tabling referenda. #### Council Proposals ##### Council Proposal (Motion and Origin) > Source: Gav (rephrased by Luke) A council motion is a mechanism that is used enact an outer `Call` dispatch (of type `Proposal`) from the council origin. The council origin is defined in srml/council/src/motion.rs and has different mechanics to other origins. It contains the council motion mechanism. ##### Council Proposal (Validity and Creation) > Source: srml/council/src/voting.rs A council proposal is valid if: * It is submitted by a councillor * It is not a duplicate proposal * It is not vetoed * The term of the council associated with the councillor proposing it does not expire before the configured voting period. If the council proposal is valid then: * The proposal's hash and the expiry block number of its voting period are stored as a tuple in the `Proposals` storage vector * The proposal's hash is mapped to the value of the proposal in storage using `ProposalsOf` * The proposal's hash is mapped to a vector of account ids that have voted for it in storage using `ProposalVoters`. Initially the account id of the councillor that created the proposal is added to the vector. * A tuple including the proposal's hash and the councillor's account id is mapped to their corresponding vote in storage using `CouncilVoteOf`. Initially the councillor that created the proposal is added with a vote of yay. ##### Council Proposal (Threshold, Voting, Approval, Execution) > Source: srml/council/src/voting.rs > Source: srml/council/src/motions.rs A councillor is a ['countable'](https://youtu.be/eO3fG_1YrE4?t=2282) stakeholder who may vote on a council proposal during the voting period if they did not create the proposal. Their vote is: * Pushed onto a storage vector `ProposalVoters` of account ids that have voted for the proposal's hash * Added to a storage mapping `CouncilVoteOf`, comprising of a tuple (the proposal's hash and the councillor's account id) that's mapped to its corresponding vote. * Added to the storage mapping `Voting` that maps a proposal's hash to a tuple containing the corresponding proposal's index, its vote threshold, and a vectors of both yay and nay voter account id's. When a council proposal is created with a threshold level of one, then it is voted upon and approved by the councillor that created it, and then executed. Whereas a council proposal with a threshold level of more than one is added to a storage mapping `Voting` that was described earlier. During council voting: * Duplicate votes from the same councillor are ignored. * Councillors may swap their vote from yay to nay and vice versa. When the tally of yay votes for a council proposal reach the council proposal's threshold level during the council voting period then the council approval is approved and elevated to the table of active referendum on the next block. Councillors that abstain from voting may postpone a council proposal from being approved or disapproved. > Note: Postponing is equivalent to vetoing since the veto only lasts for the cooldown period. Once the tally of votes result in the council proposal being approved or disapproved, we remove the motion from the `Voting` storage mapping, and remove the proposal hash from the list of active proposals `Proposals`. If the tally of votes for the council proposal was unanimous (i.e. only yay votes) and was executed, then it is elevated to the table of active referendum on the next block, and a vote threshold of 'super majority against' is applied to the referendum. Whereas if the tally of votes for the council proposal had a simple majority (i.e. more yay than nay votes) and was executed, then it is elevated to the table of active referendums on the next block, and a vote threshold of 'simple majority' is applied to the referendum. ##### Council Proposal (Veto) > Source: srml/council/src/voting.rs A councillor may veto a proposal if its stored in the `ProposalVoters` mapping on condition that they have not vetoed it previously. If their veto is valid then: * Their veto is stored in `VetoedProposal` amongst other councillors that have vetoed the proposal, which maps the proposal's hash to a tuple comprising of the block number when the veto expires, and the account id of the vetoer. * The vetoed proposal is removed from various storage locations, including the `Proposals` storage vector, the `ProposalsOf` storage mapping, the `ProposalVoters` storage mapping, and the `CouncilVoteOf` mapping. A veto cancels a proposal, but the veto is not considered a vote. Once a councillor vetoes a council proposal they cannot propose the proposal again until after a cooling off period measured in blocks. ##### Council Proposal (Majority Agreement) A majority council agreement occurs when a council proposal is elevated to the table of referenda after the tally from majority voting results in a simple majority (more explicit yay than nay votes) from the councillors. This signals a sensible and uncontroversial proposal. ##### Council Proposal (Unanimous Agreement) A unanimous council agreement occurs when a council proposal is elevated to the table of referenda after a unanimous voting tally occurs. It uses a negative AQB to encourage councillors not to [abstain](https://youtu.be/eO3fG_1YrE4?t=2525). A single veto from a councillor cancels the proposal and prevents the agreement. Council proposals submitted this way must have over 50% approval since abstention votes will be biased in favour of the proposal (alongside any nay votes). ##### Council Proposal (Elevation or Cancellation) > Source: srml/council/src/voting.rs In modules of the SRML, the `on_finalise` signature is used in the module declaration to run anything that needs to be done at the end of the block. In council voting it calls a private function `end_block` with the current block as an argument, which loops through each proposal in storage whose voting period ends at the given block. For each proposal it calls `is_aux_sub_type` and destructures the return value. The return value is a call to a function `cancel_referendum` with a `ref_index` (referendum index) argument that removes the referendum with that referendum index. When the call to the return value `cancel_referendum` returns a value, then we know that this council proposal was elevated to the table of referenda and therefore has a referendum index. We also already know that it expires on this block, so we may proceed to run the associated block of code that actually cancels the referendum by: * Dispatching event `TallyCancelation` to indicate that a voting tally has happened associated with a cancellation vote for the referendum associated with the given proposal. * The council directly calling `internal_cancel_referendum` to remove the specific referendum with given referendum index, but doing so is only permissed if the voting tally for the proposal was a unanimous vote (i.e. no nays, no abstainers). Otherwise when the call to `is_aux_sub_type` with the current proposal does not destructure to a function call that is able to cancel a referendum index associated with the proposal, then we know this council proposal has not yet been elevated to the table of referenda, so we may proceed to run the associated block of code that checks the vote tally to determine whether to start the referendum. In the associated block of code it dispatches an event `TallyReferendum` to indicate the start of a voting tally for a referendum vote on the current proposal, and if the voting tally of the current proposal has more yay votes than the combination of all nay votes and abstainers, then it: * Removes any veto imposed upon the council proposal (since the proposal voting period is expiring) If the council voting tally was unanimous then it: * Starts a referendum (elevating the proposal to the table of referendum) with a vote threshold of `SuperMajorityAgainst`. Otherwise if there were any nay voters or abstainers at the end of council voting on the proposal then it: * Starts a referendum (elevating the proposal to the table of referendum) with a vote threshold of `SimplyMajority`. ##### Referenda A council or public proposal that is elevated to the table of referenda. Each proposal is instantly executed autonomously once their votes reach a threshold level of approval. --- #### Council Seats > Source: srml/council/src/seats.rs ##### Candidate Approval Voting Call Express candidate approval voting is a public call that anyone may execute by signing and submitting an extrinsic. We ensure that information about the `origin` where the dispatch initiated is a signed account using `ensure_signed`. It performs an `O(1)` operation that involves one extra DB entry and one DB change. ##### Candidate Registration and Vote Index Candidate approval votes are only considered before the presentation period and when the candidates have a registered list slot with an approved candidate index `VoteIndex` that exists. ##### Candidate Voter's Security Bond for First Vote If it is the voter's first vote and its valid, then: * Before enacting any operation and changing the storage a "voter" security bond is deducted from the voter using the `reserve` function of the `Balances` module, as it may result in a major alteration of storage. The bond amount should be sufficient enough to cover any costs of the substantial execution in case the operation cannot proceed. The bond is a mitigation measure against the classical blockchain attack scenario since we cannot be certain that the operation will not require substantial computation. * The voter's account id is pushed onto the `Voters` vector that contains the list of present voters. ##### Candidate Voter's Subsequent Votes If it is a subsequent vote from the voter When a vote is valid: * Their vote is recorded in `LastActiveOf`, which maps their account id to the last cleared vote index that they were active at. * Their votes (i.e. yay or nay) for each candidate of a vote index is added to `ApprovalsOf` that maps ##### Candidate Voter Inactivity Reaping Removing an inactive voter is a public call. The reporter is removed if the target account is actually active and the reporter's account is removed and the reporter receivers the target's "voter" bond. It performs an `O(1)` operation that involves one fewer DB entry and one DB change. Reaping Inactive Voter's are only considered when valid satisfying the following: * Before the presentation period * When the both the reporter and the target have already voted and are recorded in `LastActiveOf` * When the assumed vote index is after an inactivity grace period (vote indexes remaining after the target voter's last active vote and when their associated approval votes are uncertain) * When both the given reporter's vote index and the given target's vote index exist * If the candidates approved index `VoteIndex` exists and matches the vote index that the reporter assumed was correct. We then determine whether the reporter has made a "valid" claim that target account was inactive, and if true remove the target inactive account, or if false remove the account that falsely reported their inactivity. We use `.zip` to enumerate over two list iterators in parallel: * `approvals_of` (maps the account id of the target voter to their list of votes for last vote index when their vote was active) * `candidates` (present list of candidate account id's) Then we deem the report's claim "invalid" if none of the following are true: * If any of the candidate account id's has a list of votes to the last vote index, and; If any of the candidate account ids isn't the default, and; If using `RegisterInfoOf` any of the candidate account ids maps to a corresponding vote index when they registered that is less than or equal to the target voter's last active vote index. This would indicate that the candidate registered before the last vote index `LastActiveOf` when the target voter was last active, and means it is a "valid" claim that the target voter was an inactive voter between the registration and the last activate vote. We then call `remove_voter` and: * Delete the inactive voter with associated vote index and list of approval votes if "valid', OR * Delete the reporter if "invalid" Lastly we perform the reaping. If the reporter's claim that the target account was inactive was: * "valid" then we call `repatriate_reserved` to slash the target account and move a `value` from their reserved account balance to the free balance of the reporter (`beneficiary`), and emit a `VoterReaped` event. * "invalid" then we call `slash_reserved` to slash the reporter for their bad behaviour making a false claim. We slash the report's account by deducting up to a `value` from their reserved balance, and decrease the total amount of stake in the system by the amount that was slashed, and emit a `BadReaperSlashed` event. --- ### Democracy Module --- #### Public Proposals and Referendums ##### Public Proposal (Proposing) Source: srml/democracy/src/lib.rs Public proposal is a public call that anyone may execute by signing and submitting an extrinsic. We ensure that information about the origin where the dispatch initiated is a signed account using `ensure_signed`. It is considered valid when the provided deposit is above the minimum amount `minimum_deposit` that is required for a public proposal and when the proposer's has a sufficient account balance to transfer that deposit into a `reserve`. We then increment the amount of public proposals `PublicPropCount` that have been made and store in `DepositOf` the proposal's index mapped to a tuple including the proposer's account id and their locked deposit. Lastly we update the unsorted list of public proposals `PublicProps` with a tuple containing the proposal's index, the proposal itself, and their proposer's account id. ##### Public Proposal (Sponsorship/Seconding) Source: srml/democracy/src/lib.rs Sponsoring a public proposal is a public call that anyone may execute by signing and submitting an extrinsic. We ensure that information about the origin where the dispatch initiated is a signed account using `ensure_signed`. It is considered valid sponsorship when: * The proposal that is to be sponsored exists and a deposit from it's proposer has been locked away in the first element of the tuple returned when we lookup the proposal index in the mapping `DepositOf` * The sponsor has a sufficient account balance to transfer a deposit into a `reserve`, where the amount matches the deposit that the proposer made. ##### Public Referendum (Voting) Source: srml/democracy/src/lib.rs Voting on a public referendum index is a public call that anyone may execute by signing and submitting an extrinsic. We ensure that information about the origin where the dispatch initiated is a signed account using `ensure_signed`. It is considered a valid vote when: * The referendum index that the voter wishes to vote is an index in the mapping `ReferendumInfoOf` (an active referendum) * The voter (transactor) has a balance above zero to signal approval If the voter has not voted for this referendum index yet (no record in `VoteOf`) then we update the `VotersFor` mapping of referendum index to associated voters, by adding the voter to to list of voters for this referendum index. Lastly we add the vote of the voter associated with the referendum index to `VoteOf` that maps a tuple of the referendum index and voter's account id to their vote (yay or nay) ##### Public Referendum (Start) Source: srml/democracy/src/lib.rs Starting a public referendum is a public call that anyone may execute by signing and submitting an extrinsic. We ensure that information about the origin where the dispatch initiated is a signed account using `ensure_signed`. It is not considered a valid public referendum when: * There are existing referendum and the new referendum has a voting period that ends before the existing referendum with the preceeding referendum index. The public referendum is allocated referendum index and the `ReferendumCount` is incremented. We map the public referendum index to a tuple containing its corresponding voting period expiry block, the proposal it relates to, and the given voting threshold before emitting a `Started` event. ##### Public Referendum (Cancel) Source: srml/democracy/src/lib.rs We may remove all information about a referendum id. ##### Public Referendum (Elevating Public Proposals, Passing and Executing Referenda) Source: srml/democracy/src/lib.rs In modules of the SRML, the `on_finalise` signature is used in the module declaration to run anything that needs to be done at the end of the block. In democracy it calls a private function `end_block` with the current block as an argument. ###### Winning Public Proposal elevated to the Table of Referenda as a Public Referendum We first check the configured `LaunchPeriod` in blocks to see if a new public referendum should be launched. If so, we find and remove as the winning index from `PublicProps` the public proposal with the largest locked deposit amount. We then use `DepositOf` to determine the account id's that locked a deposit into the winning proposal and we refund them the deposit that was reserved. We then emit a `Tabled` event to indicate that the winning proposal is being elevated to the Table of Referenda, and start a public referendum with the winning proposal using a voting threshold of 'super majority approve'. ###### Passing and Executing maturing Public Referenda Lastly we search for any public referenda that are expiring at the current block to tally their votes by calling `maturing_referendums_at`. We remove them from the Table of Referenda, and then either: * Pass and execute the public referendum if the tally met the vote threshold * Not pass the public referendum if the tally did not meet the vote threshold We then increment the next referendum index `NextTally` that should be tallied. --- ### Assets Module --- #### Asset Management (Issue, Transfer, Destroy) ##### Introduction The assets module is for asset management, including the issuance, transfer, and destruction of fungible asset classes with a fixed supply. > Note: Fungible assets may be easily interchanged by an identical equivalent, whereas non-fungible assets are digitally scarce since they offer unique characteristics. ##### Asset Issuance (Fungible) > Source: srml/assets/src/lib.rs An `origin` account may issue to themselves a `total` fixed supply in units of a new class of fungible assets that is allocated the next `AssetId` identifier. This triggers the `Issued` event. ##### Asset Transfer (Fungible) > Source: srml/assets/src/lib.rs An account may transfer an amount of units from their holding of an asset id to a recipient account `target`. A transfer is valid when: * The public call `transfer` is executed by an signed account (`origin`) when submitting an extrinsic, which we check using `ensure_signed`. * The sender's `origin` account balance is greater than the amount to be transferred It triggers the `Transferred` event. ##### Asset Destruction (Fungible) > Source: srml/assets/src/lib.rs An account may destroy their entire holding of an asset id if they have a non-zero balance. We ensure the public call `destroy` may only be executed by an signed account (`origin`) by using `ensure_signed` when submitting an extrinsic. It triggers the `Destroyed` event. --- ### Session Module --- #### Session Management ##### Introduction TODO ##### Session Keys of Validator Set for the Next Session > Source: srml/session/src/lib.rs * Session Key of a Validator that was set in the previous session with `set_key` (a public call since it uses `ensure_signed` that checks that the origin is a signed account) is used as their Validator Session Key in the next session, which uses `NextKeyFor` to store a mapping from their AccountID to the Session Key that each of them provide. > Note: Instead of only allowing inherent calls by using `ensure_inherent`, it instead uses `ensure_signed` so that it is a public call since we want to allow users to set their Session Key prior to becoming a Validator, hence the Account ID of the origin that we are storing in `NextKeyFor` may not necessarily be associated with a block author or a validator, and so we must ensure that the Session Key of reaped (deleted) accounts is removed. See https://github.com/paritytech/substrate/issues/1201. * Validator Set is set with `set_validators`, which calls `set_authority` of the Consensus SRML passing a set of Session Keys (which it generates from the provided list of Account IDs corresponding to each of the new validators that are to be set). * Session Length (amount of block numbers) is set with `set_length` during a session and is used for subsequent sessions ##### Changing Session (Rewardable or Slashable) > Source: srml/session/src/lib.rs * Change (Rotate) Session at the end of the final block of the current Session Length using the `on_finalise` method (that is called by either an origin or internally from another SRML at the end of each block). It may be configured to be a normal rotation (rewardable, with rewards applied) or an exceptional (slashable) session. At the start of the next session we allocated a Session Index and record the timestamp when it started. If a Next Session Length was recorded in the previous session we record it as the new Session Length, and if it is not the last block of the session we record it as the Last Length Change for the New Session. #### Session Key for each Authority maps to an Index of the Validator Accound IDs Lastly we iterate through each of current set of Validator Account IDs by index and check if a Session Key was created for it with `set_key` in the previous session, and if so we call `set_authority` of the Consensus SRML where we check if the Session Key of this current authority matches the Session Key (if any) stored under their index in the `AuthorityStorageVec` mapping, and if not we store their index to Session Key and update the saved list of original authorities if necessary (see https://github.com/paritytech/substrate/issues/1290). > Note: Authorities are stored in the Consensus SRML. They are represented by the Validator index from the Session SRML and allocated with a Session Key for the length of the Session. --- ### Staking Module --- #### Staking Management ##### Introduction TODO ##### Validator Configuration and Preferences > Source: srml/staking/src/lib.rs * Validator Minimum Count is set (i.e. 4) * Validator Preferences include an Unstake Threshold (i.e. 3) of slashes that are required before unstaking occurs (TODO: unstaking of whom?) * Validator Preferences include the Validator Payment (Reward) that is received up-front. Further rewards are split with the Nominators (TODO: so the more nominators that are associated with a validator, the smaller the reward for each nominator) In the Staking SRML we store accounts that have an intention to stake at the end of the `Intentions` vector when they call `stake`. Then when a user wants to unstake they call `unstake` and provide as an argument the index where their intention was stored in the `Intentions` vector. So they need to first iterate through the vector to retrieve their intention index before making this call. We may want to benchmark lookup performance of retrieving their intention index and consider using a different data structure for when we have a very large number of intentions. ##### Staking, Staking Intentions, and Unstaking > Source: srml/staking/src/lib.rs * Transactors may call `stake` to be added to the list of `Intentions` (accounts with an intention to stake) and added to `Bondage` a mapping between their Account ID and the block number when their funds will become entirely liquid again. The effects of these changes are felt at the start of the Next Era. (TODO: why is this set to T::BlockNumber::max_value() instead of say `NextSessionsPerEra`? is it because `NextSessionsPerEra` may not yet be defined so we just set it to the maximum possible block number and then set the value again at the start of the Next Era when `NextSessionsPerEra` should be defined?) * Transactors may call `unstake` and provide the Index of their Intention as an argument. So the Transactor should find the Index where their Account ID is stored in the `Intentions` vector prior to making the call. Verification occurs and prevents unstaking when there are: less staked participants than the Minimum Validator Count; or if the Account ID stored in the provided Index does not match that of the caller. After verification: the Account ID is removed from the `Intentions` vector, `ValidatorPreferences` mapping, and the `SlashCount` mapping; the block number corresponding to when their bondage duration `BondingDuration` expires is mapped to their Account ID in `Bondage` (where a default `BondingDuration` such as 1000 eras is used unless it has been set with `set_bonding_duration`). The effects of these changes are felt at the start of the Next Era. ##### Nominating, and Unnominating > Source: srml/staking/src/lib.rs * Transactors may call `nominate` and provide the `Address` of the target account that they wish to nominate. Verification occurs and prevents accounts nominating when they are already nominating or staked. After verification: we add the calling Account ID (nominator) to the list of accounts that have nominated the target account (nominee) using `NominatorsFor`; add a mapping to `Nominating` with the nominator to their nominee; add a mapping to `Bondage` from their Account ID and the block number when their funds will become entirely liquid again. The effects of these changes are felt at the start of the Next Era. > Note: `stake`, `unstake`, and `nominate` are a public calls since they use `ensure_signed` that checks that the origin account calling the function is a signed account * Transactions may call `unnominate` and provide the Index of the target account that they wish to unnominate. So the Transactor should find the Index where the target Account ID is stored in the `NominatorsFor` mapping prior to making the call. IN PROGRESS * TODO - see if add a call that calculates the "total amount staked" at the start of an era adds any value (after all Bondage values have been updated from the max possible block number to the block number when their stake becomes liquid) * TODO - see how implementers are using it to potentially improve the boilerplate (i.e. AdEx) * TODO - Update to integrate Staking SRML based on these comments: * https://github.com/paritytech/substrate/blob/master/srml/session/src/lib.rs#L180 * https://github.com/paritytech/substrate/blob/master/srml/session/src/lib.rs#L171 * explain normal rotation (rewardable, with rewards applied) session versus an exceptional (slashable) session

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully