mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-02 18:47:24 +00:00
0d73371bb8
* pallet-beefy: ensure mandatory block once per session Signed-off-by: acatangiu <adrian@parity.io> * pallet-beefy: fix tests with auth changes every session Signed-off-by: acatangiu <adrian@parity.io> * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * beefy: fix incorrect skip session metric on node restart Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
179 lines
5.0 KiB
Rust
179 lines
5.0 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#![cfg_attr(not(feature = "std"), no_std)]
|
|
|
|
use codec::Encode;
|
|
|
|
use frame_support::{traits::OneSessionHandler, Parameter};
|
|
|
|
use sp_runtime::{
|
|
generic::DigestItem,
|
|
traits::{IsMember, Member},
|
|
RuntimeAppPublic,
|
|
};
|
|
use sp_std::prelude::*;
|
|
|
|
use beefy_primitives::{AuthorityIndex, ConsensusLog, ValidatorSet, BEEFY_ENGINE_ID};
|
|
|
|
#[cfg(test)]
|
|
mod mock;
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
pub use pallet::*;
|
|
|
|
#[frame_support::pallet]
|
|
pub mod pallet {
|
|
use super::*;
|
|
use frame_support::pallet_prelude::*;
|
|
use frame_system::pallet_prelude::*;
|
|
|
|
#[pallet::config]
|
|
pub trait Config: frame_system::Config {
|
|
/// Authority identifier type
|
|
type BeefyId: Member + Parameter + RuntimeAppPublic + MaybeSerializeDeserialize;
|
|
}
|
|
|
|
#[pallet::pallet]
|
|
#[pallet::without_storage_info]
|
|
pub struct Pallet<T>(PhantomData<T>);
|
|
|
|
#[pallet::hooks]
|
|
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
|
|
|
|
#[pallet::call]
|
|
impl<T: Config> Pallet<T> {}
|
|
|
|
/// The current authorities set
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn authorities)]
|
|
pub(super) type Authorities<T: Config> = StorageValue<_, Vec<T::BeefyId>, ValueQuery>;
|
|
|
|
/// The current validator set id
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn validator_set_id)]
|
|
pub(super) type ValidatorSetId<T: Config> =
|
|
StorageValue<_, beefy_primitives::ValidatorSetId, ValueQuery>;
|
|
|
|
/// Authorities set scheduled to be used with the next session
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn next_authorities)]
|
|
pub(super) type NextAuthorities<T: Config> = StorageValue<_, Vec<T::BeefyId>, ValueQuery>;
|
|
|
|
#[pallet::genesis_config]
|
|
pub struct GenesisConfig<T: Config> {
|
|
pub authorities: Vec<T::BeefyId>,
|
|
}
|
|
|
|
#[cfg(feature = "std")]
|
|
impl<T: Config> Default for GenesisConfig<T> {
|
|
fn default() -> Self {
|
|
Self { authorities: Vec::new() }
|
|
}
|
|
}
|
|
|
|
#[pallet::genesis_build]
|
|
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
|
|
fn build(&self) {
|
|
Pallet::<T>::initialize_authorities(&self.authorities);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Config> Pallet<T> {
|
|
/// Return the current active BEEFY validator set.
|
|
pub fn validator_set() -> Option<ValidatorSet<T::BeefyId>> {
|
|
let validators: Vec<T::BeefyId> = Self::authorities();
|
|
let id: beefy_primitives::ValidatorSetId = Self::validator_set_id();
|
|
ValidatorSet::<T::BeefyId>::new(validators, id)
|
|
}
|
|
|
|
fn change_authorities(new: Vec<T::BeefyId>, queued: Vec<T::BeefyId>) {
|
|
<Authorities<T>>::put(&new);
|
|
|
|
let next_id = Self::validator_set_id() + 1u64;
|
|
<ValidatorSetId<T>>::put(next_id);
|
|
if let Some(validator_set) = ValidatorSet::<T::BeefyId>::new(new, next_id) {
|
|
let log = DigestItem::Consensus(
|
|
BEEFY_ENGINE_ID,
|
|
ConsensusLog::AuthoritiesChange(validator_set).encode(),
|
|
);
|
|
<frame_system::Pallet<T>>::deposit_log(log);
|
|
}
|
|
|
|
<NextAuthorities<T>>::put(&queued);
|
|
}
|
|
|
|
fn initialize_authorities(authorities: &[T::BeefyId]) {
|
|
if authorities.is_empty() {
|
|
return
|
|
}
|
|
|
|
assert!(<Authorities<T>>::get().is_empty(), "Authorities are already initialized!");
|
|
|
|
<Authorities<T>>::put(authorities);
|
|
<ValidatorSetId<T>>::put(0);
|
|
// Like `pallet_session`, initialize the next validator set as well.
|
|
<NextAuthorities<T>>::put(authorities);
|
|
}
|
|
}
|
|
|
|
impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
|
|
type Public = T::BeefyId;
|
|
}
|
|
|
|
impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
|
|
type Key = T::BeefyId;
|
|
|
|
fn on_genesis_session<'a, I: 'a>(validators: I)
|
|
where
|
|
I: Iterator<Item = (&'a T::AccountId, T::BeefyId)>,
|
|
{
|
|
let authorities = validators.map(|(_, k)| k).collect::<Vec<_>>();
|
|
Self::initialize_authorities(&authorities);
|
|
}
|
|
|
|
fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I)
|
|
where
|
|
I: Iterator<Item = (&'a T::AccountId, T::BeefyId)>,
|
|
{
|
|
let next_authorities = validators.map(|(_, k)| k).collect::<Vec<_>>();
|
|
let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::<Vec<_>>();
|
|
|
|
// Always issue a change on each `session`, even if validator set hasn't changed.
|
|
// We want to have at least one BEEFY mandatory block per session.
|
|
Self::change_authorities(next_authorities, next_queued_authorities);
|
|
}
|
|
|
|
fn on_disabled(i: u32) {
|
|
let log = DigestItem::Consensus(
|
|
BEEFY_ENGINE_ID,
|
|
ConsensusLog::<T::BeefyId>::OnDisabled(i as AuthorityIndex).encode(),
|
|
);
|
|
|
|
<frame_system::Pallet<T>>::deposit_log(log);
|
|
}
|
|
}
|
|
|
|
impl<T: Config> IsMember<T::BeefyId> for Pallet<T> {
|
|
fn is_member(authority_id: &T::BeefyId) -> bool {
|
|
Self::authorities().iter().any(|id| id == authority_id)
|
|
}
|
|
}
|