From 8342947b8e22d398ab981d33d9d48756a3160f77 Mon Sep 17 00:00:00 2001
From: Ermal Kaleci <ermalkaleci@gmail.com>
Date: Wed, 27 Mar 2024 15:51:45 +0100
Subject: [PATCH] process enqueued messages on idle (#3844)

This will make it possible to use remaining weight on idle for
processing enqueued messages.
More context here https://github.com/paritytech/polkadot-sdk/issues/3709

---------

Co-authored-by: Adrian Catangiu <adrian@parity.io>
---
 .../pallets/outbound-queue/src/mock.rs        |  1 +
 bridges/snowbridge/pallets/system/src/mock.rs |  1 +
 cumulus/pallets/parachain-system/src/mock.rs  |  1 +
 .../assets/asset-hub-rococo/src/lib.rs        |  1 +
 .../assets/asset-hub-westend/src/lib.rs       |  1 +
 .../bridge-hubs/bridge-hub-rococo/src/lib.rs  |  1 +
 .../bridge-hubs/bridge-hub-westend/src/lib.rs |  1 +
 .../collectives-westend/src/lib.rs            |  1 +
 .../contracts/contracts-rococo/src/lib.rs     |  1 +
 .../coretime/coretime-rococo/src/lib.rs       |  1 +
 .../coretime/coretime-westend/src/lib.rs      |  1 +
 .../glutton/glutton-westend/src/lib.rs        |  1 +
 .../runtimes/people/people-rococo/src/lib.rs  |  1 +
 .../runtimes/people/people-westend/src/lib.rs |  1 +
 .../runtimes/starters/shell/src/lib.rs        |  1 +
 .../runtimes/testing/penpal/src/lib.rs        |  1 +
 .../testing/rococo-parachain/src/lib.rs       |  1 +
 polkadot/runtime/parachains/src/mock.rs       |  1 +
 polkadot/runtime/rococo/src/lib.rs            |  1 +
 polkadot/runtime/westend/src/lib.rs           |  1 +
 .../xcm-simulator/example/src/relay_chain.rs  |  1 +
 .../xcm-simulator/fuzzer/src/relay_chain.rs   |  1 +
 prdoc/pr_3844.prdoc                           | 25 +++++++++++
 substrate/bin/node/runtime/src/lib.rs         |  1 +
 .../contracts/mock-network/src/relay_chain.rs |  1 +
 .../message-queue/src/integration_test.rs     |  1 +
 substrate/frame/message-queue/src/lib.rs      | 22 +++++++++-
 substrate/frame/message-queue/src/mock.rs     |  1 +
 substrate/frame/message-queue/src/tests.rs    | 42 +++++++++++++++++++
 templates/parachain/runtime/src/lib.rs        |  1 +
 30 files changed, 114 insertions(+), 2 deletions(-)
 create mode 100644 prdoc/pr_3844.prdoc

diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs
index 67877a05c79..5eeeeead140 100644
--- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs
+++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs
@@ -69,6 +69,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type QueuePausedQuery = ();
 }
 
diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs
index 0312456c982..687072a49e2 100644
--- a/bridges/snowbridge/pallets/system/src/mock.rs
+++ b/bridges/snowbridge/pallets/system/src/mock.rs
@@ -148,6 +148,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type QueuePausedQuery = ();
 }
 
diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs
index 0b1d536ba7c..fe89dfe68c6 100644
--- a/cumulus/pallets/parachain-system/src/mock.rs
+++ b/cumulus/pallets/parachain-system/src/mock.rs
@@ -125,6 +125,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MaxWeight;
+	type IdleMaxServiceWeight = ();
 	type WeightInfo = ();
 }
 
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
index 689d8d56c48..293416ab2a9 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
@@ -660,6 +660,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
index 48106b5f302..e92e801e9f5 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
@@ -641,6 +641,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
index 3980fa0d501..f0aa4f8e91c 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
@@ -387,6 +387,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
index 9bdea6b9a7d..3b759301d0e 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
@@ -348,6 +348,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs
index d3f588bf25f..e1c2e1a6237 100644
--- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs
@@ -423,6 +423,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs
index e1586c7d9b2..ec0a5f6fc96 100644
--- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs
@@ -318,6 +318,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
index 86eb5cdfcaf..67f48689353 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
@@ -301,6 +301,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
index c31e474cc2f..609ea5a38a8 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
@@ -301,6 +301,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs
index cee17cdc7b0..ca1a915ba74 100644
--- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs
@@ -212,6 +212,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs
index cd5f1ad3272..7c9427a2493 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs
@@ -282,6 +282,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
 }
 
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs
index e840a40f5ac..3e331e5e8eb 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs
@@ -282,6 +282,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
 }
 
diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs
index 0f4957fd802..ad79d6849bd 100644
--- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs
+++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs
@@ -232,6 +232,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
index 1d404feac3d..0a55d2dcfe5 100644
--- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
+++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
@@ -540,6 +540,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
index c6006141981..034d16267d4 100644
--- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
+++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
@@ -320,6 +320,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs
index 7ed62a392e4..461b9f4b431 100644
--- a/polkadot/runtime/parachains/src/mock.rs
+++ b/polkadot/runtime/parachains/src/mock.rs
@@ -365,6 +365,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = ConstU32<65536>;
 	type MaxStale = ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs
index 8c8abe97ede..c41ffdbe72d 100644
--- a/polkadot/runtime/rococo/src/lib.rs
+++ b/polkadot/runtime/rococo/src/lib.rs
@@ -987,6 +987,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	#[cfg(not(feature = "runtime-benchmarks"))]
 	type MessageProcessor = MessageProcessor;
 	#[cfg(feature = "runtime-benchmarks")]
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index 02397f35368..e6381513170 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -1190,6 +1190,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	#[cfg(not(feature = "runtime-benchmarks"))]
 	type MessageProcessor = MessageProcessor;
 	#[cfg(feature = "runtime-benchmarks")]
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
index 377c77f30a4..286d0038e18 100644
--- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
@@ -275,6 +275,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type MessageProcessor = MessageProcessor;
 	type QueueChangeHandler = ();
 	type QueuePausedQuery = ();
diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs
index 3224df66cbe..6790b535d16 100644
--- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs
+++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs
@@ -232,6 +232,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 	#[cfg(not(feature = "runtime-benchmarks"))]
 	type MessageProcessor = MessageProcessor;
 	#[cfg(feature = "runtime-benchmarks")]
diff --git a/prdoc/pr_3844.prdoc b/prdoc/pr_3844.prdoc
new file mode 100644
index 00000000000..a92092f91b2
--- /dev/null
+++ b/prdoc/pr_3844.prdoc
@@ -0,0 +1,25 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Add the ability for MessageQueue to process enqueued messages on idle
+
+doc:
+  - audience: Runtime Dev
+    description: |
+        Add the option to use remaining weight on idle for processing enqueued messages.
+        This will increase the chances of the messages enqueued during inherent extrinsics to be processed in the same block. 
+        New config types is added on the message-queue `Config` trait:
+        - `IdleMaxServiceWeight`
+
+        example:
+            ```rust
+            parameter_types! {
+                // The maximum weight to be used from remaining weight for processing enqueued messages on idle
+                pub const IdleMaxServiceWeight: Weight = Some(Weight);
+            }
+
+            type IdleMaxServiceWeight = IdleMaxServiceWeight; // or `()` to not use this feature
+            ```
+
+crates:
+    - name: pallet-message-queue
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index ca7e14f6eb1..a9606ac0bb7 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1303,6 +1303,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = ConstU32<{ 64 * 1024 }>;
 	type MaxStale = ConstU32<128>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 parameter_types! {
diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs
index e2a8d3d1337..470304ed357 100644
--- a/substrate/frame/contracts/mock-network/src/relay_chain.rs
+++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs
@@ -225,6 +225,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type MessageProcessor = MessageProcessor;
 	type QueueChangeHandler = ();
 	type WeightInfo = ();
diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs
index 26a330cc88e..14b8d2217eb 100644
--- a/substrate/frame/message-queue/src/integration_test.rs
+++ b/substrate/frame/message-queue/src/integration_test.rs
@@ -73,6 +73,7 @@ impl Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 /// Simulates heavy usage by enqueueing and processing large amounts of messages.
diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs
index 93cd760eeb9..ec85c785f79 100644
--- a/substrate/frame/message-queue/src/lib.rs
+++ b/substrate/frame/message-queue/src/lib.rs
@@ -525,12 +525,21 @@ pub mod pallet {
 		type MaxStale: Get<u32>;
 
 		/// The amount of weight (if any) which should be provided to the message queue for
-		/// servicing enqueued items.
+		/// servicing enqueued items `on_initialize`.
 		///
 		/// This may be legitimately `None` in the case that you will call
-		/// `ServiceQueues::service_queues` manually.
+		/// `ServiceQueues::service_queues` manually or set [`Self::IdleMaxServiceWeight`] to have
+		/// it run in `on_idle`.
 		#[pallet::constant]
 		type ServiceWeight: Get<Option<Weight>>;
+
+		/// The maximum amount of weight (if any) to be used from remaining weight `on_idle` which
+		/// should be provided to the message queue for servicing enqueued items `on_idle`.
+		/// Useful for parachains to process messages at the same block they are received.
+		///
+		/// If `None`, it will not call `ServiceQueues::service_queues` in `on_idle`.
+		#[pallet::constant]
+		type IdleMaxServiceWeight: Get<Option<Weight>>;
 	}
 
 	#[pallet::event]
@@ -643,6 +652,15 @@ pub mod pallet {
 			}
 		}
 
+		fn on_idle(_n: BlockNumberFor<T>, remaining_weight: Weight) -> Weight {
+			if let Some(weight_limit) = T::IdleMaxServiceWeight::get() {
+				// Make use of the remaining weight to process enqueued messages.
+				Self::service_queues(weight_limit.min(remaining_weight))
+			} else {
+				Weight::zero()
+			}
+		}
+
 		#[cfg(feature = "try-runtime")]
 		fn try_state(_: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
 			Self::do_try_state()
diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs
index f22f318b8ef..1281de6b0a6 100644
--- a/substrate/frame/message-queue/src/mock.rs
+++ b/substrate/frame/message-queue/src/mock.rs
@@ -56,6 +56,7 @@ impl Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ServiceWeight;
 }
 
 /// Mocked `WeightInfo` impl with allows to set the weight per call.
diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs
index 1f6e7777f01..d6788847d57 100644
--- a/substrate/frame/message-queue/src/tests.rs
+++ b/substrate/frame/message-queue/src/tests.rs
@@ -1838,3 +1838,45 @@ fn with_service_mutex_works() {
 	with_service_mutex(|| called = 3).unwrap();
 	assert_eq!(called, 3);
 }
+
+#[test]
+fn process_enqueued_on_idle() {
+	use MessageOrigin::*;
+	build_and_execute::<Test>(|| {
+		// Some messages enqueued on previous block.
+		MessageQueue::enqueue_messages(vec![msg("a"), msg("ab"), msg("abc")].into_iter(), Here);
+		assert_eq!(BookStateFor::<Test>::iter().count(), 1);
+
+		// Process enqueued messages from previous block.
+		Pallet::<Test>::on_initialize(1);
+		assert_eq!(
+			MessagesProcessed::take(),
+			vec![(b"a".to_vec(), Here), (b"ab".to_vec(), Here), (b"abc".to_vec(), Here),]
+		);
+
+		MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There);
+		assert_eq!(BookStateFor::<Test>::iter().count(), 2);
+
+		// Enough weight to process on idle.
+		Pallet::<Test>::on_idle(1, Weight::from_parts(100, 100));
+		assert_eq!(
+			MessagesProcessed::take(),
+			vec![(b"x".to_vec(), There), (b"xy".to_vec(), There), (b"xyz".to_vec(), There)]
+		);
+	})
+}
+
+#[test]
+fn process_enqueued_on_idle_requires_enough_weight() {
+	use MessageOrigin::*;
+	build_and_execute::<Test>(|| {
+		Pallet::<Test>::on_initialize(1);
+
+		MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There);
+		assert_eq!(BookStateFor::<Test>::iter().count(), 1);
+
+		// Not enough weight to process on idle.
+		Pallet::<Test>::on_idle(1, Weight::from_parts(0, 0));
+		assert_eq!(MessagesProcessed::take(), vec![]);
+	})
+}
diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs
index ad21b79a5b1..88b0f5a1474 100644
--- a/templates/parachain/runtime/src/lib.rs
+++ b/templates/parachain/runtime/src/lib.rs
@@ -414,6 +414,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
-- 
GitLab