From 7f2a99fc03b58f7be4c62eb4ecd3fe2cb743fd1a Mon Sep 17 00:00:00 2001
From: ordian <write@reusable.software>
Date: Fri, 19 Jul 2024 18:06:00 +0200
Subject: [PATCH] beefy: put not only lease parachain heads into mmr (#4751)

Short-term addresses
https://github.com/paritytech/polkadot-sdk/issues/4737.

- [x] Resolve benchmarking
I've digged into benchmarking mentioned
https://github.com/paritytech/polkadot-sdk/issues/4737#issuecomment-2155084660,
but it seemed to me that this code is different proof/path. @acatangiu
could you confirm? (btw, in this
[bench](https://github.com/paritytech/polkadot-sdk/blob/b65313e81465dd730e48d4ce00deb76922618375/bridges/modules/parachains/src/benchmarking.rs#L57),
where do you actually set the `fn parachains()` to a reasonable number?
i've only seen 1)
- [ ] Communicate to Snowfork team:
This seems to be the relevant code:
https://github.com/Snowfork/snowbridge/blob/1e18e010331777042aa7e8fff3c118094af856ba/relayer/cmd/parachain_head_proof.go#L95-L120
- [x] Is it preferred to iter() in some random order as suggested in
https://github.com/paritytech/polkadot-sdk/issues/4737#issuecomment-2155084660
or take lowest para ids instead as implemented here currently?
- [x] PRDoc

## Updating Polkadot and Kusama runtimes:

New weights need to be generated (`pallet_mmr`) and configs updated
similar to Rococo/Westend:
```patch
diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs
index 5adffbd7422..c7da339b981 100644
--- a/polkadot/runtime/rococo/src/lib.rs
+++ b/polkadot/runtime/rococo/src/lib.rs
@@ -1307,9 +1307,11 @@ impl pallet_mmr::Config for Runtime {
        const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
        type Hashing = Keccak256;
        type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
-       type WeightInfo = ();
        type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
        type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider<Runtime>;
+       type WeightInfo = weights::pallet_mmr::WeightInfo<Runtime>;
+       #[cfg(feature = "runtime-benchmarks")]
+       type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup<Runtime>;
 }

 parameter_types! {
@@ -1319,13 +1321,8 @@ parameter_types! {
 pub struct ParaHeadsRootProvider;
 impl BeefyDataProvider<H256> for ParaHeadsRootProvider {
        fn extra_data() -> H256 {
-               let mut para_heads: Vec<(u32, Vec<u8>)> = parachains_paras::Parachains::<Runtime>::get()
-                       .into_iter()
-                       .filter_map(|id| {
-                               parachains_paras::Heads::<Runtime>::get(&id).map(|head| (id.into(), head.0))
-                       })
-                       .collect();
-               para_heads.sort();
+               let para_heads: Vec<(u32, Vec<u8>)> =
+                       parachains_paras::Pallet::<Runtime>::sorted_para_heads();
                binary_merkle_tree::merkle_root::<mmr::Hashing, _>(
                        para_heads.into_iter().map(|pair| pair.encode()),
                )
@@ -1746,6 +1743,7 @@ mod benches {
                [pallet_identity, Identity]
                [pallet_indices, Indices]
                [pallet_message_queue, MessageQueue]
+               [pallet_mmr, Mmr]
                [pallet_multisig, Multisig]
                [pallet_parameters, Parameters]
                [pallet_preimage, Preimage]
```

---------

Co-authored-by: Adrian Catangiu <adrian@parity.io>
---
 Cargo.lock                                    |  2 +
 polkadot/runtime/parachains/Cargo.toml        |  7 ++
 .../parachains/src/paras/benchmarking.rs      |  1 +
 .../src/paras/benchmarking/mmr_setup.rs       | 40 ++++++++++
 polkadot/runtime/parachains/src/paras/mod.rs  | 21 ++++-
 polkadot/runtime/rococo/Cargo.toml            |  6 +-
 polkadot/runtime/rococo/src/lib.rs            | 14 ++--
 polkadot/runtime/rococo/src/weights/mod.rs    |  1 +
 .../runtime/rococo/src/weights/pallet_mmr.rs  | 77 +++++++++++++++++++
 polkadot/runtime/westend/Cargo.toml           |  6 +-
 polkadot/runtime/westend/src/lib.rs           | 14 ++--
 polkadot/runtime/westend/src/weights/mod.rs   |  1 +
 .../runtime/westend/src/weights/pallet_mmr.rs | 76 ++++++++++++++++++
 prdoc/pr_4751.prdoc                           | 22 ++++++
 substrate/bin/node/runtime/src/lib.rs         |  2 +
 substrate/frame/beefy-mmr/Cargo.toml          |  7 ++
 substrate/frame/beefy-mmr/src/mock.rs         |  3 +
 .../merkle-mountain-range/src/benchmarking.rs |  9 ++-
 .../src/default_weights.rs                    |  3 +-
 .../frame/merkle-mountain-range/src/lib.rs    | 23 +++++-
 .../frame/merkle-mountain-range/src/mock.rs   |  2 +
 umbrella/Cargo.toml                           |  1 +
 22 files changed, 311 insertions(+), 27 deletions(-)
 create mode 100644 polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs
 create mode 100644 polkadot/runtime/rococo/src/weights/pallet_mmr.rs
 create mode 100644 polkadot/runtime/westend/src/weights/pallet_mmr.rs
 create mode 100644 prdoc/pr_4751.prdoc

diff --git a/Cargo.lock b/Cargo.lock
index 6c837a051ce..2bb1a758baf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14076,6 +14076,7 @@ dependencies = [
  "pallet-balances",
  "pallet-broker",
  "pallet-message-queue",
+ "pallet-mmr",
  "pallet-session",
  "pallet-staking",
  "pallet-timestamp",
@@ -14105,6 +14106,7 @@ dependencies = [
  "sp-runtime",
  "sp-session",
  "sp-staking",
+ "sp-std 14.0.0",
  "sp-tracing 16.0.0",
  "staging-xcm",
  "staging-xcm-executor",
diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml
index 7afdf49fe55..cfe373e8cba 100644
--- a/polkadot/runtime/parachains/Cargo.toml
+++ b/polkadot/runtime/parachains/Cargo.toml
@@ -30,6 +30,7 @@ sp-keystore = { optional = true, workspace = true }
 sp-application-crypto = { optional = true, workspace = true }
 sp-tracing = { optional = true, workspace = true }
 sp-arithmetic = { workspace = true }
+sp-std = { workspace = true, optional = true }
 
 pallet-authority-discovery = { workspace = true }
 pallet-authorship = { workspace = true }
@@ -37,6 +38,7 @@ pallet-balances = { workspace = true }
 pallet-babe = { workspace = true }
 pallet-broker = { workspace = true }
 pallet-message-queue = { workspace = true }
+pallet-mmr = { workspace = true, optional = true }
 pallet-session = { workspace = true }
 pallet-staking = { workspace = true }
 pallet-timestamp = { workspace = true }
@@ -86,6 +88,7 @@ std = [
 	"pallet-balances/std",
 	"pallet-broker/std",
 	"pallet-message-queue/std",
+	"pallet-mmr?/std",
 	"pallet-session/std",
 	"pallet-staking/std",
 	"pallet-timestamp/std",
@@ -109,6 +112,7 @@ std = [
 	"sp-runtime/std",
 	"sp-session/std",
 	"sp-staking/std",
+	"sp-std?/std",
 	"xcm-executor/std",
 	"xcm/std",
 ]
@@ -120,6 +124,7 @@ runtime-benchmarks = [
 	"pallet-balances/runtime-benchmarks",
 	"pallet-broker/runtime-benchmarks",
 	"pallet-message-queue/runtime-benchmarks",
+	"pallet-mmr/runtime-benchmarks",
 	"pallet-staking/runtime-benchmarks",
 	"pallet-timestamp/runtime-benchmarks",
 	"pallet-vesting/runtime-benchmarks",
@@ -128,6 +133,7 @@ runtime-benchmarks = [
 	"sp-application-crypto",
 	"sp-runtime/runtime-benchmarks",
 	"sp-staking/runtime-benchmarks",
+	"sp-std",
 	"static_assertions",
 	"xcm-executor/runtime-benchmarks",
 ]
@@ -141,6 +147,7 @@ try-runtime = [
 	"pallet-balances/try-runtime",
 	"pallet-broker/try-runtime",
 	"pallet-message-queue/try-runtime",
+	"pallet-mmr/try-runtime",
 	"pallet-session/try-runtime",
 	"pallet-staking/try-runtime",
 	"pallet-timestamp/try-runtime",
diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs
index 630b86132ab..7bf8b833ed9 100644
--- a/polkadot/runtime/parachains/src/paras/benchmarking.rs
+++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs
@@ -24,6 +24,7 @@ use polkadot_primitives::{
 };
 use sp_runtime::traits::{One, Saturating};
 
+pub mod mmr_setup;
 mod pvf_check;
 
 use self::pvf_check::{VoteCause, VoteOutcome};
diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs b/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs
new file mode 100644
index 00000000000..ab007692e78
--- /dev/null
+++ b/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs
@@ -0,0 +1,40 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Implements benchmarking setup for the `merkle-mountain-range` pallet.
+
+use crate::paras::*;
+use pallet_mmr::BenchmarkHelper;
+use sp_std::vec;
+
+/// Struct to setup benchmarks for the `merkle-mountain-range` pallet.
+pub struct MmrSetup<T>(core::marker::PhantomData<T>);
+
+impl<T> BenchmarkHelper for MmrSetup<T>
+where
+	T: Config,
+{
+	fn setup() {
+		// Create a head with 1024 bytes of data.
+		let head = vec![42u8; 1024];
+
+		for para in 0..MAX_PARA_HEADS {
+			let id = (para as u32).into();
+			let h = head.clone().into();
+			Pallet::<T>::heads_insert(&id, h);
+		}
+	}
+}
diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs
index 3f0b8659b15..a4c404de2a6 100644
--- a/polkadot/runtime/parachains/src/paras/mod.rs
+++ b/polkadot/runtime/parachains/src/paras/mod.rs
@@ -135,7 +135,7 @@ use serde::{Deserialize, Serialize};
 pub use crate::Origin as ParachainOrigin;
 
 #[cfg(feature = "runtime-benchmarks")]
-pub(crate) mod benchmarking;
+pub mod benchmarking;
 
 #[cfg(test)]
 pub(crate) mod tests;
@@ -1222,6 +1222,15 @@ const INVALID_TX_BAD_VALIDATOR_IDX: u8 = 1;
 const INVALID_TX_BAD_SUBJECT: u8 = 2;
 const INVALID_TX_DOUBLE_VOTE: u8 = 3;
 
+/// This is intermediate "fix" for this issue:
+/// <https://github.com/paritytech/polkadot-sdk/issues/4737>
+///
+/// It does not actually fix it, but makes the worst case better. Without that limit someone
+/// could completely DoS the relay chain by registering a ridiculously high amount of paras.
+/// With this limit the same attack could lead to some parachains ceasing to being able to
+/// communicate via offchain XCMP. Snowbridge will still work as it only cares about `BridgeHub`.
+pub const MAX_PARA_HEADS: usize = 1024;
+
 impl<T: Config> Pallet<T> {
 	/// This is a call to schedule code upgrades for parachains which is safe to be called
 	/// outside of this module. That means this function does all checks necessary to ensure
@@ -1291,6 +1300,16 @@ impl<T: Config> Pallet<T> {
 		})
 	}
 
+	/// Get a list of the first [`MAX_PARA_HEADS`] para heads sorted by para_id.
+	/// This method is likely to be removed in the future.
+	pub fn sorted_para_heads() -> Vec<(u32, Vec<u8>)> {
+		let mut heads: Vec<(u32, Vec<u8>)> =
+			Heads::<T>::iter().map(|(id, head)| (id.into(), head.0)).collect();
+		heads.sort_by_key(|(id, _)| *id);
+		heads.truncate(MAX_PARA_HEADS);
+		heads
+	}
+
 	// Apply all para actions queued for the given session index.
 	//
 	// The actions to take are based on the lifecycle of of the paras.
diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml
index f93a3ad6575..50970965e11 100644
--- a/polkadot/runtime/rococo/Cargo.toml
+++ b/polkadot/runtime/rococo/Cargo.toml
@@ -226,6 +226,7 @@ runtime-benchmarks = [
 	"pallet-asset-rate/runtime-benchmarks",
 	"pallet-babe/runtime-benchmarks",
 	"pallet-balances/runtime-benchmarks",
+	"pallet-beefy-mmr/runtime-benchmarks",
 	"pallet-bounties/runtime-benchmarks",
 	"pallet-child-bounties/runtime-benchmarks",
 	"pallet-collective/runtime-benchmarks",
@@ -330,7 +331,10 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"]
 # Set timing constants (e.g. session period) to faster versions to speed up testing.
 fast-runtime = ["rococo-runtime-constants/fast-runtime"]
 
-runtime-metrics = ["polkadot-runtime-parachains/runtime-metrics", "sp-io/with-tracing"]
+runtime-metrics = [
+	"polkadot-runtime-parachains/runtime-metrics",
+	"sp-io/with-tracing",
+]
 
 # A feature that should be enabled when the runtime should be built for on-chain
 # deployment. This will disable stuff that shouldn't be part of the on-chain wasm
diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs
index 5adffbd7422..c7da339b981 100644
--- a/polkadot/runtime/rococo/src/lib.rs
+++ b/polkadot/runtime/rococo/src/lib.rs
@@ -1307,9 +1307,11 @@ impl pallet_mmr::Config for Runtime {
 	const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
 	type Hashing = Keccak256;
 	type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
-	type WeightInfo = ();
 	type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
 	type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider<Runtime>;
+	type WeightInfo = weights::pallet_mmr::WeightInfo<Runtime>;
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup<Runtime>;
 }
 
 parameter_types! {
@@ -1319,13 +1321,8 @@ parameter_types! {
 pub struct ParaHeadsRootProvider;
 impl BeefyDataProvider<H256> for ParaHeadsRootProvider {
 	fn extra_data() -> H256 {
-		let mut para_heads: Vec<(u32, Vec<u8>)> = parachains_paras::Parachains::<Runtime>::get()
-			.into_iter()
-			.filter_map(|id| {
-				parachains_paras::Heads::<Runtime>::get(&id).map(|head| (id.into(), head.0))
-			})
-			.collect();
-		para_heads.sort();
+		let para_heads: Vec<(u32, Vec<u8>)> =
+			parachains_paras::Pallet::<Runtime>::sorted_para_heads();
 		binary_merkle_tree::merkle_root::<mmr::Hashing, _>(
 			para_heads.into_iter().map(|pair| pair.encode()),
 		)
@@ -1746,6 +1743,7 @@ mod benches {
 		[pallet_identity, Identity]
 		[pallet_indices, Indices]
 		[pallet_message_queue, MessageQueue]
+		[pallet_mmr, Mmr]
 		[pallet_multisig, Multisig]
 		[pallet_parameters, Parameters]
 		[pallet_preimage, Preimage]
diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs
index 3c6845dfb43..c9204cc944f 100644
--- a/polkadot/runtime/rococo/src/weights/mod.rs
+++ b/polkadot/runtime/rococo/src/weights/mod.rs
@@ -25,6 +25,7 @@ pub mod pallet_conviction_voting;
 pub mod pallet_identity;
 pub mod pallet_indices;
 pub mod pallet_message_queue;
+pub mod pallet_mmr;
 pub mod pallet_multisig;
 pub mod pallet_nis;
 pub mod pallet_parameters;
diff --git a/polkadot/runtime/rococo/src/weights/pallet_mmr.rs b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs
new file mode 100644
index 00000000000..361bfc7a661
--- /dev/null
+++ b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs
@@ -0,0 +1,77 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Autogenerated weights for `pallet_mmr`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-07-15, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
+
+// Executed Command:
+// target/testnet/polkadot
+// benchmark
+// pallet
+// --steps=5
+// --repeat=1
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --pallet=pallet_mmr
+// --chain=westend-dev
+// --header=./polkadot/file_header.txt
+// --output=./polkadot/runtime/westend/src/weights/
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::Weight};
+use core::marker::PhantomData;
+
+/// Weight functions for `pallet_mmr`.
+pub struct WeightInfo<T>(PhantomData<T>);
+impl<T: frame_system::Config> pallet_mmr::WeightInfo for WeightInfo<T> {
+	/// Storage: `Mmr::NumberOfLeaves` (r:1 w:1)
+	/// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
+	/// Storage: `System::ParentHash` (r:1 w:0)
+	/// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
+	/// Storage: `Paras::Heads` (r:2049 w:0)
+	/// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0)
+	/// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`)
+	/// Storage: `System::Digest` (r:1 w:1)
+	/// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `Mmr::Nodes` (r:0 w:1000)
+	/// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
+	/// Storage: `Mmr::RootHash` (r:0 w:1)
+	/// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
+	/// The range of component `x` is `[1, 1000]`.
+	fn on_initialize(x: u32) -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `2140817`
+		//  Estimated: `7213082`
+		// Minimum execution time: 20_387_000_000 picoseconds.
+		Weight::from_parts(223_625_477_528, 0)
+			.saturating_add(Weight::from_parts(0, 7213082))
+			// Standard Error: 310_550_970
+			.saturating_add(Weight::from_parts(16_906_397_286, 0).saturating_mul(x.into()))
+			.saturating_add(T::DbWeight::get().reads(2053))
+			.saturating_add(T::DbWeight::get().writes(3))
+			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into())))
+	}
+}
diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml
index 9e739f4c7fe..d2bafb33d2c 100644
--- a/polkadot/runtime/westend/Cargo.toml
+++ b/polkadot/runtime/westend/Cargo.toml
@@ -240,6 +240,7 @@ runtime-benchmarks = [
 	"pallet-babe/runtime-benchmarks",
 	"pallet-bags-list/runtime-benchmarks",
 	"pallet-balances/runtime-benchmarks",
+	"pallet-beefy-mmr/runtime-benchmarks",
 	"pallet-collective/runtime-benchmarks",
 	"pallet-conviction-voting/runtime-benchmarks",
 	"pallet-delegated-staking/runtime-benchmarks",
@@ -346,7 +347,10 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"]
 # Set timing constants (e.g. session period) to faster versions to speed up testing.
 fast-runtime = []
 
-runtime-metrics = ["polkadot-runtime-parachains/runtime-metrics", "sp-io/with-tracing"]
+runtime-metrics = [
+	"polkadot-runtime-parachains/runtime-metrics",
+	"sp-io/with-tracing",
+]
 
 # A feature that should be enabled when the runtime should be built for on-chain
 # deployment. This will disable stuff that shouldn't be part of the on-chain wasm
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index f0b16e731d9..acd6f96878c 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -342,9 +342,11 @@ impl pallet_mmr::Config for Runtime {
 	const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
 	type Hashing = Keccak256;
 	type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
-	type WeightInfo = ();
 	type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
 	type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider<Runtime>;
+	type WeightInfo = weights::pallet_mmr::WeightInfo<Runtime>;
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup<Runtime>;
 }
 
 /// MMR helper types.
@@ -366,13 +368,8 @@ parameter_types! {
 pub struct ParaHeadsRootProvider;
 impl BeefyDataProvider<H256> for ParaHeadsRootProvider {
 	fn extra_data() -> H256 {
-		let mut para_heads: Vec<(u32, Vec<u8>)> = parachains_paras::Parachains::<Runtime>::get()
-			.into_iter()
-			.filter_map(|id| {
-				parachains_paras::Heads::<Runtime>::get(&id).map(|head| (id.into(), head.0))
-			})
-			.collect();
-		para_heads.sort_by_key(|k| k.0);
+		let para_heads: Vec<(u32, Vec<u8>)> =
+			parachains_paras::Pallet::<Runtime>::sorted_para_heads();
 		binary_merkle_tree::merkle_root::<mmr::Hashing, _>(
 			para_heads.into_iter().map(|pair| pair.encode()),
 		)
@@ -1755,6 +1752,7 @@ mod benches {
 		[pallet_identity, Identity]
 		[pallet_indices, Indices]
 		[pallet_message_queue, MessageQueue]
+		[pallet_mmr, Mmr]
 		[pallet_multisig, Multisig]
 		[pallet_nomination_pools, NominationPoolsBench::<Runtime>]
 		[pallet_offences, OffencesBench::<Runtime>]
diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs
index f6a9008d718..c3ed2b5a75e 100644
--- a/polkadot/runtime/westend/src/weights/mod.rs
+++ b/polkadot/runtime/westend/src/weights/mod.rs
@@ -26,6 +26,7 @@ pub mod pallet_fast_unstake;
 pub mod pallet_identity;
 pub mod pallet_indices;
 pub mod pallet_message_queue;
+pub mod pallet_mmr;
 pub mod pallet_multisig;
 pub mod pallet_nomination_pools;
 pub mod pallet_preimage;
diff --git a/polkadot/runtime/westend/src/weights/pallet_mmr.rs b/polkadot/runtime/westend/src/weights/pallet_mmr.rs
new file mode 100644
index 00000000000..1a410e7fc46
--- /dev/null
+++ b/polkadot/runtime/westend/src/weights/pallet_mmr.rs
@@ -0,0 +1,76 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Autogenerated weights for `pallet_mmr`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-07-17, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `am1max.local`, CPU: `<UNKNOWN>`
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
+
+// Executed Command:
+// target/testnet/polkadot
+// benchmark
+// pallet
+// --steps=5
+// --repeat=1
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --pallet=pallet_mmr
+// --chain=westend-dev
+// --header=./polkadot/file_header.txt
+// --output=./polkadot/runtime/westend/src/weights/
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::Weight};
+use core::marker::PhantomData;
+
+/// Weight functions for `pallet_mmr`.
+pub struct WeightInfo<T>(PhantomData<T>);
+impl<T: frame_system::Config> pallet_mmr::WeightInfo for WeightInfo<T> {
+	/// Storage: `Mmr::NumberOfLeaves` (r:1 w:1)
+	/// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
+	/// Storage: `System::ParentHash` (r:1 w:0)
+	/// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
+	/// Storage: `Paras::Heads` (r:1025 w:0)
+	/// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0)
+	/// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`)
+	/// Storage: `Mmr::Nodes` (r:8 w:4)
+	/// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
+	/// Storage: `System::Digest` (r:1 w:1)
+	/// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `Mmr::RootHash` (r:0 w:1)
+	/// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
+	/// The range of component `x` is `[1, 1000]`.
+	fn on_initialize(x: u32, ) -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `1071043 + x * (39 ±0)`
+		//  Estimated: `3608787 + x * (39 ±6)`
+		// Minimum execution time: 11_102_000_000 picoseconds.
+		Weight::from_parts(21_772_042_215, 0)
+			.saturating_add(Weight::from_parts(0, 3608787))
+			.saturating_add(T::DbWeight::get().reads(1031))
+			.saturating_add(T::DbWeight::get().writes(4))
+			.saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into()))
+	}
+}
diff --git a/prdoc/pr_4751.prdoc b/prdoc/pr_4751.prdoc
new file mode 100644
index 00000000000..5a2c4220908
--- /dev/null
+++ b/prdoc/pr_4751.prdoc
@@ -0,0 +1,22 @@
+title: "Use all parachain heads for BEEFY MMR extra data"
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      Previously, the extra data in an MMR leaf nodes was only computed based on lease-based parachain heads.
+      This PR extends the extra data to include others, including on-demand parachain heads.
+      Currently, the number of heads is limited to the first 1024 heads sorted by para id.
+
+crates:
+  - name: polkadot-runtime-parachains
+    bump: minor
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
+  - name: pallet-mmr
+    bump: major
+  - name: pallet-beefy-mmr
+    bump: minor
+  - name: polkadot-sdk
+    bump: minor
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index a1896325ee9..78c7bba6457 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1605,6 +1605,8 @@ impl pallet_mmr::Config for Runtime {
 	type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
 	type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider<Runtime>;
 	type WeightInfo = ();
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = ();
 }
 
 parameter_types! {
diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml
index 11a7b281e87..92e903af138 100644
--- a/substrate/frame/beefy-mmr/Cargo.toml
+++ b/substrate/frame/beefy-mmr/Cargo.toml
@@ -64,3 +64,10 @@ try-runtime = [
 	"pallet-session/try-runtime",
 	"sp-runtime/try-runtime",
 ]
+runtime-benchmarks = [
+	"frame-support/runtime-benchmarks",
+	"frame-system/runtime-benchmarks",
+	"pallet-mmr/runtime-benchmarks",
+	"sp-runtime/runtime-benchmarks",
+	"sp-staking/runtime-benchmarks",
+]
diff --git a/substrate/frame/beefy-mmr/src/mock.rs b/substrate/frame/beefy-mmr/src/mock.rs
index 0521bdabbe4..3adef4f32bf 100644
--- a/substrate/frame/beefy-mmr/src/mock.rs
+++ b/substrate/frame/beefy-mmr/src/mock.rs
@@ -93,6 +93,9 @@ impl pallet_mmr::Config for Test {
 	type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider<Test>;
 
 	type WeightInfo = ();
+
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = ();
 }
 
 impl pallet_beefy::Config for Test {
diff --git a/substrate/frame/merkle-mountain-range/src/benchmarking.rs b/substrate/frame/merkle-mountain-range/src/benchmarking.rs
index 9eb676a4ee4..07afd9529eb 100644
--- a/substrate/frame/merkle-mountain-range/src/benchmarking.rs
+++ b/substrate/frame/merkle-mountain-range/src/benchmarking.rs
@@ -28,10 +28,13 @@ benchmarks_instance_pallet! {
 		let x in 1 .. 1_000;
 
 		let leaves = x as NodeIndex;
-	}: {
-		for b in 0..leaves {
-			Pallet::<T, I>::on_initialize((b as u32).into());
+
+		<<T as pallet::Config::<I>>::BenchmarkHelper as BenchmarkHelper>::setup();
+		for leaf in 0..(leaves - 1) {
+			Pallet::<T, I>::on_initialize((leaf as u32).into());
 		}
+	}: {
+		Pallet::<T, I>::on_initialize((leaves as u32 - 1).into());
 	} verify {
 		assert_eq!(crate::NumberOfLeaves::<T, I>::get(), leaves);
 	}
diff --git a/substrate/frame/merkle-mountain-range/src/default_weights.rs b/substrate/frame/merkle-mountain-range/src/default_weights.rs
index 52e3f130383..b0ef0539018 100644
--- a/substrate/frame/merkle-mountain-range/src/default_weights.rs
+++ b/substrate/frame/merkle-mountain-range/src/default_weights.rs
@@ -24,7 +24,8 @@ use frame_support::weights::{
 };
 
 impl crate::WeightInfo for () {
-	fn on_initialize(peaks: u64) -> Weight {
+	fn on_initialize(peaks: u32) -> Weight {
+		let peaks = u64::from(peaks);
 		// Reading the parent hash.
 		let leaf_weight = DbWeight::get().reads(1);
 		// Blake2 hash cost.
diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs
index cacb33b5043..0ab44711bcf 100644
--- a/substrate/frame/merkle-mountain-range/src/lib.rs
+++ b/substrate/frame/merkle-mountain-range/src/lib.rs
@@ -124,7 +124,18 @@ impl<T: frame_system::Config> BlockHashProvider<BlockNumberFor<T>, T::Hash>
 }
 
 pub trait WeightInfo {
-	fn on_initialize(peaks: NodeIndex) -> Weight;
+	fn on_initialize(peaks: u32) -> Weight;
+}
+
+/// This trait decoples dependencies on pallets needed for benchmarking.
+#[cfg(feature = "runtime-benchmarks")]
+pub trait BenchmarkHelper {
+	fn setup();
+}
+
+#[cfg(feature = "runtime-benchmarks")]
+impl BenchmarkHelper for () {
+	fn setup() {}
 }
 
 /// An MMR specific to the pallet.
@@ -205,6 +216,10 @@ pub mod pallet {
 
 		/// Weights for this pallet.
 		type WeightInfo: WeightInfo;
+
+		/// Benchmarking setup helper trait.
+		#[cfg(feature = "runtime-benchmarks")]
+		type BenchmarkHelper: BenchmarkHelper;
 	}
 
 	/// Latest MMR Root hash.
@@ -238,14 +253,14 @@ pub mod pallet {
 			// MMR push never fails, but better safe than sorry.
 			if mmr.push(data).is_none() {
 				log::error!(target: "runtime::mmr", "MMR push failed");
-				return T::WeightInfo::on_initialize(peaks_before)
+				return T::WeightInfo::on_initialize(peaks_before as u32)
 			}
 			// Update the size, `mmr.finalize()` should also never fail.
 			let (leaves, root) = match mmr.finalize() {
 				Ok((leaves, root)) => (leaves, root),
 				Err(e) => {
 					log::error!(target: "runtime::mmr", "MMR finalize failed: {:?}", e);
-					return T::WeightInfo::on_initialize(peaks_before)
+					return T::WeightInfo::on_initialize(peaks_before as u32)
 				},
 			};
 			<T::OnNewRoot as primitives::OnNewRoot<_>>::on_new_root(&root);
@@ -255,7 +270,7 @@ pub mod pallet {
 
 			let peaks_after = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks();
 
-			T::WeightInfo::on_initialize(peaks_before.max(peaks_after))
+			T::WeightInfo::on_initialize(peaks_before.max(peaks_after) as u32)
 		}
 	}
 }
diff --git a/substrate/frame/merkle-mountain-range/src/mock.rs b/substrate/frame/merkle-mountain-range/src/mock.rs
index 8318b20e830..606719c6deb 100644
--- a/substrate/frame/merkle-mountain-range/src/mock.rs
+++ b/substrate/frame/merkle-mountain-range/src/mock.rs
@@ -46,6 +46,8 @@ impl Config for Test {
 	type OnNewRoot = ();
 	type BlockHashProvider = DefaultBlockHashProvider<Test>;
 	type WeightInfo = ();
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = ();
 }
 
 #[derive(Encode, Decode, Clone, Default, Eq, PartialEq, Debug)]
diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml
index 94ba09421d4..79e7c0c38ed 100644
--- a/umbrella/Cargo.toml
+++ b/umbrella/Cargo.toml
@@ -269,6 +269,7 @@ runtime-benchmarks = [
 	"pallet-babe?/runtime-benchmarks",
 	"pallet-bags-list?/runtime-benchmarks",
 	"pallet-balances?/runtime-benchmarks",
+	"pallet-beefy-mmr?/runtime-benchmarks",
 	"pallet-bounties?/runtime-benchmarks",
 	"pallet-bridge-grandpa?/runtime-benchmarks",
 	"pallet-bridge-messages?/runtime-benchmarks",
-- 
GitLab