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 #[allow(deprecated)]
363 #[pallet::validate_unsigned]
364 impl<T: Config> ValidateUnsigned for Pallet<T> {
365 type Call = Call<T>;
366
367 fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
368 Self::validate_unsigned(source, call)
369 }
370
371 fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
372 Self::pre_dispatch(call)
373 }
374 }
375}
376
377pub trait WeightInfo {
378 fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight;
379 fn note_stalled() -> Weight;
380}
381
382pub type BoundedAuthorityList<Limit> = WeakBoundedVec<(AuthorityId, AuthorityWeight), Limit>;
384
385#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
388#[codec(mel_bound(N: MaxEncodedLen, Limit: Get<u32>))]
389#[scale_info(skip_type_params(Limit))]
390pub struct StoredPendingChange<N, Limit> {
391 pub scheduled_at: N,
393 pub delay: N,
395 pub next_authorities: BoundedAuthorityList<Limit>,
397 pub forced: Option<N>,
400}
401
402#[derive(Decode, Encode, TypeInfo, MaxEncodedLen)]
406#[cfg_attr(test, derive(Debug, PartialEq))]
407pub enum StoredState<N> {
408 Live,
410 PendingPause {
413 scheduled_at: N,
415 delay: N,
417 },
418 Paused,
420 PendingResume {
423 scheduled_at: N,
425 delay: N,
427 },
428}
429
430impl<T: Config> Pallet<T> {
431 pub fn state() -> StoredState<BlockNumberFor<T>> {
433 State::<T>::get()
434 }
435
436 pub fn pending_change() -> Option<StoredPendingChange<BlockNumberFor<T>, T::MaxAuthorities>> {
438 PendingChange::<T>::get()
439 }
440
441 pub fn next_forced() -> Option<BlockNumberFor<T>> {
443 NextForced::<T>::get()
444 }
445
446 pub fn stalled() -> Option<(BlockNumberFor<T>, BlockNumberFor<T>)> {
448 Stalled::<T>::get()
449 }
450
451 pub fn current_set_id() -> SetId {
454 CurrentSetId::<T>::get()
455 }
456
457 pub fn session_for_set(set_id: SetId) -> Option<SessionIndex> {
466 SetIdSession::<T>::get(set_id)
467 }
468
469 pub fn grandpa_authorities() -> AuthorityList {
471 Authorities::<T>::get().into_inner()
472 }
473
474 pub fn schedule_pause(in_blocks: BlockNumberFor<T>) -> DispatchResult {
477 if let StoredState::Live = State::<T>::get() {
478 let scheduled_at = frame_system::Pallet::<T>::block_number();
479 State::<T>::put(StoredState::PendingPause { delay: in_blocks, scheduled_at });
480
481 Ok(())
482 } else {
483 Err(Error::<T>::PauseFailed.into())
484 }
485 }
486
487 pub fn schedule_resume(in_blocks: BlockNumberFor<T>) -> DispatchResult {
489 if let StoredState::Paused = State::<T>::get() {
490 let scheduled_at = frame_system::Pallet::<T>::block_number();
491 State::<T>::put(StoredState::PendingResume { delay: in_blocks, scheduled_at });
492
493 Ok(())
494 } else {
495 Err(Error::<T>::ResumeFailed.into())
496 }
497 }
498
499 pub fn schedule_change(
514 next_authorities: AuthorityList,
515 in_blocks: BlockNumberFor<T>,
516 forced: Option<BlockNumberFor<T>>,
517 ) -> DispatchResult {
518 if !PendingChange::<T>::exists() {
519 let scheduled_at = frame_system::Pallet::<T>::block_number();
520
521 if forced.is_some() {
522 if NextForced::<T>::get().map_or(false, |next| next > scheduled_at) {
523 return Err(Error::<T>::TooSoon.into());
524 }
525
526 NextForced::<T>::put(scheduled_at + in_blocks * 2u32.into());
529 }
530
531 let next_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
532 next_authorities,
533 Some(
534 "Warning: The number of authorities given is too big. \
535 A runtime configuration adjustment may be needed.",
536 ),
537 );
538
539 PendingChange::<T>::put(StoredPendingChange {
540 delay: in_blocks,
541 scheduled_at,
542 next_authorities,
543 forced,
544 });
545
546 Ok(())
547 } else {
548 Err(Error::<T>::ChangePending.into())
549 }
550 }
551
552 fn deposit_log(log: ConsensusLog<BlockNumberFor<T>>) {
554 let log = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode());
555 frame_system::Pallet::<T>::deposit_log(log);
556 }
557
558 fn initialize(authorities: AuthorityList) {
561 if !authorities.is_empty() {
562 assert!(Self::grandpa_authorities().is_empty(), "Authorities are already initialized!");
563 Authorities::<T>::put(
564 &BoundedAuthorityList::<T::MaxAuthorities>::try_from(authorities).expect(
565 "Grandpa: `Config::MaxAuthorities` is smaller than the number of genesis authorities!",
566 ),
567 );
568 }
569
570 SetIdSession::<T>::insert(0, 0);
574 }
575
576 pub fn submit_unsigned_equivocation_report(
581 equivocation_proof: EquivocationProof<T::Hash, BlockNumberFor<T>>,
582 key_owner_proof: T::KeyOwnerProof,
583 ) -> Option<()> {
584 T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok()
585 }
586
587 fn on_stalled(further_wait: BlockNumberFor<T>, median: BlockNumberFor<T>) {
588 Stalled::<T>::put((further_wait, median));
592 }
593}
594
595impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
596 type Public = AuthorityId;
597}
598
599impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T>
600where
601 T: pallet_session::Config,
602{
603 type Key = AuthorityId;
604
605 fn on_genesis_session<'a, I: 'a>(validators: I)
606 where
607 I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
608 {
609 let authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
610 Self::initialize(authorities);
611 }
612
613 fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued_validators: I)
614 where
615 I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
616 {
617 let mut current_set_id = CurrentSetId::<T>::get();
618
619 if changed || Stalled::<T>::exists() {
623 let next_authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
624
625 let res = match Stalled::<T>::get() {
626 Some((further_wait, median)) => {
627 Self::schedule_change(next_authorities, further_wait, Some(median))
628 },
629 None => Self::schedule_change(next_authorities, Zero::zero(), None),
630 };
631
632 if res.is_ok() {
633 Stalled::<T>::kill();
634
635 current_set_id += 1;
636 CurrentSetId::<T>::set(current_set_id);
637
638 let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1);
639 if current_set_id >= max_set_id_session_entries {
640 SetIdSession::<T>::remove(current_set_id - max_set_id_session_entries);
641 }
642 }
643 }
644
645 let session_index = pallet_session::Pallet::<T>::current_index();
648 SetIdSession::<T>::insert(current_set_id, &session_index);
649 }
650
651 fn on_disabled(i: u32) {
652 Self::deposit_log(ConsensusLog::OnDisabled(i as u64))
653 }
654}