diff --git a/Cargo.lock b/Cargo.lock
index 6c837a051ce4dfe59037867589db171b2124fa1d..2bb1a758bafad7d97dd2e597b0eee52f6ea608ee 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 7afdf49fe55165e87ab936fff3259317c020c1f1..cfe373e8cba2e6c186ea62d7121aff5f3d4cafa7 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 630b86132ab88681ed438f6a0cdd6e2d131c5522..7bf8b833ed915df49aabcb9047ec889076836af0 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 0000000000000000000000000000000000000000..ab007692e78dc2e3b56dfdd4ad682accdfa0c037
--- /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 3f0b8659b159977ec8e8544da4c5fc6a4cd6d4bf..a4c404de2a651d0a4359a59fa9efb66b275defe8 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 f93a3ad65754c7ac201841aca7098f2886da0cf8..50970965e11e6ebbd4f984ed16c21be44cd978c6 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 5adffbd7422f9fc0f7812318bb2548fff6e9c0e0..c7da339b981544823ac7ac97f43a12d719061cb4 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 3c6845dfb43e65e85dc33b2e288f35a9a8742e1e..c9204cc944fa47e3863285705395d4c7b0e63a47 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 0000000000000000000000000000000000000000..361bfc7a661b0737c936a95d20f1b6751db76aec
--- /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 9e739f4c7fe6c0de7358b5763532f761209333e7..d2bafb33d2cb429fc5661d8a2d6576c2102ba325 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 f0b16e731d9e564bbf00a9378c5247151d61ca2e..acd6f96878c9e5f812a0a6bf441b2b88859245e9 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 f6a9008d71876726dda2ad240ecdb4588a1f82a3..c3ed2b5a75ec59f0c2e4d0b4156899bb9599c65e 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 0000000000000000000000000000000000000000..1a410e7fc46ea4aa3944765ef662f4419c4cd16a
--- /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 0000000000000000000000000000000000000000..5a2c42209088039a3b570995121d661e620a9a2c
--- /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 a1896325ee936f2427dd6bc26f359195fc5c81bd..78c7bba64579a80d750c2d20ebe96dba2de7536c 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 11a7b281e87d9e3c1e49f304ae08f7206d34dffd..92e903af138d595d063b344bb24238e632a3430d 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 0521bdabbe4958c99aebceef48a4a4a8b031cb6a..3adef4f32bf43a1aca43d39483303d35ee916ff6 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 9eb676a4ee44b21cef7ced59c40366067017f7ce..07afd9529eb2608941881cf01c7d9a8e341bae7c 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 52e3f130383fdf8d9267b9b34300014741677b9f..b0ef0539018cdf8814223862a5508b81ad2863b1 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 cacb33b504347461b3a45205bad1c9c9e999dc7d..0ab44711bcf5d854c3c158434740fdbaf1931b1b 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 8318b20e83074cd3bcb540b854fd7abae998438e..606719c6deba121f693250694894d104bae030f7 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 94ba09421d409e5a2daee0c702499be3df2d4dcd..79e7c0c38edaa609ef594a9b5159ac92d4f5408c 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",