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 #[allow(deprecated)]
89 type RuntimeEvent: From<Event>
90 + Into<<Self as frame_system::Config>::RuntimeEvent>
91 + IsType<<Self as frame_system::Config>::RuntimeEvent>;
92
93 type WeightInfo: WeightInfo;
95
96 #[pallet::constant]
98 type MaxAuthorities: Get<u32>;
99
100 #[pallet::constant]
102 type MaxNominators: Get<u32>;
103
104 #[pallet::constant]
111 type MaxSetIdSessionEntries: Get<u64>;
112
113 type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount;
117
118 type EquivocationReportSystem: OffenceReportSystem<
122 Option<Self::AccountId>,
123 (EquivocationProof<Self::Hash, BlockNumberFor<Self>>, Self::KeyOwnerProof),
124 >;
125 }
126
127 #[pallet::hooks]
128 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
129 fn on_finalize(block_number: BlockNumberFor<T>) {
130 if let Some(pending_change) = PendingChange::<T>::get() {
132 if block_number == pending_change.scheduled_at {
134 let next_authorities = pending_change.next_authorities.to_vec();
135 if let Some(median) = pending_change.forced {
136 Self::deposit_log(ConsensusLog::ForcedChange(
137 median,
138 ScheduledChange { delay: pending_change.delay, next_authorities },
139 ))
140 } else {
141 Self::deposit_log(ConsensusLog::ScheduledChange(ScheduledChange {
142 delay: pending_change.delay,
143 next_authorities,
144 }));
145 }
146 }
147
148 if block_number == pending_change.scheduled_at + pending_change.delay {
150 Authorities::<T>::put(&pending_change.next_authorities);
151 Self::deposit_event(Event::NewAuthorities {
152 authority_set: pending_change.next_authorities.into_inner(),
153 });
154 PendingChange::<T>::kill();
155 }
156 }
157
158 match State::<T>::get() {
160 StoredState::PendingPause { scheduled_at, delay } => {
161 if block_number == scheduled_at {
163 Self::deposit_log(ConsensusLog::Pause(delay));
164 }
165
166 if block_number == scheduled_at + delay {
168 State::<T>::put(StoredState::Paused);
169 Self::deposit_event(Event::Paused);
170 }
171 },
172 StoredState::PendingResume { scheduled_at, delay } => {
173 if block_number == scheduled_at {
175 Self::deposit_log(ConsensusLog::Resume(delay));
176 }
177
178 if block_number == scheduled_at + delay {
180 State::<T>::put(StoredState::Live);
181 Self::deposit_event(Event::Resumed);
182 }
183 },
184 _ => {},
185 }
186 }
187 }
188
189 #[pallet::call]
190 impl<T: Config> Pallet<T> {
191 #[pallet::call_index(0)]
196 #[pallet::weight(T::WeightInfo::report_equivocation(
197 key_owner_proof.validator_count(),
198 T::MaxNominators::get(),
199 ))]
200 pub fn report_equivocation(
201 origin: OriginFor<T>,
202 equivocation_proof: Box<EquivocationProof<T::Hash, BlockNumberFor<T>>>,
203 key_owner_proof: T::KeyOwnerProof,
204 ) -> DispatchResultWithPostInfo {
205 let reporter = ensure_signed(origin)?;
206
207 T::EquivocationReportSystem::process_evidence(
208 Some(reporter),
209 (*equivocation_proof, key_owner_proof),
210 )?;
211 Ok(Pays::No.into())
213 }
214
215 #[pallet::call_index(1)]
225 #[pallet::weight(T::WeightInfo::report_equivocation(
226 key_owner_proof.validator_count(),
227 T::MaxNominators::get(),
228 ))]
229 pub fn report_equivocation_unsigned(
230 origin: OriginFor<T>,
231 equivocation_proof: Box<EquivocationProof<T::Hash, BlockNumberFor<T>>>,
232 key_owner_proof: T::KeyOwnerProof,
233 ) -> DispatchResultWithPostInfo {
234 ensure_none(origin)?;
235
236 T::EquivocationReportSystem::process_evidence(
237 None,
238 (*equivocation_proof, key_owner_proof),
239 )?;
240 Ok(Pays::No.into())
241 }
242
243 #[pallet::call_index(2)]
256 #[pallet::weight(T::WeightInfo::note_stalled())]
257 pub fn note_stalled(
258 origin: OriginFor<T>,
259 delay: BlockNumberFor<T>,
260 best_finalized_block_number: BlockNumberFor<T>,
261 ) -> DispatchResult {
262 ensure_root(origin)?;
263
264 Self::on_stalled(delay, best_finalized_block_number);
265 Ok(())
266 }
267 }
268
269 #[pallet::event]
270 #[pallet::generate_deposit(fn deposit_event)]
271 pub enum Event {
272 NewAuthorities { authority_set: AuthorityList },
274 Paused,
276 Resumed,
278 }
279
280 #[pallet::error]
281 pub enum Error<T> {
282 PauseFailed,
285 ResumeFailed,
288 ChangePending,
290 TooSoon,
292 InvalidKeyOwnershipProof,
294 InvalidEquivocationProof,
296 DuplicateOffenceReport,
298 }
299
300 #[pallet::type_value]
301 pub fn DefaultForState<T: Config>() -> StoredState<BlockNumberFor<T>> {
302 StoredState::Live
303 }
304
305 #[pallet::storage]
307 pub type State<T: Config> =
308 StorageValue<_, StoredState<BlockNumberFor<T>>, ValueQuery, DefaultForState<T>>;
309
310 #[pallet::storage]
312 pub type PendingChange<T: Config> =
313 StorageValue<_, StoredPendingChange<BlockNumberFor<T>, T::MaxAuthorities>>;
314
315 #[pallet::storage]
317 pub type NextForced<T: Config> = StorageValue<_, BlockNumberFor<T>>;
318
319 #[pallet::storage]
321 pub type Stalled<T: Config> = StorageValue<_, (BlockNumberFor<T>, BlockNumberFor<T>)>;
322
323 #[pallet::storage]
326 pub type CurrentSetId<T: Config> = StorageValue<_, SetId, ValueQuery>;
327
328 #[pallet::storage]
339 pub type SetIdSession<T: Config> = StorageMap<_, Twox64Concat, SetId, SessionIndex>;
340
341 #[pallet::storage]
343 pub type Authorities<T: Config> =
344 StorageValue<_, BoundedAuthorityList<T::MaxAuthorities>, ValueQuery>;
345
346 #[derive(frame_support::DefaultNoBound)]
347 #[pallet::genesis_config]
348 pub struct GenesisConfig<T: Config> {
349 pub authorities: AuthorityList,
350 #[serde(skip)]
351 pub _config: core::marker::PhantomData<T>,
352 }
353
354 #[pallet::genesis_build]
355 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
356 fn build(&self) {
357 CurrentSetId::<T>::put(SetId::default());
358 Pallet::<T>::initialize(self.authorities.clone())
359 }
360 }
361
362 #[pallet::validate_unsigned]
363 impl<T: Config> ValidateUnsigned for Pallet<T> {
364 type Call = Call<T>;
365
366 fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
367 Self::validate_unsigned(source, call)
368 }
369
370 fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
371 Self::pre_dispatch(call)
372 }
373 }
374}
375
376pub trait WeightInfo {
377 fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight;
378 fn note_stalled() -> Weight;
379}
380
381pub type BoundedAuthorityList<Limit> = WeakBoundedVec<(AuthorityId, AuthorityWeight), Limit>;
383
384#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
387#[codec(mel_bound(N: MaxEncodedLen, Limit: Get<u32>))]
388#[scale_info(skip_type_params(Limit))]
389pub struct StoredPendingChange<N, Limit> {
390 pub scheduled_at: N,
392 pub delay: N,
394 pub next_authorities: BoundedAuthorityList<Limit>,
396 pub forced: Option<N>,
399}
400
401#[derive(Decode, Encode, TypeInfo, MaxEncodedLen)]
405#[cfg_attr(test, derive(Debug, PartialEq))]
406pub enum StoredState<N> {
407 Live,
409 PendingPause {
412 scheduled_at: N,
414 delay: N,
416 },
417 Paused,
419 PendingResume {
422 scheduled_at: N,
424 delay: N,
426 },
427}
428
429impl<T: Config> Pallet<T> {
430 pub fn state() -> StoredState<BlockNumberFor<T>> {
432 State::<T>::get()
433 }
434
435 pub fn pending_change() -> Option<StoredPendingChange<BlockNumberFor<T>, T::MaxAuthorities>> {
437 PendingChange::<T>::get()
438 }
439
440 pub fn next_forced() -> Option<BlockNumberFor<T>> {
442 NextForced::<T>::get()
443 }
444
445 pub fn stalled() -> Option<(BlockNumberFor<T>, BlockNumberFor<T>)> {
447 Stalled::<T>::get()
448 }
449
450 pub fn current_set_id() -> SetId {
453 CurrentSetId::<T>::get()
454 }
455
456 pub fn session_for_set(set_id: SetId) -> Option<SessionIndex> {
465 SetIdSession::<T>::get(set_id)
466 }
467
468 pub fn grandpa_authorities() -> AuthorityList {
470 Authorities::<T>::get().into_inner()
471 }
472
473 pub fn schedule_pause(in_blocks: BlockNumberFor<T>) -> DispatchResult {
476 if let StoredState::Live = State::<T>::get() {
477 let scheduled_at = frame_system::Pallet::<T>::block_number();
478 State::<T>::put(StoredState::PendingPause { delay: in_blocks, scheduled_at });
479
480 Ok(())
481 } else {
482 Err(Error::<T>::PauseFailed.into())
483 }
484 }
485
486 pub fn schedule_resume(in_blocks: BlockNumberFor<T>) -> DispatchResult {
488 if let StoredState::Paused = State::<T>::get() {
489 let scheduled_at = frame_system::Pallet::<T>::block_number();
490 State::<T>::put(StoredState::PendingResume { delay: in_blocks, scheduled_at });
491
492 Ok(())
493 } else {
494 Err(Error::<T>::ResumeFailed.into())
495 }
496 }
497
498 pub fn schedule_change(
513 next_authorities: AuthorityList,
514 in_blocks: BlockNumberFor<T>,
515 forced: Option<BlockNumberFor<T>>,
516 ) -> DispatchResult {
517 if !PendingChange::<T>::exists() {
518 let scheduled_at = frame_system::Pallet::<T>::block_number();
519
520 if forced.is_some() {
521 if NextForced::<T>::get().map_or(false, |next| next > scheduled_at) {
522 return Err(Error::<T>::TooSoon.into())
523 }
524
525 NextForced::<T>::put(scheduled_at + in_blocks * 2u32.into());
528 }
529
530 let next_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
531 next_authorities,
532 Some(
533 "Warning: The number of authorities given is too big. \
534 A runtime configuration adjustment may be needed.",
535 ),
536 );
537
538 PendingChange::<T>::put(StoredPendingChange {
539 delay: in_blocks,
540 scheduled_at,
541 next_authorities,
542 forced,
543 });
544
545 Ok(())
546 } else {
547 Err(Error::<T>::ChangePending.into())
548 }
549 }
550
551 fn deposit_log(log: ConsensusLog<BlockNumberFor<T>>) {
553 let log = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode());
554 frame_system::Pallet::<T>::deposit_log(log);
555 }
556
557 fn initialize(authorities: AuthorityList) {
560 if !authorities.is_empty() {
561 assert!(Self::grandpa_authorities().is_empty(), "Authorities are already initialized!");
562 Authorities::<T>::put(
563 &BoundedAuthorityList::<T::MaxAuthorities>::try_from(authorities).expect(
564 "Grandpa: `Config::MaxAuthorities` is smaller than the number of genesis authorities!",
565 ),
566 );
567 }
568
569 SetIdSession::<T>::insert(0, 0);
573 }
574
575 pub fn submit_unsigned_equivocation_report(
580 equivocation_proof: EquivocationProof<T::Hash, BlockNumberFor<T>>,
581 key_owner_proof: T::KeyOwnerProof,
582 ) -> Option<()> {
583 T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok()
584 }
585
586 fn on_stalled(further_wait: BlockNumberFor<T>, median: BlockNumberFor<T>) {
587 Stalled::<T>::put((further_wait, median));
591 }
592}
593
594impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
595 type Public = AuthorityId;
596}
597
598impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T>
599where
600 T: pallet_session::Config,
601{
602 type Key = AuthorityId;
603
604 fn on_genesis_session<'a, I: 'a>(validators: I)
605 where
606 I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
607 {
608 let authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
609 Self::initialize(authorities);
610 }
611
612 fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued_validators: I)
613 where
614 I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
615 {
616 let current_set_id = if changed || Stalled::<T>::exists() {
620 let next_authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
621
622 let res = if let Some((further_wait, median)) = Stalled::<T>::take() {
623 Self::schedule_change(next_authorities, further_wait, Some(median))
624 } else {
625 Self::schedule_change(next_authorities, Zero::zero(), None)
626 };
627
628 if res.is_ok() {
629 let current_set_id = CurrentSetId::<T>::mutate(|s| {
630 *s += 1;
631 *s
632 });
633
634 let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1);
635 if current_set_id >= max_set_id_session_entries {
636 SetIdSession::<T>::remove(current_set_id - max_set_id_session_entries);
637 }
638
639 current_set_id
640 } else {
641 CurrentSetId::<T>::get()
645 }
646 } else {
647 CurrentSetId::<T>::get()
650 };
651
652 let session_index = pallet_session::Pallet::<T>::current_index();
655 SetIdSession::<T>::insert(current_set_id, &session_index);
656 }
657
658 fn on_disabled(i: u32) {
659 Self::deposit_log(ConsensusLog::OnDisabled(i as u64))
660 }
661}