Skip to content

Commit

Permalink
Benchmarks for message delivery transaction (paritytech#567)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
2 people authored and serban300 committed Apr 9, 2024
1 parent 003a95d commit 5cc6259
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 18 deletions.
1 change: 1 addition & 0 deletions bridges/bin/rialto/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
76 changes: 75 additions & 1 deletion bridges/bin/rialto/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,17 +806,22 @@ 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,
1_000_000_000_000,
);
}

fn prepare_message(
fn prepare_outbound_message(
params: MessageLaneMessageParams<Self::AccountId>,
) -> (millau_messages::ToMillauMessagePayload, Balance) {
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion bridges/bin/rialto/runtime/src/millau_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
11 changes: 11 additions & 0 deletions bridges/bin/runtime-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }

Expand All @@ -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",
]
1 change: 1 addition & 0 deletions bridges/bin/runtime-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
#![cfg_attr(not(feature = "std"), no_std)]

pub mod messages;
pub mod messages_benchmarking;
12 changes: 9 additions & 3 deletions bridges/bin/runtime-common/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
144 changes: 144 additions & 0 deletions bridges/bin/runtime-common/src/messages_benchmarking.rs
Original file line number Diff line number Diff line change
@@ -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"),
)
}
Loading

0 comments on commit 5cc6259

Please sign in to comment.