1#![cfg_attr(not(feature = "std"), no_std)]
108
109pub mod disabling;
110#[cfg(feature = "historical")]
111pub mod historical;
112pub mod migrations;
113#[cfg(test)]
114mod mock;
115#[cfg(test)]
116mod tests;
117pub mod weights;
118
119extern crate alloc;
120
121use alloc::{boxed::Box, vec::Vec};
122use codec::{Decode, MaxEncodedLen};
123use core::{
124 marker::PhantomData,
125 ops::{Rem, Sub},
126};
127use disabling::DisablingStrategy;
128use frame_support::{
129 dispatch::DispatchResult,
130 ensure,
131 traits::{
132 fungible::{hold::Mutate as HoldMutate, Inspect, Mutate},
133 Defensive, EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get,
134 OneSessionHandler, ValidatorRegistration, ValidatorSet,
135 },
136 weights::Weight,
137 Parameter,
138};
139use frame_system::pallet_prelude::BlockNumberFor;
140use sp_runtime::{
141 traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero},
142 ConsensusEngineId, DispatchError, KeyTypeId, Permill, RuntimeAppPublic,
143};
144use sp_staking::{offence::OffenceSeverity, SessionIndex};
145
146pub use pallet::*;
147pub use weights::WeightInfo;
148
149#[cfg(any(feature = "try-runtime"))]
150use sp_runtime::TryRuntimeError;
151
152pub(crate) const LOG_TARGET: &str = "runtime::session";
153
154#[macro_export]
156macro_rules! log {
157 ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
158 log::$level!(
159 target: crate::LOG_TARGET,
160 concat!("[{:?}] 💸 ", $patter), <frame_system::Pallet<T>>::block_number() $(, $values)*
161 )
162 };
163}
164
165pub trait ShouldEndSession<BlockNumber> {
167 fn should_end_session(now: BlockNumber) -> bool;
169}
170
171pub struct PeriodicSessions<Period, Offset>(PhantomData<(Period, Offset)>);
177
178impl<
179 BlockNumber: Rem<Output = BlockNumber> + Sub<Output = BlockNumber> + Zero + PartialOrd,
180 Period: Get<BlockNumber>,
181 Offset: Get<BlockNumber>,
182 > ShouldEndSession<BlockNumber> for PeriodicSessions<Period, Offset>
183{
184 fn should_end_session(now: BlockNumber) -> bool {
185 let offset = Offset::get();
186 now >= offset && ((now - offset) % Period::get()).is_zero()
187 }
188}
189
190impl<
191 BlockNumber: AtLeast32BitUnsigned + Clone,
192 Period: Get<BlockNumber>,
193 Offset: Get<BlockNumber>,
194 > EstimateNextSessionRotation<BlockNumber> for PeriodicSessions<Period, Offset>
195{
196 fn average_session_length() -> BlockNumber {
197 Period::get()
198 }
199
200 fn estimate_current_session_progress(now: BlockNumber) -> (Option<Permill>, Weight) {
201 let offset = Offset::get();
202 let period = Period::get();
203
204 let progress = if now >= offset {
208 let current = (now - offset) % period.clone() + One::one();
209 Some(Permill::from_rational(current, period))
210 } else {
211 Some(Permill::from_rational(now + One::one(), offset))
212 };
213
214 (progress, Zero::zero())
219 }
220
221 fn estimate_next_session_rotation(now: BlockNumber) -> (Option<BlockNumber>, Weight) {
222 let offset = Offset::get();
223 let period = Period::get();
224
225 let next_session = if now > offset {
226 let block_after_last_session = (now.clone() - offset) % period.clone();
227 if block_after_last_session > Zero::zero() {
228 now.saturating_add(period.saturating_sub(block_after_last_session))
229 } else {
230 now + period
235 }
236 } else {
237 offset
238 };
239
240 (Some(next_session), Zero::zero())
245 }
246}
247
248pub trait SessionManager<ValidatorId> {
250 fn new_session(new_index: SessionIndex) -> Option<Vec<ValidatorId>>;
264 fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<ValidatorId>> {
269 Self::new_session(new_index)
270 }
271 fn end_session(end_index: SessionIndex);
276 fn start_session(start_index: SessionIndex);
280}
281
282impl<A> SessionManager<A> for () {
283 fn new_session(_: SessionIndex) -> Option<Vec<A>> {
284 None
285 }
286 fn start_session(_: SessionIndex) {}
287 fn end_session(_: SessionIndex) {}
288}
289
290pub trait SessionHandler<ValidatorId> {
292 const KEY_TYPE_IDS: &'static [KeyTypeId];
298
299 fn on_genesis_session<Ks: OpaqueKeys>(validators: &[(ValidatorId, Ks)]);
304
305 fn on_new_session<Ks: OpaqueKeys>(
315 changed: bool,
316 validators: &[(ValidatorId, Ks)],
317 queued_validators: &[(ValidatorId, Ks)],
318 );
319
320 fn on_before_session_ending() {}
325
326 fn on_disabled(validator_index: u32);
328}
329
330#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
331#[tuple_types_custom_trait_bound(OneSessionHandler<AId>)]
332impl<AId> SessionHandler<AId> for Tuple {
333 for_tuples!(
334 const KEY_TYPE_IDS: &'static [KeyTypeId] = &[ #( <Tuple::Key as RuntimeAppPublic>::ID ),* ];
335 );
336
337 fn on_genesis_session<Ks: OpaqueKeys>(validators: &[(AId, Ks)]) {
338 for_tuples!(
339 #(
340 let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
341 .filter_map(|k|
342 k.1.get::<Tuple::Key>(<Tuple::Key as RuntimeAppPublic>::ID).map(|k1| (&k.0, k1))
343 )
344 );
345
346 Tuple::on_genesis_session(our_keys);
347 )*
348 )
349 }
350
351 fn on_new_session<Ks: OpaqueKeys>(
352 changed: bool,
353 validators: &[(AId, Ks)],
354 queued_validators: &[(AId, Ks)],
355 ) {
356 for_tuples!(
357 #(
358 let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
359 .filter_map(|k|
360 k.1.get::<Tuple::Key>(<Tuple::Key as RuntimeAppPublic>::ID).map(|k1| (&k.0, k1))
361 ));
362 let queued_keys: Box<dyn Iterator<Item=_>> = Box::new(queued_validators.iter()
363 .filter_map(|k|
364 k.1.get::<Tuple::Key>(<Tuple::Key as RuntimeAppPublic>::ID).map(|k1| (&k.0, k1))
365 ));
366 Tuple::on_new_session(changed, our_keys, queued_keys);
367 )*
368 )
369 }
370
371 fn on_before_session_ending() {
372 for_tuples!( #( Tuple::on_before_session_ending(); )* )
373 }
374
375 fn on_disabled(i: u32) {
376 for_tuples!( #( Tuple::on_disabled(i); )* )
377 }
378}
379
380pub struct TestSessionHandler;
382impl<AId> SessionHandler<AId> for TestSessionHandler {
383 const KEY_TYPE_IDS: &'static [KeyTypeId] = &[sp_runtime::key_types::DUMMY];
384 fn on_genesis_session<Ks: OpaqueKeys>(_: &[(AId, Ks)]) {}
385 fn on_new_session<Ks: OpaqueKeys>(_: bool, _: &[(AId, Ks)], _: &[(AId, Ks)]) {}
386 fn on_before_session_ending() {}
387 fn on_disabled(_: u32) {}
388}
389
390pub trait SessionInterface {
398 type ValidatorId: Clone;
400
401 type AccountId;
403
404 type Keys: OpaqueKeys + codec::Decode;
406
407 fn validators() -> Vec<Self::ValidatorId>;
409
410 fn prune_up_to(index: SessionIndex);
412
413 fn report_offence(offender: Self::ValidatorId, severity: OffenceSeverity);
417
418 fn set_keys(account: &Self::AccountId, keys: Self::Keys) -> DispatchResult;
427
428 fn purge_keys(account: &Self::AccountId) -> DispatchResult;
433
434 fn set_keys_weight() -> Weight;
436
437 fn purge_keys_weight() -> Weight;
439}
440
441#[frame_support::pallet]
442pub mod pallet {
443 use super::*;
444 use frame_support::pallet_prelude::*;
445 use frame_system::pallet_prelude::*;
446
447 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
449
450 #[pallet::pallet]
451 #[pallet::storage_version(STORAGE_VERSION)]
452 #[pallet::without_storage_info]
453 pub struct Pallet<T>(_);
454
455 #[pallet::config]
456 pub trait Config: frame_system::Config {
457 #[allow(deprecated)]
459 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
460
461 type ValidatorId: Member
463 + Parameter
464 + MaybeSerializeDeserialize
465 + MaxEncodedLen
466 + TryFrom<Self::AccountId>;
467
468 type ValidatorIdOf: Convert<Self::AccountId, Option<Self::ValidatorId>>;
476
477 type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
479
480 type NextSessionRotation: EstimateNextSessionRotation<BlockNumberFor<Self>>;
484
485 type SessionManager: SessionManager<Self::ValidatorId>;
487
488 type SessionHandler: SessionHandler<Self::ValidatorId>;
490
491 type Keys: OpaqueKeys + Member + Parameter + MaybeSerializeDeserialize;
493
494 type DisablingStrategy: DisablingStrategy<Self>;
496
497 type WeightInfo: WeightInfo;
499
500 type Currency: Mutate<Self::AccountId>
502 + HoldMutate<Self::AccountId, Reason: From<HoldReason>>;
503
504 #[pallet::constant]
506 type KeyDeposit: Get<
507 <<Self as Config>::Currency as Inspect<<Self as frame_system::Config>::AccountId>>::Balance,
508 >;
509 }
510
511 #[pallet::genesis_config]
512 #[derive(frame_support::DefaultNoBound)]
513 pub struct GenesisConfig<T: Config> {
514 pub keys: Vec<(T::AccountId, T::ValidatorId, T::Keys)>,
518 pub non_authority_keys: Vec<(T::AccountId, T::ValidatorId, T::Keys)>,
522 }
523
524 #[pallet::genesis_build]
525 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
526 fn build(&self) {
527 if T::SessionHandler::KEY_TYPE_IDS.len() != T::Keys::key_ids().len() {
528 panic!("Number of keys in session handler and session keys does not match");
529 }
530
531 T::SessionHandler::KEY_TYPE_IDS
532 .iter()
533 .zip(T::Keys::key_ids())
534 .enumerate()
535 .for_each(|(i, (sk, kk))| {
536 if sk != kk {
537 panic!(
538 "Session handler and session key expect different key type at index: {}",
539 i,
540 );
541 }
542 });
543
544 for (account, val, keys) in
545 self.keys.iter().chain(self.non_authority_keys.iter()).cloned()
546 {
547 Pallet::<T>::inner_set_keys(&val, keys)
548 .expect("genesis config must not contain duplicates; qed");
549 if frame_system::Pallet::<T>::inc_consumers_without_limit(&account).is_err() {
550 frame_system::Pallet::<T>::inc_providers(&account);
555 }
556 }
557
558 let initial_validators_0 =
559 T::SessionManager::new_session_genesis(0).unwrap_or_else(|| {
560 frame_support::print(
561 "No initial validator provided by `SessionManager`, use \
562 session config keys to generate initial validator set.",
563 );
564 self.keys.iter().map(|x| x.1.clone()).collect()
565 });
566
567 let initial_validators_1 = T::SessionManager::new_session_genesis(1)
568 .unwrap_or_else(|| initial_validators_0.clone());
569
570 let queued_keys: Vec<_> = initial_validators_1
571 .into_iter()
572 .filter_map(|v| Pallet::<T>::load_keys(&v).map(|k| (v, k)))
573 .collect();
574
575 T::SessionHandler::on_genesis_session::<T::Keys>(&queued_keys);
577
578 Validators::<T>::put(initial_validators_0);
579 QueuedKeys::<T>::put(queued_keys);
580
581 T::SessionManager::start_session(0);
582 }
583 }
584
585 #[pallet::composite_enum]
587 pub enum HoldReason {
588 #[codec(index = 0)]
590 Keys,
591 }
592
593 #[pallet::storage]
595 pub type Validators<T: Config> = StorageValue<_, Vec<T::ValidatorId>, ValueQuery>;
596
597 #[pallet::storage]
599 pub type CurrentIndex<T> = StorageValue<_, SessionIndex, ValueQuery>;
600
601 #[pallet::storage]
604 pub type QueuedChanged<T> = StorageValue<_, bool, ValueQuery>;
605
606 #[pallet::storage]
609 pub type QueuedKeys<T: Config> = StorageValue<_, Vec<(T::ValidatorId, T::Keys)>, ValueQuery>;
610
611 #[pallet::storage]
617 pub type DisabledValidators<T> = StorageValue<_, Vec<(u32, OffenceSeverity)>, ValueQuery>;
618
619 #[pallet::storage]
621 pub type NextKeys<T: Config> =
622 StorageMap<_, Twox64Concat, T::ValidatorId, T::Keys, OptionQuery>;
623
624 #[pallet::storage]
626 pub type KeyOwner<T: Config> =
627 StorageMap<_, Twox64Concat, (KeyTypeId, Vec<u8>), T::ValidatorId, OptionQuery>;
628
629 #[pallet::storage]
634 pub type ExternallySetKeys<T: Config> =
635 StorageMap<_, Twox64Concat, T::AccountId, (), OptionQuery>;
636
637 #[pallet::event]
638 #[pallet::generate_deposit(pub(super) fn deposit_event)]
639 pub enum Event<T: Config> {
640 NewSession { session_index: SessionIndex },
643 NewQueued,
646 ValidatorDisabled { validator: T::ValidatorId },
648 ValidatorReenabled { validator: T::ValidatorId },
650 }
651
652 #[pallet::error]
654 pub enum Error<T> {
655 InvalidProof,
657 NoAssociatedValidatorId,
659 DuplicatedKey,
661 NoKeys,
663 NoAccount,
665 }
666
667 #[pallet::hooks]
668 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
669 fn on_initialize(n: BlockNumberFor<T>) -> Weight {
672 if T::ShouldEndSession::should_end_session(n) {
673 Self::rotate_session();
674 T::BlockWeights::get().max_block
675 } else {
676 Weight::zero()
680 }
681 }
682
683 #[cfg(feature = "try-runtime")]
684 fn try_state(_n: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
685 Self::do_try_state()
686 }
687 }
688
689 #[pallet::call]
690 impl<T: Config> Pallet<T> {
691 #[pallet::call_index(0)]
703 #[pallet::weight(T::WeightInfo::set_keys())]
704 pub fn set_keys(origin: OriginFor<T>, keys: T::Keys, proof: Vec<u8>) -> DispatchResult {
705 let who = ensure_signed(origin)?;
706 ensure!(
707 who.using_encoded(|who| keys.ownership_proof_is_valid(who, &proof)),
708 Error::<T>::InvalidProof,
709 );
710
711 Self::do_set_keys(&who, keys)?;
712 Ok(())
713 }
714
715 #[pallet::call_index(1)]
724 #[pallet::weight(T::WeightInfo::purge_keys())]
725 pub fn purge_keys(origin: OriginFor<T>) -> DispatchResult {
726 let who = ensure_signed(origin)?;
727 Self::do_purge_keys(&who)?;
728 Ok(())
729 }
730 }
731
732 #[cfg(feature = "runtime-benchmarks")]
733 impl<T: Config> Pallet<T> {
734 pub fn ensure_can_pay_key_deposit(who: &T::AccountId) -> Result<(), DispatchError> {
739 use frame_support::traits::tokens::{Fortitude, Preservation};
740 let deposit = T::KeyDeposit::get();
741 let has = T::Currency::reducible_balance(who, Preservation::Protect, Fortitude::Force);
742 if let Some(deficit) = deposit.checked_sub(&has) {
743 T::Currency::mint_into(who, deficit.max(T::Currency::minimum_balance()))
744 .map(|_inc| ())
745 } else {
746 Ok(())
747 }
748 }
749 }
750}
751
752impl<T: Config> Pallet<T> {
753 pub fn validators() -> Vec<T::ValidatorId> {
755 Validators::<T>::get()
756 }
757
758 pub fn current_index() -> SessionIndex {
760 CurrentIndex::<T>::get()
761 }
762
763 pub fn queued_keys() -> Vec<(T::ValidatorId, T::Keys)> {
765 QueuedKeys::<T>::get()
766 }
767
768 pub fn disabled_validators() -> Vec<u32> {
770 DisabledValidators::<T>::get().iter().map(|(i, _)| *i).collect()
771 }
772
773 pub fn rotate_session() {
777 let session_index = CurrentIndex::<T>::get();
778 let changed = QueuedChanged::<T>::get();
779
780 T::SessionHandler::on_before_session_ending();
782 T::SessionManager::end_session(session_index);
783 log!(trace, "ending_session {:?}", session_index);
784
785 let session_keys = QueuedKeys::<T>::get();
787 let validators =
788 session_keys.iter().map(|(validator, _)| validator.clone()).collect::<Vec<_>>();
789 Validators::<T>::put(&validators);
790
791 if changed {
792 log!(trace, "resetting disabled validators");
793 DisabledValidators::<T>::kill();
795 }
796
797 let session_index = session_index + 1;
799 CurrentIndex::<T>::put(session_index);
800 T::SessionManager::start_session(session_index);
801 log!(trace, "starting_session {:?}", session_index);
802
803 let maybe_next_validators = T::SessionManager::new_session(session_index + 1);
805 log!(
806 trace,
807 "planning_session {:?} with {:?} validators",
808 session_index + 1,
809 maybe_next_validators.as_ref().map(|v| v.len())
810 );
811 let (next_validators, next_identities_changed) =
812 if let Some(validators) = maybe_next_validators {
813 Self::deposit_event(Event::<T>::NewQueued);
817 (validators, true)
818 } else {
819 (Validators::<T>::get(), false)
820 };
821
822 let (queued_amalgamated, next_changed) = {
824 let mut changed = next_identities_changed;
827
828 let mut now_session_keys = session_keys.iter();
829 let mut check_next_changed = |keys: &T::Keys| {
830 if changed {
831 return;
832 }
833 if let Some((_, old_keys)) = now_session_keys.next() {
837 if old_keys != keys {
838 changed = true;
839 }
840 }
841 };
842 let queued_amalgamated =
843 next_validators
844 .into_iter()
845 .filter_map(|a| {
846 let k =
847 Self::load_keys(&a).or_else(|| {
848 log!(warn, "failed to load session key for {:?}, skipping for next session, maybe you need to set session keys for them?", a);
849 None
850 })?;
851 check_next_changed(&k);
852 Some((a, k))
853 })
854 .collect::<Vec<_>>();
855
856 (queued_amalgamated, changed)
857 };
858
859 QueuedKeys::<T>::put(queued_amalgamated.clone());
860 QueuedChanged::<T>::put(next_changed);
861
862 Self::deposit_event(Event::NewSession { session_index });
864
865 T::SessionHandler::on_new_session::<T::Keys>(changed, &session_keys, &queued_amalgamated);
867 }
868
869 pub fn upgrade_keys<Old, F>(upgrade: F)
885 where
886 Old: OpaqueKeys + Member + Decode,
887 F: Fn(T::ValidatorId, Old) -> T::Keys,
888 {
889 let old_ids = Old::key_ids();
890 let new_ids = T::Keys::key_ids();
891
892 NextKeys::<T>::translate::<Old, _>(|val, old_keys| {
894 for i in old_ids.iter() {
897 Self::clear_key_owner(*i, old_keys.get_raw(*i));
898 }
899
900 let new_keys = upgrade(val.clone(), old_keys);
901
902 for i in new_ids.iter() {
904 Self::put_key_owner(*i, new_keys.get_raw(*i), &val);
905 }
906
907 Some(new_keys)
908 });
909
910 let _ = QueuedKeys::<T>::translate::<Vec<(T::ValidatorId, Old)>, _>(|k| {
911 k.map(|k| {
912 k.into_iter()
913 .map(|(val, old_keys)| (val.clone(), upgrade(val, old_keys)))
914 .collect::<Vec<_>>()
915 })
916 });
917 }
918
919 fn do_set_keys(account: &T::AccountId, keys: T::Keys) -> DispatchResult {
924 let who = T::ValidatorIdOf::convert(account.clone())
925 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
926
927 let needs_new_consumer =
931 !NextKeys::<T>::contains_key(&who) || ExternallySetKeys::<T>::contains_key(account);
932 if needs_new_consumer {
933 ensure!(frame_system::Pallet::<T>::can_inc_consumer(account), Error::<T>::NoAccount);
934 }
935
936 let old_keys = Self::inner_set_keys(&who, keys)?;
937
938 let needs_local_setup =
942 old_keys.is_none() || ExternallySetKeys::<T>::take(account).is_some();
943 if needs_local_setup {
944 let deposit = T::KeyDeposit::get();
945 if !deposit.is_zero() {
946 T::Currency::hold(&HoldReason::Keys.into(), account, deposit)?;
947 }
948
949 let assertion = frame_system::Pallet::<T>::inc_consumers(account).is_ok();
950 debug_assert!(assertion, "can_inc_consumer() returned true; no change since; qed");
951 }
952
953 Ok(())
954 }
955
956 fn inner_set_keys(
963 who: &T::ValidatorId,
964 keys: T::Keys,
965 ) -> Result<Option<T::Keys>, DispatchError> {
966 let old_keys = Self::load_keys(who);
967
968 for id in T::Keys::key_ids() {
969 let key = keys.get_raw(*id);
970
971 ensure!(
973 Self::key_owner(*id, key).map_or(true, |owner| &owner == who),
974 Error::<T>::DuplicatedKey,
975 );
976 }
977
978 for id in T::Keys::key_ids() {
979 let key = keys.get_raw(*id);
980
981 if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(*id)) {
982 if key == old {
983 continue;
984 }
985
986 Self::clear_key_owner(*id, old);
987 }
988
989 Self::put_key_owner(*id, key, who);
990 }
991
992 Self::put_keys(who, &keys);
993 Ok(old_keys)
994 }
995
996 fn do_purge_keys(account: &T::AccountId) -> DispatchResult {
997 let who = T::ValidatorIdOf::convert(account.clone())
998 .or_else(|| T::ValidatorId::try_from(account.clone()).ok())
1002 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
1003
1004 let old_keys = Self::take_keys(&who).ok_or(Error::<T>::NoKeys)?;
1005 for id in T::Keys::key_ids() {
1006 let key_data = old_keys.get_raw(*id);
1007 Self::clear_key_owner(*id, key_data);
1008 }
1009
1010 let _ = T::Currency::release_all(
1012 &HoldReason::Keys.into(),
1013 account,
1014 frame_support::traits::tokens::Precision::BestEffort,
1015 );
1016
1017 if ExternallySetKeys::<T>::take(account).is_none() {
1018 frame_system::Pallet::<T>::dec_consumers(account);
1020 }
1021
1022 Ok(())
1023 }
1024
1025 pub fn load_keys(v: &T::ValidatorId) -> Option<T::Keys> {
1026 NextKeys::<T>::get(v)
1027 }
1028
1029 fn take_keys(v: &T::ValidatorId) -> Option<T::Keys> {
1030 NextKeys::<T>::take(v)
1031 }
1032
1033 fn put_keys(v: &T::ValidatorId, keys: &T::Keys) {
1034 NextKeys::<T>::insert(v, keys);
1035 }
1036
1037 pub fn key_owner(id: KeyTypeId, key_data: &[u8]) -> Option<T::ValidatorId> {
1039 KeyOwner::<T>::get((id, key_data))
1040 }
1041
1042 fn put_key_owner(id: KeyTypeId, key_data: &[u8], v: &T::ValidatorId) {
1043 KeyOwner::<T>::insert((id, key_data), v)
1044 }
1045
1046 fn clear_key_owner(id: KeyTypeId, key_data: &[u8]) {
1047 KeyOwner::<T>::remove((id, key_data));
1048 }
1049
1050 pub fn disable_index_with_severity(i: u32, severity: OffenceSeverity) -> bool {
1056 if i >= Validators::<T>::decode_len().defensive_unwrap_or(0) as u32 {
1057 return false;
1058 }
1059
1060 DisabledValidators::<T>::mutate(|disabled| {
1061 match disabled.binary_search_by_key(&i, |(index, _)| *index) {
1062 Ok(index) => {
1064 let current_severity = &mut disabled[index].1;
1065 if severity > *current_severity {
1066 log!(
1067 trace,
1068 "updating disablement severity of validator {:?} from {:?} to {:?}",
1069 i,
1070 *current_severity,
1071 severity
1072 );
1073 *current_severity = severity;
1074 }
1075 true
1076 },
1077 Err(index) => {
1079 log!(trace, "disabling validator {:?}", i);
1080 Self::deposit_event(Event::ValidatorDisabled {
1081 validator: Validators::<T>::get()[i as usize].clone(),
1082 });
1083 disabled.insert(index, (i, severity));
1084 T::SessionHandler::on_disabled(i);
1085 true
1086 },
1087 }
1088 })
1089 }
1090
1091 pub fn disable_index(i: u32) -> bool {
1094 let default_severity = OffenceSeverity::default();
1095 Self::disable_index_with_severity(i, default_severity)
1096 }
1097
1098 pub fn reenable_index(i: u32) -> bool {
1100 if i >= Validators::<T>::decode_len().defensive_unwrap_or(0) as u32 {
1101 return false;
1102 }
1103
1104 DisabledValidators::<T>::mutate(|disabled| {
1105 if let Ok(index) = disabled.binary_search_by_key(&i, |(index, _)| *index) {
1106 log!(trace, "reenabling validator {:?}", i);
1107 Self::deposit_event(Event::ValidatorReenabled {
1108 validator: Validators::<T>::get()[i as usize].clone(),
1109 });
1110 disabled.remove(index);
1111 return true;
1112 }
1113 false
1114 })
1115 }
1116
1117 pub fn validator_id_to_index(id: &T::ValidatorId) -> Option<u32> {
1120 Validators::<T>::get().iter().position(|i| i == id).map(|i| i as u32)
1121 }
1122
1123 pub fn report_offence(validator: T::ValidatorId, severity: OffenceSeverity) {
1126 let decision =
1127 T::DisablingStrategy::decision(&validator, severity, &DisabledValidators::<T>::get());
1128 log!(
1129 debug,
1130 "reporting offence for {:?} with {:?}, decision: {:?}",
1131 validator,
1132 severity,
1133 decision
1134 );
1135
1136 if let Some(offender_idx) = decision.disable {
1138 Self::disable_index_with_severity(offender_idx, severity);
1139 }
1140
1141 if let Some(reenable_idx) = decision.reenable {
1143 Self::reenable_index(reenable_idx);
1144 }
1145 }
1146
1147 #[cfg(any(test, feature = "try-runtime"))]
1148 pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
1149 ensure!(
1151 DisabledValidators::<T>::get().windows(2).all(|pair| pair[0].0 <= pair[1].0),
1152 "DisabledValidators is not sorted"
1153 );
1154 Ok(())
1155 }
1156}
1157
1158impl<T: Config> ValidatorRegistration<T::ValidatorId> for Pallet<T> {
1159 fn is_registered(id: &T::ValidatorId) -> bool {
1160 Self::load_keys(id).is_some()
1161 }
1162}
1163
1164impl<T: Config> ValidatorSet<T::AccountId> for Pallet<T> {
1165 type ValidatorId = T::ValidatorId;
1166 type ValidatorIdOf = T::ValidatorIdOf;
1167
1168 fn session_index() -> sp_staking::SessionIndex {
1169 CurrentIndex::<T>::get()
1170 }
1171
1172 fn validators() -> Vec<Self::ValidatorId> {
1173 Validators::<T>::get()
1174 }
1175}
1176
1177impl<T: Config> EstimateNextNewSession<BlockNumberFor<T>> for Pallet<T> {
1178 fn average_session_length() -> BlockNumberFor<T> {
1179 T::NextSessionRotation::average_session_length()
1180 }
1181
1182 fn estimate_next_new_session(now: BlockNumberFor<T>) -> (Option<BlockNumberFor<T>>, Weight) {
1185 T::NextSessionRotation::estimate_next_session_rotation(now)
1186 }
1187}
1188
1189impl<T: Config> frame_support::traits::DisabledValidators for Pallet<T> {
1190 fn is_disabled(index: u32) -> bool {
1191 DisabledValidators::<T>::get().binary_search_by_key(&index, |(i, _)| *i).is_ok()
1192 }
1193
1194 fn disabled_validators() -> Vec<u32> {
1195 Self::disabled_validators()
1196 }
1197}
1198
1199#[cfg(feature = "historical")]
1200impl<T: Config + historical::Config> SessionInterface for Pallet<T> {
1201 type ValidatorId = T::ValidatorId;
1202 type AccountId = T::AccountId;
1203 type Keys = T::Keys;
1204
1205 fn validators() -> Vec<Self::ValidatorId> {
1206 Self::validators()
1207 }
1208
1209 fn prune_up_to(index: SessionIndex) {
1210 historical::Pallet::<T>::prune_up_to(index)
1211 }
1212
1213 fn report_offence(offender: Self::ValidatorId, severity: OffenceSeverity) {
1214 Self::report_offence(offender, severity)
1215 }
1216
1217 fn set_keys(account: &Self::AccountId, keys: Self::Keys) -> DispatchResult {
1218 let who = T::ValidatorIdOf::convert(account.clone())
1219 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
1220 let old_keys = Self::inner_set_keys(&who, keys)?;
1221 if old_keys.is_some() && !ExternallySetKeys::<T>::contains_key(account) {
1223 let _ = T::Currency::release_all(
1224 &HoldReason::Keys.into(),
1225 account,
1226 frame_support::traits::tokens::Precision::BestEffort,
1227 );
1228 frame_system::Pallet::<T>::dec_consumers(account);
1229 }
1230 ExternallySetKeys::<T>::insert(account, ());
1231 Ok(())
1232 }
1233
1234 fn purge_keys(account: &Self::AccountId) -> DispatchResult {
1235 let who = T::ValidatorIdOf::convert(account.clone())
1236 .ok_or(Error::<T>::NoAssociatedValidatorId)?;
1237
1238 let old_keys = Self::take_keys(&who).ok_or(Error::<T>::NoKeys)?;
1239 for id in T::Keys::key_ids() {
1240 let key_data = old_keys.get_raw(*id);
1241 Self::clear_key_owner(*id, key_data);
1242 }
1243 let _ = T::Currency::release_all(
1244 &HoldReason::Keys.into(),
1245 account,
1246 frame_support::traits::tokens::Precision::BestEffort,
1247 );
1248 if ExternallySetKeys::<T>::take(account).is_none() {
1249 frame_system::Pallet::<T>::dec_consumers(account);
1250 }
1251 Ok(())
1252 }
1253
1254 fn set_keys_weight() -> Weight {
1255 T::WeightInfo::set_keys()
1256 }
1257
1258 fn purge_keys_weight() -> Weight {
1259 T::WeightInfo::purge_keys()
1260 }
1261}
1262
1263pub struct FindAccountFromAuthorIndex<T, Inner>(core::marker::PhantomData<(T, Inner)>);
1267
1268impl<T: Config, Inner: FindAuthor<u32>> FindAuthor<T::ValidatorId>
1269 for FindAccountFromAuthorIndex<T, Inner>
1270{
1271 fn find_author<'a, I>(digests: I) -> Option<T::ValidatorId>
1272 where
1273 I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
1274 {
1275 let i = Inner::find_author(digests)?;
1276
1277 let validators = Validators::<T>::get();
1278 validators.get(i as usize).cloned()
1279 }
1280}