1#![cfg_attr(not(feature = "std"), no_std)]
109
110pub mod disabling;
111#[cfg(feature = "historical")]
112pub mod historical;
113pub mod migrations;
114#[cfg(test)]
115mod mock;
116#[cfg(test)]
117mod tests;
118pub mod weights;
119
120extern crate alloc;
121
122use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
123use codec::{Decode, MaxEncodedLen};
124use core::{
125 marker::PhantomData,
126 ops::{Rem, Sub},
127};
128use disabling::DisablingStrategy;
129use frame_support::{
130 dispatch::DispatchResult,
131 ensure,
132 traits::{
133 fungible::{hold::Mutate as HoldMutate, Inspect, Mutate},
134 Defensive, EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get,
135 OneSessionHandler, ValidatorRegistration, ValidatorSet,
136 },
137 weights::Weight,
138 Parameter,
139};
140use frame_system::pallet_prelude::BlockNumberFor;
141use sp_runtime::{
142 traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero},
143 ConsensusEngineId, DispatchError, KeyTypeId, Permill, RuntimeAppPublic,
144};
145use sp_staking::{offence::OffenceSeverity, SessionIndex};
146
147pub use pallet::*;
148pub use weights::WeightInfo;
149
150#[cfg(any(feature = "try-runtime"))]
151use sp_runtime::TryRuntimeError;
152
153pub(crate) const LOG_TARGET: &str = "runtime::session";
154
155#[macro_export]
157macro_rules! log {
158 ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
159 log::$level!(
160 target: crate::LOG_TARGET,
161 concat!("[{:?}] 💸 ", $patter), <frame_system::Pallet<T>>::block_number() $(, $values)*
162 )
163 };
164}
165
166pub trait ShouldEndSession<BlockNumber> {
168 fn should_end_session(now: BlockNumber) -> bool;
170}
171
172pub struct PeriodicSessions<Period, Offset>(PhantomData<(Period, Offset)>);
178
179impl<
180 BlockNumber: Rem<Output = BlockNumber> + Sub<Output = BlockNumber> + Zero + PartialOrd,
181 Period: Get<BlockNumber>,
182 Offset: Get<BlockNumber>,
183 > ShouldEndSession<BlockNumber> for PeriodicSessions<Period, Offset>
184{
185 fn should_end_session(now: BlockNumber) -> bool {
186 let offset = Offset::get();
187 now >= offset && ((now - offset) % Period::get()).is_zero()
188 }
189}
190
191impl<
192 BlockNumber: AtLeast32BitUnsigned + Clone,
193 Period: Get<BlockNumber>,
194 Offset: Get<BlockNumber>,
195 > EstimateNextSessionRotation<BlockNumber> for PeriodicSessions<Period, Offset>
196{
197 fn average_session_length() -> BlockNumber {
198 Period::get()
199 }
200
201 fn estimate_current_session_progress(now: BlockNumber) -> (Option<Permill>, Weight) {
202 let offset = Offset::get();
203 let period = Period::get();
204
205 let progress = if now >= offset {
209 let current = (now - offset) % period.clone() + One::one();
210 Some(Permill::from_rational(current, period))
211 } else {
212 Some(Permill::from_rational(now + One::one(), offset))
213 };
214
215 (progress, Zero::zero())
220 }
221
222 fn estimate_next_session_rotation(now: BlockNumber) -> (Option<BlockNumber>, Weight) {
223 let offset = Offset::get();
224 let period = Period::get();
225
226 let next_session = if now > offset {
227 let block_after_last_session = (now.clone() - offset) % period.clone();
228 if block_after_last_session > Zero::zero() {
229 now.saturating_add(period.saturating_sub(block_after_last_session))
230 } else {
231 now + period
236 }
237 } else {
238 offset
239 };
240
241 (Some(next_session), Zero::zero())
246 }
247}
248
249pub trait SessionManager<ValidatorId> {
251 fn new_session(new_index: SessionIndex) -> Option<Vec<ValidatorId>>;
265 fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<ValidatorId>> {
270 Self::new_session(new_index)
271 }
272 fn end_session(end_index: SessionIndex);
277 fn start_session(start_index: SessionIndex);
281}
282
283impl<A> SessionManager<A> for () {
284 fn new_session(_: SessionIndex) -> Option<Vec<A>> {
285 None
286 }
287 fn start_session(_: SessionIndex) {}
288 fn end_session(_: SessionIndex) {}
289}
290
291pub struct UnionSessionManager<A, B>(PhantomData<(A, B)>);
298
299impl<A, B> UnionSessionManager<A, B> {
300 fn union<ValidatorId: Clone + Ord>(
301 a: Option<Vec<ValidatorId>>,
302 b: Option<Vec<ValidatorId>>,
303 ) -> Option<Vec<ValidatorId>> {
304 match (a, b) {
305 (Some(a), Some(b)) => {
306 let mut seen = BTreeSet::new();
307 Some(a.into_iter().chain(b).filter(|id| seen.insert(id.clone())).collect())
308 },
309 (a, None) => a,
310 (None, b) => b,
311 }
312 }
313}
314
315impl<ValidatorId, A, B> SessionManager<ValidatorId> for UnionSessionManager<A, B>
316where
317 ValidatorId: Clone + Ord,
318 A: SessionManager<ValidatorId>,
319 B: SessionManager<ValidatorId>,
320{
321 fn new_session(new_index: SessionIndex) -> Option<Vec<ValidatorId>> {
322 Self::union(A::new_session(new_index), B::new_session(new_index))
323 }
324
325 fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<ValidatorId>> {
326 Self::union(A::new_session_genesis(new_index), B::new_session_genesis(new_index))
327 }
328
329 fn start_session(start_index: SessionIndex) {
330 A::start_session(start_index);
331 B::start_session(start_index);
332 }
333
334 fn end_session(end_index: SessionIndex) {
335 A::end_session(end_index);
336 B::end_session(end_index);
337 }
338}
339
340pub trait SessionHandler<ValidatorId> {
342 const KEY_TYPE_IDS: &'static [KeyTypeId];
348
349 fn on_genesis_session<Ks: OpaqueKeys>(validators: &[(ValidatorId, Ks)]);
354
355 fn on_new_session<Ks: OpaqueKeys>(
365 changed: bool,
366 validators: &[(ValidatorId, Ks)],
367 queued_validators: &[(ValidatorId, Ks)],
368 );
369
370 fn on_before_session_ending() {}
375
376 fn on_disabled(validator_index: u32);
378}
379
380#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
381#[tuple_types_custom_trait_bound(OneSessionHandler<AId>)]
382impl<AId> SessionHandler<AId> for Tuple {
383 for_tuples!(
384 const KEY_TYPE_IDS: &'static [KeyTypeId] = &[ #( <Tuple::Key as RuntimeAppPublic>::ID ),* ];
385 );
386
387 fn on_genesis_session<Ks: OpaqueKeys>(validators: &[(AId, Ks)]) {
388 for_tuples!(
389 #(
390 let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
391 .filter_map(|k|
392 k.1.get::<Tuple::Key>(<Tuple::Key as RuntimeAppPublic>::ID).map(|k1| (&k.0, k1))
393 )
394 );
395
396 Tuple::on_genesis_session(our_keys);
397 )*
398 )
399 }
400
401 fn on_new_session<Ks: OpaqueKeys>(
402 changed: bool,
403 validators: &[(AId, Ks)],
404 queued_validators: &[(AId, Ks)],
405 ) {
406 for_tuples!(
407 #(
408 let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
409 .filter_map(|k|
410 k.1.get::<Tuple::Key>(<Tuple::Key as RuntimeAppPublic>::ID).map(|k1| (&k.0, k1))
411 ));
412 let queued_keys: Box<dyn Iterator<Item=_>> = Box::new(queued_validators.iter()
413 .filter_map(|k|
414 k.1.get::<Tuple::Key>(<Tuple::Key as RuntimeAppPublic>::ID).map(|k1| (&k.0, k1))
415 ));
416 Tuple::on_new_session(changed, our_keys, queued_keys);
417 )*
418 )
419 }
420
421 fn on_before_session_ending() {
422 for_tuples!( #( Tuple::on_before_session_ending(); )* )
423 }
424
425 fn on_disabled(i: u32) {
426 for_tuples!( #( Tuple::on_disabled(i); )* )
427 }
428}
429
430pub struct TestSessionHandler;
432impl<AId> SessionHandler<AId> for TestSessionHandler {
433 const KEY_TYPE_IDS: &'static [KeyTypeId] = &[sp_runtime::key_types::DUMMY];
434 fn on_genesis_session<Ks: OpaqueKeys>(_: &[(AId, Ks)]) {}
435 fn on_new_session<Ks: OpaqueKeys>(_: bool, _: &[(AId, Ks)], _: &[(AId, Ks)]) {}
436 fn on_before_session_ending() {}
437 fn on_disabled(_: u32) {}
438}
439
440pub trait SessionInterface {
448 type ValidatorId: Clone;
450
451 type AccountId;
453
454 type Keys: OpaqueKeys + codec::Decode;
456
457 fn validators() -> Vec<Self::ValidatorId>;
459
460 fn prune_up_to(index: SessionIndex);
462
463 fn report_offence(offender: Self::ValidatorId, severity: OffenceSeverity);
467
468 fn set_keys(account: &Self::AccountId, keys: Self::Keys) -> DispatchResult;
477
478 fn purge_keys(account: &Self::AccountId) -> DispatchResult;
483
484 fn set_keys_weight() -> Weight;
486
487 fn purge_keys_weight() -> Weight;
489}
490
491#[frame_support::pallet]
492pub mod pallet {
493 use super::*;
494 use frame_support::pallet_prelude::*;
495 use frame_system::pallet_prelude::*;
496
497 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
499
500 #[pallet::pallet]
501 #[pallet::storage_version(STORAGE_VERSION)]
502 #[pallet::without_storage_info]
503 pub struct Pallet<T>(_);
504
505 #[pallet::config]
506 pub trait Config: frame_system::Config {
507 #[allow(deprecated)]
509 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
510
511 type ValidatorId: Member
513 + Parameter
514 + MaybeSerializeDeserialize
515 + MaxEncodedLen
516 + TryFrom<Self::AccountId>;
517
518 type ValidatorIdOf: Convert<Self::AccountId, Option<Self::ValidatorId>>;
526
527 type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
529
530 type NextSessionRotation: EstimateNextSessionRotation<BlockNumberFor<Self>>;
534
535 type SessionManager: SessionManager<Self::ValidatorId>;
537
538 type SessionHandler: SessionHandler<Self::ValidatorId>;
540
541 type Keys: OpaqueKeys + Member + Parameter + MaybeSerializeDeserialize;
543
544 type DisablingStrategy: DisablingStrategy<Self>;
546
547 type WeightInfo: WeightInfo;
549
550 type Currency: Mutate<Self::AccountId>
552 + HoldMutate<Self::AccountId, Reason: From<HoldReason>>;
553
554 #[pallet::constant]
556 type KeyDeposit: Get<
557 <<Self as Config>::Currency as Inspect<<Self as frame_system::Config>::AccountId>>::Balance,
558 >;
559 }
560
561 #[pallet::genesis_config]
562 #[derive(frame_support::DefaultNoBound)]
563 pub struct GenesisConfig<T: Config> {
564 pub keys: Vec<(T::AccountId, T::ValidatorId, T::Keys)>,
568 pub non_authority_keys: Vec<(T::AccountId, T::ValidatorId, T::Keys)>,
572 }
573
574 #[pallet::genesis_build]
575 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
576 fn build(&self) {
577 if T::SessionHandler::KEY_TYPE_IDS.len() != T::Keys::key_ids().len() {
578 panic!("Number of keys in session handler and session keys does not match");
579 }
580
581 T::SessionHandler::KEY_TYPE_IDS
582 .iter()
583 .zip(T::Keys::key_ids())
584 .enumerate()
585 .for_each(|(i, (sk, kk))| {
586 if sk != kk {
587 panic!(
588 "Session handler and session key expect different key type at index: {}",
589 i,
590 );
591 }
592 });
593
594 for (account, val, keys) in
595 self.keys.iter().chain(self.non_authority_keys.iter()).cloned()
596 {
597 Pallet::<T>::inner_set_keys(&val, keys)
598 .expect("genesis config must not contain duplicates; qed");
599 if frame_system::Pallet::<T>::inc_consumers_without_limit(&account).is_err() {
600 frame_system::Pallet::<T>::inc_providers(&account);
605 }
606 }
607
608 let initial_validators_0 =
609 T::SessionManager::new_session_genesis(0).unwrap_or_else(|| {
610 log!(
611 warn,
612 "No initial validator provided by `SessionManager`, use \
613 session config keys to generate initial validator set.",
614 );
615 self.keys.iter().map(|x| x.1.clone()).collect()
616 });
617
618 let initial_validators_1 = T::SessionManager::new_session_genesis(1)
619 .unwrap_or_else(|| initial_validators_0.clone());
620
621 let queued_keys: Vec<_> = initial_validators_1
622 .into_iter()
623 .filter_map(|v| Pallet::<T>::load_keys(&v).map(|k| (v, k)))
624 .collect();
625
626 T::SessionHandler::on_genesis_session::<T::Keys>(&queued_keys);
628
629 Validators::<T>::put(initial_validators_0);
630 QueuedKeys::<T>::put(queued_keys);
631
632 T::SessionManager::start_session(0);
633 }
634 }
635
636 #[pallet::composite_enum]
638 pub enum HoldReason {
639 #[codec(index = 0)]
641 Keys,
642 }
643
644 #[pallet::storage]
646 pub type Validators<T: Config> = StorageValue<_, Vec<T::ValidatorId>, ValueQuery>;
647
648 #[pallet::storage]
650 pub type CurrentIndex<T> = StorageValue<_, SessionIndex, ValueQuery>;
651
652 #[pallet::storage]
655 pub type QueuedChanged<T> = StorageValue<_, bool, ValueQuery>;
656
657 #[pallet::storage]
660 pub type QueuedKeys<T: Config> = StorageValue<_, Vec<(T::ValidatorId, T::Keys)>, ValueQuery>;
661
662 #[pallet::storage]
668 pub type DisabledValidators<T> = StorageValue<_, Vec<(u32, OffenceSeverity)>, ValueQuery>;
669
670 #[pallet::storage]
672 pub type NextKeys<T: Config> =
673 StorageMap<_, Twox64Concat, T::ValidatorId, T::Keys, OptionQuery>;
674
675 #[pallet::storage]
677 pub type KeyOwner<T: Config> =
678 StorageMap<_, Twox64Concat, (KeyTypeId, Vec<u8>), T::ValidatorId, OptionQuery>;
679
680 #[pallet::storage]
685 pub type ExternallySetKeys<T: Config> =
686 StorageMap<_, Twox64Concat, T::AccountId, (), OptionQuery>;
687
688 #[pallet::event]
689 #[pallet::generate_deposit(pub(super) fn deposit_event)]
690 pub enum Event<T: Config> {
691 NewSession { session_index: SessionIndex },
694 NewQueued,
697 ValidatorDisabled { validator: T::ValidatorId },
699 ValidatorReenabled { validator: T::ValidatorId },
701 }
702
703 #[pallet::error]
705 pub enum Error<T> {
706 InvalidProof,
708 NoAssociatedValidatorId,
710 DuplicatedKey,
712 NoKeys,
714 NoAccount,
716 }
717
718 #[pallet::hooks]
719 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
720 fn on_initialize(n: BlockNumberFor<T>) -> Weight {
723 if T::ShouldEndSession::should_end_session(n) {
724 Self::rotate_session();
725 T::BlockWeights::get().max_block
726 } else {
727 Weight::zero()
731 }
732 }
733
734 #[cfg(feature = "try-runtime")]
735 fn try_state(_n: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
736 Self::do_try_state()
737 }
738 }
739
740 #[pallet::call]
741 impl<T: Config> Pallet<T> {
742 #[pallet::call_index(0)]
754 #[pallet::weight(T::WeightInfo::set_keys())]
755 pub fn set_keys(origin: OriginFor<T>, keys: T::Keys, proof: Vec<u8>) -> DispatchResult {
756 let who = ensure_signed(origin)?;
757 ensure!(
758 who.using_encoded(|who| keys.ownership_proof_is_valid(who, &proof)),
759 Error::<T>::InvalidProof,
760 );
761
762 Self::do_set_keys(&who, keys)?;
763 Ok(())
764 }
765
766 #[pallet::call_index(1)]
775 #[pallet::weight(T::WeightInfo::purge_keys())]
776 pub fn purge_keys(origin: OriginFor<T>) -> DispatchResult {
777 let account = ensure_signed(origin)?;
778 let who = T::ValidatorIdOf::convert(account.clone())
779 .or_else(|| T::ValidatorId::try_from(account.clone()).ok())
783 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
784 Self::do_purge_keys(&account, &who)
785 }
786 }
787
788 #[cfg(feature = "runtime-benchmarks")]
789 impl<T: Config> Pallet<T> {
790 pub fn ensure_can_pay_key_deposit(who: &T::AccountId) -> Result<(), DispatchError> {
795 let amount = T::KeyDeposit::get().max(T::Currency::minimum_balance());
796 T::Currency::mint_into(who, amount).map(|_inc| ())
797 }
798 }
799}
800
801impl<T: Config> Pallet<T> {
802 pub fn validators() -> Vec<T::ValidatorId> {
804 Validators::<T>::get()
805 }
806
807 pub fn current_index() -> SessionIndex {
809 CurrentIndex::<T>::get()
810 }
811
812 pub fn queued_keys() -> Vec<(T::ValidatorId, T::Keys)> {
814 QueuedKeys::<T>::get()
815 }
816
817 pub fn disabled_validators() -> Vec<u32> {
819 DisabledValidators::<T>::get().iter().map(|(i, _)| *i).collect()
820 }
821
822 pub fn rotate_session() {
826 let session_index = CurrentIndex::<T>::get();
827 let changed = QueuedChanged::<T>::get();
828
829 T::SessionHandler::on_before_session_ending();
831 T::SessionManager::end_session(session_index);
832 log!(trace, "ending_session {:?}", session_index);
833
834 let session_keys = QueuedKeys::<T>::get();
836 let validators =
837 session_keys.iter().map(|(validator, _)| validator.clone()).collect::<Vec<_>>();
838 Validators::<T>::put(&validators);
839
840 if changed {
841 log!(trace, "resetting disabled validators");
842 DisabledValidators::<T>::kill();
844 }
845
846 let session_index = session_index + 1;
848 CurrentIndex::<T>::put(session_index);
849 T::SessionManager::start_session(session_index);
850 log!(trace, "starting_session {:?}", session_index);
851
852 let maybe_next_validators = T::SessionManager::new_session(session_index + 1);
854 log!(
855 trace,
856 "planning_session {:?} with {:?} validators",
857 session_index + 1,
858 maybe_next_validators.as_ref().map(|v| v.len())
859 );
860 let (next_validators, next_identities_changed) =
861 if let Some(validators) = maybe_next_validators {
862 Self::deposit_event(Event::<T>::NewQueued);
866 (validators, true)
867 } else {
868 (Validators::<T>::get(), false)
869 };
870
871 let (queued_amalgamated, next_changed) = {
873 let mut changed = next_identities_changed;
876
877 let mut now_session_keys = session_keys.iter();
878 let mut check_next_changed = |keys: &T::Keys| {
879 if changed {
880 return;
881 }
882 if let Some((_, old_keys)) = now_session_keys.next() {
886 if old_keys != keys {
887 changed = true;
888 }
889 }
890 };
891 let queued_amalgamated =
892 next_validators
893 .into_iter()
894 .filter_map(|a| {
895 let k =
896 Self::load_keys(&a).or_else(|| {
897 log!(warn, "failed to load session key for {:?}, skipping for next session, maybe you need to set session keys for them?", a);
898 None
899 })?;
900 check_next_changed(&k);
901 Some((a, k))
902 })
903 .collect::<Vec<_>>();
904
905 (queued_amalgamated, changed)
906 };
907
908 QueuedKeys::<T>::put(queued_amalgamated.clone());
909 QueuedChanged::<T>::put(next_changed);
910
911 Self::deposit_event(Event::NewSession { session_index });
913
914 T::SessionHandler::on_new_session::<T::Keys>(changed, &session_keys, &queued_amalgamated);
916 }
917
918 pub fn upgrade_keys<Old, F>(upgrade: F)
934 where
935 Old: OpaqueKeys + Member + Decode,
936 F: Fn(T::ValidatorId, Old) -> T::Keys,
937 {
938 let old_ids = Old::key_ids();
939 let new_ids = T::Keys::key_ids();
940
941 NextKeys::<T>::translate::<Old, _>(|val, old_keys| {
943 for i in old_ids.iter() {
946 Self::clear_key_owner(*i, old_keys.get_raw(*i));
947 }
948
949 let new_keys = upgrade(val.clone(), old_keys);
950
951 for i in new_ids.iter() {
953 Self::put_key_owner(*i, new_keys.get_raw(*i), &val);
954 }
955
956 Some(new_keys)
957 });
958
959 let _ = QueuedKeys::<T>::translate::<Vec<(T::ValidatorId, Old)>, _>(|k| {
960 k.map(|k| {
961 k.into_iter()
962 .map(|(val, old_keys)| (val.clone(), upgrade(val, old_keys)))
963 .collect::<Vec<_>>()
964 })
965 });
966 }
967
968 fn do_set_keys(account: &T::AccountId, keys: T::Keys) -> DispatchResult {
973 let who = T::ValidatorIdOf::convert(account.clone())
974 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
975
976 let needs_new_consumer =
980 !NextKeys::<T>::contains_key(&who) || ExternallySetKeys::<T>::contains_key(account);
981 if needs_new_consumer {
982 ensure!(frame_system::Pallet::<T>::can_inc_consumer(account), Error::<T>::NoAccount);
983 }
984
985 let old_keys = Self::inner_set_keys(&who, keys)?;
986
987 let needs_local_setup =
991 old_keys.is_none() || ExternallySetKeys::<T>::take(account).is_some();
992 if needs_local_setup {
993 let deposit = T::KeyDeposit::get();
994 if !deposit.is_zero() {
995 T::Currency::hold(&HoldReason::Keys.into(), account, deposit)?;
996 }
997
998 let assertion = frame_system::Pallet::<T>::inc_consumers(account).is_ok();
999 debug_assert!(assertion, "can_inc_consumer() returned true; no change since; qed");
1000 }
1001
1002 Ok(())
1003 }
1004
1005 fn inner_set_keys(
1012 who: &T::ValidatorId,
1013 keys: T::Keys,
1014 ) -> Result<Option<T::Keys>, DispatchError> {
1015 let old_keys = Self::load_keys(who);
1016
1017 for id in T::Keys::key_ids() {
1018 let key = keys.get_raw(*id);
1019
1020 ensure!(
1022 Self::key_owner(*id, key).map_or(true, |owner| &owner == who),
1023 Error::<T>::DuplicatedKey,
1024 );
1025 }
1026
1027 for id in T::Keys::key_ids() {
1028 let key = keys.get_raw(*id);
1029
1030 if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(*id)) {
1031 if key == old {
1032 continue;
1033 }
1034
1035 Self::clear_key_owner(*id, old);
1036 }
1037
1038 Self::put_key_owner(*id, key, who);
1039 }
1040
1041 Self::put_keys(who, &keys);
1042 Ok(old_keys)
1043 }
1044
1045 fn do_purge_keys(account: &T::AccountId, who: &T::ValidatorId) -> DispatchResult {
1046 let old_keys = Self::take_keys(who).ok_or(Error::<T>::NoKeys)?;
1047 for id in T::Keys::key_ids() {
1048 let key_data = old_keys.get_raw(*id);
1049 Self::clear_key_owner(*id, key_data);
1050 }
1051
1052 let _ = T::Currency::release_all(
1054 &HoldReason::Keys.into(),
1055 account,
1056 frame_support::traits::tokens::Precision::BestEffort,
1057 );
1058
1059 if ExternallySetKeys::<T>::take(account).is_none() {
1060 frame_system::Pallet::<T>::dec_consumers(account);
1062 }
1063
1064 Ok(())
1065 }
1066
1067 pub fn load_keys(v: &T::ValidatorId) -> Option<T::Keys> {
1068 NextKeys::<T>::get(v)
1069 }
1070
1071 fn take_keys(v: &T::ValidatorId) -> Option<T::Keys> {
1072 NextKeys::<T>::take(v)
1073 }
1074
1075 fn put_keys(v: &T::ValidatorId, keys: &T::Keys) {
1076 NextKeys::<T>::insert(v, keys);
1077 }
1078
1079 pub fn key_owner(id: KeyTypeId, key_data: &[u8]) -> Option<T::ValidatorId> {
1081 KeyOwner::<T>::get((id, key_data))
1082 }
1083
1084 fn put_key_owner(id: KeyTypeId, key_data: &[u8], v: &T::ValidatorId) {
1085 KeyOwner::<T>::insert((id, key_data), v)
1086 }
1087
1088 fn clear_key_owner(id: KeyTypeId, key_data: &[u8]) {
1089 KeyOwner::<T>::remove((id, key_data));
1090 }
1091
1092 pub fn disable_index_with_severity(i: u32, severity: OffenceSeverity) -> bool {
1098 if i >= Validators::<T>::decode_len().defensive_unwrap_or(0) as u32 {
1099 return false;
1100 }
1101
1102 DisabledValidators::<T>::mutate(|disabled| {
1103 match disabled.binary_search_by_key(&i, |(index, _)| *index) {
1104 Ok(index) => {
1106 let current_severity = &mut disabled[index].1;
1107 if severity > *current_severity {
1108 log!(
1109 trace,
1110 "updating disablement severity of validator {:?} from {:?} to {:?}",
1111 i,
1112 *current_severity,
1113 severity
1114 );
1115 *current_severity = severity;
1116 }
1117 true
1118 },
1119 Err(index) => {
1121 log!(trace, "disabling validator {:?}", i);
1122 Self::deposit_event(Event::ValidatorDisabled {
1123 validator: Validators::<T>::get()[i as usize].clone(),
1124 });
1125 disabled.insert(index, (i, severity));
1126 T::SessionHandler::on_disabled(i);
1127 true
1128 },
1129 }
1130 })
1131 }
1132
1133 pub fn disable_index(i: u32) -> bool {
1136 let default_severity = OffenceSeverity::default();
1137 Self::disable_index_with_severity(i, default_severity)
1138 }
1139
1140 pub fn reenable_index(i: u32) -> bool {
1142 if i >= Validators::<T>::decode_len().defensive_unwrap_or(0) as u32 {
1143 return false;
1144 }
1145
1146 DisabledValidators::<T>::mutate(|disabled| {
1147 if let Ok(index) = disabled.binary_search_by_key(&i, |(index, _)| *index) {
1148 log!(trace, "reenabling validator {:?}", i);
1149 Self::deposit_event(Event::ValidatorReenabled {
1150 validator: Validators::<T>::get()[i as usize].clone(),
1151 });
1152 disabled.remove(index);
1153 return true;
1154 }
1155 false
1156 })
1157 }
1158
1159 pub fn validator_id_to_index(id: &T::ValidatorId) -> Option<u32> {
1162 Validators::<T>::get().iter().position(|i| i == id).map(|i| i as u32)
1163 }
1164
1165 pub fn report_offence(validator: T::ValidatorId, severity: OffenceSeverity) {
1168 let decision =
1169 T::DisablingStrategy::decision(&validator, severity, &DisabledValidators::<T>::get());
1170 log!(
1171 debug,
1172 "reporting offence for {:?} with {:?}, decision: {:?}",
1173 validator,
1174 severity,
1175 decision
1176 );
1177
1178 if let Some(offender_idx) = decision.disable {
1180 Self::disable_index_with_severity(offender_idx, severity);
1181 }
1182
1183 if let Some(reenable_idx) = decision.reenable {
1185 Self::reenable_index(reenable_idx);
1186 }
1187 }
1188
1189 #[cfg(any(test, feature = "try-runtime"))]
1190 pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
1191 ensure!(
1193 DisabledValidators::<T>::get().windows(2).all(|pair| pair[0].0 <= pair[1].0),
1194 "DisabledValidators is not sorted"
1195 );
1196 Ok(())
1197 }
1198}
1199
1200impl<T: Config> ValidatorRegistration<T::ValidatorId> for Pallet<T> {
1201 fn is_registered(id: &T::ValidatorId) -> bool {
1202 Self::load_keys(id).is_some()
1203 }
1204}
1205
1206impl<T: Config> ValidatorSet<T::AccountId> for Pallet<T> {
1207 type ValidatorId = T::ValidatorId;
1208 type ValidatorIdOf = T::ValidatorIdOf;
1209
1210 fn session_index() -> sp_staking::SessionIndex {
1211 CurrentIndex::<T>::get()
1212 }
1213
1214 fn validators() -> Vec<Self::ValidatorId> {
1215 Validators::<T>::get()
1216 }
1217}
1218
1219impl<T: Config> EstimateNextNewSession<BlockNumberFor<T>> for Pallet<T> {
1220 fn average_session_length() -> BlockNumberFor<T> {
1221 T::NextSessionRotation::average_session_length()
1222 }
1223
1224 fn estimate_next_new_session(now: BlockNumberFor<T>) -> (Option<BlockNumberFor<T>>, Weight) {
1227 T::NextSessionRotation::estimate_next_session_rotation(now)
1228 }
1229}
1230
1231impl<T: Config> frame_support::traits::DisabledValidators for Pallet<T> {
1232 fn is_disabled(index: u32) -> bool {
1233 DisabledValidators::<T>::get().binary_search_by_key(&index, |(i, _)| *i).is_ok()
1234 }
1235
1236 fn disabled_validators() -> Vec<u32> {
1237 Self::disabled_validators()
1238 }
1239}
1240
1241#[cfg(feature = "historical")]
1242impl<T: Config + historical::Config> SessionInterface for Pallet<T> {
1243 type ValidatorId = T::ValidatorId;
1244 type AccountId = T::AccountId;
1245 type Keys = T::Keys;
1246
1247 fn validators() -> Vec<Self::ValidatorId> {
1248 Self::validators()
1249 }
1250
1251 fn prune_up_to(index: SessionIndex) {
1252 historical::Pallet::<T>::prune_up_to(index)
1253 }
1254
1255 fn report_offence(offender: Self::ValidatorId, severity: OffenceSeverity) {
1256 Self::report_offence(offender, severity)
1257 }
1258
1259 fn set_keys(account: &Self::AccountId, keys: Self::Keys) -> DispatchResult {
1260 let who = T::ValidatorIdOf::convert(account.clone())
1261 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
1262 let old_keys = Self::inner_set_keys(&who, keys)?;
1263 if old_keys.is_some() && !ExternallySetKeys::<T>::contains_key(account) {
1265 let _ = T::Currency::release_all(
1266 &HoldReason::Keys.into(),
1267 account,
1268 frame_support::traits::tokens::Precision::BestEffort,
1269 );
1270 frame_system::Pallet::<T>::dec_consumers(account);
1271 }
1272 ExternallySetKeys::<T>::insert(account, ());
1273 Ok(())
1274 }
1275
1276 fn purge_keys(account: &Self::AccountId) -> DispatchResult {
1277 let who = T::ValidatorIdOf::convert(account.clone())
1278 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
1279
1280 Self::do_purge_keys(account, &who)
1281 }
1282
1283 fn set_keys_weight() -> Weight {
1284 T::WeightInfo::set_keys()
1285 }
1286
1287 fn purge_keys_weight() -> Weight {
1288 T::WeightInfo::purge_keys()
1289 }
1290}
1291
1292pub struct FindAccountFromAuthorIndex<T, Inner>(core::marker::PhantomData<(T, Inner)>);
1296
1297impl<T: Config, Inner: FindAuthor<u32>> FindAuthor<T::ValidatorId>
1298 for FindAccountFromAuthorIndex<T, Inner>
1299{
1300 fn find_author<'a, I>(digests: I) -> Option<T::ValidatorId>
1301 where
1302 I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
1303 {
1304 let i = Inner::find_author(digests)?;
1305
1306 let validators = Validators::<T>::get();
1307 validators.get(i as usize).cloned()
1308 }
1309}