Skip to content
131 changes: 86 additions & 45 deletions polkadot/runtime/parachains/src/hrmp/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

#![cfg(feature = "runtime-benchmarks")]

use crate::{
configuration::Pallet as Configuration,
hrmp::{Pallet as Hrmp, *},
paras::{Pallet as Paras, ParaKind, ParachainsCache},
shared::Pallet as Shared,
};
use frame_benchmarking::v2::*;
use frame_support::{assert_ok, traits::Currency};

type BalanceOf<T> =
Expand Down Expand Up @@ -138,10 +141,12 @@ static_assertions::const_assert!(MAX_UNIQUE_CHANNELS < PREFIX_0);
static_assertions::const_assert!(HRMP_MAX_INBOUND_CHANNELS_BOUND < PREFIX_0);
static_assertions::const_assert!(HRMP_MAX_OUTBOUND_CHANNELS_BOUND < PREFIX_0);

frame_benchmarking::benchmarks! {
where_clause { where <T as frame_system::Config>::RuntimeOrigin: From<crate::Origin> }
#[benchmarks(where <T as frame_system::Config>::RuntimeOrigin: From<crate::Origin>)]
mod benchmarks {
use super::*;

hrmp_init_open_channel {
#[benchmark]
fn hrmp_init_open_channel () {
let sender_id: ParaId = 1u32.into();
let sender_origin: crate::Origin = 1u32.into();

Expand All @@ -155,45 +160,57 @@ frame_benchmarking::benchmarks! {

let capacity = Configuration::<T>::config().hrmp_channel_max_capacity;
let message_size = Configuration::<T>::config().hrmp_channel_max_message_size;
}: _(sender_origin, recipient_id, capacity, message_size)
verify {

#[extrinsic_call]
_(sender_origin, recipient_id, capacity, message_size);

assert_last_event::<T>(
Event::<T>::OpenChannelRequested(sender_id, recipient_id, capacity, message_size).into()
);
}

hrmp_accept_open_channel {
#[benchmark]
fn hrmp_accept_open_channel () {
let [(sender, _), (recipient, recipient_origin)] =
establish_para_connection::<T>(1, 2, ParachainSetupStep::Requested);
}: _(recipient_origin, sender)
verify {

#[extrinsic_call]
_(recipient_origin, sender);

assert_last_event::<T>(Event::<T>::OpenChannelAccepted(sender, recipient).into());
}

hrmp_close_channel {
#[benchmark]
fn hrmp_close_channel () {
let [(sender, sender_origin), (recipient, _)] =
establish_para_connection::<T>(1, 2, ParachainSetupStep::Established);
let channel_id = HrmpChannelId { sender, recipient };
}: _(sender_origin, channel_id.clone())
verify {

#[extrinsic_call]
_(sender_origin, channel_id.clone());

assert_last_event::<T>(Event::<T>::ChannelClosed(sender, channel_id).into());
}

// NOTE: a single parachain should have the maximum number of allowed ingress and egress
// channels.
force_clean_hrmp {
#[benchmark]
fn force_clean_hrmp (
// ingress channels to a single leaving parachain that need to be closed.
let i in 0 .. (HRMP_MAX_INBOUND_CHANNELS_BOUND - 1);
i: Linear<0, { HRMP_MAX_INBOUND_CHANNELS_BOUND - 1 }>,
// egress channels to a single leaving parachain that need to be closed.
let e in 0 .. (HRMP_MAX_OUTBOUND_CHANNELS_BOUND - 1);

e: Linear<0, { HRMP_MAX_OUTBOUND_CHANNELS_BOUND - 1 }>
) {
// first, update the configs to support this many open channels...
assert_ok!(
Configuration::<T>::set_hrmp_max_parachain_outbound_channels(frame_system::RawOrigin::Root.into(), e + 1)
);
assert_ok!(
Configuration::<T>::set_hrmp_max_parachain_inbound_channels(frame_system::RawOrigin::Root.into(), i + 1)
);
assert_ok!(
Configuration::<T>::set_max_downward_message_size(frame_system::RawOrigin::Root.into(), 1024)
);
// .. and enact it.
Configuration::<T>::initializer_on_new_session(&Shared::<T>::scheduled_session());

Expand Down Expand Up @@ -225,48 +242,58 @@ frame_benchmarking::benchmarks! {

// all in all, we have created this many channels.
assert_eq!(HrmpChannels::<T>::iter().count() as u32, i + e);
}: _(frame_system::Origin::<T>::Root, para, i, e) verify {

#[extrinsic_call]
_(frame_system::Origin::<T>::Root, para, i, e);

// all in all, all of them must be gone by now.
assert_eq!(HrmpChannels::<T>::iter().count() as u32, 0);
// borrow this function from the tests to make sure state is clear, given that we do a lot
// of out-of-ordinary ops here.
Hrmp::<T>::assert_storage_consistency_exhaustive();
}

force_process_hrmp_open {
#[benchmark]
fn force_process_hrmp_open (
// number of channels that need to be processed. Worse case is an N-M relation: unique
// sender and recipients for all channels.
let c in 0 .. MAX_UNIQUE_CHANNELS;

c: Linear<0, MAX_UNIQUE_CHANNELS>
) {
for id in 0 .. c {
let _ = establish_para_connection::<T>(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::Accepted);
}
assert_eq!(HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, c);
}: _(frame_system::Origin::<T>::Root, c)
verify {

#[extrinsic_call]
_(frame_system::Origin::<T>::Root, c);

assert_eq!(HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, 0);
}

force_process_hrmp_close {
#[benchmark]
fn force_process_hrmp_close (
// number of channels that need to be processed. Worse case is an N-M relation: unique
// sender and recipients for all channels.
let c in 0 .. MAX_UNIQUE_CHANNELS;

c: Linear<0, MAX_UNIQUE_CHANNELS>
) {
for id in 0 .. c {
let _ = establish_para_connection::<T>(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::CloseRequested);
}

assert_eq!(HrmpCloseChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, c);
}: _(frame_system::Origin::<T>::Root, c)
verify {

#[extrinsic_call]
_(frame_system::Origin::<T>::Root, c);

assert_eq!(HrmpCloseChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, 0);
}

hrmp_cancel_open_request {
#[benchmark]
fn hrmp_cancel_open_request (
// number of items already existing in the `HrmpOpenChannelRequestsList`, other than the
// one that we remove.
let c in 0 .. MAX_UNIQUE_CHANNELS;

c: Linear<0, MAX_UNIQUE_CHANNELS>
) {
for id in 0 .. c {
let _ = establish_para_connection::<T>(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::Requested);
}
Expand All @@ -275,16 +302,18 @@ frame_benchmarking::benchmarks! {
establish_para_connection::<T>(1, 2, ParachainSetupStep::Requested);
assert_eq!(HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, c + 1);
let channel_id = HrmpChannelId { sender, recipient };
}: _(sender_origin, channel_id, c + 1)
verify {

#[extrinsic_call]
_(sender_origin, channel_id, c + 1);

assert_eq!(HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, c);
}

// worse case will be `n` parachain channel requests, where in all of them either the sender or
// the recipient need to be cleaned. This enforces the deposit of at least one to be processed.
// No code path for triggering two deposit process exists.
clean_open_channel_requests {
let c in 0 .. MAX_UNIQUE_CHANNELS;
#[benchmark]
fn clean_open_channel_requests (c: Linear<0, MAX_UNIQUE_CHANNELS>) {

for id in 0 .. c {
let _ = establish_para_connection::<T>(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::Requested);
Expand All @@ -293,13 +322,17 @@ frame_benchmarking::benchmarks! {
assert_eq!(HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, c);
let outgoing = (0..c).map(|id| (id + PREFIX_1).into()).collect::<Vec<ParaId>>();
let config = Configuration::<T>::config();
}: {
Hrmp::<T>::clean_open_channel_requests(&config, &outgoing);
} verify {

#[block]
{
Hrmp::<T>::clean_open_channel_requests(&config, &outgoing);
}

assert_eq!(HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32, 0);
}

force_open_hrmp_channel {
#[benchmark]
fn force_open_hrmp_channel () {
let sender_id: ParaId = 1u32.into();
let sender_origin: crate::Origin = 1u32.into();
let recipient_id: ParaId = 2u32.into();
Expand Down Expand Up @@ -344,14 +377,17 @@ frame_benchmarking::benchmarks! {

// but the _channel_ should not exist
assert!(HrmpChannels::<T>::get(&channel_id).is_none());
}: _(frame_system::Origin::<T>::Root, sender_id, recipient_id, capacity, message_size)
verify {

#[extrinsic_call]
_(frame_system::Origin::<T>::Root, sender_id, recipient_id, capacity, message_size);

assert_last_event::<T>(
Event::<T>::HrmpChannelForceOpened(sender_id, recipient_id, capacity, message_size).into()
);
}

establish_system_channel {
#[benchmark]
fn establish_system_channel () {
let sender_id: ParaId = 1u32.into();
let recipient_id: ParaId = 2u32.into();

Expand All @@ -364,14 +400,17 @@ frame_benchmarking::benchmarks! {

let capacity = config.hrmp_channel_max_capacity;
let message_size = config.hrmp_channel_max_message_size;
}: _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id)
verify {

#[extrinsic_call]
_(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id);

assert_last_event::<T>(
Event::<T>::HrmpSystemChannelOpened(sender_id, recipient_id, capacity, message_size).into()
);
}

poke_channel_deposits {
#[benchmark]
fn poke_channel_deposits () {
let sender_id: ParaId = 1u32.into();
let recipient_id: ParaId = 2u32.into();
let channel_id = HrmpChannelId {sender: sender_id, recipient: recipient_id };
Expand Down Expand Up @@ -403,8 +442,10 @@ frame_benchmarking::benchmarks! {
// Actually reserve the deposits.
let _ = T::Currency::reserve(&sender_id.into_account_truncating(), sender_deposit);
let _ = T::Currency::reserve(&recipient_id.into_account_truncating(), recipient_deposit);
}: _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id)
verify {

#[extrinsic_call]
_(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id);

assert_last_event::<T>(
Event::<T>::OpenChannelDepositsUpdated(sender_id, recipient_id).into()
);
Expand Down