From 5922da95e595280f64a115e9531e2e58cd648337 Mon Sep 17 00:00:00 2001
From: Georges <georges.dib@gmail.com>
Date: Wed, 22 Sep 2021 23:49:36 +0100
Subject: [PATCH] Generate storage info for pallet babe (#9760)

* Adding MaxEncodedLen for:
* NextConfigDescriptor
* AllowedSlots
* BabeEpochConfiguration

In prepation for adding storage information on pallet babe

* Adding stotage_info to pallet babe

Refactored UNDER_CONSTRUCTION_SEGMENT_LENGTH to become a runtime
parameter MaxSegmentLength

* Reinstate Slice as opposed to Vec

* Refactoring code to make it neater

* Replace `MaxSegmentLength` by
`UNDER_CONSTRUCTION_SEGMENT_LENGTH`
Stop exposing the bounds to the runtime

* Removing extra line

Co-authored-by: thiolliere <gui.thiolliere@gmail.com>
---
 substrate/bin/node/runtime/src/lib.rs         |  3 +-
 substrate/frame/babe/src/lib.rs               | 86 ++++++++++++++-----
 substrate/frame/babe/src/mock.rs              |  3 +
 substrate/frame/babe/src/tests.rs             |  2 +-
 .../primitives/consensus/babe/src/digests.rs  |  6 +-
 .../primitives/consensus/babe/src/lib.rs      |  6 +-
 substrate/test-utils/runtime/src/lib.rs       |  4 +-
 7 files changed, 80 insertions(+), 30 deletions(-)

diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index af465fc0ffc..587a54ebd0d 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -376,6 +376,7 @@ impl pallet_babe::Config for Runtime {
 		pallet_babe::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;
 
 	type WeightInfo = ();
+	type MaxAuthorities = MaxAuthorities;
 }
 
 parameter_types! {
@@ -1441,7 +1442,7 @@ impl_runtime_apis! {
 				slot_duration: Babe::slot_duration(),
 				epoch_length: EpochDuration::get(),
 				c: BABE_GENESIS_EPOCH_CONFIG.c,
-				genesis_authorities: Babe::authorities(),
+				genesis_authorities: Babe::authorities().to_vec(),
 				randomness: Babe::randomness(),
 				allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots,
 			}
diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs
index b39074bb3f0..4ccfdf6c13f 100644
--- a/substrate/frame/babe/src/lib.rs
+++ b/substrate/frame/babe/src/lib.rs
@@ -25,11 +25,13 @@ use codec::{Decode, Encode};
 use frame_support::{
 	dispatch::DispatchResultWithPostInfo,
 	traits::{
-		DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, OneSessionHandler,
+		ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet,
+		OneSessionHandler,
 	},
 	weights::{Pays, Weight},
+	BoundedVec, WeakBoundedVec,
 };
-use sp_application_crypto::Public;
+use sp_application_crypto::{Public, TryFrom};
 use sp_runtime::{
 	generic::DigestItem,
 	traits::{IsMember, One, SaturatedConversion, Saturating, Zero},
@@ -100,7 +102,7 @@ impl EpochChangeTrigger for SameAuthoritiesForever {
 	}
 }
 
-const UNDER_CONSTRUCTION_SEGMENT_LENGTH: usize = 256;
+const UNDER_CONSTRUCTION_SEGMENT_LENGTH: u32 = 256;
 
 type MaybeRandomness = Option<schnorrkel::Randomness>;
 
@@ -113,6 +115,7 @@ pub mod pallet {
 	/// The BABE Pallet
 	#[pallet::pallet]
 	#[pallet::generate_store(pub(super) trait Store)]
+	#[pallet::generate_storage_info]
 	pub struct Pallet<T>(_);
 
 	#[pallet::config]
@@ -169,6 +172,10 @@ pub mod pallet {
 		type HandleEquivocation: HandleEquivocation<Self>;
 
 		type WeightInfo: WeightInfo;
+
+		/// Max number of authorities allowed
+		#[pallet::constant]
+		type MaxAuthorities: Get<u32>;
 	}
 
 	#[pallet::error]
@@ -189,7 +196,11 @@ pub mod pallet {
 	/// Current epoch authorities.
 	#[pallet::storage]
 	#[pallet::getter(fn authorities)]
-	pub type Authorities<T> = StorageValue<_, Vec<(AuthorityId, BabeAuthorityWeight)>, ValueQuery>;
+	pub type Authorities<T: Config> = StorageValue<
+		_,
+		WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>,
+		ValueQuery,
+	>;
 
 	/// The slot at which the first epoch actually started. This is 0
 	/// until the first block of the chain.
@@ -229,8 +240,11 @@ pub mod pallet {
 
 	/// Next epoch authorities.
 	#[pallet::storage]
-	pub(super) type NextAuthorities<T> =
-		StorageValue<_, Vec<(AuthorityId, BabeAuthorityWeight)>, ValueQuery>;
+	pub(super) type NextAuthorities<T: Config> = StorageValue<
+		_,
+		WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>,
+		ValueQuery,
+	>;
 
 	/// Randomness under construction.
 	///
@@ -246,8 +260,13 @@ pub mod pallet {
 
 	/// TWOX-NOTE: `SegmentIndex` is an increasing integer, so this is okay.
 	#[pallet::storage]
-	pub(super) type UnderConstruction<T> =
-		StorageMap<_, Twox64Concat, u32, Vec<schnorrkel::Randomness>, ValueQuery>;
+	pub(super) type UnderConstruction<T: Config> = StorageMap<
+		_,
+		Twox64Concat,
+		u32,
+		BoundedVec<schnorrkel::Randomness, ConstU32<UNDER_CONSTRUCTION_SEGMENT_LENGTH>>,
+		ValueQuery,
+	>;
 
 	/// Temporary value (cleared at block finalization) which is `Some`
 	/// if per-block initialization has already been called for current block.
@@ -503,8 +522,8 @@ impl<T: Config> Pallet<T> {
 	/// Typically, this is not handled directly by the user, but by higher-level validator-set
 	/// manager logic like `pallet-session`.
 	pub fn enact_epoch_change(
-		authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
-		next_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
+		authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>,
+		next_authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>,
 	) {
 		// PRECONDITION: caller has done initialization and is guaranteed
 		// by the session module to be called before this.
@@ -541,8 +560,10 @@ impl<T: Config> Pallet<T> {
 		// so that nodes can track changes.
 		let next_randomness = NextRandomness::<T>::get();
 
-		let next_epoch =
-			NextEpochDescriptor { authorities: next_authorities, randomness: next_randomness };
+		let next_epoch = NextEpochDescriptor {
+			authorities: next_authorities.to_vec(),
+			randomness: next_randomness,
+		};
 		Self::deposit_consensus(ConsensusLog::NextEpochData(next_epoch));
 
 		if let Some(next_config) = NextEpochConfig::<T>::get() {
@@ -571,7 +592,7 @@ impl<T: Config> Pallet<T> {
 			epoch_index: EpochIndex::<T>::get(),
 			start_slot: Self::current_epoch_start(),
 			duration: T::EpochDuration::get(),
-			authorities: Self::authorities(),
+			authorities: Self::authorities().to_vec(),
 			randomness: Self::randomness(),
 			config: EpochConfig::<T>::get()
 				.expect("EpochConfig is initialized in genesis; we never `take` or `kill` it; qed"),
@@ -590,7 +611,7 @@ impl<T: Config> Pallet<T> {
 			epoch_index: next_epoch_index,
 			start_slot: Self::epoch_start(next_epoch_index),
 			duration: T::EpochDuration::get(),
-			authorities: NextAuthorities::<T>::get(),
+			authorities: NextAuthorities::<T>::get().to_vec(),
 			randomness: NextRandomness::<T>::get(),
 			config: NextEpochConfig::<T>::get().unwrap_or_else(|| {
 				EpochConfig::<T>::get().expect(
@@ -619,14 +640,18 @@ impl<T: Config> Pallet<T> {
 	fn deposit_randomness(randomness: &schnorrkel::Randomness) {
 		let segment_idx = SegmentIndex::<T>::get();
 		let mut segment = UnderConstruction::<T>::get(&segment_idx);
-		if segment.len() < UNDER_CONSTRUCTION_SEGMENT_LENGTH {
+		if segment.try_push(*randomness).is_ok() {
 			// push onto current segment: not full.
-			segment.push(*randomness);
 			UnderConstruction::<T>::insert(&segment_idx, &segment);
 		} else {
 			// move onto the next segment and update the index.
 			let segment_idx = segment_idx + 1;
-			UnderConstruction::<T>::insert(&segment_idx, &vec![randomness.clone()]);
+			let bounded_randomness =
+				BoundedVec::<_, ConstU32<UNDER_CONSTRUCTION_SEGMENT_LENGTH>>::try_from(vec![
+					randomness.clone(),
+				])
+				.expect("UNDER_CONSTRUCTION_SEGMENT_LENGTH >= 1");
+			UnderConstruction::<T>::insert(&segment_idx, bounded_randomness);
 			SegmentIndex::<T>::put(&segment_idx);
 		}
 	}
@@ -667,7 +692,7 @@ impl<T: Config> Pallet<T> {
 				// we use the same values as genesis because we haven't collected any
 				// randomness yet.
 				let next = NextEpochDescriptor {
-					authorities: Self::authorities(),
+					authorities: Self::authorities().to_vec(),
 					randomness: Self::randomness(),
 				};
 
@@ -732,7 +757,7 @@ impl<T: Config> Pallet<T> {
 		let segment_idx: u32 = SegmentIndex::<T>::mutate(|s| sp_std::mem::replace(s, 0));
 
 		// overestimate to the segment being full.
-		let rho_size = segment_idx.saturating_add(1) as usize * UNDER_CONSTRUCTION_SEGMENT_LENGTH;
+		let rho_size = (segment_idx.saturating_add(1) * UNDER_CONSTRUCTION_SEGMENT_LENGTH) as usize;
 
 		let next_randomness = compute_randomness(
 			this_randomness,
@@ -747,8 +772,11 @@ impl<T: Config> Pallet<T> {
 	fn initialize_authorities(authorities: &[(AuthorityId, BabeAuthorityWeight)]) {
 		if !authorities.is_empty() {
 			assert!(Authorities::<T>::get().is_empty(), "Authorities are already initialized!");
-			Authorities::<T>::put(authorities);
-			NextAuthorities::<T>::put(authorities);
+			let bounded_authorities =
+				WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.to_vec())
+					.expect("Initial number of authorities should be lower than T::MaxAuthorities");
+			Authorities::<T>::put(&bounded_authorities);
+			NextAuthorities::<T>::put(&bounded_authorities);
 		}
 	}
 
@@ -878,10 +906,24 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
 		I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
 	{
 		let authorities = validators.map(|(_account, k)| (k, 1)).collect::<Vec<_>>();
+		let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
+			authorities,
+			Some(
+				"Warning: The session has more validators than expected. \
+				A runtime configuration adjustment may be needed.",
+			),
+		);
 
 		let next_authorities = queued_validators.map(|(_account, k)| (k, 1)).collect::<Vec<_>>();
+		let next_bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
+			next_authorities,
+			Some(
+				"Warning: The session has more queued validators than expected. \
+				A runtime configuration adjustment may be needed.",
+			),
+		);
 
-		Self::enact_epoch_change(authorities, next_authorities)
+		Self::enact_epoch_change(bounded_authorities, next_bounded_authorities)
 	}
 
 	fn on_disabled(i: usize) {
diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs
index 833a68fbddb..a05072bc331 100644
--- a/substrate/frame/babe/src/mock.rs
+++ b/substrate/frame/babe/src/mock.rs
@@ -230,6 +230,8 @@ parameter_types! {
 	pub const ExpectedBlockTime: u64 = 1;
 	pub const ReportLongevity: u64 =
 		BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get();
+	pub const MaxAuthorities: u32 = 10;
+	pub const MaxSegmentLength: u32 = 256;
 }
 
 impl Config for Test {
@@ -252,6 +254,7 @@ impl Config for Test {
 		super::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;
 
 	type WeightInfo = ();
+	type MaxAuthorities = MaxAuthorities;
 }
 
 pub fn go_to_block(n: u64, s: u64) {
diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs
index dc2f74c7195..34d861d5d97 100644
--- a/substrate/frame/babe/src/tests.rs
+++ b/substrate/frame/babe/src/tests.rs
@@ -92,7 +92,7 @@ fn first_block_epoch_zero_start() {
 
 		let consensus_log = sp_consensus_babe::ConsensusLog::NextEpochData(
 			sp_consensus_babe::digests::NextEpochDescriptor {
-				authorities: Babe::authorities(),
+				authorities: Babe::authorities().to_vec(),
 				randomness: Babe::randomness(),
 			},
 		);
diff --git a/substrate/primitives/consensus/babe/src/digests.rs b/substrate/primitives/consensus/babe/src/digests.rs
index 470a028021c..1c908fe61fc 100644
--- a/substrate/primitives/consensus/babe/src/digests.rs
+++ b/substrate/primitives/consensus/babe/src/digests.rs
@@ -21,7 +21,7 @@ use super::{
 	AllowedSlots, AuthorityId, AuthorityIndex, AuthoritySignature, BabeAuthorityWeight,
 	BabeEpochConfiguration, Slot, BABE_ENGINE_ID,
 };
-use codec::{Codec, Decode, Encode};
+use codec::{Codec, Decode, Encode, MaxEncodedLen};
 use sp_runtime::{DigestItem, RuntimeDebug};
 use sp_std::vec::Vec;
 
@@ -134,7 +134,9 @@ pub struct NextEpochDescriptor {
 
 /// Information about the next epoch config, if changed. This is broadcast in the first
 /// block of the epoch, and applies using the same rules as `NextEpochDescriptor`.
-#[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug, scale_info::TypeInfo)]
+#[derive(
+	Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo,
+)]
 pub enum NextConfigDescriptor {
 	/// Version 1.
 	#[codec(index = 1)]
diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs
index 4417670f414..560866cfb2a 100644
--- a/substrate/primitives/consensus/babe/src/lib.rs
+++ b/substrate/primitives/consensus/babe/src/lib.rs
@@ -28,7 +28,7 @@ pub use sp_consensus_vrf::schnorrkel::{
 	Randomness, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH,
 };
 
-use codec::{Decode, Encode};
+use codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
@@ -214,7 +214,7 @@ pub struct BabeGenesisConfiguration {
 }
 
 /// Types of allowed slots.
-#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
+#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub enum AllowedSlots {
 	/// Only allow primary slots.
@@ -247,7 +247,7 @@ impl sp_consensus::SlotData for BabeGenesisConfiguration {
 }
 
 /// Configuration data used by the BABE consensus engine.
-#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
+#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub struct BabeEpochConfiguration {
 	/// A constant value that is used in the threshold calculation formula.
diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs
index 0d880d508ef..479d69c4375 100644
--- a/substrate/test-utils/runtime/src/lib.rs
+++ b/substrate/test-utils/runtime/src/lib.rs
@@ -574,6 +574,7 @@ impl pallet_timestamp::Config for Runtime {
 parameter_types! {
 	pub const EpochDuration: u64 = 6;
 	pub const ExpectedBlockTime: u64 = 10_000;
+	pub const MaxAuthorities: u32 = 10;
 }
 
 impl pallet_babe::Config for Runtime {
@@ -596,8 +597,9 @@ impl pallet_babe::Config for Runtime {
 	)>>::IdentificationTuple;
 
 	type HandleEquivocation = ();
-
 	type WeightInfo = ();
+
+	type MaxAuthorities = MaxAuthorities;
 }
 
 /// Adds one to the given input and returns the final result.
-- 
GitLab