mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 01:41:03 +00:00
Benchmarks for message delivery transaction (#567)
* benchmarks for pallet_message_lane::receive_messages_proof * use CallOrigin::TargetAccount (worst case of CallOrigin) * fmt * closures * Update modules/message-lane/src/benchmarking.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * Update modules/message-lane/src/benchmarking.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * fix compilation Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
f26775d690
commit
6317a31e25
@@ -115,6 +115,7 @@ std = [
|
||||
"sp-version/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"bridge-runtime-common/runtime-benchmarks",
|
||||
"frame-benchmarking",
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
|
||||
@@ -806,9 +806,14 @@ impl_runtime_apis! {
|
||||
Module as MessageLaneBench,
|
||||
Config as MessageLaneConfig,
|
||||
MessageParams as MessageLaneMessageParams,
|
||||
MessageProofParams as MessageLaneMessageProofParams,
|
||||
};
|
||||
|
||||
impl MessageLaneConfig<WithMillauMessageLaneInstance> for Runtime {
|
||||
fn bridged_relayer_id() -> Self::InboundRelayer {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn endow_account(account: &Self::AccountId) {
|
||||
pallet_balances::Module::<Runtime>::make_free_balance_be(
|
||||
account,
|
||||
@@ -816,7 +821,7 @@ impl_runtime_apis! {
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_message(
|
||||
fn prepare_outbound_message(
|
||||
params: MessageLaneMessageParams<Self::AccountId>,
|
||||
) -> (millau_messages::ToMillauMessagePayload, Balance) {
|
||||
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
|
||||
@@ -842,6 +847,75 @@ impl_runtime_apis! {
|
||||
};
|
||||
(message, 1_000_000_000)
|
||||
}
|
||||
|
||||
fn prepare_message_proof(
|
||||
params: MessageLaneMessageProofParams,
|
||||
) -> (millau_messages::FromMillauMessagesProof, Weight) {
|
||||
use crate::millau_messages::{Millau, WithMillauMessageBridge};
|
||||
use bp_message_lane::MessageKey;
|
||||
use bridge_runtime_common::{
|
||||
messages::ChainWithMessageLanes,
|
||||
messages_benchmarking::{ed25519_sign, prepare_message_proof},
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_support::weights::GetDispatchInfo;
|
||||
use pallet_message_lane::storage_keys;
|
||||
use sp_runtime::traits::Header;
|
||||
|
||||
let call = Call::System(SystemCall::remark(vec![]));
|
||||
let call_weight = call.get_dispatch_info().weight;
|
||||
|
||||
let millau_account_id: bp_millau::AccountId = Default::default();
|
||||
let (rialto_raw_public, rialto_raw_signature) = ed25519_sign(
|
||||
&call,
|
||||
&millau_account_id,
|
||||
);
|
||||
let rialto_public = MultiSigner::Ed25519(sp_core::ed25519::Public::from_raw(rialto_raw_public));
|
||||
let rialto_signature = MultiSignature::Ed25519(sp_core::ed25519::Signature::from_raw(
|
||||
rialto_raw_signature,
|
||||
));
|
||||
|
||||
let make_millau_message_key = |message_key: MessageKey| storage_keys::message_key::<
|
||||
Runtime,
|
||||
<Millau as ChainWithMessageLanes>::MessageLaneInstance,
|
||||
>(
|
||||
&message_key.lane_id, message_key.nonce,
|
||||
).0;
|
||||
let make_millau_outbound_lane_data_key = |lane_id| storage_keys::outbound_lane_data_key::<
|
||||
<Millau as ChainWithMessageLanes>::MessageLaneInstance,
|
||||
>(
|
||||
&lane_id,
|
||||
).0;
|
||||
let make_millau_header = |state_root| bp_millau::Header::new(
|
||||
0,
|
||||
Default::default(),
|
||||
state_root,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
prepare_message_proof::<WithMillauMessageBridge, bp_millau::Hasher, Runtime, _, _, _>(
|
||||
params,
|
||||
make_millau_message_key,
|
||||
make_millau_outbound_lane_data_key,
|
||||
make_millau_header,
|
||||
call_weight,
|
||||
pallet_bridge_call_dispatch::MessagePayload {
|
||||
spec_version: VERSION.spec_version,
|
||||
weight: call_weight,
|
||||
origin: pallet_bridge_call_dispatch::CallOrigin::<
|
||||
bp_millau::AccountId,
|
||||
MultiSigner,
|
||||
Signature,
|
||||
>::TargetAccount(
|
||||
millau_account_id,
|
||||
rialto_public,
|
||||
rialto_signature,
|
||||
),
|
||||
call: call.encode(),
|
||||
}.encode(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
add_benchmark!(params, batches, pallet_bridge_eth_poa, BridgeKovan);
|
||||
|
||||
@@ -71,7 +71,7 @@ pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDi
|
||||
>;
|
||||
|
||||
/// Messages proof for Millau -> Rialto messages.
|
||||
type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesProof<WithMillauMessageBridge>;
|
||||
pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesProof<WithMillauMessageBridge>;
|
||||
|
||||
/// Messages delivery proof for Rialto -> Millau messages.
|
||||
type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<WithMillauMessageBridge>;
|
||||
|
||||
@@ -9,6 +9,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, features = ["derive"] }
|
||||
ed25519-dalek = { version = "1.0", default-features = false, optional = true }
|
||||
hash-db = { version = "0.15.2", default-features = false }
|
||||
|
||||
# Bridge dependencies
|
||||
@@ -23,7 +24,9 @@ pallet-substrate-bridge = { path = "../../modules/substrate", default-features =
|
||||
# Substrate dependencies
|
||||
|
||||
frame-support = { 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 }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||
sp-state-machine = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false, optional = true }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||
sp-trie = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||
|
||||
@@ -39,7 +42,15 @@ std = [
|
||||
"pallet-bridge-call-dispatch/std",
|
||||
"pallet-message-lane/std",
|
||||
"pallet-substrate-bridge/std",
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
"sp-state-machine/std",
|
||||
"sp-std/std",
|
||||
"sp-trie/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"ed25519-dalek/u64_backend",
|
||||
"pallet-message-lane/runtime-benchmarks",
|
||||
"pallet-substrate-bridge/runtime-benchmarks",
|
||||
"sp-state-machine",
|
||||
]
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod messages;
|
||||
pub mod messages_benchmarking;
|
||||
|
||||
@@ -27,7 +27,7 @@ use bp_message_lane::{
|
||||
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||
};
|
||||
use bp_runtime::InstanceId;
|
||||
use codec::{Compact, Decode, Input};
|
||||
use codec::{Compact, Decode, Encode, Input};
|
||||
use frame_support::{traits::Instance, RuntimeDebug};
|
||||
use hash_db::Hasher;
|
||||
use pallet_substrate_bridge::StorageProofChecker;
|
||||
@@ -96,14 +96,14 @@ pub trait ChainWithMessageLanes {
|
||||
/// Signature type used on the chain.
|
||||
type Signature: Decode;
|
||||
/// Call type on the chain.
|
||||
type Call: Decode;
|
||||
type Call: Encode + Decode;
|
||||
/// Type of weight that is used on the chain. This would almost always be a regular
|
||||
/// `frame_support::weight::Weight`. But since the meaning of weight on different chains
|
||||
/// may be different, the `WeightOf<>` construct is used to avoid confusion between
|
||||
/// different weights.
|
||||
type Weight: From<frame_support::weights::Weight> + PartialOrd;
|
||||
/// Type of balances that is used on the chain.
|
||||
type Balance: Decode + CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From<u32> + Copy;
|
||||
type Balance: Encode + Decode + CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From<u32> + Copy;
|
||||
|
||||
/// Instance of the message-lane pallet.
|
||||
type MessageLaneInstance: Instance;
|
||||
@@ -327,6 +327,12 @@ pub mod target {
|
||||
/// Message payload for Bridged -> This messages.
|
||||
pub struct FromBridgedChainMessagePayload<B: MessageBridge>(pub(crate) FromBridgedChainDecodedMessagePayload<B>);
|
||||
|
||||
impl<B: MessageBridge> From<FromBridgedChainDecodedMessagePayload<B>> for FromBridgedChainMessagePayload<B> {
|
||||
fn from(decoded_payload: FromBridgedChainDecodedMessagePayload<B>) -> Self {
|
||||
Self(decoded_payload)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: MessageBridge> Decode for FromBridgedChainMessagePayload<B> {
|
||||
fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
|
||||
// for bridged chain our Calls are opaque - they're encoded to Vec<u8> by submitter
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Everything required to run benchmarks of message-lanes, based on
|
||||
//! `bridge_runtime_common::messages` implementation.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use crate::messages::{target::FromBridgedChainMessagesProof, BalanceOf, BridgedChain, HashOf, MessageBridge};
|
||||
|
||||
use bp_message_lane::{LaneId, MessageData, MessageKey, MessagePayload};
|
||||
use codec::Encode;
|
||||
use ed25519_dalek::{PublicKey, SecretKey, Signer, KEYPAIR_LENGTH, SECRET_KEY_LENGTH};
|
||||
use frame_support::weights::Weight;
|
||||
use pallet_message_lane::benchmarking::MessageProofParams;
|
||||
use sp_core::Hasher;
|
||||
use sp_runtime::traits::Header;
|
||||
use sp_std::prelude::*;
|
||||
use sp_trie::{read_trie_value_with, trie_types::TrieDBMut, Layout, MemoryDB, Recorder, StorageProof, TrieMut};
|
||||
|
||||
/// Generate ed25519 signature to be used in `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`.
|
||||
///
|
||||
/// Returns public key of the signer and the signature itself.
|
||||
pub fn ed25519_sign(target_call: &impl Encode, source_account_id: &impl Encode) -> ([u8; 32], [u8; 64]) {
|
||||
// key from the repo example (https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.SecretKey.html)
|
||||
let target_secret = SecretKey::from_bytes(&[
|
||||
157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073, 197, 105, 123, 050,
|
||||
105, 025, 112, 059, 172, 003, 028, 174, 127, 096,
|
||||
])
|
||||
.expect("harcoded key is valid");
|
||||
let target_public: PublicKey = (&target_secret).into();
|
||||
|
||||
let mut target_pair_bytes = [0u8; KEYPAIR_LENGTH];
|
||||
target_pair_bytes[..SECRET_KEY_LENGTH].copy_from_slice(&target_secret.to_bytes());
|
||||
target_pair_bytes[SECRET_KEY_LENGTH..].copy_from_slice(&target_public.to_bytes());
|
||||
let target_pair = ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid");
|
||||
|
||||
let mut signature_message = Vec::new();
|
||||
target_call.encode_to(&mut signature_message);
|
||||
source_account_id.encode_to(&mut signature_message);
|
||||
let target_origin_signature = target_pair
|
||||
.try_sign(&signature_message)
|
||||
.expect("Ed25519 try_sign should not fail in benchmarks");
|
||||
|
||||
(target_public.to_bytes(), target_origin_signature.to_bytes())
|
||||
}
|
||||
|
||||
/// Prepare proof of messages for the `receive_messages_proof` call.
|
||||
pub fn prepare_message_proof<B, H, R, MM, ML, MH>(
|
||||
params: MessageProofParams,
|
||||
make_bridged_message_storage_key: MM,
|
||||
make_bridged_outbound_lane_data_key: ML,
|
||||
make_bridged_header: MH,
|
||||
message_dispatch_weight: Weight,
|
||||
message_payload: MessagePayload,
|
||||
) -> (FromBridgedChainMessagesProof<B>, Weight)
|
||||
where
|
||||
B: MessageBridge,
|
||||
H: Hasher,
|
||||
R: pallet_substrate_bridge::Config,
|
||||
<R::BridgedChain as bp_runtime::Chain>::Hash: Into<HashOf<BridgedChain<B>>>,
|
||||
MM: Fn(MessageKey) -> Vec<u8>,
|
||||
ML: Fn(LaneId) -> Vec<u8>,
|
||||
MH: Fn(H::Out) -> <R::BridgedChain as bp_runtime::Chain>::Header,
|
||||
{
|
||||
// prepare Bridged chain storage with messages and (optionally) outbound lane state
|
||||
let message_count = params
|
||||
.message_nonces
|
||||
.end()
|
||||
.saturating_sub(*params.message_nonces.start())
|
||||
+ 1;
|
||||
let mut storage_keys = Vec::with_capacity(message_count as usize + 1);
|
||||
let mut root = Default::default();
|
||||
let mut mdb = MemoryDB::default();
|
||||
{
|
||||
let mut trie = TrieDBMut::<H>::new(&mut mdb, &mut root);
|
||||
|
||||
// insert messages
|
||||
for nonce in params.message_nonces.clone() {
|
||||
let message_key = MessageKey {
|
||||
lane_id: params.lane,
|
||||
nonce,
|
||||
};
|
||||
let message_data = MessageData {
|
||||
fee: BalanceOf::<BridgedChain<B>>::from(0),
|
||||
payload: message_payload.clone(),
|
||||
};
|
||||
let storage_key = make_bridged_message_storage_key(message_key);
|
||||
trie.insert(&storage_key, &message_data.encode())
|
||||
.map_err(|_| "TrieMut::insert has failed")
|
||||
.expect("TrieMut::insert should not fail in benchmarks");
|
||||
storage_keys.push(storage_key);
|
||||
}
|
||||
|
||||
// insert outbound lane state
|
||||
if let Some(outbound_lane_data) = params.outbound_lane_data {
|
||||
let storage_key = make_bridged_outbound_lane_data_key(params.lane);
|
||||
trie.insert(&storage_key, &outbound_lane_data.encode())
|
||||
.map_err(|_| "TrieMut::insert has failed")
|
||||
.expect("TrieMut::insert should not fail in benchmarks");
|
||||
storage_keys.push(storage_key);
|
||||
}
|
||||
}
|
||||
|
||||
// generate storage proof to be delivered to This chain
|
||||
let mut proof_recorder = Recorder::<H::Out>::new();
|
||||
for storage_key in storage_keys {
|
||||
read_trie_value_with::<Layout<H>, _, _>(&mdb, &root, &storage_key, &mut proof_recorder)
|
||||
.map_err(|_| "read_trie_value_with has failed")
|
||||
.expect("read_trie_value_with should not fail in benchmarks");
|
||||
}
|
||||
let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect();
|
||||
|
||||
// prepare Bridged chain header and insert it into the Substrate pallet
|
||||
let bridged_header = make_bridged_header(root);
|
||||
let bridged_header_hash = bridged_header.hash();
|
||||
pallet_substrate_bridge::initialize_for_benchmarks::<R>(bridged_header);
|
||||
|
||||
(
|
||||
(
|
||||
bridged_header_hash.into(),
|
||||
StorageProof::new(storage_proof),
|
||||
params.lane,
|
||||
*params.message_nonces.start(),
|
||||
*params.message_nonces.end(),
|
||||
),
|
||||
message_dispatch_weight
|
||||
.checked_mul(message_count)
|
||||
.expect("too many messages requested by benchmark"),
|
||||
)
|
||||
}
|
||||
@@ -16,14 +16,16 @@
|
||||
|
||||
//! Message lane pallet benchmarking.
|
||||
|
||||
use crate::{Call, Instance};
|
||||
use crate::{inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane, Call, Instance};
|
||||
|
||||
use bp_message_lane::{LaneId, MessageData, MessageNonce};
|
||||
use bp_message_lane::{
|
||||
target_chain::SourceHeaderChain, InboundLaneData, LaneId, MessageData, MessageNonce, OutboundLaneData,
|
||||
};
|
||||
use frame_benchmarking::{account, benchmarks_instance};
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use frame_system::RawOrigin;
|
||||
use num_traits::Zero;
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::{convert::TryInto, ops::RangeInclusive, prelude::*};
|
||||
|
||||
/// Message crafted with this size factor should be the largest possible message.
|
||||
pub const WORST_MESSAGE_SIZE_FACTOR: u32 = 1000;
|
||||
@@ -43,27 +45,52 @@ pub struct MessageParams<ThisAccountId> {
|
||||
pub sender_account: ThisAccountId,
|
||||
}
|
||||
|
||||
/// Benchmark-specific message proof parameters.
|
||||
pub struct MessageProofParams {
|
||||
/// Id of the lane.
|
||||
pub lane: LaneId,
|
||||
/// Range of messages to include in the proof.
|
||||
pub message_nonces: RangeInclusive<MessageNonce>,
|
||||
/// If `Some`, the proof needs to include this outbound lane data.
|
||||
pub outbound_lane_data: Option<OutboundLaneData>,
|
||||
}
|
||||
|
||||
/// Trait that must be implemented by runtime.
|
||||
pub trait Config<I: Instance>: crate::Config<I> {
|
||||
/// Return id of relayer account at the bridged chain.
|
||||
fn bridged_relayer_id() -> Self::InboundRelayer;
|
||||
/// 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::AccountId>) -> (Self::OutboundPayload, Self::OutboundMessageFee);
|
||||
fn prepare_outbound_message(
|
||||
params: MessageParams<Self::AccountId>,
|
||||
) -> (Self::OutboundPayload, Self::OutboundMessageFee);
|
||||
/// Prepare messages proof to receive by the module.
|
||||
fn prepare_message_proof(
|
||||
params: MessageProofParams,
|
||||
) -> (
|
||||
<Self::SourceHeaderChain as SourceHeaderChain<Self::InboundMessageFee>>::MessagesProof,
|
||||
Weight,
|
||||
);
|
||||
}
|
||||
|
||||
benchmarks_instance! {
|
||||
_ { }
|
||||
|
||||
//
|
||||
// Benchmarks that are used directly by the runtime.
|
||||
//
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Results of this benchmark may be directly used in the `send_message`.
|
||||
send_message_worst_case {
|
||||
let i in 1..100;
|
||||
|
||||
let lane_id = bench_lane_id();
|
||||
let sender = account("sender", i, SEED);
|
||||
let sender = account("sender", 0, SEED);
|
||||
T::endow_account(&sender);
|
||||
|
||||
// 'send' messages that are to be pruned when our message is sent
|
||||
@@ -72,11 +99,181 @@ benchmarks_instance! {
|
||||
}
|
||||
confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
|
||||
|
||||
let (payload, fee) = T::prepare_message(MessageParams {
|
||||
let (payload, fee) = T::prepare_outbound_message(MessageParams {
|
||||
size_factor: WORST_MESSAGE_SIZE_FACTOR,
|
||||
sender_account: sender.clone(),
|
||||
});
|
||||
}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::outbound_latest_generated_nonce(bench_lane_id()),
|
||||
T::MaxMessagesToPruneAtOnce::get() + 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions:
|
||||
// * proof does not include outbound lane state proof;
|
||||
// * inbound lane already has state, so it needs to be read and decoded;
|
||||
// * message is successfully dispatched;
|
||||
// * message requires all heavy checks done by dispatcher.
|
||||
//
|
||||
// This is base benchmark for all other message delivery benchmarks.
|
||||
receive_single_message_proof {
|
||||
let relayer_id_on_source = T::bridged_relayer_id();
|
||||
let relayer_id_on_target = account("relayer", 0, SEED);
|
||||
|
||||
let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams {
|
||||
lane: bench_lane_id(),
|
||||
message_nonces: 1..=1,
|
||||
outbound_lane_data: None,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, dispatch_weight)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_received_nonce(bench_lane_id()),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `receive_messages_proof` extrinsic with two minimal-weight messages and following conditions:
|
||||
// * proof does not include outbound lane state proof;
|
||||
// * inbound lane already has state, so it needs to be read and decoded;
|
||||
// * message is successfully dispatched;
|
||||
// * message requires all heavy checks done by dispatcher.
|
||||
//
|
||||
// The weight of single message delivery could be approximated as
|
||||
// `weight(receive_two_messages_proof) - weight(receive_single_message_proof)`.
|
||||
// This won't be super-accurate if message has non-zero dispatch weight, but estimation should
|
||||
// be close enough to real weight.
|
||||
receive_two_messages_proof {
|
||||
let relayer_id_on_source = T::bridged_relayer_id();
|
||||
let relayer_id_on_target = account("relayer", 0, SEED);
|
||||
|
||||
let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams {
|
||||
lane: bench_lane_id(),
|
||||
message_nonces: 1..=2,
|
||||
outbound_lane_data: None,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, dispatch_weight)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_received_nonce(bench_lane_id()),
|
||||
2,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions:
|
||||
// * proof includes outbound lane state proof;
|
||||
// * inbound lane already has state, so it needs to be read and decoded;
|
||||
// * message is successfully dispatched;
|
||||
// * message requires all heavy checks done by dispatcher.
|
||||
//
|
||||
// The weight of outbound lane state delivery would be
|
||||
// `weight(receive_single_message_proof_with_outbound_lane_state) - weight(receive_single_message_proof)`.
|
||||
// This won't be super-accurate if message has non-zero dispatch weight, but estimation should
|
||||
// be close enough to real weight.
|
||||
receive_single_message_proof_with_outbound_lane_state {
|
||||
let relayer_id_on_source = T::bridged_relayer_id();
|
||||
let relayer_id_on_target = account("relayer", 0, SEED);
|
||||
|
||||
// mark messages 1..=20 as delivered
|
||||
receive_messages::<T, I>(20);
|
||||
|
||||
let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams {
|
||||
lane: bench_lane_id(),
|
||||
message_nonces: 21..=21,
|
||||
outbound_lane_data: Some(OutboundLaneData {
|
||||
oldest_unpruned_nonce: 21,
|
||||
latest_received_nonce: 20,
|
||||
latest_generated_nonce: 21,
|
||||
}),
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, dispatch_weight)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_received_nonce(bench_lane_id()),
|
||||
21,
|
||||
);
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_confirmed_nonce(bench_lane_id()),
|
||||
20,
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Benchmarks for manual checks.
|
||||
//
|
||||
|
||||
// Benchmark `receive_messages_proof` extrinsic with multiple minimal-weight messages and following conditions:
|
||||
// * proof does not include outbound lane state proof;
|
||||
// * inbound lane already has state, so it needs to be read and decoded;
|
||||
// * message is successfully dispatched;
|
||||
// * message requires all heavy checks done by dispatcher.
|
||||
//
|
||||
// This benchmarks gives us an approximation of single message delivery weight. It is similar to the
|
||||
// `weight(receive_two_messages_proof) - weight(receive_single_message_proof)`. So it may be used
|
||||
// to verify that the other approximation is correct.
|
||||
receive_multiple_messages_proof {
|
||||
let i in 1..T::MaxMessagesInDeliveryTransaction::get()
|
||||
.try_into()
|
||||
.expect("Value of MaxMessagesInDeliveryTransaction is too large");
|
||||
|
||||
let relayer_id_on_source = T::bridged_relayer_id();
|
||||
let relayer_id_on_target = account("relayer", 0, SEED);
|
||||
|
||||
let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams {
|
||||
lane: bench_lane_id(),
|
||||
message_nonces: 1..=i as _,
|
||||
outbound_lane_data: None,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, dispatch_weight)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_received_nonce(bench_lane_id()),
|
||||
i as MessageNonce,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `receive_messages_proof` extrinsic with multiple minimal-weight messages and following conditions:
|
||||
// * proof includes outbound lane state proof;
|
||||
// * inbound lane already has state, so it needs to be read and decoded;
|
||||
// * message is successfully dispatched;
|
||||
// * message requires all heavy checks done by dispatcher.
|
||||
//
|
||||
// This benchmarks gives us an approximation of outbound lane state delivery weight. It is similar to the
|
||||
// `weight(receive_single_message_proof_with_outbound_lane_state) - weight(receive_single_message_proof)`.
|
||||
// So it may be used to verify that the other approximation is correct.
|
||||
receive_multiple_messages_proof_with_outbound_lane_state {
|
||||
let i in 1..T::MaxMessagesInDeliveryTransaction::get()
|
||||
.try_into()
|
||||
.expect("Value of MaxMessagesInDeliveryTransaction is too large");
|
||||
|
||||
let relayer_id_on_source = T::bridged_relayer_id();
|
||||
let relayer_id_on_target = account("relayer", 0, SEED);
|
||||
|
||||
// mark messages 1..=20 as delivered
|
||||
receive_messages::<T, I>(20);
|
||||
|
||||
let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams {
|
||||
lane: bench_lane_id(),
|
||||
message_nonces: 21..=20 + i as MessageNonce,
|
||||
outbound_lane_data: Some(OutboundLaneData {
|
||||
oldest_unpruned_nonce: 21,
|
||||
latest_received_nonce: 20,
|
||||
latest_generated_nonce: 21,
|
||||
}),
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, dispatch_weight)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_received_nonce(bench_lane_id()),
|
||||
20 + i as MessageNonce,
|
||||
);
|
||||
assert_eq!(
|
||||
crate::Module::<T, I>::inbound_latest_confirmed_nonce(bench_lane_id()),
|
||||
20,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn bench_lane_id() -> LaneId {
|
||||
@@ -84,7 +281,7 @@ fn bench_lane_id() -> LaneId {
|
||||
}
|
||||
|
||||
fn send_regular_message<T: Config<I>, I: Instance>() {
|
||||
let mut outbound_lane = crate::outbound_lane::<T, I>(bench_lane_id());
|
||||
let mut outbound_lane = outbound_lane::<T, I>(bench_lane_id());
|
||||
outbound_lane.send_message(MessageData {
|
||||
payload: vec![],
|
||||
fee: Zero::zero(),
|
||||
@@ -92,6 +289,15 @@ fn send_regular_message<T: Config<I>, I: Instance>() {
|
||||
}
|
||||
|
||||
fn confirm_message_delivery<T: Config<I>, I: Instance>(nonce: MessageNonce) {
|
||||
let mut outbound_lane = crate::outbound_lane::<T, I>(bench_lane_id());
|
||||
let mut outbound_lane = outbound_lane::<T, I>(bench_lane_id());
|
||||
assert!(outbound_lane.confirm_delivery(nonce).is_some());
|
||||
}
|
||||
|
||||
fn receive_messages<T: Config<I>, I: Instance>(nonce: MessageNonce) {
|
||||
let mut inbound_lane_storage = inbound_lane_storage::<T, I>(bench_lane_id());
|
||||
inbound_lane_storage.set_data(InboundLaneData {
|
||||
relayers: vec![(1, nonce, T::bridged_relayer_id())].into_iter().collect(),
|
||||
latest_received_nonce: nonce,
|
||||
latest_confirmed_nonce: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -558,11 +558,16 @@ fn ensure_operational<T: Config<I>, I: Instance>() -> Result<(), Error<T, I>> {
|
||||
|
||||
/// Creates new inbound lane object, backed by runtime storage.
|
||||
fn inbound_lane<T: Config<I>, I: Instance>(lane_id: LaneId) -> InboundLane<RuntimeInboundLaneStorage<T, I>> {
|
||||
InboundLane::new(RuntimeInboundLaneStorage {
|
||||
InboundLane::new(inbound_lane_storage::<T, I>(lane_id))
|
||||
}
|
||||
|
||||
/// Creates new runtime inbound lane storage.
|
||||
fn inbound_lane_storage<T: Config<I>, I: Instance>(lane_id: LaneId) -> RuntimeInboundLaneStorage<T, I> {
|
||||
RuntimeInboundLaneStorage {
|
||||
lane_id,
|
||||
cached_data: RefCell::new(None),
|
||||
_phantom: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new outbound lane object, backed by runtime storage.
|
||||
|
||||
@@ -47,3 +47,4 @@ std = [
|
||||
"sp-std/std",
|
||||
"sp-trie/std",
|
||||
]
|
||||
runtime-benchmarks = []
|
||||
|
||||
@@ -370,6 +370,18 @@ fn ensure_operational<T: Config>() -> Result<(), Error<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// (Re)initialize bridge with given header for using it in external benchmarks.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub fn initialize_for_benchmarks<T: Config>(header: HeaderOf<T::BridgedChain>) {
|
||||
initialize_bridge::<T>(InitializationData {
|
||||
header,
|
||||
authority_list: Vec::new(), // we don't verify any proofs in external benchmarks
|
||||
set_id: 0,
|
||||
scheduled_change: None,
|
||||
is_halted: false,
|
||||
});
|
||||
}
|
||||
|
||||
/// Since this writes to storage with no real checks this should only be used in functions that were
|
||||
/// called by a trusted origin.
|
||||
fn initialize_bridge<T: Config>(init_params: InitializationData<BridgedHeader<T>>) {
|
||||
|
||||
Reference in New Issue
Block a user