1#![cfg_attr(not(feature = "std"), no_std)]
30
31extern crate alloc;
32
33pub use sp_consensus_grandpa::{
35 self as fg_primitives, AuthorityId, AuthorityList, AuthorityWeight,
36};
37
38use alloc::{boxed::Box, vec::Vec};
39use codec::{Decode, Encode, MaxEncodedLen};
40use frame_support::{
41 dispatch::{DispatchResultWithPostInfo, Pays},
42 pallet_prelude::Get,
43 traits::OneSessionHandler,
44 weights::Weight,
45 WeakBoundedVec,
46};
47use frame_system::pallet_prelude::BlockNumberFor;
48use scale_info::TypeInfo;
49use sp_consensus_grandpa::{
50 ConsensusLog, EquivocationProof, ScheduledChange, SetId, GRANDPA_ENGINE_ID,
51 RUNTIME_LOG_TARGET as LOG_TARGET,
52};
53use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult};
54use sp_session::{GetSessionNumber, GetValidatorCount};
55use sp_staking::{offence::OffenceReportSystem, SessionIndex};
56
57mod default_weights;
58mod equivocation;
59pub mod migrations;
60
61#[cfg(any(feature = "runtime-benchmarks", test))]
62mod benchmarking;
63#[cfg(all(feature = "std", test))]
64mod mock;
65#[cfg(all(feature = "std", test))]
66mod tests;
67
68pub use equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot};
69
70pub use pallet::*;
71
72#[frame_support::pallet]
73pub mod pallet {
74 use super::*;
75 use frame_support::{dispatch::DispatchResult, pallet_prelude::*};
76 use frame_system::pallet_prelude::*;
77
78 const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
80
81 #[pallet::pallet]
82 #[pallet::storage_version(STORAGE_VERSION)]
83 pub struct Pallet<T>(_);
84
85 #[pallet::config]
86 pub trait Config: frame_system::Config {
87 type RuntimeEvent: From<Event>
89 + Into<<Self as frame_system::Config>::RuntimeEvent>
90 + IsType<<Self as frame_system::Config>::RuntimeEvent>;
91
92 type WeightInfo: WeightInfo;
94
95 #[pallet::constant]
97 type MaxAuthorities: Get<u32>;
98
99 #[pallet::constant]
101 type MaxNominators: Get<u32>;
102
103 #[pallet::constant]
110 type MaxSetIdSessionEntries: Get<u64>;
111
112 type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount;
116
117 type EquivocationReportSystem: OffenceReportSystem<
121 Option<Self::AccountId>,
122 (EquivocationProof<Self::Hash, BlockNumberFor<Self>>, Self::KeyOwnerProof),
123 >;
124 }
125
126 #[pallet::hooks]
127 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
128 fn on_finalize(block_number: BlockNumberFor<T>) {
129 if let Some(pending_change) = PendingChange::<T>::get() {
131 if block_number == pending_change.scheduled_at {
133 let next_authorities = pending_change.next_authorities.to_vec();
134 if let Some(median) = pending_change.forced {
135 Self::deposit_log(ConsensusLog::ForcedChange(
136 median,
137 ScheduledChange { delay: pending_change.delay, next_authorities },
138 ))
139 } else {
140 Self::deposit_log(ConsensusLog::ScheduledChange(ScheduledChange {
141 delay: pending_change.delay,
142 next_authorities,
143 }));
144 }
145 }
146
147 if block_number == pending_change.scheduled_at + pending_change.delay {
149 Authorities::<T>::put(&pending_change.next_authorities);
150 Self::deposit_event(Event::NewAuthorities {
151 authority_set: pending_change.next_authorities.into_inner(),
152 });
153 PendingChange::<T>::kill();
154 }
155 }
156
157 match State::<T>::get() {
159 StoredState::PendingPause { scheduled_at, delay } => {
160 if block_number == scheduled_at {
162 Self::deposit_log(ConsensusLog::Pause(delay));
163 }
164
165 if block_number == scheduled_at + delay {
167 State::<T>::put(StoredState::Paused);
168 Self::deposit_event(Event::Paused);
169 }
170 },
171 StoredState::PendingResume { scheduled_at, delay } => {
172 if block_number == scheduled_at {
174 Self::deposit_log(ConsensusLog::Resume(delay));
175 }
176
177 if block_number == scheduled_at + delay {
179 State::<T>::put(StoredState::Live);
180 Self::deposit_event(Event::Resumed);
181 }
182 },
183 _ => {},
184 }
185 }
186 }
187
188 #[pallet::call]
189 impl<T: Config> Pallet<T> {
190 #[pallet::call_index(0)]
195 #[pallet::weight(T::WeightInfo::report_equivocation(
196 key_owner_proof.validator_count(),
197 T::MaxNominators::get(),
198 ))]
199 pub fn report_equivocation(
200 origin: OriginFor<T>,
201 equivocation_proof: Box<EquivocationProof<T::Hash, BlockNumberFor<T>>>,
202 key_owner_proof: T::KeyOwnerProof,
203 ) -> DispatchResultWithPostInfo {
204 let reporter = ensure_signed(origin)?;
205
206 T::EquivocationReportSystem::process_evidence(
207 Some(reporter),
208 (*equivocation_proof, key_owner_proof),
209 )?;
210 Ok(Pays::No.into())
212 }
213
214 #[pallet::call_index(1)]
224 #[pallet::weight(T::WeightInfo::report_equivocation(
225 key_owner_proof.validator_count(),
226 T::MaxNominators::get(),
227 ))]
228 pub fn report_equivocation_unsigned(
229 origin: OriginFor<T>,
230 equivocation_proof: Box<EquivocationProof<T::Hash, BlockNumberFor<T>>>,
231 key_owner_proof: T::KeyOwnerProof,
232 ) -> DispatchResultWithPostInfo {
233 ensure_none(origin)?;
234
235 T::EquivocationReportSystem::process_evidence(
236 None,
237 (*equivocation_proof, key_owner_proof),
238 )?;
239 Ok(Pays::No.into())
240 }
241
242 #[pallet::call_index(2)]
255 #[pallet::weight(T::WeightInfo::note_stalled())]
256 pub fn note_stalled(
257 origin: OriginFor<T>,
258 delay: BlockNumberFor<T>,
259 best_finalized_block_number: BlockNumberFor<T>,
260 ) -> DispatchResult {
261 ensure_root(origin)?;
262
263 Self::on_stalled(delay, best_finalized_block_number);
264 Ok(())
265 }
266 }
267
268 #[pallet::event]
269 #[pallet::generate_deposit(fn deposit_event)]
270 pub enum Event {
271 NewAuthorities { authority_set: AuthorityList },
273 Paused,
275 Resumed,
277 }
278
279 #[pallet::error]
280 pub enum Error<T> {
281 PauseFailed,
284 ResumeFailed,
287 ChangePending,
289 TooSoon,
291 InvalidKeyOwnershipProof,
293 InvalidEquivocationProof,
295 DuplicateOffenceReport,
297 }
298
299 #[pallet::type_value]
300 pub fn DefaultForState<T: Config>() -> StoredState<BlockNumberFor<T>> {
301 StoredState::Live
302 }
303
304 #[pallet::storage]
306 pub type State<T: Config> =
307 StorageValue<_, StoredState<BlockNumberFor<T>>, ValueQuery, DefaultForState<T>>;
308
309 #[pallet::storage]
311 pub type PendingChange<T: Config> =
312 StorageValue<_, StoredPendingChange<BlockNumberFor<T>, T::MaxAuthorities>>;
313
314 #[pallet::storage]
316 pub type NextForced<T: Config> = StorageValue<_, BlockNumberFor<T>>;
317
318 #[pallet::storage]
320 pub type Stalled<T: Config> = StorageValue<_, (BlockNumberFor<T>, BlockNumberFor<T>)>;
321
322 #[pallet::storage]
325 pub type CurrentSetId<T: Config> = StorageValue<_, SetId, ValueQuery>;
326
327 #[pallet::storage]
338 pub type SetIdSession<T: Config> = StorageMap<_, Twox64Concat, SetId, SessionIndex>;
339
340 #[pallet::storage]
342 pub type Authorities<T: Config> =
343 StorageValue<_, BoundedAuthorityList<T::MaxAuthorities>, ValueQuery>;
344
345 #[derive(frame_support::DefaultNoBound)]
346 #[pallet::genesis_config]
347 pub struct GenesisConfig<T: Config> {
348 pub authorities: AuthorityList,
349 #[serde(skip)]
350 pub _config: core::marker::PhantomData<T>,
351 }
352
353 #[pallet::genesis_build]
354 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
355 fn build(&self) {
356 CurrentSetId::<T>::put(SetId::default());
357 Pallet::<T>::initialize(self.authorities.clone())
358 }
359 }
360
361 #[pallet::validate_unsigned]
362 impl<T: Config> ValidateUnsigned for Pallet<T> {
363 type Call = Call<T>;
364
365 fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
366 Self::validate_unsigned(source, call)
367 }
368
369 fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
370 Self::pre_dispatch(call)
371 }
372 }
373}
374
375pub trait WeightInfo {
376 fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight;
377 fn note_stalled() -> Weight;
378}
379
380pub type BoundedAuthorityList<Limit> = WeakBoundedVec<(AuthorityId, AuthorityWeight), Limit>;
382
383#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
386#[codec(mel_bound(N: MaxEncodedLen, Limit: Get<u32>))]
387#[scale_info(skip_type_params(Limit))]
388pub struct StoredPendingChange<N, Limit> {
389 pub scheduled_at: N,
391 pub delay: N,
393 pub next_authorities: BoundedAuthorityList<Limit>,
395 pub forced: Option<N>,
398}
399
400#[derive(Decode, Encode, TypeInfo, MaxEncodedLen)]
404#[cfg_attr(test, derive(Debug, PartialEq))]
405pub enum StoredState<N> {
406 Live,
408 PendingPause {
411 scheduled_at: N,
413 delay: N,
415 },
416 Paused,
418 PendingResume {
421 scheduled_at: N,
423 delay: N,
425 },
426}
427
428impl<T: Config> Pallet<T> {
429 pub fn state() -> StoredState<BlockNumberFor<T>> {
431 State::<T>::get()
432 }
433
434 pub fn pending_change() -> Option<StoredPendingChange<BlockNumberFor<T>, T::MaxAuthorities>> {
436 PendingChange::<T>::get()
437 }
438
439 pub fn next_forced() -> Option<BlockNumberFor<T>> {
441 NextForced::<T>::get()
442 }
443
444 pub fn stalled() -> Option<(BlockNumberFor<T>, BlockNumberFor<T>)> {
446 Stalled::<T>::get()
447 }
448
449 pub fn current_set_id() -> SetId {
452 CurrentSetId::<T>::get()
453 }
454
455 pub fn session_for_set(set_id: SetId) -> Option<SessionIndex> {
464 SetIdSession::<T>::get(set_id)
465 }
466
467 pub fn grandpa_authorities() -> AuthorityList {
469 Authorities::<T>::get().into_inner()
470 }
471
472 pub fn schedule_pause(in_blocks: BlockNumberFor<T>) -> DispatchResult {
475 if let StoredState::Live = State::<T>::get() {
476 let scheduled_at = frame_system::Pallet::<T>::block_number();
477 State::<T>::put(StoredState::PendingPause { delay: in_blocks, scheduled_at });
478
479 Ok(())
480 } else {
481 Err(Error::<T>::PauseFailed.into())
482 }
483 }
484
485 pub fn schedule_resume(in_blocks: BlockNumberFor<T>) -> DispatchResult {
487 if let StoredState::Paused = State::<T>::get() {
488 let scheduled_at = frame_system::Pallet::<T>::block_number();
489 State::<T>::put(StoredState::PendingResume { delay: in_blocks, scheduled_at });
490
491 Ok(())
492 } else {
493 Err(Error::<T>::ResumeFailed.into())
494 }
495 }
496
497 pub fn schedule_change(
512 next_authorities: AuthorityList,
513 in_blocks: BlockNumberFor<T>,
514 forced: Option<BlockNumberFor<T>>,
515 ) -> DispatchResult {
516 if !PendingChange::<T>::exists() {
517 let scheduled_at = frame_system::Pallet::<T>::block_number();
518
519 if forced.is_some() {
520 if NextForced::<T>::get().map_or(false, |next| next > scheduled_at) {
521 return Err(Error::<T>::TooSoon.into())
522 }
523
524 NextForced::<T>::put(scheduled_at + in_blocks * 2u32.into());
527 }
528
529 let next_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
530 next_authorities,
531 Some(
532 "Warning: The number of authorities given is too big. \
533 A runtime configuration adjustment may be needed.",
534 ),
535 );
536
537 PendingChange::<T>::put(StoredPendingChange {
538 delay: in_blocks,
539 scheduled_at,
540 next_authorities,
541 forced,
542 });
543
544 Ok(())
545 } else {
546 Err(Error::<T>::ChangePending.into())
547 }
548 }
549
550 fn deposit_log(log: ConsensusLog<BlockNumberFor<T>>) {
552 let log = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode());
553 frame_system::Pallet::<T>::deposit_log(log);
554 }
555
556 fn initialize(authorities: AuthorityList) {
559 if !authorities.is_empty() {
560 assert!(Self::grandpa_authorities().is_empty(), "Authorities are already initialized!");
561 Authorities::<T>::put(
562 &BoundedAuthorityList::<T::MaxAuthorities>::try_from(authorities).expect(
563 "Grandpa: `Config::MaxAuthorities` is smaller than the number of genesis authorities!",
564 ),
565 );
566 }
567
568 SetIdSession::<T>::insert(0, 0);
572 }
573
574 pub fn submit_unsigned_equivocation_report(
579 equivocation_proof: EquivocationProof<T::Hash, BlockNumberFor<T>>,
580 key_owner_proof: T::KeyOwnerProof,
581 ) -> Option<()> {
582 T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok()
583 }
584
585 fn on_stalled(further_wait: BlockNumberFor<T>, median: BlockNumberFor<T>) {
586 Stalled::<T>::put((further_wait, median));
590 }
591}
592
593impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
594 type Public = AuthorityId;
595}
596
597impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T>
598where
599 T: pallet_session::Config,
600{
601 type Key = AuthorityId;
602
603 fn on_genesis_session<'a, I: 'a>(validators: I)
604 where
605 I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
606 {
607 let authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
608 Self::initialize(authorities);
609 }
610
611 fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued_validators: I)
612 where
613 I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
614 {
615 let current_set_id = if changed || Stalled::<T>::exists() {
619 let next_authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
620
621 let res = if let Some((further_wait, median)) = Stalled::<T>::take() {
622 Self::schedule_change(next_authorities, further_wait, Some(median))
623 } else {
624 Self::schedule_change(next_authorities, Zero::zero(), None)
625 };
626
627 if res.is_ok() {
628 let current_set_id = CurrentSetId::<T>::mutate(|s| {
629 *s += 1;
630 *s
631 });
632
633 let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1);
634 if current_set_id >= max_set_id_session_entries {
635 SetIdSession::<T>::remove(current_set_id - max_set_id_session_entries);
636 }
637
638 current_set_id
639 } else {
640 CurrentSetId::<T>::get()
644 }
645 } else {
646 CurrentSetId::<T>::get()
649 };
650
651 let session_index = pallet_session::Pallet::<T>::current_index();
654 SetIdSession::<T>::insert(current_set_id, &session_index);
655 }
656
657 fn on_disabled(i: u32) {
658 Self::deposit_log(ConsensusLog::OnDisabled(i as u64))
659 }
660}