Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Implement MaxEncodedLen on pallet-beefy #11584

Merged
merged 9 commits into from
Jun 13, 2022
1 change: 1 addition & 0 deletions frame/beefy-mmr/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ impl pallet_mmr::Config for Test {

impl pallet_beefy::Config for Test {
type BeefyId = BeefyId;
type MaxAuthorities = ConstU32<100>;
}

parameter_types! {
Expand Down
58 changes: 40 additions & 18 deletions frame/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

#![cfg_attr(not(feature = "std"), no_std)]

use codec::Encode;
use codec::{Encode, MaxEncodedLen};

use frame_support::{traits::OneSessionHandler, Parameter};
use frame_support::{traits::OneSessionHandler, BoundedSlice, Parameter, WeakBoundedVec};

use sp_runtime::{
generic::DigestItem,
Expand All @@ -42,28 +42,28 @@ pub use 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;
type BeefyId: Member
+ Parameter
+ RuntimeAppPublic
+ MaybeSerializeDeserialize
+ MaxEncodedLen;

/// The maximum number of authorities that can be added.
type MaxAuthorities: Get<u32>;
}

#[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>;
pub(super) type Authorities<T: Config> =
StorageValue<_, WeakBoundedVec<T::BeefyId, T::MaxAuthorities>, ValueQuery>;

/// The current validator set id
#[pallet::storage]
Expand All @@ -74,7 +74,8 @@ pub mod pallet {
/// 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>;
pub(super) type NextAuthorities<T: Config> =
StorageValue<_, WeakBoundedVec<T::BeefyId, T::MaxAuthorities>, ValueQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
Expand All @@ -99,12 +100,15 @@ pub mod pallet {
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 validators: WeakBoundedVec<T::BeefyId, T::MaxAuthorities> = Self::authorities();
KiChjang marked this conversation as resolved.
Show resolved Hide resolved
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>) {
fn change_authorities(
new: WeakBoundedVec<T::BeefyId, T::MaxAuthorities>,
queued: WeakBoundedVec<T::BeefyId, T::MaxAuthorities>,
) {
<Authorities<T>>::put(&new);

let next_id = Self::validator_set_id() + 1u64;
Expand All @@ -127,10 +131,14 @@ impl<T: Config> Pallet<T> {

assert!(<Authorities<T>>::get().is_empty(), "Authorities are already initialized!");

<Authorities<T>>::put(authorities);
let bounded_authorities =
BoundedSlice::<T::BeefyId, T::MaxAuthorities>::try_from(authorities)
.expect("Authorities vec too big");
KiChjang marked this conversation as resolved.
Show resolved Hide resolved

<Authorities<T>>::put(bounded_authorities);
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
<ValidatorSetId<T>>::put(0);
// Like `pallet_session`, initialize the next validator set as well.
<NextAuthorities<T>>::put(authorities);
<NextAuthorities<T>>::put(bounded_authorities);
}
}

Expand All @@ -154,11 +162,25 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
I: Iterator<Item = (&'a T::AccountId, T::BeefyId)>,
{
let next_authorities = validators.map(|(_, k)| k).collect::<Vec<_>>();
let bounded_next_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
next_authorities,
Some(
"Warning: The session has more validators than expected. \
A runtime configuration adjustment may be needed.",
),
);
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::<Vec<_>>();
let bounded_next_queued_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
next_queued_authorities,
Some(
"Warning: The session has more queued validators than expected. \
A runtime configuration adjustment may be needed.",
),
);

// 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);
Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities);
}

fn on_disabled(i: u32) {
Expand Down
3 changes: 2 additions & 1 deletion frame/beefy/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ construct_runtime!(
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Beefy: pallet_beefy::{Pallet, Call, Config<T>, Storage},
Beefy: pallet_beefy::{Pallet, Config<T>, Storage},
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
}
);
Expand Down Expand Up @@ -86,6 +86,7 @@ impl frame_system::Config for Test {

impl pallet_beefy::Config for Test {
type BeefyId = BeefyId;
type MaxAuthorities = ConstU32<100>;
}

parameter_types! {
Expand Down
9 changes: 9 additions & 0 deletions frame/support/src/storage/bounded_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ where
#[scale_info(skip_type_params(S))]
pub struct BoundedSlice<'a, T, S>(&'a [T], PhantomData<S>);

impl<'a, T, S> Clone for BoundedSlice<'a, T, S> {
fn clone(&self) -> Self {
BoundedSlice(self.0, PhantomData)
}
}

// Since a slice `&[]` is always `Copy`, so is `BoundedSlice`.
impl<'a, T, S> Copy for BoundedSlice<'a, T, S> {}

// `BoundedSlice`s encode to something which will always decode into a `BoundedVec`,
// `WeakBoundedVec`, or a `Vec`.
impl<'a, T: Encode + Decode, S: Get<u32>> EncodeLike<BoundedVec<T, S>> for BoundedSlice<'a, T, S> {}
Expand Down