diff --git a/src/frame/mod.rs b/src/frame/mod.rs index 898031f753..949f0b3183 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -35,6 +35,7 @@ use sp_core::storage::StorageKey; pub mod balances; pub mod contracts; pub mod system; +pub mod staking; /// Store trait. pub trait Store: Encode { diff --git a/src/frame/staking.rs b/src/frame/staking.rs new file mode 100644 index 0000000000..2527586f25 --- /dev/null +++ b/src/frame/staking.rs @@ -0,0 +1,202 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of substrate-subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with substrate-subxt. If not, see . + +//! Implements support for the frame_staking module. + +use codec::{Codec, Decode, Encode, HasCompact}; +use frame_support::Parameter; +use serde::de::DeserializeOwned; +use sp_core::storage::StorageKey; +use sp_runtime::{ + traits::{ + AtLeast32Bit, Bounded, CheckEqual, Extrinsic, Hash, Header, MaybeDisplay, + MaybeMallocSizeOf, MaybeSerialize, MaybeSerializeDeserialize, Member, + SimpleBitOps, + }, + RuntimeDebug, +}; +use std::fmt::Debug; +use std::marker::PhantomData; +use crate::{ + frame::{Call, Store}, + metadata::{Metadata, MetadataError}, +}; + +/// Data type used to index nominators in the compact type +pub type NominatorIndex = u32; + +/// Data type used to index validators in the compact type. +pub type ValidatorIndex = u16; + +/// Maximum number of stakers that can be stored in a snapshot. +pub(crate) const MAX_VALIDATORS: usize = ValidatorIndex::max_value() as usize; +pub(crate) const MAX_NOMINATORS: usize = NominatorIndex::max_value() as usize; + +/// Counter for the number of eras that have passed. +pub type EraIndex = u32; + +/// Counter for the number of "reward" points earned by a given validator. +pub type RewardPoint = u32; + + +/// The subset of the `frame::Trait` that a client must implement. +pub trait Staking: super::system::System { + /* + type UnixTime; + type CurrencyToVote; + type RewardRemainder; + type Event; + type Slash; + type Reward; + type SessionsPerEra; + type BondingDuration; + type SlashDeferDuration; + type SlashCancelOrigin; + type SessionInterface; + type RewardCurve; + type NextNewSession; + type ElectionLookahead; + type Call; + type MaxIterations; + type MaxNominatorRewardPerValidator; + type UnsignedPriority; */ +} + +/// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +pub struct UnlockChunk { + /// Amount of funds to be unlocked. + #[codec(compact)] + value: Balance, + /// Era number at which point it'll be unlocked. + #[codec(compact)] + era: EraIndex, +} + +/// The ledger of a (bonded) stash. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +pub struct StakingLedger { + /// The stash account whose balance is actually locked and at stake. + pub stash: AccountId, + /// The total amount of the stash's balance that we are currently accounting for. + /// It's just `active` plus all the `unlocking` balances. + #[codec(compact)] + pub total: Balance, + /// The total amount of the stash's balance that will be at stake in any forthcoming + /// rounds. + #[codec(compact)] + pub active: Balance, + /// Any balance that is becoming free, which may eventually be transferred out + /// of the stash (assuming it doesn't get slashed first). + pub unlocking: Vec>, + /// List of eras for which the stakers behind a validator have claimed rewards. Only updated + /// for validators. + pub claimed_rewards: Vec, +} + +const MODULE: &str = "Staking"; + +/// Number of eras to keep in history. +/// +/// Information is kept for eras in `[current_era - history_depth; current_era]`. +/// +/// Must be more than the number of eras delayed by session otherwise. +/// I.e. active era must always be in history. +/// I.e. `active_era > current_era - history_depth` must be guaranteed. +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct HistoryDepth(PhantomData); + +impl Store for HistoryDepth { + const MODULE: &'static str = MODULE; + const FIELD: &'static str = "HistoryDepth"; + type Returns = u32; + + fn key(&self, metadata: &Metadata) -> Result { + Ok(metadata.module(Self::MODULE)?.storage(Self::FIELD)?.plain()?.key()) + } +} + +/// The ideal number of staking participants. +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct ValidatorCount(PhantomData); + +impl Store for ValidatorCount { + const MODULE: &'static str = MODULE; + const FIELD: &'static str = "ValidatorCount"; + type Returns = u32; + + fn key(&self, metadata: &Metadata) -> Result { + Ok(metadata.module(Self::MODULE)?.storage(Self::FIELD)?.plain()?.key()) + } +} + +/// Minimum number of staking participants before emergency conditions are imposed. +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct MinimumValidatorCount(PhantomData); + +impl Store for MinimumValidatorCount { + const MODULE: &'static str = MODULE; + const FIELD: &'static str = "MinimumValidatorCount"; + type Returns = u32; + + fn key(&self, metadata: &Metadata) -> Result { + Ok(metadata.module(Self::MODULE)?.storage(Self::FIELD)?.plain()?.key()) + } +} + +/// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're +/// easy to initialize and the performance hit is minimal (we expect no more than four +/// invulnerables) and restricted to testnets. +#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct Invulnerables(pub core::marker::PhantomData); + +impl Store for Invulnerables { + const MODULE: &'static str = MODULE; + const FIELD: &'static str = "Invulnerables"; + type Returns = Vec; + + fn key(&self, metadata: &Metadata) -> Result { + Ok(metadata.module(Self::MODULE)?.storage(Self::FIELD)?.plain()?.key()) + } +} + +/// Map from all locked "stash" accounts to the controller account. +#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct Bonded(pub PhantomData); + +impl Store for Bonded { + const MODULE: &'static str = MODULE; + const FIELD: &'static str = "Bonded"; + type Returns = Vec; + + fn key(&self, metadata: &Metadata) -> Result { + Ok(metadata.module(Self::MODULE)?.storage(Self::FIELD)?.map()?.key(&self.0)) + } +} + +/// Map from all (unlocked) "controller" accounts to the info regarding the staking. +#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct Ledger(pub T::AccountId); + +impl Store for Ledger { + const MODULE: &'static str = MODULE; + const FIELD: &'static str = "Ledger"; + type Returns = Option>; + + fn key(&self, metadata: &Metadata) -> Result { + Ok(metadata.module(Self::MODULE)?.storage(Self::FIELD)?.map()?.key(&self.0)) + } +}