Generate large messages (#700)

* generate large messages

* consider headers sync lag when computing number of rewards in confirmation

* more fixes

* fix logs

* fix warnings

* do not wait until tx that has delivered nonces will be finalized before submitting other tx

* tests for maximal weight/size

* cleanup

* cleanup

* clippy

* compilation

* args for dispatch weight and remark size

* ExplicitOrMaximal

* clippy
This commit is contained in:
Svyatoslav Nikolsky
2021-02-22 18:55:40 +03:00
committed by Bastian Köcher
parent 3dfef2cd2c
commit 1b2e6cdeb0
3 changed files with 238 additions and 33 deletions
+43 -2
View File
@@ -17,6 +17,7 @@
//! Deal with CLI args of substrate-to-substrate relay.
use bp_message_lane::LaneId;
use frame_support::weights::Weight;
use sp_core::Bytes;
use sp_finality_grandpa::SetId as GrandpaAuthoritiesSetId;
use structopt::{clap::arg_enum, StructOpt};
@@ -153,6 +154,9 @@ pub enum SendMessage {
/// Hex-encoded lane id.
#[structopt(long)]
lane: HexLaneId,
/// Dispatch weight of the message. If not passed, determined automatically.
#[structopt(long)]
dispatch_weight: Option<ExplicitOrMaximal<Weight>>,
/// Delivery and dispatch fee. If not passed, determined automatically.
#[structopt(long)]
fee: Option<bp_millau::Balance>,
@@ -174,6 +178,9 @@ pub enum SendMessage {
/// Hex-encoded lane id.
#[structopt(long)]
lane: HexLaneId,
/// Dispatch weight of the message. If not passed, determined automatically.
#[structopt(long)]
dispatch_weight: Option<ExplicitOrMaximal<Weight>>,
/// Delivery and dispatch fee. If not passed, determined automatically.
#[structopt(long)]
fee: Option<bp_rialto::Balance>,
@@ -190,7 +197,11 @@ pub enum SendMessage {
#[derive(StructOpt, Debug)]
pub enum ToRialtoMessage {
/// Make an on-chain remark (comment).
Remark,
Remark {
/// Remark size. If not passed, small UTF8-encoded string is generated by relay as remark.
#[structopt(long)]
remark_size: Option<ExplicitOrMaximal<usize>>,
},
/// Transfer the specified `amount` of native tokens to a particular `recipient`.
Transfer {
#[structopt(long)]
@@ -204,7 +215,11 @@ pub enum ToRialtoMessage {
#[derive(StructOpt, Debug)]
pub enum ToMillauMessage {
/// Make an on-chain remark (comment).
Remark,
Remark {
/// Size of the remark. If not passed, small UTF8-encoded string is generated by relay as remark.
#[structopt(long)]
remark_size: Option<ExplicitOrMaximal<usize>>,
},
/// Transfer the specified `amount` of native tokens to a particular `recipient`.
Transfer {
#[structopt(long)]
@@ -273,6 +288,32 @@ impl From<PrometheusParams> for Option<relay_utils::metrics::MetricsParams> {
}
}
/// Either explicit or maximal allowed value.
#[derive(Debug)]
pub enum ExplicitOrMaximal<V> {
/// User has explicitly specified argument value.
Explicit(V),
/// Maximal allowed value for this argument.
Maximal,
}
impl<V: std::str::FromStr> std::str::FromStr for ExplicitOrMaximal<V>
where
V::Err: std::fmt::Debug,
{
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.to_lowercase() == "max" {
return Ok(ExplicitOrMaximal::Maximal);
}
V::from_str(s)
.map(ExplicitOrMaximal::Explicit)
.map_err(|e| format!("Failed to parse '{:?}'. Expected 'max' or explicit value", e))
}
}
macro_rules! declare_chain_options {
($chain:ident, $chain_prefix:ident) => {
paste::item! {
+193 -29
View File
@@ -19,7 +19,7 @@
#![warn(missing_docs)]
use codec::{Decode, Encode};
use frame_support::weights::GetDispatchInfo;
use frame_support::weights::{GetDispatchInfo, Weight};
use pallet_bridge_call_dispatch::{CallOrigin, MessagePayload};
use relay_kusama_client::Kusama;
use relay_millau_client::{Millau, SigningParams as MillauSigningParams};
@@ -232,6 +232,7 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
rialto_sign,
lane,
message,
dispatch_weight,
fee,
origin,
..
@@ -241,7 +242,9 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
let rialto_sign = rialto_sign.parse()?;
let rialto_call = message.into_call();
let payload = millau_to_rialto_message_payload(&millau_sign, &rialto_sign, &rialto_call, origin);
let payload =
millau_to_rialto_message_payload(&millau_sign, &rialto_sign, &rialto_call, origin, dispatch_weight);
let dispatch_weight = payload.weight;
let lane = lane.into();
let fee = get_fee(fee, || {
@@ -254,8 +257,6 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
})
.await?;
log::info!(target: "bridge", "Sending message to Rialto. Fee: {}", fee);
let millau_call = millau_runtime::Call::BridgeRialtoMessageLane(
millau_runtime::MessageLaneCall::send_message(lane, payload, fee),
);
@@ -267,11 +268,18 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
.next_account_index(millau_sign.signer.public().clone().into())
.await?,
millau_call,
)
.encode();
log::info!(
target: "bridge",
"Sending message to Rialto. Size: {}. Dispatch weight: {}. Fee: {}",
signed_millau_call.len(),
dispatch_weight,
fee,
);
millau_client
.submit_extrinsic(Bytes(signed_millau_call.encode()))
.await?;
millau_client.submit_extrinsic(Bytes(signed_millau_call)).await?;
}
cli::SendMessage::RialtoToMillau {
rialto,
@@ -279,6 +287,7 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
millau_sign,
lane,
message,
dispatch_weight,
fee,
origin,
..
@@ -288,7 +297,9 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
let millau_sign = millau_sign.parse()?;
let millau_call = message.into_call();
let payload = rialto_to_millau_message_payload(&rialto_sign, &millau_sign, &millau_call, origin);
let payload =
rialto_to_millau_message_payload(&rialto_sign, &millau_sign, &millau_call, origin, dispatch_weight);
let dispatch_weight = payload.weight;
let lane = lane.into();
let fee = get_fee(fee, || {
@@ -301,8 +312,6 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
})
.await?;
log::info!(target: "bridge", "Sending message to Millau. Fee: {}", fee);
let rialto_call = rialto_runtime::Call::BridgeMillauMessageLane(
rialto_runtime::MessageLaneCall::send_message(lane, payload, fee),
);
@@ -314,11 +323,18 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
.next_account_index(rialto_sign.signer.public().clone().into())
.await?,
rialto_call,
)
.encode();
log::info!(
target: "bridge",
"Sending message to Millau. Size: {}. Dispatch weight: {}. Fee: {}",
signed_rialto_call.len(),
dispatch_weight,
fee,
);
rialto_client
.submit_extrinsic(Bytes(signed_rialto_call.encode()))
.await?;
rialto_client.submit_extrinsic(Bytes(signed_rialto_call)).await?;
}
}
Ok(())
@@ -338,16 +354,20 @@ async fn estimate_message_delivery_and_dispatch_fee<Fee: Decode, C: Chain, P: En
Ok(decoded_response)
}
fn remark_payload() -> Vec<u8> {
format!(
"Unix time: {}",
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
)
.as_bytes()
.to_vec()
fn remark_payload(remark_size: Option<cli::ExplicitOrMaximal<usize>>, maximal_allowed_size: u32) -> Vec<u8> {
match remark_size {
Some(cli::ExplicitOrMaximal::Explicit(remark_size)) => vec![0; remark_size],
Some(cli::ExplicitOrMaximal::Maximal) => vec![0; maximal_allowed_size as _],
None => format!(
"Unix time: {}",
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
)
.as_bytes()
.to_vec(),
}
}
fn rialto_to_millau_message_payload(
@@ -355,8 +375,13 @@ fn rialto_to_millau_message_payload(
millau_sign: &MillauSigningParams,
millau_call: &millau_runtime::Call,
origin: cli::Origins,
user_specified_dispatch_weight: Option<cli::ExplicitOrMaximal<Weight>>,
) -> rialto_runtime::millau_messages::ToMillauMessagePayload {
let millau_call_weight = millau_call.get_dispatch_info().weight;
let millau_call_weight = prepare_call_dispatch_weight(
user_specified_dispatch_weight,
cli::ExplicitOrMaximal::Explicit(millau_call.get_dispatch_info().weight),
compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight()),
);
let rialto_sender_public: bp_rialto::AccountSigner = rialto_sign.signer.public().clone().into();
let rialto_account_id: bp_rialto::AccountId = rialto_sender_public.into_account();
let millau_origin_public = millau_sign.signer.public();
@@ -387,8 +412,13 @@ fn millau_to_rialto_message_payload(
rialto_sign: &RialtoSigningParams,
rialto_call: &rialto_runtime::Call,
origin: cli::Origins,
user_specified_dispatch_weight: Option<cli::ExplicitOrMaximal<Weight>>,
) -> millau_runtime::rialto_messages::ToRialtoMessagePayload {
let rialto_call_weight = rialto_call.get_dispatch_info().weight;
let rialto_call_weight = prepare_call_dispatch_weight(
user_specified_dispatch_weight,
cli::ExplicitOrMaximal::Explicit(rialto_call.get_dispatch_info().weight),
compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight()),
);
let millau_sender_public: bp_millau::AccountSigner = millau_sign.signer.public().clone().into();
let millau_account_id: bp_millau::AccountId = millau_sender_public.into_account();
let rialto_origin_public = rialto_sign.signer.public();
@@ -414,6 +444,17 @@ fn millau_to_rialto_message_payload(
}
}
fn prepare_call_dispatch_weight(
user_specified_dispatch_weight: Option<cli::ExplicitOrMaximal<Weight>>,
weight_from_pre_dispatch_call: cli::ExplicitOrMaximal<Weight>,
maximal_allowed_weight: Weight,
) -> Weight {
match user_specified_dispatch_weight.unwrap_or(weight_from_pre_dispatch_call) {
cli::ExplicitOrMaximal::Explicit(weight) => weight,
cli::ExplicitOrMaximal::Maximal => maximal_allowed_weight,
}
}
async fn get_fee<Fee, F, R, E>(fee: Option<Fee>, f: F) -> Result<Fee, String>
where
Fee: Decode,
@@ -431,6 +472,30 @@ where
}
}
fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight {
bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight)
}
fn compute_maximal_message_arguments_size(
maximal_source_extrinsic_size: u32,
maximal_target_extrinsic_size: u32,
) -> u32 {
// assume that both signed extensions and other arguments fit 1KB
let service_tx_bytes_on_source_chain = 1024;
let maximal_source_extrinsic_size = maximal_source_extrinsic_size - service_tx_bytes_on_source_chain;
let maximal_call_size =
bridge_runtime_common::messages::target::maximal_incoming_message_size(maximal_target_extrinsic_size);
let maximal_call_size = if maximal_call_size > maximal_source_extrinsic_size {
maximal_source_extrinsic_size
} else {
maximal_call_size
};
// bytes in Call encoding that are used to encode everything except arguments
let service_bytes = 1 + 1 + 4;
maximal_call_size - service_bytes
}
impl crate::cli::RialtoSigningParams {
/// Parse CLI parameters into typed signing params.
pub fn parse(self) -> Result<RialtoSigningParams, String> {
@@ -472,8 +537,14 @@ impl crate::cli::ToRialtoMessage {
/// Convert CLI call request into runtime `Call` instance.
pub fn into_call(self) -> rialto_runtime::Call {
match self {
cli::ToRialtoMessage::Remark => {
rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(remark_payload()))
cli::ToRialtoMessage::Remark { remark_size } => {
rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(remark_payload(
remark_size,
compute_maximal_message_arguments_size(
bp_millau::max_extrinsic_size(),
bp_rialto::max_extrinsic_size(),
),
)))
}
cli::ToRialtoMessage::Transfer { recipient, amount } => {
rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient, amount))
@@ -486,8 +557,14 @@ impl crate::cli::ToMillauMessage {
/// Convert CLI call request into runtime `Call` instance.
pub fn into_call(self) -> millau_runtime::Call {
match self {
cli::ToMillauMessage::Remark => {
millau_runtime::Call::System(millau_runtime::SystemCall::remark(remark_payload()))
cli::ToMillauMessage::Remark { remark_size } => {
millau_runtime::Call::System(millau_runtime::SystemCall::remark(remark_payload(
remark_size,
compute_maximal_message_arguments_size(
bp_rialto::max_extrinsic_size(),
bp_millau::max_extrinsic_size(),
),
)))
}
cli::ToMillauMessage::Transfer { recipient, amount } => {
millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer(recipient, amount))
@@ -498,6 +575,8 @@ impl crate::cli::ToMillauMessage {
#[cfg(test)]
mod tests {
use super::*;
use bp_message_lane::source_chain::TargetHeaderChain;
use sp_core::Pair;
use sp_runtime::traits::{IdentifyAccount, Verify};
@@ -542,4 +621,89 @@ mod tests {
assert!(signature.verify(&digest[..], &millau_signer.signer.public()));
}
#[test]
fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() {
use rialto_runtime::millau_messages::Millau;
let maximal_remark_size =
compute_maximal_message_arguments_size(bp_rialto::max_extrinsic_size(), bp_millau::max_extrinsic_size());
let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into();
let payload = pallet_bridge_call_dispatch::MessagePayload {
spec_version: Default::default(),
weight: call.get_dispatch_info().weight,
origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot,
call: call.encode(),
};
assert_eq!(Millau::verify_message(&payload), Ok(()));
let call: millau_runtime::Call =
millau_runtime::SystemCall::remark(vec![42; (maximal_remark_size + 1) as _]).into();
let payload = pallet_bridge_call_dispatch::MessagePayload {
spec_version: Default::default(),
weight: call.get_dispatch_info().weight,
origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot,
call: call.encode(),
};
assert!(Millau::verify_message(&payload).is_err());
}
#[test]
fn maximal_size_remark_to_rialto_is_generated_correctly() {
assert!(
bridge_runtime_common::messages::target::maximal_incoming_message_size(
bp_rialto::max_extrinsic_size()
) > bp_millau::max_extrinsic_size(),
"We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large",
)
}
#[test]
fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() {
use rialto_runtime::millau_messages::Millau;
let maximal_dispatch_weight = compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight());
let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into();
let payload = pallet_bridge_call_dispatch::MessagePayload {
spec_version: Default::default(),
weight: maximal_dispatch_weight,
origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot,
call: call.encode(),
};
assert_eq!(Millau::verify_message(&payload), Ok(()));
let payload = pallet_bridge_call_dispatch::MessagePayload {
spec_version: Default::default(),
weight: maximal_dispatch_weight + 1,
origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot,
call: call.encode(),
};
assert!(Millau::verify_message(&payload).is_err());
}
#[test]
fn maximal_weight_fill_block_to_rialto_is_generated_correctly() {
use millau_runtime::rialto_messages::Rialto;
let maximal_dispatch_weight = compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight());
let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into();
let payload = pallet_bridge_call_dispatch::MessagePayload {
spec_version: Default::default(),
weight: maximal_dispatch_weight,
origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot,
call: call.encode(),
};
assert_eq!(Rialto::verify_message(&payload), Ok(()));
let payload = pallet_bridge_call_dispatch::MessagePayload {
spec_version: Default::default(),
weight: maximal_dispatch_weight + 1,
origin: pallet_bridge_call_dispatch::CallOrigin::SourceRoot,
call: call.encode(),
};
assert!(Rialto::verify_message(&payload).is_err());
}
}
@@ -166,7 +166,7 @@ mod tests {
#[test]
fn select_delivery_transaction_limits_works() {
let (max_count, max_weight) = select_delivery_transaction_limits::<RialtoToMillauMessageLaneWeights>(
bp_rialto::max_extrinsic_weight(),
bp_millau::max_extrinsic_weight(),
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
);
assert_eq!(
@@ -176,7 +176,7 @@ mod tests {
// reserved for messages dispatch allows dispatch of non-trivial messages.
//
// Any significant change in this values should attract additional attention.
(1024, 866_583_333_334),
(955, 216_583_333_334),
);
}
}