diff --git a/Cargo.lock b/Cargo.lock index d8f52aa141a95..d5197ba4ea65b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1628,6 +1628,7 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", + "sp-staking", "sp-state-machine", "sp-std", "sp-tracing", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6a9919fcbc8bc..c2a2542b5588a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -830,6 +830,7 @@ impl frame_system::offchain::SendTransactionTypes for Runtime where impl pallet_im_online::Config for Runtime { type AuthorityId = ImOnlineId; type Event = Event; + type ValidatorSet = Historical; type SessionDuration = SessionDuration; type ReportUnresponsiveness = Offences; type UnsignedPriority = ImOnlineUnsignedPriority; diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 7e43f49c4dd7c..61937da286ada 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -46,7 +46,7 @@ use sp_std::{result, prelude::*}; use codec::{Encode, Decode}; -use frame_support::{Parameter, traits::{Get, FindAuthor}, ConsensusEngineId}; +use frame_support::{Parameter, traits::{Get, FindAuthor, OneSessionHandler}, ConsensusEngineId}; use sp_runtime::{ RuntimeAppPublic, traits::{SaturatedConversion, Saturating, Zero, Member, IsMember}, generic::DigestItem, @@ -144,7 +144,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for Pallet { type Public = T::AuthorityId; } -impl pallet_session::OneSessionHandler for Pallet { +impl OneSessionHandler for Pallet { type Key = T::AuthorityId; fn on_genesis_session<'a, I: 'a>(validators: I) diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 219219b9957bd..cc3f41f59ed89 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -24,7 +24,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -use frame_support::{decl_module, decl_storage}; +use frame_support::{decl_module, decl_storage, traits::OneSessionHandler}; use sp_authority_discovery::AuthorityId; /// The module's config trait. @@ -85,7 +85,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for Module { type Public = AuthorityId; } -impl pallet_session::OneSessionHandler for Module { +impl OneSessionHandler for Module { type Key = AuthorityId; fn on_genesis_session<'a, I: 'a>(authorities: I) @@ -265,7 +265,7 @@ mod tests { let mut externalities = TestExternalities::new(t); externalities.execute_with(|| { - use pallet_session::OneSessionHandler; + use frame_support::traits::OneSessionHandler; AuthorityDiscovery::on_genesis_session( first_authorities.iter().map(|id| (id, id.clone())) diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index e34de5d6c532d..0afa0e1d0980f 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -25,7 +25,7 @@ use codec::{Decode, Encode}; use frame_support::{ decl_error, decl_module, decl_storage, dispatch::DispatchResultWithPostInfo, - traits::{FindAuthor, Get, KeyOwnerProofSystem, Randomness as RandomnessT}, + traits::{FindAuthor, Get, KeyOwnerProofSystem, OneSessionHandler, Randomness as RandomnessT}, weights::{Pays, Weight}, Parameter, }; @@ -769,7 +769,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for Module { type Public = AuthorityId; } -impl pallet_session::OneSessionHandler for Module { +impl OneSessionHandler for Module { type Key = AuthorityId; fn on_genesis_session<'a, I: 'a>(validators: I) diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 078acbaa57561..b68624df7b5dc 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -41,7 +41,7 @@ use fg_primitives::{ }; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResultWithPostInfo, - storage, traits::KeyOwnerProofSystem, weights::{Pays, Weight}, Parameter, + storage, traits::{OneSessionHandler, KeyOwnerProofSystem}, weights::{Pays, Weight}, Parameter, }; use frame_system::{ensure_none, ensure_root, ensure_signed}; use sp_runtime::{ @@ -587,7 +587,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for Module { type Public = AuthorityId; } -impl pallet_session::OneSessionHandler for Module +impl OneSessionHandler for Module where T: pallet_session::Config { type Key = AuthorityId; diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 0e2a458a3dfe1..4870bf606286c 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -25,11 +25,10 @@ use codec::{Decode, Encode}; use fg_primitives::ScheduledChange; use frame_support::{ assert_err, assert_ok, - traits::{Currency, OnFinalize}, + traits::{Currency, OnFinalize, OneSessionHandler}, weights::{GetDispatchInfo, Pays}, }; use frame_system::{EventRecord, Phase}; -use pallet_session::OneSessionHandler; use sp_core::H256; use sp_keyring::Ed25519Keyring; use sp_runtime::testing::Digest; diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index fc84a8d8cb1ba..41eb433478d4e 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -19,7 +19,6 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = sp-core = { version = "2.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.101", optional = true } -pallet-session = { version = "2.0.0", default-features = false, path = "../session" } sp-io = { version = "2.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "2.0.0", default-features = false, path = "../../primitives/staking" } @@ -28,8 +27,11 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system" frame-benchmarking = { version = "2.0.0", default-features = false, path = "../benchmarking", optional = true } +[dev-dependencies] +pallet-session = { version = "2.0.0", path = "../session" } + [features] -default = ["std", "pallet-session/historical"] +default = ["std"] std = [ "sp-application-crypto/std", "pallet-authorship/std", @@ -37,7 +39,6 @@ std = [ "sp-core/std", "sp-std/std", "serde", - "pallet-session/std", "sp-io/std", "sp-runtime/std", "sp-staking/std", diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 71ee25d779bdd..bd597acfb1ed5 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -79,7 +79,6 @@ use codec::{Encode, Decode}; use sp_core::offchain::OpaqueNetworkState; use sp_std::prelude::*; use sp_std::convert::TryInto; -use pallet_session::historical::IdentificationTuple; use sp_runtime::{ offchain::storage::StorageValueRef, RuntimeDebug, @@ -95,7 +94,7 @@ use sp_staking::{ }; use frame_support::{ decl_module, decl_event, decl_storage, Parameter, debug, decl_error, - traits::Get, + traits::{Get, ValidatorSet, ValidatorSetWithIdentification, OneSessionHandler}, }; use frame_system::ensure_none; use frame_system::offchain::{ @@ -227,7 +226,19 @@ pub struct Heartbeat pub validators_len: u32, } -pub trait Config: SendTransactionTypes> + pallet_session::historical::Config { +/// A type for representing the validator id in a session. +pub type ValidatorId = < + ::ValidatorSet as ValidatorSet<::AccountId> +>::ValidatorId; + +/// A tuple of (ValidatorId, Identification) where `Identification` is the full identification of `ValidatorId`. +pub type IdentificationTuple = ( + ValidatorId, + <::ValidatorSet as + ValidatorSetWithIdentification<::AccountId>>::Identification, +); + +pub trait Config: SendTransactionTypes> + frame_system::Config { /// The identifier type for an authority. type AuthorityId: Member + Parameter + RuntimeAppPublic + Default + Ord; @@ -242,6 +253,9 @@ pub trait Config: SendTransactionTypes> + pallet_session::historical: /// there is a chance the authority will produce a block and they won't be necessary. type SessionDuration: Get; + /// A type for retrieving the validators supposed to be online in a session. + type ValidatorSet: ValidatorSetWithIdentification; + /// A type that gives us the ability to submit unresponsiveness offence reports. type ReportUnresponsiveness: ReportOffence< @@ -293,10 +307,10 @@ decl_storage! { double_map hasher(twox_64_concat) SessionIndex, hasher(twox_64_concat) AuthIndex => Option>; - /// For each session index, we keep a mapping of `T::ValidatorId` to the + /// For each session index, we keep a mapping of `ValidatorId` to the /// number of blocks authored by the given authority. AuthoredBlocks get(fn authored_blocks): - double_map hasher(twox_64_concat) SessionIndex, hasher(twox_64_concat) T::ValidatorId + double_map hasher(twox_64_concat) SessionIndex, hasher(twox_64_concat) ValidatorId => u32; } add_extra_genesis { @@ -345,7 +359,7 @@ decl_module! { ) { ensure_none(origin)?; - let current_session = >::current_index(); + let current_session = T::ValidatorSet::session_index(); let exists = ::contains_key( ¤t_session, &heartbeat.authority_index @@ -397,12 +411,15 @@ type OffchainResult = Result::B /// Keep track of number of authored blocks per authority, uncles are counted as /// well since they're a valid proof of being online. -impl pallet_authorship::EventHandler for Module { - fn note_author(author: T::ValidatorId) { +impl< + T: Config + pallet_authorship::Config, +> pallet_authorship::EventHandler, T::BlockNumber> for Module +{ + fn note_author(author: ValidatorId) { Self::note_authorship(author); } - fn note_uncle(author: T::ValidatorId, _age: T::BlockNumber) { + fn note_uncle(author: ValidatorId, _age: T::BlockNumber) { Self::note_authorship(author); } } @@ -413,7 +430,7 @@ impl Module { /// authored at least one block, during the current session. Otherwise /// `false`. pub fn is_online(authority_index: AuthIndex) -> bool { - let current_validators = >::validators(); + let current_validators = T::ValidatorSet::validators(); if authority_index >= current_validators.len() as u32 { return false; @@ -424,8 +441,8 @@ impl Module { Self::is_online_aux(authority_index, authority) } - fn is_online_aux(authority_index: AuthIndex, authority: &T::ValidatorId) -> bool { - let current_session = >::current_index(); + fn is_online_aux(authority_index: AuthIndex, authority: &ValidatorId) -> bool { + let current_session = T::ValidatorSet::session_index(); ::contains_key(¤t_session, &authority_index) || >::get( @@ -437,13 +454,13 @@ impl Module { /// Returns `true` if a heartbeat has been received for the authority at `authority_index` in /// the authorities series, during the current session. Otherwise `false`. pub fn received_heartbeat_in_current_session(authority_index: AuthIndex) -> bool { - let current_session = >::current_index(); + let current_session = T::ValidatorSet::session_index(); ::contains_key(¤t_session, &authority_index) } /// Note that the given authority has authored a block in the current session. - fn note_authorship(author: T::ValidatorId) { - let current_session = >::current_index(); + fn note_authorship(author: ValidatorId) { + let current_session = T::ValidatorSet::session_index(); >::mutate( ¤t_session, @@ -460,8 +477,8 @@ impl Module { return Err(OffchainErr::TooEarly(heartbeat_after)) } - let session_index = >::current_index(); - let validators_len = >::validators().len() as u32; + let session_index = T::ValidatorSet::session_index(); + let validators_len = Keys::::decode_len().unwrap_or_default() as u32; Ok(Self::local_authority_keys() .map(move |(authority_index, key)| @@ -614,7 +631,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for Module { type Public = T::AuthorityId; } -impl pallet_session::OneSessionHandler for Module { +impl OneSessionHandler for Module { type Key = T::AuthorityId; fn on_genesis_session<'a, I: 'a>(validators: I) @@ -639,22 +656,24 @@ impl pallet_session::OneSessionHandler for Module { } fn on_before_session_ending() { - let session_index = >::current_index(); + let session_index = T::ValidatorSet::session_index(); let keys = Keys::::get(); - let current_validators = >::validators(); + let current_validators = T::ValidatorSet::validators(); let offenders = current_validators.into_iter().enumerate() .filter(|(index, id)| !Self::is_online_aux(*index as u32, id) ).filter_map(|(_, id)| - T::FullIdentificationOf::convert(id.clone()).map(|full_id| (id, full_id)) + >::IdentificationOf::convert( + id.clone() + ).map(|full_id| (id, full_id)) ).collect::>>(); // Remove all received heartbeats and number of authored blocks from the // current session, they have already been processed and won't be needed // anymore. - ::remove_prefix(&>::current_index()); - >::remove_prefix(&>::current_index()); + ::remove_prefix(&T::ValidatorSet::session_index()); + >::remove_prefix(&T::ValidatorSet::session_index()); if offenders.is_empty() { Self::deposit_event(RawEvent::AllGood); @@ -691,7 +710,7 @@ impl frame_support::unsigned::ValidateUnsigned for Module { } // check if session index from heartbeat is recent - let current_session = >::current_index(); + let current_session = T::ValidatorSet::session_index(); if heartbeat.session_index != current_session { return InvalidTransaction::Stale.into(); } diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 624014cd55f78..cf2138e941d05 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -179,6 +179,7 @@ impl Config for Runtime { type AuthorityId = UintAuthorityId; type Event = (); type ReportUnresponsiveness = OffenceHandler; + type ValidatorSet = Historical; type SessionDuration = Period; type UnsignedPriority = UnsignedPriority; type WeightInfo = (); @@ -195,6 +196,7 @@ impl frame_system::offchain::SendTransactionTypes for Runt pub type ImOnline = Module; pub type System = frame_system::Module; pub type Session = pallet_session::Module; +pub type Historical = pallet_session::historical::Module; pub fn advance_session() { let now = System::block_number().max(1); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 06a0e33a9cf46..57672f13ed711 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -26,7 +26,7 @@ use sp_std::vec; use frame_system::{RawOrigin, Module as System, Config as SystemConfig}; use frame_benchmarking::{benchmarks, account}; -use frame_support::traits::{Currency, OnInitialize}; +use frame_support::traits::{Currency, OnInitialize, ValidatorSet, ValidatorSetWithIdentification}; use sp_runtime::{Perbill, traits::{Convert, StaticLookup, Saturating, UniqueSaturatedInto}}; use sp_staking::offence::{ReportOffence, Offence, OffenceDetails}; @@ -176,6 +176,34 @@ fn make_offenders(num_offenders: u32, num_nominators: u32) -> Result< Ok((id_tuples, offenders)) } +fn make_offenders_im_online(num_offenders: u32, num_nominators: u32) -> Result< + (Vec>, Vec>), + &'static str +> { + Staking::::new_session(0); + + let mut offenders = vec![]; + for i in 0 .. num_offenders { + let offender = create_offender::(i + 1, num_nominators)?; + offenders.push(offender); + } + + Staking::::start_session(0); + + let id_tuples = offenders.iter() + .map(|offender| < + ::ValidatorSet as ValidatorSet + >::ValidatorIdOf::convert(offender.controller.clone()) + .expect("failed to get validator id from account id")) + .map(|validator_id| < + ::ValidatorSet as ValidatorSetWithIdentification + >::IdentificationOf::convert(validator_id.clone()) + .map(|full_id| (validator_id, full_id)) + .expect("failed to convert validator id to full identification")) + .collect::>>(); + Ok((id_tuples, offenders)) +} + #[cfg(test)] fn check_events::Event>>(expected: I) { let events = System::::events() .into_iter() @@ -220,7 +248,7 @@ benchmarks! { // make sure reporters actually get rewarded Staking::::set_slash_reward_fraction(Perbill::one()); - let (offenders, raw_offenders) = make_offenders::(o, n)?; + let (offenders, raw_offenders) = make_offenders_im_online::(o, n)?; let keys = ImOnline::::keys(); let validator_set_count = keys.len() as u32; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 6ebb9f19e6ae9..5d6d13aa30913 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -29,7 +29,7 @@ use sp_runtime::{ traits::IdentityLookup, testing::{Header, UintAuthorityId}, }; - +use pallet_session::historical as pallet_session_historical; type AccountId = u64; type AccountIndex = u32; @@ -130,6 +130,7 @@ impl pallet_session::Config for Test { type DisabledValidatorsThreshold = (); type WeightInfo = (); } + pallet_staking_reward_curve::build! { const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( min_inflation: 0_025_000, @@ -175,6 +176,7 @@ impl pallet_staking::Config for Test { impl pallet_im_online::Config for Test { type AuthorityId = UintAuthorityId; type Event = Event; + type ValidatorSet = Historical; type SessionDuration = Period; type ReportUnresponsiveness = Offences; type UnsignedPriority = (); @@ -214,6 +216,7 @@ frame_support::construct_runtime!( Session: pallet_session::{Module, Call, Storage, Event, Config}, ImOnline: pallet_im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, Offences: pallet_offences::{Module, Call, Storage, Event}, + Historical: pallet_session_historical::{Module}, } ); diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 48f32af7b474c..9b4d2704cf456 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -31,8 +31,10 @@ use codec::{Encode, Decode}; use sp_runtime::KeyTypeId; use sp_runtime::traits::{Convert, OpaqueKeys}; use sp_session::{MembershipProof, ValidatorCount}; -use frame_support::{decl_module, decl_storage}; -use frame_support::{Parameter, print}; +use frame_support::{ + decl_module, decl_storage, Parameter, print, + traits::{ValidatorSet, ValidatorSetWithIdentification}, +}; use sp_trie::{MemoryDB, Trie, TrieMut, Recorder, EMPTY_PREFIX}; use sp_trie::trie_types::{TrieDBMut, TrieDB}; use super::{SessionIndex, Module as SessionModule}; @@ -102,6 +104,24 @@ impl Module { } } +impl ValidatorSet for Module { + type ValidatorId = T::ValidatorId; + type ValidatorIdOf = T::ValidatorIdOf; + + fn session_index() -> sp_staking::SessionIndex { + super::Module::::current_index() + } + + fn validators() -> Vec { + super::Module::::validators() + } +} + +impl ValidatorSetWithIdentification for Module { + type Identification = T::FullIdentification; + type IdentificationOf = T::FullIdentificationOf; +} + /// Specialization of the crate-level `SessionManager` which returns the set of full identification /// when creating a new session. pub trait SessionManager: crate::SessionManager { diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 74105ade15f17..0793d5e74b988 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -116,13 +116,14 @@ pub mod weights; use sp_std::{prelude::*, marker::PhantomData, ops::{Sub, Rem}}; use codec::Decode; -use sp_runtime::{KeyTypeId, Perbill, RuntimeAppPublic, BoundToRuntimeAppPublic}; +use sp_runtime::{KeyTypeId, Perbill, RuntimeAppPublic}; use sp_runtime::traits::{Convert, Zero, Member, OpaqueKeys, Saturating}; use sp_staking::SessionIndex; use frame_support::{ ensure, decl_module, decl_event, decl_storage, decl_error, ConsensusEngineId, Parameter, traits::{ Get, FindAuthor, ValidatorRegistration, EstimateNextSessionRotation, EstimateNextNewSession, + OneSessionHandler, ValidatorSet, }, dispatch::{self, DispatchResult, DispatchError}, weights::Weight, @@ -256,40 +257,6 @@ pub trait SessionHandler { fn on_disabled(validator_index: usize); } -/// A session handler for specific key type. -pub trait OneSessionHandler: BoundToRuntimeAppPublic { - /// The key type expected. - type Key: Decode + Default + RuntimeAppPublic; - - fn on_genesis_session<'a, I: 'a>(validators: I) - where I: Iterator, ValidatorId: 'a; - - /// Session set has changed; act appropriately. Note that this can be called - /// before initialization of your module. - /// - /// `changed` is true when at least one of the session keys - /// or the underlying economic identities/distribution behind one the - /// session keys has changed, false otherwise. - /// - /// The `validators` are the validators of the incoming session, and `queued_validators` - /// will follow. - fn on_new_session<'a, I: 'a>( - changed: bool, - validators: I, - queued_validators: I, - ) where I: Iterator, ValidatorId: 'a; - - - /// A notification for end of the session. - /// - /// Note it is triggered before any `SessionManager::end_session` handlers, - /// so we can still affect the validator set. - fn on_before_session_ending() {} - - /// A validator got disabled. Act accordingly until a new session begins. - fn on_disabled(_validator_index: usize); -} - #[impl_trait_for_tuples::impl_for_tuples(1, 30)] #[tuple_types_no_default_trait_bound] impl SessionHandler for Tuple { @@ -830,6 +797,19 @@ impl Module { } } +impl ValidatorSet for Module { + type ValidatorId = T::ValidatorId; + type ValidatorIdOf = T::ValidatorIdOf; + + fn session_index() -> sp_staking::SessionIndex { + Module::::current_index() + } + + fn validators() -> Vec { + Module::::validators() + } +} + /// Wraps the author-scraping logic for consensus engines that can recover /// the canonical index of an author. This then transforms it into the /// registering account-ID of that session key index. diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 7c1d3c9dcdd24..c876770c74bcc 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -18,6 +18,7 @@ // Tests for the Session Pallet use super::*; +use codec::Decode; use frame_support::{traits::OnInitialize, assert_ok}; use sp_core::crypto::key_types::DUMMY; use sp_runtime::testing::UintAuthorityId; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5c3261414d2bc..0eb77e7c14ac1 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -21,7 +21,7 @@ use crate::*; use crate as staking; use frame_support::{ assert_ok, parameter_types, - traits::{Currency, FindAuthor, Get, OnFinalize, OnInitialize}, + traits::{Currency, FindAuthor, Get, OnFinalize, OnInitialize, OneSessionHandler}, weights::{constants::RocksDbWeight, Weight}, IterableStorageMap, StorageDoubleMap, StorageMap, StorageValue, }; @@ -53,7 +53,7 @@ thread_local! { /// Another session handler struct to test on_disabled. pub struct OtherSessionHandler; -impl pallet_session::OneSessionHandler for OtherSessionHandler { +impl OneSessionHandler for OtherSessionHandler { type Key = UintAuthorityId; fn on_genesis_session<'a, I: 'a>(_: I) diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 3354f17d27c90..294e4c1574a32 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -24,6 +24,7 @@ sp-tracing = { version = "2.0.0", default-features = false, path = "../../primit sp-core = { version = "2.0.0", default-features = false, path = "../../primitives/core" } sp-arithmetic = { version = "2.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "2.0.0", default-features = false, path = "../../primitives/inherents" } +sp-staking = { version = "2.0.0", default-features = false, path = "../../primitives/staking" } frame-support-procedural = { version = "2.0.1", default-features = false, path = "./procedural" } paste = "0.1.6" once_cell = { version = "1", default-features = false, optional = true } @@ -52,6 +53,7 @@ std = [ "sp-arithmetic/std", "frame-metadata/std", "sp-inherents/std", + "sp-staking/std", "sp-state-machine", "frame-support-procedural/std", ] diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 2888abc306b3d..c52aa60c20b15 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -23,13 +23,15 @@ use sp_std::{prelude::*, result, marker::PhantomData, ops::Div, fmt::Debug}; use codec::{FullCodec, Codec, Encode, Decode, EncodeLike}; use sp_core::u32_trait::Value as U32; use sp_runtime::{ - RuntimeDebug, ConsensusEngineId, DispatchResult, DispatchError, + RuntimeAppPublic, RuntimeDebug, BoundToRuntimeAppPublic, + ConsensusEngineId, DispatchResult, DispatchError, traits::{ - MaybeSerializeDeserialize, AtLeast32Bit, Saturating, TrailingZeroInput, Bounded, Zero, - BadOrigin, AtLeast32BitUnsigned, UniqueSaturatedFrom, UniqueSaturatedInto, - SaturatedConversion, StoredMapError, + MaybeSerializeDeserialize, AtLeast32Bit, Saturating, TrailingZeroInput, Bounded, Zero, + BadOrigin, AtLeast32BitUnsigned, Convert, UniqueSaturatedFrom, UniqueSaturatedInto, + SaturatedConversion, StoredMapError, }, }; +use sp_staking::SessionIndex; use crate::dispatch::Parameter; use crate::storage::StorageMap; use crate::weights::Weight; @@ -40,6 +42,67 @@ use impl_trait_for_tuples::impl_for_tuples; #[doc(hidden)] pub use sp_std::{mem::{swap, take}, cell::RefCell, vec::Vec, boxed::Box}; +/// A trait for online node inspection in a session. +/// +/// Something that can give information about the current validator set. +pub trait ValidatorSet { + /// Type for representing validator id in a session. + type ValidatorId: Parameter; + /// A type for converting `AccountId` to `ValidatorId`. + type ValidatorIdOf: Convert>; + + /// Returns current session index. + fn session_index() -> SessionIndex; + + /// Returns the active set of validators. + fn validators() -> Vec; +} + +/// [`ValidatorSet`] combined with an identification. +pub trait ValidatorSetWithIdentification: ValidatorSet { + /// Full identification of `ValidatorId`. + type Identification: Parameter; + /// A type for converting `ValidatorId` to `Identification`. + type IdentificationOf: Convert>; +} + +/// A session handler for specific key type. +pub trait OneSessionHandler: BoundToRuntimeAppPublic { + /// The key type expected. + type Key: Decode + Default + RuntimeAppPublic; + + /// The given validator set will be used for the genesis session. + /// It is guaranteed that the given validator set will also be used + /// for the second session, therefore the first call to `on_new_session` + /// should provide the same validator set. + fn on_genesis_session<'a, I: 'a>(validators: I) + where I: Iterator, ValidatorId: 'a; + + /// Session set has changed; act appropriately. Note that this can be called + /// before initialization of your module. + /// + /// `changed` is true when at least one of the session keys + /// or the underlying economic identities/distribution behind one the + /// session keys has changed, false otherwise. + /// + /// The `validators` are the validators of the incoming session, and `queued_validators` + /// will follow. + fn on_new_session<'a, I: 'a>( + changed: bool, + validators: I, + queued_validators: I, + ) where I: Iterator, ValidatorId: 'a; + + /// A notification for end of the session. + /// + /// Note it is triggered before any `SessionManager::end_session` handlers, + /// so we can still affect the validator set. + fn on_before_session_ending() {} + + /// A validator got disabled. Act accordingly until a new session begins. + fn on_disabled(_validator_index: usize); +} + /// Simple trait for providing a filter over a reference to some type. pub trait Filter { /// Determine if a given value should be allowed through the filter (returns `true`) or not.