Skip to content

Commit 2a1f188

Browse files
bkchractions-user
authored andcommitted
pallet-message-queue: Fix max message size calculation (#6205)
The max size of a message should not depend on the weight left in a given execution context. Instead the max message size depends on the service weights configured for the pallet. A message that may does not fit into `on_idle` is not automatically overweight, because it may can be executed successfully in `on_initialize` or in another block in `on_idle` when there is more weight left. --------- Co-authored-by: GitHub Action <[email protected]> (cherry picked from commit 5d7181c)
1 parent 835e076 commit 2a1f188

File tree

4 files changed

+106
-52
lines changed

4 files changed

+106
-52
lines changed

prdoc/pr_6205.prdoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
title: 'pallet-message-queue: Fix max message size calculation'
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
The max size of a message should not depend on the weight left in a given execution context. Instead the max message size depends on the service weights configured for the pallet. A message that may does not fit into `on_idle` is not automatically overweight, because it may can be executed successfully in `on_initialize` or in another block in `on_idle` when there is more weight left.
6+
crates:
7+
- name: pallet-message-queue
8+
bump: patch

substrate/frame/message-queue/src/lib.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -868,13 +868,26 @@ impl<T: Config> Pallet<T> {
868868
}
869869
}
870870

871-
/// The maximal weight that a single message can consume.
871+
/// The maximal weight that a single message ever can consume.
872872
///
873873
/// Any message using more than this will be marked as permanently overweight and not
874874
/// automatically re-attempted. Returns `None` if the servicing of a message cannot begin.
875875
/// `Some(0)` means that only messages with no weight may be served.
876876
fn max_message_weight(limit: Weight) -> Option<Weight> {
877-
limit.checked_sub(&Self::single_msg_overhead())
877+
let service_weight = T::ServiceWeight::get().unwrap_or_default();
878+
let on_idle_weight = T::IdleMaxServiceWeight::get().unwrap_or_default();
879+
880+
// Whatever weight is set, the one with the biggest one is used as the maximum weight. If a
881+
// message is tried in one context and fails, it will be retried in the other context later.
882+
let max_message_weight =
883+
if service_weight.any_gt(on_idle_weight) { service_weight } else { on_idle_weight };
884+
885+
if max_message_weight.is_zero() {
886+
// If no service weight is set, we need to use the given limit as max message weight.
887+
limit.checked_sub(&Self::single_msg_overhead())
888+
} else {
889+
max_message_weight.checked_sub(&Self::single_msg_overhead())
890+
}
878891
}
879892

880893
/// The overhead of servicing a single message.
@@ -896,6 +909,8 @@ impl<T: Config> Pallet<T> {
896909
fn do_integrity_test() -> Result<(), String> {
897910
ensure!(!MaxMessageLenOf::<T>::get().is_zero(), "HeapSize too low");
898911

912+
let max_block = T::BlockWeights::get().max_block;
913+
899914
if let Some(service) = T::ServiceWeight::get() {
900915
if Self::max_message_weight(service).is_none() {
901916
return Err(format!(
@@ -904,6 +919,31 @@ impl<T: Config> Pallet<T> {
904919
Self::single_msg_overhead(),
905920
))
906921
}
922+
923+
if service.any_gt(max_block) {
924+
return Err(format!(
925+
"ServiceWeight {service} is bigger than max block weight {max_block}"
926+
))
927+
}
928+
}
929+
930+
if let Some(on_idle) = T::IdleMaxServiceWeight::get() {
931+
if on_idle.any_gt(max_block) {
932+
return Err(format!(
933+
"IdleMaxServiceWeight {on_idle} is bigger than max block weight {max_block}"
934+
))
935+
}
936+
}
937+
938+
if let (Some(service_weight), Some(on_idle)) =
939+
(T::ServiceWeight::get(), T::IdleMaxServiceWeight::get())
940+
{
941+
if !(service_weight.all_gt(on_idle) ||
942+
on_idle.all_gt(service_weight) ||
943+
service_weight == on_idle)
944+
{
945+
return Err("One of `ServiceWeight` or `IdleMaxServiceWeight` needs to be `all_gt` or both need to be equal.".into())
946+
}
907947
}
908948

909949
Ok(())
@@ -1509,7 +1549,7 @@ impl<T: Config> Pallet<T> {
15091549
let mut weight = WeightMeter::with_limit(weight_limit);
15101550

15111551
// Get the maximum weight that processing a single message may take:
1512-
let max_weight = Self::max_message_weight(weight_limit).unwrap_or_else(|| {
1552+
let overweight_limit = Self::max_message_weight(weight_limit).unwrap_or_else(|| {
15131553
if matches!(context, ServiceQueuesContext::OnInitialize) {
15141554
defensive!("Not enough weight to service a single message.");
15151555
}
@@ -1527,7 +1567,8 @@ impl<T: Config> Pallet<T> {
15271567
let mut last_no_progress = None;
15281568

15291569
loop {
1530-
let (progressed, n) = Self::service_queue(next.clone(), &mut weight, max_weight);
1570+
let (progressed, n) =
1571+
Self::service_queue(next.clone(), &mut weight, overweight_limit);
15311572
next = match n {
15321573
Some(n) =>
15331574
if !progressed {

substrate/frame/message-queue/src/mock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl frame_system::Config for Test {
4242
type Block = Block;
4343
}
4444
parameter_types! {
45-
pub const HeapSize: u32 = 24;
45+
pub const HeapSize: u32 = 40;
4646
pub const MaxStale: u32 = 2;
4747
pub const ServiceWeight: Option<Weight> = Some(Weight::from_parts(100, 100));
4848
}

0 commit comments

Comments
 (0)