diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e690ce8a3b3a4..5604279750548 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -883,6 +883,7 @@ parameter_types! { pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; + pub const MaxAuthorities: u32 = 100; } impl frame_system::offchain::CreateSignedTransaction for Runtime @@ -955,7 +956,9 @@ impl pallet_offences::Config for Runtime { type OnOffenceHandler = Staking; } -impl pallet_authority_discovery::Config for Runtime {} +impl pallet_authority_discovery::Config for Runtime { + type MaxAuthorities = MaxAuthorities; +} impl pallet_grandpa::Config for Runtime { type Event = Event; diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 4577a9dd17226..d093b1533c693 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -23,10 +23,15 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::OneSessionHandler; +use frame_support::{ + traits::{Get, OneSessionHandler}, + WeakBoundedVec, +}; use sp_authority_discovery::AuthorityId; use sp_std::prelude::*; +use core::convert::TryFrom; + pub use pallet::*; #[frame_support::pallet] @@ -36,21 +41,27 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] /// The pallet's config trait. - pub trait Config: frame_system::Config + pallet_session::Config {} + pub trait Config: frame_system::Config + pallet_session::Config { + /// The maximum number of authorities that can be added. + type MaxAuthorities: Get; + } #[pallet::storage] #[pallet::getter(fn keys)] /// Keys of the current authority set. - pub(super) type Keys = StorageValue<_, Vec, ValueQuery>; + pub(super) type Keys = + StorageValue<_, WeakBoundedVec, ValueQuery>; #[pallet::storage] #[pallet::getter(fn next_keys)] /// Keys of the next authority set. - pub(super) type NextKeys = StorageValue<_, Vec, ValueQuery>; + pub(super) type NextKeys = + StorageValue<_, WeakBoundedVec, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { @@ -75,31 +86,36 @@ impl Pallet { /// Retrieve authority identifiers of the current and next authority set /// sorted and deduplicated. pub fn authorities() -> Vec { - let mut keys = Keys::::get(); - let next = NextKeys::::get(); + let mut keys = Keys::::get().to_vec(); + let next = NextKeys::::get().to_vec(); keys.extend(next); keys.sort(); keys.dedup(); - keys + keys.to_vec() } /// Retrieve authority identifiers of the current authority set in the original order. - pub fn current_authorities() -> Vec { + pub fn current_authorities() -> WeakBoundedVec { Keys::::get() } /// Retrieve authority identifiers of the next authority set in the original order. - pub fn next_authorities() -> Vec { + pub fn next_authorities() -> WeakBoundedVec { NextKeys::::get() } - fn initialize_keys(keys: &[AuthorityId]) { + fn initialize_keys(keys: &Vec) { if !keys.is_empty() { assert!(Keys::::get().is_empty(), "Keys are already initialized!"); - Keys::::put(keys); - NextKeys::::put(keys); + + let bounded_keys = + WeakBoundedVec::::try_from((*keys).clone()) + .expect("Keys vec too big"); + + Keys::::put(&bounded_keys); + NextKeys::::put(&bounded_keys); } } } @@ -124,10 +140,29 @@ impl OneSessionHandler for Pallet { { // Remember who the authorities are for the new and next session. if changed { - let keys = validators.map(|x| x.1); - Keys::::put(keys.collect::>()); - let next_keys = queued_validators.map(|x| x.1); - NextKeys::::put(next_keys.collect::>()); + let keys = validators.map(|x| x.1).collect::>(); + + let bounded_keys = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( + keys, + Some( + "Warning: The session has more validators than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); + + Keys::::put(bounded_keys); + + let next_keys = queued_validators.map(|x| x.1).collect::>(); + + let next_bounded_keys = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( + next_keys, + Some( + "Warning: The session has more queued validators than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); + + NextKeys::::put(next_bounded_keys); } } @@ -166,10 +201,13 @@ mod tests { } ); - impl Config for Test {} - parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); + pub const MaxAuthorities: u32 = 100; + } + + impl Config for Test { + type MaxAuthorities = MaxAuthorities; } impl pallet_session::Config for Test { diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 95b8c1f11f80c..43a14e29f4ee5 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -259,6 +259,7 @@ macro_rules! app_crypto_public_not_full_crypto { $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, + $crate::codec::MaxEncodedLen, )] pub struct Public($public); } diff --git a/primitives/consensus/slots/src/lib.rs b/primitives/consensus/slots/src/lib.rs index 545d18af1f9be..0b66ac8c9cb6f 100644 --- a/primitives/consensus/slots/src/lib.rs +++ b/primitives/consensus/slots/src/lib.rs @@ -19,10 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; /// Unit type wrapper that represents a slot. -#[derive(Debug, Encode, Decode, Eq, Clone, Copy, Default, Ord)] +#[derive(Debug, Encode, MaxEncodedLen, Decode, Eq, Clone, Copy, Default, Ord)] pub struct Slot(u64); impl core::ops::Deref for Slot {