-
Notifications
You must be signed in to change notification settings - Fork 262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Staking support #99
Staking support #99
Changes from 34 commits
6bdf5e8
10667e3
d4a085a
c08e22a
93c347c
fef1260
3d6e2ee
c0b1904
8721237
a28fb20
cfabfe8
ff967e9
716dd13
88ac3cb
122260f
ffbffd4
1b4dc07
ebfdc17
aaf190e
5ff1b17
58da217
ab9612b
193104c
7868f2c
c4942c4
c6ade8b
36b124d
bc19991
9fd2949
e3e30cf
ba4f90c
06aa7e2
49b3b1e
3314ea1
57e2390
067c6f9
83c6c61
5bdeee4
7587469
06bc4ab
6ccfc9c
d4d7b1d
c63b74c
4d8ccab
90e3b9b
2bea59f
a95fd8a
f15c5f6
d3df9ea
ff8e37f
fe20eb5
e80ddd4
94ce5ce
ae676c9
e829a46
6bf960f
528b218
7bad6c6
da36675
d5b1138
28533f6
c330e68
59decaf
93fafcd
8bcde31
b03b28b
2744127
3efe16f
dd15f22
773d43e
d3865a6
0084f87
33f1710
9f34f76
1df5a64
c622641
b253a7a
1394bb9
9a86802
0e7bc2d
92bcd26
95c8900
b3687af
3020f32
303c5f4
2e74c1e
f0a5f61
e0b41af
0516987
dffbba6
0860bad
ec96a42
01869a7
b54b1b9
68ff645
9c6c663
bc8bc36
dd4dce9
1eb67d9
d63661f
369cb88
24848b3
e2862d8
8a79571
f3da309
18e8029
f7cda4a
15c0206
d659e91
52960b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright 2019-2020 Parity Technologies (UK) Ltd. | ||
// This file is part of substrate-subxt. | ||
// | ||
// subxt is free software: you can redistribute it and/or modify | ||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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, | ||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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 <http://www.gnu.org/licenses/>. | ||
// Copyright 2019-2020 Parity Technologies (UK) Ltd. | ||
|
||
//! Session support | ||
use crate::frame::system::{ | ||
System, | ||
SystemEventsDecoder as _, | ||
}; | ||
use codec::Encode; | ||
use frame_support::Parameter; | ||
use std::{ | ||
fmt::Debug, | ||
marker::PhantomData, | ||
}; | ||
use substrate_subxt_proc_macro::Store; | ||
|
||
/// The trait needed for this module. | ||
#[module] | ||
pub trait Session: System { | ||
/// The validator account identifier type for the runtime. | ||
type ValidatorId: Parameter + Debug + Ord + Default + Send + Sync + 'static; | ||
|
||
/// The validator account identifier type for the runtime. | ||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
type SessionIndex: Parameter + Debug + Ord + Default + Send + Sync + 'static; | ||
} | ||
|
||
/// The current set of validators. | ||
#[derive(Encode, Store)] | ||
pub struct ValidatorsStore<T: Session> { | ||
#[store(returns = Vec<<T as Session>::ValidatorId>)] | ||
/// Marker for the runtime | ||
pub _runtime: PhantomData<T>, | ||
} | ||
|
||
/// Current index of the session. | ||
#[derive(Encode, Store)] | ||
pub struct CurrentIndexStore<T: Session> { | ||
#[store(returns = <T as Session>::SessionIndex)] | ||
/// Marker for the runtime | ||
pub _runtime: PhantomData<T>, | ||
} | ||
|
||
/// True if the underlying economic identities or weighting behind the validators | ||
/// has changed in the queued validator set. | ||
#[derive(Encode, Store)] | ||
pub struct QueuedChangedStore<T: Session> { | ||
#[store(returns = bool)] | ||
/// Marker for the runtime | ||
pub _runtime: PhantomData<T>, | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,313 @@ | ||||||
// Copyright 2019-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 <http://www.gnu.org/licenses/>. | ||||||
|
||||||
//! Implements support for the frame_staking module. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
use super::system::{ | ||||||
System, | ||||||
SystemEventsDecoder as _, | ||||||
}; | ||||||
use codec::{ | ||||||
Decode, | ||||||
Encode, | ||||||
HasCompact, | ||||||
}; | ||||||
use sp_runtime::Perbill; | ||||||
use std::{ | ||||||
fmt::Debug, | ||||||
marker::PhantomData, | ||||||
}; | ||||||
|
||||||
/// A record of the nominations made by a specific account. | ||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug, Ord, PartialOrd, Hash)] | ||||||
pub struct Nominations<AccountId> { | ||||||
/// The targets of nomination. | ||||||
pub targets: Vec<AccountId>, | ||||||
/// The era the nominations were submitted. | ||||||
/// | ||||||
/// Except for initial nominations which are considered submitted at era 0. | ||||||
pub submitted_in: EraIndex, | ||||||
/// Whether the nominations have been suppressed. | ||||||
pub suppressed: bool, | ||||||
} | ||||||
|
||||||
/// Information regarding the active era (era in used in session). | ||||||
#[derive(Encode, Decode, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] | ||||||
pub struct ActiveEraInfo { | ||||||
Demi-Marie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
/// Index of era. | ||||||
pub index: EraIndex, | ||||||
/// Moment of start expresed as millisecond from `$UNIX_EPOCH`. | ||||||
/// | ||||||
/// Start can be none if start hasn't been set for the era yet, | ||||||
/// Start is set on the first on_finalize of the era to guarantee usage of `Time`. | ||||||
pub start: Option<u64>, | ||||||
} | ||||||
|
||||||
/// Data type used to index nominators in the compact type | ||||||
pub type NominatorIndex = u32; | ||||||
Demi-Marie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
/// Data type used to index validators in the compact type. | ||||||
pub type ValidatorIndex = u16; | ||||||
|
||||||
/// Maximum number of validators that can be stored in a snapshot. | ||||||
pub const MAX_VALIDATORS: usize = ValidatorIndex::max_value() as usize; | ||||||
|
||||||
/// Maximum number of nominators that can be stored in a snapshot. | ||||||
pub 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; | ||||||
|
||||||
/// A destination account for payment. | ||||||
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug)] | ||||||
pub enum RewardDestination { | ||||||
/// Pay into the stash account, increasing the amount at stake accordingly. | ||||||
Staked, | ||||||
/// Pay into the stash account, not increasing the amount at stake. | ||||||
Stash, | ||||||
/// Pay into the controller account. | ||||||
Controller, | ||||||
} | ||||||
|
||||||
/// Preference of what happens regarding validation. | ||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug, Call)] | ||||||
pub struct SetPayeeCall<T: Staking> { | ||||||
/// The payee | ||||||
pub payee: Perbill, | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// Preference of what happens regarding validation. | ||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)] | ||||||
pub struct ValidatorPrefs { | ||||||
/// Reward that validator takes up-front; only the rest is split between themselves and | ||||||
/// nominators. | ||||||
#[codec(compact)] | ||||||
pub commission: Perbill, | ||||||
} | ||||||
|
||||||
impl Default for ValidatorPrefs { | ||||||
fn default() -> Self { | ||||||
ValidatorPrefs { | ||||||
commission: Default::default(), | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/// The subset of the `frame::Trait` that a client must implement. | ||||||
#[module] | ||||||
pub trait Staking: System {} | ||||||
|
||||||
/// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, Ord, PartialOrd, Hash)] | ||||||
pub struct UnlockChunk<Balance: HasCompact> { | ||||||
/// Amount of funds to be unlocked. | ||||||
#[codec(compact)] | ||||||
pub value: Balance, | ||||||
/// Era number at which point it'll be unlocked. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
#[codec(compact)] | ||||||
pub era: EraIndex, | ||||||
} | ||||||
|
||||||
/// The ledger of a (bonded) stash. | ||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, Ord, PartialOrd, Hash)] | ||||||
pub struct StakingLedger<AccountId, Balance: HasCompact> { | ||||||
/// 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<UnlockChunk<Balance>>, | ||||||
/// List of eras for which the stakers behind a validator have claimed rewards. Only updated | ||||||
/// for validators. | ||||||
pub claimed_rewards: Vec<EraIndex>, | ||||||
} | ||||||
|
||||||
/// 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, Store, | ||||||
)] | ||||||
pub struct HistoryDepthStore<T: Staking> { | ||||||
#[store(returns = u32)] | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// The ideal number of staking participants. | ||||||
#[derive( | ||||||
Encode, Decode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store, | ||||||
)] | ||||||
pub struct ValidatorCountStore<T: Staking> { | ||||||
#[store(returns = u32)] | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// Minimum number of staking participants before emergency conditions are imposed. | ||||||
#[derive( | ||||||
Encode, Decode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store, | ||||||
)] | ||||||
pub struct MinimumValidatorCountStore<T: Staking> { | ||||||
#[store(returns = u32)] | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// 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, Store)] | ||||||
pub struct InvulnerablesStore<T: Staking> { | ||||||
#[store(returns = Vec<T::AccountId>)] | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// Map from all locked "stash" accounts to the controller account. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct BondedStore<T: Staking> { | ||||||
#[store(returns = Vec<T::AccountId>)] | ||||||
/// Tٗhe stash account | ||||||
pub stash: T::AccountId, | ||||||
} | ||||||
|
||||||
/// Map from all (unlocked) "controller" accounts to the info regarding the staking. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct LedgerStore<T: Staking> { | ||||||
#[store(returns = Option<StakingLedger<T::AccountId, ()>>)] | ||||||
/// The controller account | ||||||
pub controller: T::AccountId, | ||||||
} | ||||||
|
||||||
/// Where the reward payment should be made. Keyed by stash. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct PayeeStore<T: Staking> { | ||||||
#[store(returns = RewardDestination)] | ||||||
/// Tٗhe stash account | ||||||
pub stash: T::AccountId, | ||||||
} | ||||||
|
||||||
/// The map from (wannabe) validator stash key to the preferences of that validator. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct ValidatorsStore<T: Staking> { | ||||||
#[store(returns = ValidatorPrefs)] | ||||||
/// Tٗhe stash account | ||||||
pub stash: T::AccountId, | ||||||
} | ||||||
|
||||||
/// The map from nominator stash key to the set of stash keys of all validators to nominate. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct NominatorsStore<T: Staking> { | ||||||
#[store(returns = Option<Nominations<T::AccountId>>)] | ||||||
/// Tٗhe stash account | ||||||
pub stash: T::AccountId, | ||||||
} | ||||||
|
||||||
/// The current era index. | ||||||
/// | ||||||
/// This is the latest planned era, depending on how the Session pallet queues the validator | ||||||
/// set, it might be active or not. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct CurrentEraStore<T: Staking> { | ||||||
#[store(returns = Option<EraIndex>)] | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// The active era information, it holds index and start. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
/// | ||||||
/// The active era is the era currently rewarded. | ||||||
/// Validator set of this era must be equal to `SessionInterface::validators`. | ||||||
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)] | ||||||
pub struct ActiveEraStore<T: Staking> { | ||||||
#[store(returns = Option<ActiveEraInfo>)] | ||||||
/// Marker for the runtime | ||||||
pub _runtime: PhantomData<T>, | ||||||
} | ||||||
|
||||||
/// Declare the desire to validate for the origin controller. | ||||||
/// | ||||||
/// Effects will be felt at the beginning of the next era. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
or perhaps "If successful, effective from the beginning of the next era."? |
||||||
/// | ||||||
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash. | ||||||
/// And, it can be only called when [`EraElectionStatus`] is `Closed`. | ||||||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
/// | ||||||
/// # <weight> | ||||||
/// - Independent of the arguments. Insignificant complexity. | ||||||
/// - Contains a limited number of reads. | ||||||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
/// - Writes are limited to the `origin` account key. | ||||||
/// ----------- | ||||||
/// Base Weight: 17.13 µs | ||||||
/// DB Weight: | ||||||
/// - Read: Era Election Status, Ledger | ||||||
/// - Write: Nominators, Validators | ||||||
/// # </weight> | ||||||
#[derive(Clone, Debug, PartialEq, Call, Encode)] | ||||||
pub struct ValidateCall<T: Staking> { | ||||||
/// Runtime marker. | ||||||
pub _runtime: PhantomData<T>, | ||||||
/// Validation preferences. | ||||||
pub prefs: ValidatorPrefs, | ||||||
} | ||||||
|
||||||
/// Declare the desire to nominate `targets` for the origin controller. | ||||||
/// | ||||||
/// Effects will be felt at the beginning of the next era. This can only be called when | ||||||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
/// [`EraElectionStatus`] is `Closed`. | ||||||
/// | ||||||
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash. | ||||||
/// And, it can be only called when [`EraElectionStatus`] is `Closed`. | ||||||
DemiMarie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
/// | ||||||
/// # <weight> | ||||||
/// - The transaction's complexity is proportional to the size of `targets` (N) | ||||||
/// which is capped at CompactAssignments::LIMIT (MAX_NOMINATIONS). | ||||||
/// - Both the reads and writes follow a similar pattern. | ||||||
/// --------- | ||||||
/// Base Weight: 22.34 + .36 * N µs | ||||||
/// where N is the number of targets | ||||||
/// DB Weight: | ||||||
/// - Reads: Era Election Status, Ledger, Current Era | ||||||
/// - Writes: Validators, Nominators | ||||||
/// # </weight> | ||||||
#[derive(Call, Encode)] | ||||||
pub struct NominateCall<T: Staking> { | ||||||
/// The targets that are being nominated | ||||||
pub targets: Vec<T::Address>, | ||||||
} | ||||||
|
||||||
/// Claim a payout. | ||||||
#[derive(PartialEq, Eq, Clone, Call, Encode, Decode)] | ||||||
struct PayoutStakersCall<'a, T: System> { | ||||||
pub validator_stash: &'a T::AccountId, | ||||||
pub era: EraIndex, | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please open an issue for this, or provide some context here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a long time to figure this out, so I added this for the benefit of others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this info – which I agree is useful – should move or be copied to the docs for
module
/Call
macros?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've raised an issue for it to improve the error message: #170. But probably we should remove from the readme since it doesn't make sense without any context.