Refactoring Checkpoint: (WIP)

This commit is contained in:
2025-12-14 10:29:31 +03:00
parent 09735eb97a
commit c89d7cac55
1424 changed files with 6415 additions and 6064 deletions
@@ -0,0 +1,341 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Benchmarking setup for pezcumulus-pezpallet-xcmp-queue
use crate::{weights_ext::get_average_page_pos, *};
use alloc::vec;
use codec::DecodeAll;
use pezframe_benchmarking::v2::*;
use pezframe_support::{assert_ok, traits::Hooks};
use pezframe_system::RawOrigin;
use xcm::MAX_INSTRUCTIONS_TO_DECODE;
#[benchmarks]
mod benchmarks {
use super::*;
/// Modify any of the `QueueConfig` fields with a new `u32` value.
///
/// Used as weight for:
/// - update_suspend_threshold
/// - update_drop_threshold
/// - update_resume_threshold
#[benchmark]
fn set_config_with_u32() {
#[extrinsic_call]
Pallet::<T>::update_resume_threshold(RawOrigin::Root, 1);
}
/// Add a XCMP message of `n` bytes to the message queue.
///
/// The message will be added on a new page and also, the `BookState` will be added
/// to the ready ring.
#[benchmark]
fn enqueue_n_bytes_xcmp_message(n: Linear<0, { MaxXcmpMessageLenOf::<T>::get() }>) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
}
let msg = BoundedVec::try_from(vec![0; n as usize]).unwrap();
#[cfg(not(test))]
let fp_before = T::XcmpQueue::footprint(0.into());
#[block]
{
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&[msg.as_bounded_slice()],
true,
&mut WeightMeter::new()
));
}
#[cfg(not(test))]
{
let fp_after = T::XcmpQueue::footprint(0.into());
assert_eq!(fp_after.ready_pages, fp_before.ready_pages + 1);
}
}
/// Add `n` XCMP message of 0 bytes to the message queue.
///
/// Only for the first message a new page will be created and the `BookState` will be added
/// to the ready ring.
#[benchmark]
fn enqueue_n_empty_xcmp_messages(n: Linear<0, 1000>) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
<QueueConfig<T>>::set(QueueConfigData {
suspend_threshold: 1100,
drop_threshold: 1100,
resume_threshold: 1100,
});
}
let msg = BoundedVec::new();
let msgs = vec![msg.as_bounded_slice(); n as usize];
#[cfg(not(test))]
let fp_before = T::XcmpQueue::footprint(0.into());
#[block]
{
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&msgs,
true,
&mut WeightMeter::new()
));
}
#[cfg(not(test))]
{
let fp_after = T::XcmpQueue::footprint(0.into());
if !msgs.is_empty() {
assert_eq!(fp_after.ready_pages, fp_before.ready_pages + 1);
}
}
}
/// Add an XCMP message of 0 bytes to the message queue at the provided position
/// on an existing page.
#[benchmark(pov_mode = Measured)]
fn enqueue_empty_xcmp_message_at(
n: Linear<0, { crate::MaxXcmpMessageLenOf::<T>::get() - 10 }>,
) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
}
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&[BoundedVec::try_from(vec![0; n as usize]).unwrap().as_bounded_slice()],
true,
&mut WeightMeter::new()
));
#[cfg(not(test))]
let fp_before = T::XcmpQueue::footprint(0.into());
#[block]
{
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&[BoundedVec::new().as_bounded_slice()],
true,
&mut WeightMeter::new()
));
}
#[cfg(not(test))]
{
let fp_after = T::XcmpQueue::footprint(0.into());
assert_eq!(fp_after.ready_pages, fp_before.ready_pages);
}
}
/// Add `n` pages to the message queue.
///
/// We add one page by enqueueing a maximal size message which fills it.
#[benchmark]
fn enqueue_n_full_pages(n: Linear<0, 100>) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
}
<QueueConfig<T>>::set(QueueConfigData {
suspend_threshold: 200,
drop_threshold: 200,
resume_threshold: 200,
});
let max_msg_len = MaxXcmpMessageLenOf::<T>::get() as usize;
let mut msgs = vec![];
for _i in 0..n {
let msg = BoundedVec::try_from(vec![0; max_msg_len]).unwrap();
msgs.push(msg);
}
#[cfg(not(test))]
let fp_before = T::XcmpQueue::footprint(0.into());
#[block]
{
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&msgs.iter().map(|msg| msg.as_bounded_slice()).collect::<Vec<_>>(),
true,
&mut WeightMeter::new()
));
}
#[cfg(not(test))]
{
let fp_after = T::XcmpQueue::footprint(0.into());
assert_eq!(fp_after.ready_pages, fp_before.ready_pages + n);
}
}
#[benchmark(pov_mode = Measured)]
fn enqueue_1000_small_xcmp_messages() {
#[cfg(test)]
{
<QueueConfig<T>>::set(QueueConfigData {
suspend_threshold: 1100,
drop_threshold: 1100,
resume_threshold: 1100,
});
}
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&[BoundedVec::try_from(vec![
0;
get_average_page_pos(MaxXcmpMessageLenOf::<T>::get())
as usize
])
.unwrap()
.as_bounded_slice()],
true,
&mut WeightMeter::new()
));
let mut msgs = vec![];
for _i in 0..1000 {
msgs.push(BoundedVec::try_from(vec![0; 3]).unwrap());
}
#[cfg(not(test))]
let fp_before = T::XcmpQueue::footprint(0.into());
#[block]
{
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&msgs.iter().map(|msg| msg.as_bounded_slice()).collect::<Vec<_>>(),
true,
&mut WeightMeter::new()
));
}
#[cfg(not(test))]
{
let fp_after = T::XcmpQueue::footprint(0.into());
assert_eq!(fp_after.ready_pages, fp_before.ready_pages);
}
}
#[benchmark]
fn suspend_channel() {
let para = 123.into();
let data = ChannelSignal::Suspend.encode();
#[block]
{
ChannelSignal::decode_all(&mut &data[..]).unwrap();
Pallet::<T>::suspend_channel(para);
}
assert_eq!(
OutboundXcmpStatus::<T>::get()
.iter()
.find(|p| p.recipient == para)
.unwrap()
.state,
OutboundState::Suspended
);
}
#[benchmark]
fn resume_channel() {
let para = 123.into();
let data = ChannelSignal::Resume.encode();
Pallet::<T>::suspend_channel(para);
#[block]
{
ChannelSignal::decode_all(&mut &data[..]).unwrap();
Pallet::<T>::resume_channel(para);
}
assert!(
OutboundXcmpStatus::<T>::get().iter().all(|p| p.recipient != para),
"No messages in the channel; therefore removed."
);
}
/// Split a singular XCM.
#[benchmark]
fn take_first_concatenated_xcm(
n: Linear<0, { MAX_INSTRUCTIONS_TO_DECODE as u32 - MAX_XCM_DECODE_DEPTH }>,
) {
let mut xcm = Xcm::<T>(vec![ClearOrigin; n as usize]);
for _ in 0..MAX_XCM_DECODE_DEPTH - 1 {
xcm = Xcm::<T>(vec![Instruction::SetAppendix(xcm)]);
}
let data = VersionedXcm::<T>::from(xcm).encode();
#[block]
{
Pallet::<T>::take_first_concatenated_xcm(&mut &data[..], &mut WeightMeter::new())
.unwrap();
}
}
/// Benchmark the migration for a maximal sized message.
#[benchmark]
fn on_idle_good_msg() {
use migration::v3;
let block = 5;
let para = ParaId::from(4);
let message = vec![123u8; MaxXcmpMessageLenOf::<T>::get() as usize];
let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)];
v3::InboundXcmpMessages::<T>::insert(para, block, message);
v3::InboundXcmpStatus::<T>::set(Some(vec![v3::InboundChannelDetails {
sender: para,
state: v3::InboundState::Ok,
message_metadata,
}]));
#[block]
{
Pallet::<T>::on_idle(0u32.into(), Weight::MAX);
}
}
/// Benchmark the migration with a 64 KiB message that will not be possible to enqueue.
#[benchmark]
fn on_idle_large_msg() {
use migration::v3;
let block = 5;
let para = ParaId::from(4);
let message = vec![123u8; 1 << 16]; // 64 KiB message
let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)];
v3::InboundXcmpMessages::<T>::insert(para, block, message);
v3::InboundXcmpStatus::<T>::set(Some(vec![v3::InboundChannelDetails {
sender: para,
state: v3::InboundState::Ok,
message_metadata,
}]));
#[block]
{
Pallet::<T>::on_idle(0u32.into(), Weight::MAX);
}
}
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}
@@ -0,0 +1,101 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{pallet, OutboundState};
use pezcumulus_primitives_core::ParaId;
use xcm::latest::prelude::*;
/// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks
/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `Location` if any of those is
/// suspended.
pub struct InAndOutXcmpChannelStatusProvider<Runtime>(core::marker::PhantomData<Runtime>);
impl<Runtime: crate::Config> bp_xcm_bridge_hub_router::XcmChannelStatusProvider
for InAndOutXcmpChannelStatusProvider<Runtime>
{
fn is_congested(with: &Location) -> bool {
// handle congestion only for a sibling teyrchain locations.
let sibling_para_id: ParaId = match with.unpack() {
(_, [Teyrchain(para_id)]) => (*para_id).into(),
_ => return false,
};
// if the inbound channel with recipient is suspended, it means that we are unable to
// receive congestion reports from the `with` location. So we assume the pipeline is
// congested too.
if pallet::Pallet::<Runtime>::is_inbound_channel_suspended(sibling_para_id) {
return true;
}
// if the outbound channel with recipient is suspended, it means that one of further
// queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall
// take larger fee for our outbound messages
OutXcmpChannelStatusProvider::<Runtime>::is_congested(with)
}
}
/// Adapter implementation for `bp_xcm_bridge::ChannelStatusProvider` and/or
/// `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks only `OutboundXcmpStatus`
/// for defined `Location` if is suspended.
pub struct OutXcmpChannelStatusProvider<Runtime>(core::marker::PhantomData<Runtime>);
impl<Runtime: crate::Config> OutXcmpChannelStatusProvider<Runtime> {
fn is_congested(with: &Location) -> bool {
// handle congestion only for a sibling teyrchain locations.
let sibling_para_id: ParaId = match with.unpack() {
(_, [Teyrchain(para_id)]) => (*para_id).into(),
_ => return false,
};
// let's find the channel's state with the sibling teyrchain,
let Some((outbound_state, queued_pages)) =
pallet::Pallet::<Runtime>::outbound_channel_state(sibling_para_id)
else {
return false;
};
// suspended channel => it is congested
if outbound_state == OutboundState::Suspended {
return true;
}
// It takes some time for target teyrchain to suspend inbound channel with the target BH and
// during that we will keep accepting new message delivery transactions. Let's also reject
// new deliveries if there are too many "pages" (concatenated XCM messages) in the target BH
// -> target teyrchain queue.
// If the outbound channel has at least `N` pages enqueued, let's assume it is congested.
// Normally, the chain with a few opened HRMP channels, will "send" pages at every block.
// Having `N` pages means that for last `N` blocks we either have not sent any messages,
// or have sent signals.
const MAX_QUEUED_PAGES_BEFORE_DEACTIVATION: u16 = 4;
if queued_pages > MAX_QUEUED_PAGES_BEFORE_DEACTIVATION {
return true;
}
false
}
}
impl<Runtime: crate::Config> bp_xcm_bridge_hub_router::XcmChannelStatusProvider
for OutXcmpChannelStatusProvider<Runtime>
{
fn is_congested(with: &Location) -> bool {
Self::is_congested(with)
}
}
#[cfg(feature = "runtime-benchmarks")]
pub fn suspend_channel_for_benchmarks<T: crate::Config>(target: ParaId) {
pallet::Pallet::<T>::suspend_channel(target)
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,427 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezcumulus.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A module that is responsible for migration of storage.
pub mod v5;
use crate::{Config, OverweightIndex, Pallet, QueueConfig, QueueConfigData, DEFAULT_POV_SIZE};
use alloc::vec::Vec;
use pezcumulus_primitives_core::XcmpMessageFormat;
use pezframe_support::{
pezpallet_prelude::*,
traits::{EnqueueMessage, StorageVersion, UncheckedOnRuntimeUpgrade},
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight},
};
/// The in-code storage version.
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
pub const LOG: &str = "runtime::xcmp-queue-migration";
mod v1 {
use super::*;
use codec::{Decode, Encode};
#[pezframe_support::storage_alias]
pub(crate) type QueueConfig<T: Config> = StorageValue<Pallet<T>, QueueConfigData, ValueQuery>;
#[derive(Encode, Decode, Debug)]
pub struct QueueConfigData {
pub suspend_threshold: u32,
pub drop_threshold: u32,
pub resume_threshold: u32,
pub threshold_weight: u64,
pub weight_restrict_decay: u64,
pub xcmp_max_individual_weight: u64,
}
impl Default for QueueConfigData {
fn default() -> Self {
QueueConfigData {
suspend_threshold: 2,
drop_threshold: 5,
resume_threshold: 1,
threshold_weight: 100_000,
weight_restrict_decay: 2,
xcmp_max_individual_weight: 20u64 * WEIGHT_REF_TIME_PER_MILLIS,
}
}
}
}
pub mod v2 {
use super::*;
#[pezframe_support::storage_alias]
pub(crate) type QueueConfig<T: Config> = StorageValue<Pallet<T>, QueueConfigData, ValueQuery>;
#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct QueueConfigData {
pub suspend_threshold: u32,
pub drop_threshold: u32,
pub resume_threshold: u32,
pub threshold_weight: Weight,
pub weight_restrict_decay: Weight,
pub xcmp_max_individual_weight: Weight,
}
impl Default for QueueConfigData {
fn default() -> Self {
Self {
suspend_threshold: 2,
drop_threshold: 5,
resume_threshold: 1,
threshold_weight: Weight::from_parts(100_000, 0),
weight_restrict_decay: Weight::from_parts(2, 0),
xcmp_max_individual_weight: Weight::from_parts(
20u64 * WEIGHT_REF_TIME_PER_MILLIS,
DEFAULT_POV_SIZE,
),
}
}
}
/// Migrates `QueueConfigData` from v1 (using only reference time weights) to v2 (with
/// 2D weights).
pub struct UncheckedMigrationToV2<T: Config>(PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for UncheckedMigrationToV2<T> {
#[allow(deprecated)]
fn on_runtime_upgrade() -> Weight {
let translate = |pre: v1::QueueConfigData| -> v2::QueueConfigData {
v2::QueueConfigData {
suspend_threshold: pre.suspend_threshold,
drop_threshold: pre.drop_threshold,
resume_threshold: pre.resume_threshold,
threshold_weight: Weight::from_parts(pre.threshold_weight, 0),
weight_restrict_decay: Weight::from_parts(pre.weight_restrict_decay, 0),
xcmp_max_individual_weight: Weight::from_parts(
pre.xcmp_max_individual_weight,
DEFAULT_POV_SIZE,
),
}
};
if v2::QueueConfig::<T>::translate(|pre| pre.map(translate)).is_err() {
tracing::error!(
target: crate::LOG_TARGET,
"unexpected error when performing translation of the QueueConfig type \
during storage upgrade to v2"
);
}
T::DbWeight::get().reads_writes(1, 1)
}
}
/// [`UncheckedMigrationToV2`] wrapped in a
/// [`VersionedMigration`](pezframe_support::migrations::VersionedMigration), ensuring the
/// migration is only performed when on-chain version is 1.
#[allow(dead_code)]
pub type MigrationToV2<T> = pezframe_support::migrations::VersionedMigration<
1,
2,
UncheckedMigrationToV2<T>,
Pallet<T>,
<T as pezframe_system::Config>::DbWeight,
>;
}
pub mod v3 {
use super::*;
use crate::*;
/// Status of the inbound XCMP channels.
#[pezframe_support::storage_alias]
pub(crate) type InboundXcmpStatus<T: Config> =
StorageValue<Pallet<T>, Vec<InboundChannelDetails>, OptionQuery>;
/// Inbound aggregate XCMP messages. It can only be one per ParaId/block.
#[pezframe_support::storage_alias]
pub(crate) type InboundXcmpMessages<T: Config> = StorageDoubleMap<
Pallet<T>,
Blake2_128Concat,
ParaId,
Twox64Concat,
RelayBlockNumber,
Vec<u8>,
OptionQuery,
>;
#[pezframe_support::storage_alias]
pub(crate) type QueueConfig<T: Config> =
StorageValue<Pallet<T>, v2::QueueConfigData, ValueQuery>;
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub struct InboundChannelDetails {
/// The `ParaId` of the teyrchain that this channel is connected with.
pub sender: ParaId,
/// The state of the channel.
pub state: InboundState,
/// The ordered metadata of each inbound message.
///
/// Contains info about the relay block number that the message was sent at, and the format
/// of the incoming message.
pub message_metadata: Vec<(RelayBlockNumber, XcmpMessageFormat)>,
}
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo,
)]
pub enum InboundState {
Ok,
Suspended,
}
/// Migrates the pallet storage to v3.
pub struct UncheckedMigrationToV3<T: Config>(PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for UncheckedMigrationToV3<T> {
fn on_runtime_upgrade() -> Weight {
#[pezframe_support::storage_alias]
type Overweight<T: Config> =
CountedStorageMap<Pallet<T>, Twox64Concat, OverweightIndex, ParaId>;
let overweight_messages = Overweight::<T>::initialize_counter() as u64;
T::DbWeight::get().reads_writes(overweight_messages, 1)
}
}
/// [`UncheckedMigrationToV3`] wrapped in a
/// [`VersionedMigration`](pezframe_support::migrations::VersionedMigration), ensuring the
/// migration is only performed when on-chain version is 2.
pub type MigrationToV3<T> = pezframe_support::migrations::VersionedMigration<
2,
3,
UncheckedMigrationToV3<T>,
Pallet<T>,
<T as pezframe_system::Config>::DbWeight,
>;
pub fn lazy_migrate_inbound_queue<T: Config>() {
let Some(mut states) = v3::InboundXcmpStatus::<T>::get() else {
tracing::debug!(target: LOG, "Lazy migration finished: item gone");
return;
};
let Some(ref mut next) = states.first_mut() else {
tracing::debug!(target: LOG, "Lazy migration finished: item empty");
v3::InboundXcmpStatus::<T>::kill();
return;
};
tracing::debug!(
target: LOG,
sibling=?next.sender,
msgs_left=%next.message_metadata.len(),
"Migrating inbound HRMP channel."
);
// We take the last element since the MQ is a FIFO and we want to keep the order.
let Some((block_number, format)) = next.message_metadata.pop() else {
states.remove(0);
v3::InboundXcmpStatus::<T>::put(states);
return;
};
if format != XcmpMessageFormat::ConcatenatedVersionedXcm {
tracing::warn!(
target: LOG,
?format,
"Dropping message (not ConcatenatedVersionedXcm)"
);
v3::InboundXcmpMessages::<T>::remove(&next.sender, &block_number);
v3::InboundXcmpStatus::<T>::put(states);
return;
}
let Some(msg) = v3::InboundXcmpMessages::<T>::take(&next.sender, &block_number) else {
defensive!("Storage corrupted: HRMP message missing:", (next.sender, block_number));
v3::InboundXcmpStatus::<T>::put(states);
return;
};
let Ok(msg): Result<BoundedVec<_, _>, _> = msg.try_into() else {
tracing::error!(target: LOG, "Message dropped: too big");
v3::InboundXcmpStatus::<T>::put(states);
return;
};
// Finally! We have a proper message.
T::XcmpQueue::enqueue_message(msg.as_bounded_slice(), next.sender);
tracing::debug!(target: LOG, next_sender=?next.sender, ?block_number, "Migrated HRMP message to MQ");
v3::InboundXcmpStatus::<T>::put(states);
}
}
pub mod v4 {
use super::*;
/// Migrates `QueueConfigData` to v4, removing deprecated fields and bumping page
/// thresholds to at least the default values.
pub struct UncheckedMigrationToV4<T: Config>(PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for UncheckedMigrationToV4<T> {
fn on_runtime_upgrade() -> Weight {
let translate = |pre: v2::QueueConfigData| -> QueueConfigData {
let pre_default = v2::QueueConfigData::default();
// If the previous values are the default ones, let's replace them with the new
// default.
if pre.suspend_threshold == pre_default.suspend_threshold &&
pre.drop_threshold == pre_default.drop_threshold &&
pre.resume_threshold == pre_default.resume_threshold
{
return QueueConfigData::default();
}
// If the previous values are not the default ones, let's leave them as they are.
QueueConfigData {
suspend_threshold: pre.suspend_threshold,
drop_threshold: pre.drop_threshold,
resume_threshold: pre.resume_threshold,
}
};
if QueueConfig::<T>::translate(|pre| pre.map(translate)).is_err() {
tracing::error!(
target: crate::LOG_TARGET,
"unexpected error when performing translation of the QueueConfig type \
during storage upgrade to v4"
);
}
T::DbWeight::get().reads_writes(1, 1)
}
}
/// [`UncheckedMigrationToV4`] wrapped in a
/// [`VersionedMigration`](pezframe_support::migrations::VersionedMigration), ensuring the
/// migration is only performed when on-chain version is 3.
pub type MigrationToV4<T> = pezframe_support::migrations::VersionedMigration<
3,
4,
UncheckedMigrationToV4<T>,
Pallet<T>,
<T as pezframe_system::Config>::DbWeight,
>;
}
#[cfg(all(feature = "try-runtime", test))]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test};
use pezframe_support::traits::OnRuntimeUpgrade;
#[test]
#[allow(deprecated)]
fn test_migration_to_v2() {
let v1 = v1::QueueConfigData {
suspend_threshold: 5,
drop_threshold: 12,
resume_threshold: 3,
threshold_weight: 333_333,
weight_restrict_decay: 1,
xcmp_max_individual_weight: 10_000_000_000,
};
new_test_ext().execute_with(|| {
let storage_version = StorageVersion::new(1);
storage_version.put::<Pallet<Test>>();
pezframe_support::storage::unhashed::put_raw(
&crate::QueueConfig::<Test>::hashed_key(),
&v1.encode(),
);
let bytes = v2::MigrationToV2::<Test>::pre_upgrade();
assert!(bytes.is_ok());
v2::MigrationToV2::<Test>::on_runtime_upgrade();
assert!(v2::MigrationToV2::<Test>::post_upgrade(bytes.unwrap()).is_ok());
let v2 = v2::QueueConfig::<Test>::get();
assert_eq!(v1.suspend_threshold, v2.suspend_threshold);
assert_eq!(v1.drop_threshold, v2.drop_threshold);
assert_eq!(v1.resume_threshold, v2.resume_threshold);
assert_eq!(v1.threshold_weight, v2.threshold_weight.ref_time());
assert_eq!(v1.weight_restrict_decay, v2.weight_restrict_decay.ref_time());
assert_eq!(v1.xcmp_max_individual_weight, v2.xcmp_max_individual_weight.ref_time());
});
}
#[test]
#[allow(deprecated)]
fn test_migration_to_v4() {
new_test_ext().execute_with(|| {
let storage_version = StorageVersion::new(3);
storage_version.put::<Pallet<Test>>();
let v2 = v2::QueueConfigData {
drop_threshold: 5,
suspend_threshold: 2,
resume_threshold: 1,
..Default::default()
};
pezframe_support::storage::unhashed::put_raw(
&crate::QueueConfig::<Test>::hashed_key(),
&v2.encode(),
);
let bytes = v4::MigrationToV4::<Test>::pre_upgrade();
assert!(bytes.is_ok());
v4::MigrationToV4::<Test>::on_runtime_upgrade();
assert!(v4::MigrationToV4::<Test>::post_upgrade(bytes.unwrap()).is_ok());
let v4 = QueueConfig::<Test>::get();
assert_eq!(
v4,
QueueConfigData { suspend_threshold: 32, drop_threshold: 48, resume_threshold: 8 }
);
});
new_test_ext().execute_with(|| {
let storage_version = StorageVersion::new(3);
storage_version.put::<Pallet<Test>>();
let v2 = v2::QueueConfigData {
drop_threshold: 100,
suspend_threshold: 50,
resume_threshold: 40,
..Default::default()
};
pezframe_support::storage::unhashed::put_raw(
&crate::QueueConfig::<Test>::hashed_key(),
&v2.encode(),
);
let bytes = v4::MigrationToV4::<Test>::pre_upgrade();
assert!(bytes.is_ok());
v4::MigrationToV4::<Test>::on_runtime_upgrade();
assert!(v4::MigrationToV4::<Test>::post_upgrade(bytes.unwrap()).is_ok());
let v4 = QueueConfig::<Test>::get();
assert_eq!(
v4,
QueueConfigData {
suspend_threshold: 50,
drop_threshold: 100,
resume_threshold: 40
}
);
});
}
}
@@ -0,0 +1,109 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezcumulus.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Migrates the storage to version 5.
use crate::*;
use alloc::vec::Vec;
use pezcumulus_primitives_core::ListChannelInfos;
use pezframe_support::{pezpallet_prelude::*, traits::UncheckedOnRuntimeUpgrade};
/// Configs needed to run the V5 migration.
pub trait V5Config: Config {
/// List all outbound channels with their target `ParaId` and maximum message size.
type ChannelList: ListChannelInfos;
}
/// Ensures that the storage migrates cleanly to V5.
///
/// The migration itself is a no-op, but it checks that none of the `BoundedVec`s would truncate on
/// the next decode after the upgrade was applied.
pub type MigrateV4ToV5<T> = pezframe_support::migrations::VersionedMigration<
4,
5,
unversioned::UncheckedMigrateV4ToV5<T>,
Pallet<T>,
<T as pezframe_system::Config>::DbWeight,
>;
// V4 storage aliases
mod v4 {
use super::*;
#[pezframe_support::storage_alias]
pub(super) type OutboundXcmpStatus<T: Config> =
StorageValue<Pallet<T>, Vec<OutboundChannelDetails>, ValueQuery>;
#[pezframe_support::storage_alias]
pub(super) type OutboundXcmpMessages<T: Config> = StorageDoubleMap<
Pallet<T>,
Blake2_128Concat,
ParaId,
Twox64Concat,
u16,
Vec<u8>,
ValueQuery,
>;
#[pezframe_support::storage_alias]
pub(super) type SignalMessages<T: Config> =
StorageMap<Pallet<T>, Blake2_128Concat, ParaId, Vec<u8>, ValueQuery>;
}
// Private module to hide the migration.
mod unversioned {
/// Please use [`MigrateV4ToV5`] instead.
pub struct UncheckedMigrateV4ToV5<T: super::V5Config>(core::marker::PhantomData<T>);
}
impl<T: V5Config> UncheckedOnRuntimeUpgrade for unversioned::UncheckedMigrateV4ToV5<T> {
fn on_runtime_upgrade() -> pezframe_support::weights::Weight {
Default::default()
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), pezsp_runtime::DispatchError> {
// We dont need any front-run protection for this since channels are opened by governance.
ensure!(
v4::OutboundXcmpStatus::<T>::get().len() as u32 <= T::MaxActiveOutboundChannels::get(),
"Too many outbound channels. Close some channels or increase `MaxActiveOutboundChannels`."
);
ensure!(T::MaxPageSize::get() >= 16, "Sanity check failed: MaxPageSize too small");
// Check if any channels have a too large message max sizes.
let max_msg_len = T::MaxPageSize::get() - XcmpMessageFormat::max_encoded_len() as u32;
for channel in T::ChannelList::outgoing_channels() {
let info = T::ChannelInfo::get_channel_info(channel)
.expect("All listed channels must provide info");
if info.max_message_size > max_msg_len {
tracing::error!(
target: "runtime::xcmp-queue-migration::v5",
channel_max=%info.max_message_size,
max_page_size=%max_msg_len,
"Max message size for channel is too large. This means that the V5 \
migration can be front-run and an attacker could place a large message just right \
before the migration to make other messages un-decodable. Please either increase \
`MaxPageSize` or decrease the `max_message_size` for this channel."
);
return Err("Migration can be front-run".into());
}
}
Ok(())
}
}
@@ -0,0 +1,303 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::*;
use crate as xcmp_queue;
use alloc::collections::BTreeMap;
use core::marker::PhantomData;
use pezcumulus_pezpallet_teyrchain_system::AnyRelayNumber;
use pezcumulus_primitives_core::{ChannelInfo, IsSystem, ParaId};
use pezframe_support::{
derive_impl, parameter_types,
traits::{BatchesFootprints, ConstU32, Everything, OriginTrait},
BoundedSlice,
};
use pezframe_system::EnsureRoot;
use pezsp_core::H256;
use pezsp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};
use xcm::prelude::*;
use xcm_executor::traits::ConvertOrigin;
type Block = pezframe_system::mocking::MockBlock<Test>;
// Configure a mock runtime to test the pallet.
pezframe_support::construct_runtime!(
pub enum Test
{
System: pezframe_system::{Pallet, Call, Config<T>, Storage, Event<T>},
Balances: pezpallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
TeyrchainSystem: pezcumulus_pezpallet_teyrchain_system::{
Pallet, Call, Config<T>, Storage, Inherent, Event<T>,
},
XcmpQueue: xcmp_queue::{Pallet, Call, Storage, Event<T>},
}
);
parameter_types! {
pub const SS58Prefix: u8 = 42;
}
type AccountId = u64;
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
impl pezframe_system::Config for Test {
type BaseCallFilter = Everything;
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pezpallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = SS58Prefix;
type OnSetCode = pezcumulus_pezpallet_teyrchain_system::TeyrchainSetCode<Test>;
type MaxConsumers = pezframe_support::traits::ConstU32<16>;
}
parameter_types! {
pub const ExistentialDeposit: u64 = 5;
}
pub type Balance = u64;
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
impl pezpallet_balances::Config for Test {
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
}
impl pezcumulus_pezpallet_teyrchain_system::Config for Test {
type WeightInfo = ();
type RuntimeEvent = RuntimeEvent;
type OnSystemEvent = ();
type SelfParaId = ();
type OutboundXcmpMessageSource = XcmpQueue;
// Ignore all DMP messages by enqueueing them into `()`:
type DmpQueue = pezframe_support::traits::EnqueueWithOrigin<(), pezsp_core::ConstU8<0>>;
type ReservedDmpWeight = ();
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ();
type CheckAssociatedRelayNumber = AnyRelayNumber;
type ConsensusHook = pezcumulus_pezpallet_teyrchain_system::consensus_hook::ExpectParentIncluded;
type RelayParentOffset = ConstU32<0>;
}
parameter_types! {
pub const RelayChain: Location = Location::parent();
pub UniversalLocation: InteriorLocation = [Teyrchain(1u32)].into();
pub UnitWeightCost: Weight = Weight::from_parts(1_000_000, 1024);
pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64;
}
pub struct SystemTeyrchainAsSuperuser<RuntimeOrigin>(PhantomData<RuntimeOrigin>);
impl<RuntimeOrigin: OriginTrait> ConvertOrigin<RuntimeOrigin>
for SystemTeyrchainAsSuperuser<RuntimeOrigin>
{
fn convert_origin(
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
if kind == OriginKind::Superuser &&
matches!(
origin.unpack(),
(1, [Teyrchain(id)]) if ParaId::from(*id).is_system(),
) {
Ok(RuntimeOrigin::root())
} else {
Err(origin)
}
}
}
parameter_types! {
pub static EnqueuedMessages: Vec<(ParaId, Vec<u8>)> = Default::default();
pub static FirstPagePos: BTreeMap<ParaId, usize> = Default::default();
}
/// An `EnqueueMessage` implementation that puts all messages in thread-local storage.
pub struct EnqueueToLocalStorage<T>(PhantomData<T>);
impl<T: OnQueueChanged<ParaId>> EnqueueMessage<ParaId> for EnqueueToLocalStorage<T> {
type MaxMessageLen = pezsp_core::ConstU32<256>;
fn enqueue_message(message: BoundedSlice<u8, Self::MaxMessageLen>, origin: ParaId) {
let mut msgs = EnqueuedMessages::get();
msgs.push((origin, message.to_vec()));
EnqueuedMessages::set(msgs);
T::on_queue_changed(origin, Self::footprint(origin));
}
fn enqueue_messages<'a>(
iter: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
origin: ParaId,
) {
let mut msgs = EnqueuedMessages::get();
msgs.extend(iter.map(|m| (origin, m.to_vec())));
EnqueuedMessages::set(msgs);
T::on_queue_changed(origin, Self::footprint(origin));
}
fn sweep_queue(origin: ParaId) {
let mut msgs = EnqueuedMessages::get();
msgs.retain(|(o, _)| o != &origin);
EnqueuedMessages::set(msgs);
T::on_queue_changed(origin, Self::footprint(origin));
}
}
impl<T: OnQueueChanged<ParaId>> QueueFootprintQuery<ParaId> for EnqueueToLocalStorage<T> {
type MaxMessageLen = pezsp_core::ConstU32<256>;
fn footprint(origin: ParaId) -> QueueFootprint {
let msgs = EnqueuedMessages::get();
let mut footprint = QueueFootprint::default();
for (o, m) in msgs {
if o == origin {
footprint.storage.count += 1;
footprint.storage.size += m.len() as u64;
}
}
// Let's consider that we add one message per page
footprint.pages = footprint.storage.count as u32;
footprint.ready_pages = footprint.pages;
footprint
}
fn get_batches_footprints<'a>(
origin: ParaId,
msgs: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
total_pages_limit: u32,
) -> BatchesFootprints {
// Let's consider that we add one message per page
let footprint = Self::footprint(origin);
let mut batches_footprints = BatchesFootprints {
first_page_pos: *FirstPagePos::get().entry(origin).or_default(),
footprints: vec![],
};
for (idx, msg) in msgs.enumerate() {
if footprint.pages + idx as u32 + 1 > total_pages_limit {
break;
}
batches_footprints.push(msg.into(), true);
}
batches_footprints
}
}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = AssetId(RelayChain::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: Balance = 300_000_000;
/// The fee per byte
pub const ByteFee: Balance = 1_000_000;
}
pub type PriceForSiblingTeyrchainDelivery = pezkuwi_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
ByteFee,
XcmpQueue,
>;
impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type ChannelInfo = MockedChannelInfo;
type VersionWrapper = ();
type XcmpQueue = EnqueueToLocalStorage<Pallet<Test>>;
type MaxInboundSuspended = ConstU32<1_000>;
type MaxActiveOutboundChannels = ConstU32<128>;
// Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we
// need to set the page size larger than that until we reduce the channel size on-chain.
type MaxPageSize = ConstU32<{ 103 * 1024 }>;
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = SystemTeyrchainAsSuperuser<RuntimeOrigin>;
type WeightInfo = ();
type PriceForSiblingDelivery = PriceForSiblingTeyrchainDelivery;
}
pub fn new_test_ext() -> pezsp_io::TestExternalities {
pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap().into()
}
/// A para that we have an HRMP channel with.
pub const HRMP_PARA_ID: u32 = 7777;
pub struct MockedChannelInfo;
impl GetChannelInfo for MockedChannelInfo {
fn get_channel_status(id: ParaId) -> ChannelStatus {
if id == HRMP_PARA_ID.into() {
return ChannelStatus::Ready(usize::MAX, usize::MAX);
}
TeyrchainSystem::get_channel_status(id)
}
fn get_channel_info(id: ParaId) -> Option<ChannelInfo> {
if id == HRMP_PARA_ID.into() {
return Some(ChannelInfo {
max_capacity: u32::MAX,
max_total_size: u32::MAX,
max_message_size: u32::MAX,
msg_count: 0,
total_size: 0,
});
}
TeyrchainSystem::get_channel_info(id)
}
}
pub(crate) fn mk_page() -> Vec<u8> {
let mut page = Vec::<u8>::new();
let newer_xcm_version = xcm::prelude::XCM_VERSION;
let older_xcm_version = newer_xcm_version - 1;
for i in 0..100 {
page.extend(match i % 2 {
0 => versioned_xcm(older_xcm_version).encode(),
1 => versioned_xcm(newer_xcm_version).encode(),
// We cannot push an undecodable XCM here since it would break the decode stream.
_ => unreachable!(),
});
}
page
}
pub(crate) fn versioned_xcm(version: XcmVersion) -> VersionedXcm<()> {
let instr = Instruction::<()>::Trap(1);
VersionedXcm::from(Xcm::<()>(vec![instr; 3]))
.into_version(version)
.expect("Version conversion should work")
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,458 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Autogenerated weights for `pezcumulus_pezpallet_xcmp_queue`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
//! DATE: 2025-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `Serbans-MacBook-Pro.local`, CPU: `<UNKNOWN>`
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
// Executed Command:
// ./target/release/pezkuwi-teyrchain
// benchmark
// pallet
// --pallet
// pezcumulus-pezpallet-xcmp-queue
// --chain
// asset-hub-zagros-dev
// --output
// pezcumulus/pezpallets/xcmp-queue/src/weights.rs
// --template
// bizinikiwi/.maintain/frame-weight-template.hbs
// --extrinsic
//
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
#![allow(dead_code)]
use pezframe_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weight functions needed for `pezcumulus_pezpallet_xcmp_queue`.
pub trait WeightInfo {
fn set_config_with_u32() -> Weight;
fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight;
fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight;
fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight;
fn enqueue_n_full_pages(n: u32, ) -> Weight;
fn enqueue_1000_small_xcmp_messages() -> Weight;
fn suspend_channel() -> Weight;
fn resume_channel() -> Weight;
fn take_first_concatenated_xcm(n: u32, ) -> Weight;
fn on_idle_good_msg() -> Weight;
fn on_idle_large_msg() -> Weight;
}
/// Weights for `pezcumulus_pezpallet_xcmp_queue` using the Bizinikiwi node and recommended hardware.
pub struct BizinikiwiWeight<T>(PhantomData<T>);
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:1)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
fn set_config_with_u32() -> Weight {
// Proof Size summary in bytes:
// Measured: `175`
// Estimated: `1497`
// Minimum execution time: 3_000_000 picoseconds.
Weight::from_parts(4_000_000, 1497)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
/// The range of component `n` is `[0, 105467]`.
fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `251`
// Estimated: `5487`
// Minimum execution time: 11_000_000 picoseconds.
Weight::from_parts(12_262_916, 5487)
// Standard Error: 0
.saturating_add(Weight::from_parts(187, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
/// The range of component `n` is `[0, 1000]`.
fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `251`
// Estimated: `5487`
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(13_664_993, 5487)
// Standard Error: 220
.saturating_add(Weight::from_parts(131_195, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `Measured`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`)
/// Storage: `MessageQueue::Pages` (r:1 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `Measured`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `Measured`)
/// The range of component `n` is `[0, 105457]`.
fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `434 + n * (1 ±0)`
// Estimated: `3897 + n * (1 ±0)`
// Minimum execution time: 16_000_000 picoseconds.
Weight::from_parts(16_490_667, 3897)
// Standard Error: 2
.saturating_add(Weight::from_parts(720, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
.saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into()))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:100)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
/// The range of component `n` is `[0, 100]`.
fn enqueue_n_full_pages(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `286`
// Estimated: `5487`
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(10_000_000, 5487)
// Standard Error: 26_047
.saturating_add(Weight::from_parts(23_938_725, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into())))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `Measured`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`)
/// Storage: `MessageQueue::Pages` (r:1 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `Measured`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `Measured`)
fn enqueue_1000_small_xcmp_messages() -> Weight {
// Proof Size summary in bytes:
// Measured: `53167`
// Estimated: `56632`
// Minimum execution time: 175_000_000 picoseconds.
Weight::from_parts(181_000_000, 56632)
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
/// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1)
/// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`)
fn suspend_channel() -> Weight {
// Proof Size summary in bytes:
// Measured: `175`
// Estimated: `2767`
// Minimum execution time: 2_000_000 picoseconds.
Weight::from_parts(2_000_000, 2767)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1)
/// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`)
fn resume_channel() -> Weight {
// Proof Size summary in bytes:
// Measured: `210`
// Estimated: `2767`
// Minimum execution time: 3_000_000 picoseconds.
Weight::from_parts(3_000_000, 2767)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// The range of component `n` is `[0, 92]`.
fn take_first_concatenated_xcm(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 1_000_000 picoseconds.
Weight::from_parts(1_878_097, 0)
// Standard Error: 558
.saturating_add(Weight::from_parts(44_593, 0).saturating_mul(n.into()))
}
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
fn on_idle_good_msg() -> Weight {
// Proof Size summary in bytes:
// Measured: `105816`
// Estimated: `109281`
// Minimum execution time: 63_000_000 picoseconds.
Weight::from_parts(67_000_000, 109281)
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().writes(5_u64))
}
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
fn on_idle_large_msg() -> Weight {
// Proof Size summary in bytes:
// Measured: `65885`
// Estimated: `69350`
// Minimum execution time: 42_000_000 picoseconds.
Weight::from_parts(47_000_000, 69350)
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().writes(5_u64))
}
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:1)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
fn set_config_with_u32() -> Weight {
// Proof Size summary in bytes:
// Measured: `175`
// Estimated: `1497`
// Minimum execution time: 3_000_000 picoseconds.
Weight::from_parts(4_000_000, 1497)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
/// The range of component `n` is `[0, 105467]`.
fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `251`
// Estimated: `5487`
// Minimum execution time: 11_000_000 picoseconds.
Weight::from_parts(12_262_916, 5487)
// Standard Error: 0
.saturating_add(Weight::from_parts(187, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
/// The range of component `n` is `[0, 1000]`.
fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `251`
// Estimated: `5487`
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(13_664_993, 5487)
// Standard Error: 220
.saturating_add(Weight::from_parts(131_195, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `Measured`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`)
/// Storage: `MessageQueue::Pages` (r:1 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `Measured`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `Measured`)
/// The range of component `n` is `[0, 105457]`.
fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `434 + n * (1 ±0)`
// Estimated: `3897 + n * (1 ±0)`
// Minimum execution time: 16_000_000 picoseconds.
Weight::from_parts(16_490_667, 3897)
// Standard Error: 2
.saturating_add(Weight::from_parts(720, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
.saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into()))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:100)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
/// The range of component `n` is `[0, 100]`.
fn enqueue_n_full_pages(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `286`
// Estimated: `5487`
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(10_000_000, 5487)
// Standard Error: 26_047
.saturating_add(Weight::from_parts(23_938_725, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into())))
}
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `Measured`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`)
/// Storage: `MessageQueue::Pages` (r:1 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `Measured`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `Measured`)
fn enqueue_1000_small_xcmp_messages() -> Weight {
// Proof Size summary in bytes:
// Measured: `53167`
// Estimated: `56632`
// Minimum execution time: 175_000_000 picoseconds.
Weight::from_parts(181_000_000, 56632)
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
}
/// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1)
/// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`)
fn suspend_channel() -> Weight {
// Proof Size summary in bytes:
// Measured: `175`
// Estimated: `2767`
// Minimum execution time: 2_000_000 picoseconds.
Weight::from_parts(2_000_000, 2767)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1)
/// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`)
fn resume_channel() -> Weight {
// Proof Size summary in bytes:
// Measured: `210`
// Estimated: `2767`
// Minimum execution time: 3_000_000 picoseconds.
Weight::from_parts(3_000_000, 2767)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// The range of component `n` is `[0, 92]`.
fn take_first_concatenated_xcm(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 1_000_000 picoseconds.
Weight::from_parts(1_878_097, 0)
// Standard Error: 558
.saturating_add(Weight::from_parts(44_593, 0).saturating_mul(n.into()))
}
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
fn on_idle_good_msg() -> Weight {
// Proof Size summary in bytes:
// Measured: `105816`
// Estimated: `109281`
// Minimum execution time: 63_000_000 picoseconds.
Weight::from_parts(67_000_000, 109281)
.saturating_add(RocksDbWeight::get().reads(6_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
}
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1)
/// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:1)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::ServiceHead` (r:1 w:1)
/// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::QueueConfig` (r:1 w:0)
/// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0)
/// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`)
/// Storage: `MessageQueue::Pages` (r:0 w:1)
/// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`)
fn on_idle_large_msg() -> Weight {
// Proof Size summary in bytes:
// Measured: `65885`
// Estimated: `69350`
// Minimum execution time: 42_000_000 picoseconds.
Weight::from_parts(47_000_000, 69350)
.saturating_add(RocksDbWeight::get().reads(6_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
}
}
@@ -0,0 +1,104 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Weight-related utilities.
use crate::weights::WeightInfo;
use pezframe_support::{traits::BatchFootprint, weights::Weight};
use pezsp_runtime::SaturatedConversion;
pub(crate) fn get_average_page_pos(max_message_len: u32) -> u32 {
max_message_len / 2
}
/// Extended weight info.
pub trait WeightInfoExt: WeightInfo {
fn uncached_enqueue_xcmp_messages() -> Weight {
Self::enqueue_n_full_pages(0)
}
fn enqueue_xcmp_messages(
first_page_pos: u32,
batch_footprint: &BatchFootprint,
is_first_sender_batch: bool,
) -> Weight {
let message_count = batch_footprint.msgs_count.saturated_into();
let size_in_bytes = batch_footprint.size_in_bytes.saturated_into();
// The cost of adding `n` empty pages on the message queue.
let pages_overhead = {
let full_message_overhead = Self::enqueue_n_full_pages(1)
.saturating_sub(Self::enqueue_n_empty_xcmp_messages(1));
let n_full_messages_overhead =
full_message_overhead.saturating_mul(batch_footprint.new_pages_count as u64);
Self::enqueue_n_full_pages(batch_footprint.new_pages_count)
.saturating_sub(Self::enqueue_n_full_pages(0))
.saturating_sub(n_full_messages_overhead)
};
// The overhead of enqueueing `n` empty messages on the message queue.
let messages_overhead = {
Self::enqueue_n_empty_xcmp_messages(message_count)
.saturating_sub(Self::enqueue_n_empty_xcmp_messages(0))
};
// The overhead of enqueueing `n` bytes on the message queue.
let bytes_overhead = {
Self::enqueue_n_bytes_xcmp_message(size_in_bytes)
.saturating_sub(Self::enqueue_n_bytes_xcmp_message(0))
};
// If the messages are not added to the beginning of the first page, the page will be
// decoded and re-encoded once. Let's account for this.
let pos_overhead = {
let mut pos_overhead = Self::enqueue_empty_xcmp_message_at(first_page_pos)
.saturating_sub(Self::enqueue_empty_xcmp_message_at(0));
// We need to account for the PoV size of the first page in the message queue only the
// first time when we access it.
if !is_first_sender_batch {
pos_overhead = pos_overhead.set_proof_size(0);
}
pos_overhead
};
pages_overhead
.saturating_add(messages_overhead)
.saturating_add(bytes_overhead)
.saturating_add(pos_overhead)
}
fn check_accuracy<MaxMessageLen: bounded_collections::Get<u32>>(err_margin: f64) {
assert!(err_margin < 1f64);
let estimated_weight =
Self::uncached_enqueue_xcmp_messages().saturating_add(Self::enqueue_xcmp_messages(
get_average_page_pos(MaxMessageLen::get()),
&BatchFootprint { msgs_count: 1000, size_in_bytes: 3000, new_pages_count: 0 },
true,
));
let actual_weight = Self::enqueue_1000_small_xcmp_messages();
// Check that the ref_time diff is less than err_margin
approx::assert_relative_eq!(
estimated_weight.ref_time() as f64,
actual_weight.ref_time() as f64,
max_relative = err_margin
);
}
}
impl<T: WeightInfo> WeightInfoExt for T {}