Skip to content

Commit 6a66aa3

Browse files
XCMP weight metering: account for the MQ page position (#8344)
Related to #8308 Follow-up for #8021 --------- Co-authored-by: command-bot <> Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 5d71d47 commit 6a66aa3

23 files changed

Lines changed: 868 additions & 512 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cumulus/pallets/xcmp-queue/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ xcm-executor = { workspace = true }
3434
# Cumulus
3535
cumulus-primitives-core = { workspace = true }
3636

37+
# Optional import for weight accuracy testing
38+
approx = { workspace = true }
3739
# Optional import for benchmarking
3840
bounded-collections = { workspace = true }
3941
frame-benchmarking = { optional = true, workspace = true }
@@ -53,6 +55,7 @@ cumulus-pallet-parachain-system = { workspace = true, default-features = true }
5355
[features]
5456
default = ["std"]
5557
std = [
58+
"approx/std",
5659
"bounded-collections/std",
5760
"bp-xcm-bridge-hub-router?/std",
5861
"codec/std",

cumulus/pallets/xcmp-queue/src/benchmarking.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
//! Benchmarking setup for cumulus-pallet-xcmp-queue
1717
18-
use crate::*;
18+
use crate::{weights_ext::get_average_page_pos, *};
1919

2020
use alloc::vec;
2121
use codec::DecodeAll;
@@ -107,6 +107,40 @@ mod benchmarks {
107107
}
108108
}
109109

110+
/// Add an XCMP message of 0 bytes to the message queue at the provided position
111+
/// on an existing page.
112+
#[benchmark]
113+
fn enqueue_empty_xcmp_message_at(
114+
n: Linear<0, { crate::MaxXcmpMessageLenOf::<T>::get() - 10 }>,
115+
) {
116+
#[cfg(test)]
117+
{
118+
mock::EnqueuedMessages::set(vec![]);
119+
}
120+
121+
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
122+
0.into(),
123+
&[BoundedVec::try_from(vec![0; n as usize]).unwrap()],
124+
&mut WeightMeter::new()
125+
));
126+
127+
#[cfg(not(test))]
128+
let fp_before = T::XcmpQueue::footprint(0.into());
129+
#[block]
130+
{
131+
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
132+
0.into(),
133+
&[Default::default()],
134+
&mut WeightMeter::new()
135+
));
136+
}
137+
#[cfg(not(test))]
138+
{
139+
let fp_after = T::XcmpQueue::footprint(0.into());
140+
assert_eq!(fp_after.ready_pages, fp_before.ready_pages);
141+
}
142+
}
143+
110144
/// Add `n` pages to the message queue.
111145
///
112146
/// We add one page by enqueueing a maximal size message which fills it.
@@ -157,6 +191,17 @@ mod benchmarks {
157191
});
158192
}
159193

194+
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
195+
0.into(),
196+
&[BoundedVec::try_from(vec![
197+
0;
198+
get_average_page_pos(MaxXcmpMessageLenOf::<T>::get())
199+
as usize
200+
])
201+
.unwrap()],
202+
&mut WeightMeter::new()
203+
));
204+
160205
let mut msgs = vec![];
161206
for _i in 0..1000 {
162207
msgs.push(BoundedVec::try_from(vec![0; 3]).unwrap());
@@ -175,7 +220,7 @@ mod benchmarks {
175220
#[cfg(not(test))]
176221
{
177222
let fp_after = T::XcmpQueue::footprint(0.into());
178-
assert_eq!(fp_after.ready_pages, fp_before.ready_pages + 1);
223+
assert_eq!(fp_after.ready_pages, fp_before.ready_pages);
179224
}
180225
}
181226

cumulus/pallets/xcmp-queue/src/lib.rs

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ pub mod weights;
5151
pub mod weights_ext;
5252

5353
pub use weights::WeightInfo;
54-
#[cfg(feature = "std")]
55-
pub use weights_ext::check_weight_info_ext_accuracy;
5654
pub use weights_ext::WeightInfoExt;
5755

5856
extern crate alloc;
@@ -68,8 +66,8 @@ use cumulus_primitives_core::{
6866
use frame_support::{
6967
defensive, defensive_assert,
7068
traits::{
71-
BatchFootprint, Defensive, EnqueueMessage, EnsureOrigin, Get, QueueFootprint,
72-
QueueFootprintQuery, QueuePausedQuery,
69+
Defensive, EnqueueMessage, EnsureOrigin, Get, QueueFootprint, QueueFootprintQuery,
70+
QueuePausedQuery,
7371
},
7472
weights::{Weight, WeightMeter},
7573
BoundedVec,
@@ -79,7 +77,7 @@ use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery;
7977
use polkadot_runtime_parachains::{FeeTracker, GetMinFeeFactor};
8078
use scale_info::TypeInfo;
8179
use sp_core::MAX_POSSIBLE_ALLOCATION;
82-
use sp_runtime::{FixedU128, RuntimeDebug, WeakBoundedVec};
80+
use sp_runtime::{FixedU128, RuntimeDebug, SaturatedConversion, WeakBoundedVec};
8381
use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH};
8482
use xcm_builder::InspectMessageQueues;
8583
use xcm_executor::traits::ConvertOrigin;
@@ -264,9 +262,13 @@ pub mod pallet {
264262
#[pallet::hooks]
265263
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
266264
fn integrity_test() {
265+
assert!(!T::MaxPageSize::get().is_zero(), "MaxPageSize too low");
266+
267267
let w = Self::on_idle_weight();
268268
assert!(w != Weight::zero());
269269
assert!(w.all_lte(T::BlockWeights::get().max_block));
270+
271+
<T::WeightInfo as WeightInfoExt>::check_accuracy::<MaxXcmpMessageLenOf<T>>(0.15);
270272
}
271273

272274
fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
@@ -643,39 +645,21 @@ impl<T: Config> Pallet<T> {
643645
drop_threshold,
644646
);
645647

646-
// `batches_footprints[n]` contains the footprint of the batch `xcms[0..n]`,
647-
// so as `n` increases `batches_footprints[n]` contains the footprint of a bigger batch.
648-
let best_batch_idx = batches_footprints.binary_search_by(|batch_info| {
648+
let best_batch_footprint = batches_footprints.search_best_by(|batch_info| {
649649
let required_weight = T::WeightInfo::enqueue_xcmp_messages(
650-
batch_info.new_pages_count,
651-
batch_info.msgs_count,
652-
batch_info.size_in_bytes,
650+
batches_footprints.first_page_pos.saturated_into(),
651+
batch_info,
653652
);
654653

655654
match meter.can_consume(required_weight) {
656655
true => core::cmp::Ordering::Less,
657656
false => core::cmp::Ordering::Greater,
658657
}
659658
});
660-
let best_batch_idx = match best_batch_idx {
661-
Ok(last_ok_idx) => {
662-
// We should never reach this branch since we never return `Ordering::Equal`.
663-
defensive!("Unexpected best_batch_idx found: Ok({})", last_ok_idx);
664-
Some(last_ok_idx)
665-
},
666-
Err(first_err_idx) => first_err_idx.checked_sub(1),
667-
};
668-
let best_batch_footprint = match best_batch_idx {
669-
Some(best_batch_idx) => batches_footprints.get(best_batch_idx).ok_or_else(|| {
670-
defensive!("Invalid best_batch_idx: {}", best_batch_idx);
671-
})?,
672-
None => &BatchFootprint { msgs_count: 0, size_in_bytes: 0, new_pages_count: 0 },
673-
};
674659

675660
meter.consume(T::WeightInfo::enqueue_xcmp_messages(
676-
best_batch_footprint.new_pages_count,
677-
best_batch_footprint.msgs_count,
678-
best_batch_footprint.size_in_bytes,
661+
batches_footprints.first_page_pos.saturated_into(),
662+
best_batch_footprint,
679663
));
680664
T::XcmpQueue::enqueue_messages(
681665
xcms.iter()

cumulus/pallets/xcmp-queue/src/mock.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use cumulus_pallet_parachain_system::AnyRelayNumber;
2020
use cumulus_primitives_core::{ChannelInfo, IsSystem, ParaId};
2121
use frame_support::{
2222
derive_impl, parameter_types,
23-
traits::{ConstU32, Everything, OriginTrait},
23+
traits::{BatchesFootprints, ConstU32, Everything, OriginTrait},
2424
BoundedSlice,
2525
};
2626
use frame_system::EnsureRoot;
@@ -193,24 +193,16 @@ impl<T: OnQueueChanged<ParaId>> QueueFootprintQuery<ParaId> for EnqueueToLocalSt
193193
origin: ParaId,
194194
msgs: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
195195
total_pages_limit: u32,
196-
) -> Vec<BatchFootprint> {
196+
) -> BatchesFootprints {
197197
// Let's consider that we add one message per page
198198
let footprint = Self::footprint(origin);
199-
let mut batches_footprints = vec![];
200-
let mut new_pages_count = 0;
201-
let mut total_size = 0;
199+
let mut batches_footprints = BatchesFootprints::default();
202200
for (idx, msg) in msgs.enumerate() {
203-
new_pages_count += 1;
204-
if footprint.pages + new_pages_count > total_pages_limit {
201+
if footprint.pages + idx as u32 + 1 > total_pages_limit {
205202
break;
206203
}
207204

208-
total_size += msg.len();
209-
batches_footprints.push(BatchFootprint {
210-
msgs_count: idx + 1,
211-
size_in_bytes: total_size,
212-
new_pages_count,
213-
})
205+
batches_footprints.push(msg.into(), true);
214206
}
215207
batches_footprints
216208
}

cumulus/pallets/xcmp-queue/src/tests.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ use XcmpMessageFormat::*;
2222
use codec::Input;
2323
use cumulus_primitives_core::{ParaId, XcmpMessageHandler};
2424
use frame_support::{
25-
assert_err, assert_noop, assert_ok, assert_storage_noop, hypothetically, traits::Hooks,
25+
assert_err, assert_noop, assert_ok, assert_storage_noop, hypothetically,
26+
traits::{BatchFootprint, Hooks},
2627
StorageNoopGuard,
2728
};
2829
use mock::{new_test_ext, ParachainSystem, RuntimeOrigin as Origin, Test, XcmpQueue};
@@ -210,9 +211,12 @@ fn xcm_enqueueing_starts_dropping_on_out_of_weight() {
210211

211212
total_size += xcm.len();
212213
let required_weight = <<Test as Config>::WeightInfo>::enqueue_xcmp_messages(
213-
idx as u32 + 1,
214-
idx + 1,
215-
total_size,
214+
0,
215+
&BatchFootprint {
216+
msgs_count: idx + 1,
217+
size_in_bytes: total_size,
218+
new_pages_count: idx as u32 + 1,
219+
},
216220
);
217221

218222
let mut weight_meter = WeightMeter::with_limit(required_weight);

0 commit comments

Comments
 (0)