From 81a268217e1d824548a617c5ee5ea368afd4d86d Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 9 Dec 2020 01:27:21 +0300 Subject: [PATCH] Message lane benchmarks: start (#554) * message lane benchmarks: start * finish send_message_worst_case benchmark * fix compilation * removed redundant bench param --- bridges/bin/rialto/runtime/Cargo.toml | 1 + bridges/bin/rialto/runtime/src/lib.rs | 47 ++++++++++ .../bin/rialto/runtime/src/millau_messages.rs | 2 +- bridges/bin/runtime-common/src/messages.rs | 11 ++- bridges/modules/message-lane/Cargo.toml | 6 ++ .../modules/message-lane/src/benchmarking.rs | 92 +++++++++++++++++++ bridges/modules/message-lane/src/lib.rs | 11 ++- 7 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 bridges/modules/message-lane/src/benchmarking.rs diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml index aa426c02ec5a1..29226e1cb114b 100644 --- a/bridges/bin/rialto/runtime/Cargo.toml +++ b/bridges/bin/rialto/runtime/Cargo.toml @@ -121,5 +121,6 @@ runtime-benchmarks = [ "libsecp256k1", "pallet-bridge-currency-exchange/runtime-benchmarks", "pallet-bridge-eth-poa/runtime-benchmarks", + "pallet-message-lane/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index 2e5220b790588..b5b1d2dddee91 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -437,6 +437,7 @@ parameter_types! { bp_rialto::MAX_MESSAGES_IN_DELIVERY_TRANSACTION; } +pub(crate) type WithMillauMessageLaneInstance = pallet_message_lane::DefaultInstance; impl pallet_message_lane::Trait for Runtime { type Event = Event; type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; @@ -814,6 +815,46 @@ impl_runtime_apis! { } } + use pallet_message_lane::benchmarking::{ + Module as MessageLaneBench, + Trait as MessageLaneTrait, + MessageParams as MessageLaneMessageParams, + }; + + impl MessageLaneTrait for Runtime { + fn endow_account(account: &Self::AccountId) { + pallet_balances::Module::::make_free_balance_be( + account, + 1_000_000_000_000, + ); + } + + fn prepare_message( + params: MessageLaneMessageParams, + ) -> (millau_messages::ToMillauMessagePayload, Balance) { + use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge}; + use bridge_runtime_common::messages; + use pallet_message_lane::benchmarking::WORST_MESSAGE_SIZE_FACTOR; + + let max_message_size = messages::source::maximal_message_size::(); + let message_size = match params.size_factor { + 0 => 1, + factor => max_message_size / WORST_MESSAGE_SIZE_FACTOR + * sp_std::cmp::min(factor, WORST_MESSAGE_SIZE_FACTOR), + }; + let message_payload = vec![0; message_size as usize]; + let dispatch_origin = pallet_bridge_call_dispatch::CallOrigin::SourceAccount(Default::default()); + + let message = ToMillauMessagePayload { + spec_version: 0, + weight: message_size as _, + origin: dispatch_origin, + call: message_payload, + }; + (message, 1_000_000_000) + } + } + add_benchmark!(params, batches, pallet_bridge_eth_poa, BridgeKovan); add_benchmark!( params, @@ -821,6 +862,12 @@ impl_runtime_apis! { pallet_bridge_currency_exchange, BridgeCurrencyExchangeBench:: ); + add_benchmark!( + params, + batches, + pallet_message_lane, + MessageLaneBench:: + ); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/bridges/bin/rialto/runtime/src/millau_messages.rs b/bridges/bin/rialto/runtime/src/millau_messages.rs index db2076eaa1702..680fcb747f8cd 100644 --- a/bridges/bin/rialto/runtime/src/millau_messages.rs +++ b/bridges/bin/rialto/runtime/src/millau_messages.rs @@ -143,7 +143,7 @@ impl messages::ChainWithMessageLanes for Rialto { type Weight = Weight; type Balance = bp_rialto::Balance; - type MessageLaneInstance = pallet_message_lane::DefaultInstance; + type MessageLaneInstance = crate::WithMillauMessageLaneInstance; } /// Millau chain from message lane point of view. diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs index 82c28bfa7f68d..e0fc4bcfe60d2 100644 --- a/bridges/bin/runtime-common/src/messages.rs +++ b/bridges/bin/runtime-common/src/messages.rs @@ -174,6 +174,11 @@ pub mod source { } } + /// Return maximal message size of This -> Bridged chain message. + pub fn maximal_message_size() -> u32 { + B::maximal_extrinsic_size_on_target_chain() / 3 * 2 + } + /// Do basic Bridged-chain specific verification of This -> Bridged chain message. /// /// Ok result from this function means that the delivery transaction with this message @@ -197,7 +202,7 @@ pub mod source { // is enormously large, it should be several dozens/hundreds of bytes. The delivery // transaction also contains signatures and signed extensions. Because of this, we reserve // 1/3 of the the maximal extrinsic weight for this data. - if payload.call.len() > B::maximal_extrinsic_size_on_target_chain() as usize * 2 / 3 { + if payload.call.len() > maximal_message_size::() as usize { return Err("The message is too large to be sent over the lane"); } @@ -856,7 +861,7 @@ mod tests { spec_version: 1, weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - call: vec![0; BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE as usize * 2 / 3 + 1], + call: vec![0; source::maximal_message_size::() as usize + 1], },) .is_err() ); @@ -871,7 +876,7 @@ mod tests { spec_version: 1, weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - call: vec![0; BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE as usize * 2 / 3], + call: vec![0; source::maximal_message_size::() as _], },), Ok(()), ); diff --git a/bridges/modules/message-lane/Cargo.toml b/bridges/modules/message-lane/Cargo.toml index 05f16f189923d..7f443732cbf8f 100644 --- a/bridges/modules/message-lane/Cargo.toml +++ b/bridges/modules/message-lane/Cargo.toml @@ -8,6 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false } +num-traits = { version = "0.2", default-features = false } serde = { version = "1.0.101", optional = true, features = ["derive"] } # Bridge dependencies @@ -17,6 +18,7 @@ bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Dependencies +frame-benchmarking = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false, optional = true } frame-support = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false } frame-system = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false } sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false } @@ -35,8 +37,12 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", + "num-traits/std", "serde", "sp-core/std", "sp-runtime/std", "sp-std/std", ] +runtime-benchmarks = [ + "frame-benchmarking", +] diff --git a/bridges/modules/message-lane/src/benchmarking.rs b/bridges/modules/message-lane/src/benchmarking.rs new file mode 100644 index 0000000000000..98fc68eae00d6 --- /dev/null +++ b/bridges/modules/message-lane/src/benchmarking.rs @@ -0,0 +1,92 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Message lane pallet benchmarking. + +use crate::{Call, Instance}; + +use bp_message_lane::{LaneId, MessageData, MessageNonce}; +use frame_benchmarking::{account, benchmarks_instance}; +use frame_support::traits::Get; +use frame_system::RawOrigin; +use num_traits::Zero; +use sp_std::prelude::*; + +/// Message crafted with this size factor should be the largest possible message. +pub const WORST_MESSAGE_SIZE_FACTOR: u32 = 1000; + +const SEED: u32 = 0; + +/// Module we're benchmarking here. +pub struct Module, I: crate::Instance>(crate::Module); + +/// Benchmark-specific message parameters. +pub struct MessageParams { + /// Size factor of the message payload. Message payload grows with every factor + /// increment. Zero is the smallest possible message and the `WORST_MESSAGE_SIZE_FACTOR` is + /// largest possible message. + pub size_factor: u32, +} + +/// Trait that must be implemented by runtime. +pub trait Trait: crate::Trait { + /// Create given account and give it enough balance for test purposes. + fn endow_account(account: &Self::AccountId); + /// Prepare message to send over lane. + fn prepare_message(params: MessageParams) -> (Self::OutboundPayload, Self::OutboundMessageFee); +} + +benchmarks_instance! { + _ { } + + // Benchmark `send_message` extrinsic with the worst possible conditions: + // * outbound lane already has state, so it needs to be read and decoded; + // * relayers fund account does not exists (in practice it needs to exist in production environment); + // * maximal number of messages is being pruned during the call; + // * message size is maximal for the target chain. + send_message_worst_case { + let i in 1..100; + + let lane_id = bench_lane_id(); + let sender = account("sender", i, SEED); + T::endow_account(&sender); + + // 'send' messages that are to be pruned when our message is sent + for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() { + send_regular_message::(); + } + confirm_message_delivery::(T::MaxMessagesToPruneAtOnce::get()); + + let (payload, fee) = T::prepare_message(MessageParams { size_factor: WORST_MESSAGE_SIZE_FACTOR }); + }: send_message(RawOrigin::Signed(sender), lane_id, payload, fee) +} + +fn bench_lane_id() -> LaneId { + *b"test" +} + +fn send_regular_message, I: Instance>() { + let mut outbound_lane = crate::outbound_lane::(bench_lane_id()); + outbound_lane.send_message(MessageData { + payload: vec![], + fee: Zero::zero(), + }); +} + +fn confirm_message_delivery, I: Instance>(nonce: MessageNonce) { + let mut outbound_lane = crate::outbound_lane::(bench_lane_id()); + assert!(outbound_lane.confirm_delivery(nonce).is_some()); +} diff --git a/bridges/modules/message-lane/src/lib.rs b/bridges/modules/message-lane/src/lib.rs index 4ef8f690f3e1e..13d43848938d2 100644 --- a/bridges/modules/message-lane/src/lib.rs +++ b/bridges/modules/message-lane/src/lib.rs @@ -45,6 +45,7 @@ use frame_support::{ Parameter, StorageMap, }; use frame_system::{ensure_signed, RawOrigin}; +use num_traits::Zero; use sp_runtime::{traits::BadOrigin, DispatchResult}; use sp_std::{cell::RefCell, marker::PhantomData, prelude::*}; @@ -53,6 +54,9 @@ mod outbound_lane; pub mod instant_payments; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + #[cfg(test)] mod mock; @@ -71,9 +75,8 @@ pub trait Trait: frame_system::Trait { /// They overarching event type. type Event: From> + Into<::Event>; /// Maximal number of messages that may be pruned during maintenance. Maintenance occurs - /// whenever outbound lane is updated - i.e. when new message is sent, or receival is - /// confirmed. The reason is that if you want to use lane, you should be ready to pay - /// for it. + /// whenever new message is sent. The reason is that if you want to use lane, you should + /// be ready to pay for its maintenance. type MaxMessagesToPruneAtOnce: Get; /// Maximal number of unrewarded relayer entries at inbound lane. Unrewarded means that the /// relayer has delivered messages, but either confirmations haven't been delivered back to the @@ -99,7 +102,7 @@ pub trait Trait: frame_system::Trait { /// Payload type of outbound messages. This payload is dispatched on the bridged chain. type OutboundPayload: Parameter; /// Message fee type of outbound messages. This fee is paid on this chain. - type OutboundMessageFee: Parameter; + type OutboundMessageFee: Parameter + Zero; /// Payload type of inbound messages. This payload is dispatched on this chain. type InboundPayload: Decode;