mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 02:51:01 +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",
|
"sp-version/std",
|
||||||
]
|
]
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
|
"bridge-runtime-common/runtime-benchmarks",
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support/runtime-benchmarks",
|
"frame-support/runtime-benchmarks",
|
||||||
"frame-system/runtime-benchmarks",
|
"frame-system/runtime-benchmarks",
|
||||||
|
|||||||
@@ -806,9 +806,14 @@ impl_runtime_apis! {
|
|||||||
Module as MessageLaneBench,
|
Module as MessageLaneBench,
|
||||||
Config as MessageLaneConfig,
|
Config as MessageLaneConfig,
|
||||||
MessageParams as MessageLaneMessageParams,
|
MessageParams as MessageLaneMessageParams,
|
||||||
|
MessageProofParams as MessageLaneMessageProofParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl MessageLaneConfig<WithMillauMessageLaneInstance> for Runtime {
|
impl MessageLaneConfig<WithMillauMessageLaneInstance> for Runtime {
|
||||||
|
fn bridged_relayer_id() -> Self::InboundRelayer {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
fn endow_account(account: &Self::AccountId) {
|
fn endow_account(account: &Self::AccountId) {
|
||||||
pallet_balances::Module::<Runtime>::make_free_balance_be(
|
pallet_balances::Module::<Runtime>::make_free_balance_be(
|
||||||
account,
|
account,
|
||||||
@@ -816,7 +821,7 @@ impl_runtime_apis! {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_message(
|
fn prepare_outbound_message(
|
||||||
params: MessageLaneMessageParams<Self::AccountId>,
|
params: MessageLaneMessageParams<Self::AccountId>,
|
||||||
) -> (millau_messages::ToMillauMessagePayload, Balance) {
|
) -> (millau_messages::ToMillauMessagePayload, Balance) {
|
||||||
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
|
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
|
||||||
@@ -842,6 +847,75 @@ impl_runtime_apis! {
|
|||||||
};
|
};
|
||||||
(message, 1_000_000_000)
|
(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);
|
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.
|
/// 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.
|
/// Messages delivery proof for Rialto -> Millau messages.
|
||||||
type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<WithMillauMessageBridge>;
|
type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<WithMillauMessageBridge>;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] }
|
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 }
|
hash-db = { version = "0.15.2", default-features = false }
|
||||||
|
|
||||||
# Bridge dependencies
|
# Bridge dependencies
|
||||||
@@ -23,7 +24,9 @@ pallet-substrate-bridge = { path = "../../modules/substrate", default-features =
|
|||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
|
|
||||||
frame-support = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
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-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-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 }
|
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-bridge-call-dispatch/std",
|
||||||
"pallet-message-lane/std",
|
"pallet-message-lane/std",
|
||||||
"pallet-substrate-bridge/std",
|
"pallet-substrate-bridge/std",
|
||||||
|
"sp-core/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
|
"sp-state-machine/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
"sp-trie/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)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
|
pub mod messages_benchmarking;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use bp_message_lane::{
|
|||||||
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||||
};
|
};
|
||||||
use bp_runtime::InstanceId;
|
use bp_runtime::InstanceId;
|
||||||
use codec::{Compact, Decode, Input};
|
use codec::{Compact, Decode, Encode, Input};
|
||||||
use frame_support::{traits::Instance, RuntimeDebug};
|
use frame_support::{traits::Instance, RuntimeDebug};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use pallet_substrate_bridge::StorageProofChecker;
|
use pallet_substrate_bridge::StorageProofChecker;
|
||||||
@@ -96,14 +96,14 @@ pub trait ChainWithMessageLanes {
|
|||||||
/// Signature type used on the chain.
|
/// Signature type used on the chain.
|
||||||
type Signature: Decode;
|
type Signature: Decode;
|
||||||
/// Call type on the chain.
|
/// 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
|
/// 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
|
/// `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
|
/// may be different, the `WeightOf<>` construct is used to avoid confusion between
|
||||||
/// different weights.
|
/// different weights.
|
||||||
type Weight: From<frame_support::weights::Weight> + PartialOrd;
|
type Weight: From<frame_support::weights::Weight> + PartialOrd;
|
||||||
/// Type of balances that is used on the chain.
|
/// 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.
|
/// Instance of the message-lane pallet.
|
||||||
type MessageLaneInstance: Instance;
|
type MessageLaneInstance: Instance;
|
||||||
@@ -327,6 +327,12 @@ pub mod target {
|
|||||||
/// Message payload for Bridged -> This messages.
|
/// Message payload for Bridged -> This messages.
|
||||||
pub struct FromBridgedChainMessagePayload<B: MessageBridge>(pub(crate) FromBridgedChainDecodedMessagePayload<B>);
|
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> {
|
impl<B: MessageBridge> Decode for FromBridgedChainMessagePayload<B> {
|
||||||
fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
|
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
|
// 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.
|
//! 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_benchmarking::{account, benchmarks_instance};
|
||||||
use frame_support::traits::Get;
|
use frame_support::{traits::Get, weights::Weight};
|
||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
use num_traits::Zero;
|
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.
|
/// Message crafted with this size factor should be the largest possible message.
|
||||||
pub const WORST_MESSAGE_SIZE_FACTOR: u32 = 1000;
|
pub const WORST_MESSAGE_SIZE_FACTOR: u32 = 1000;
|
||||||
@@ -43,27 +45,52 @@ pub struct MessageParams<ThisAccountId> {
|
|||||||
pub sender_account: 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.
|
/// Trait that must be implemented by runtime.
|
||||||
pub trait Config<I: Instance>: crate::Config<I> {
|
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.
|
/// Create given account and give it enough balance for test purposes.
|
||||||
fn endow_account(account: &Self::AccountId);
|
fn endow_account(account: &Self::AccountId);
|
||||||
/// Prepare message to send over lane.
|
/// 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_instance! {
|
||||||
_ { }
|
_ { }
|
||||||
|
|
||||||
|
//
|
||||||
|
// Benchmarks that are used directly by the runtime.
|
||||||
|
//
|
||||||
|
|
||||||
// Benchmark `send_message` extrinsic with the worst possible conditions:
|
// Benchmark `send_message` extrinsic with the worst possible conditions:
|
||||||
// * outbound lane already has state, so it needs to be read and decoded;
|
// * 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);
|
// * 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;
|
// * maximal number of messages is being pruned during the call;
|
||||||
// * message size is maximal for the target chain.
|
// * message size is maximal for the target chain.
|
||||||
|
//
|
||||||
|
// Results of this benchmark may be directly used in the `send_message`.
|
||||||
send_message_worst_case {
|
send_message_worst_case {
|
||||||
let i in 1..100;
|
|
||||||
|
|
||||||
let lane_id = bench_lane_id();
|
let lane_id = bench_lane_id();
|
||||||
let sender = account("sender", i, SEED);
|
let sender = account("sender", 0, SEED);
|
||||||
T::endow_account(&sender);
|
T::endow_account(&sender);
|
||||||
|
|
||||||
// 'send' messages that are to be pruned when our message is sent
|
// '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());
|
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,
|
size_factor: WORST_MESSAGE_SIZE_FACTOR,
|
||||||
sender_account: sender.clone(),
|
sender_account: sender.clone(),
|
||||||
});
|
});
|
||||||
}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
|
}: 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 {
|
fn bench_lane_id() -> LaneId {
|
||||||
@@ -84,7 +281,7 @@ fn bench_lane_id() -> LaneId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn send_regular_message<T: Config<I>, I: Instance>() {
|
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 {
|
outbound_lane.send_message(MessageData {
|
||||||
payload: vec![],
|
payload: vec![],
|
||||||
fee: Zero::zero(),
|
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) {
|
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());
|
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.
|
/// Creates new inbound lane object, backed by runtime storage.
|
||||||
fn inbound_lane<T: Config<I>, I: Instance>(lane_id: LaneId) -> InboundLane<RuntimeInboundLaneStorage<T, I>> {
|
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,
|
lane_id,
|
||||||
cached_data: RefCell::new(None),
|
cached_data: RefCell::new(None),
|
||||||
_phantom: Default::default(),
|
_phantom: Default::default(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new outbound lane object, backed by runtime storage.
|
/// Creates new outbound lane object, backed by runtime storage.
|
||||||
|
|||||||
@@ -47,3 +47,4 @@ std = [
|
|||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
"sp-trie/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
|
/// Since this writes to storage with no real checks this should only be used in functions that were
|
||||||
/// called by a trusted origin.
|
/// called by a trusted origin.
|
||||||
fn initialize_bridge<T: Config>(init_params: InitializationData<BridgedHeader<T>>) {
|
fn initialize_bridge<T: Config>(init_params: InitializationData<BridgedHeader<T>>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user