// Copyright 2019-2021 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 .
//! Rialto <> Millau Bridge commands.
pub mod cli;
pub mod millau_headers_to_rialto;
pub mod millau_messages_to_rialto;
pub mod rialto_headers_to_millau;
pub mod rialto_messages_to_millau;
pub mod westend_headers_to_millau;
/// Millau node client.
pub type MillauClient = relay_substrate_client::Client;
/// Rialto node client.
pub type RialtoClient = relay_substrate_client::Client;
use crate::cli::{
CliChain, ExplicitOrMaximal, HexBytes, Origins, SourceConnectionParams, SourceSigningParams,
TargetConnectionParams, TargetSigningParams,
};
use codec::{Decode, Encode};
use frame_support::weights::{GetDispatchInfo, Weight};
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
use relay_millau_client::Millau;
use relay_rialto_client::Rialto;
use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme};
use relay_westend_client::Westend;
use sp_core::{Bytes, Pair};
use sp_runtime::{traits::IdentifyAccount, MultiSigner};
use sp_version::RuntimeVersion;
use std::fmt::Debug;
async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
match command {
cli::SendMessage::MillauToRialto {
source,
source_sign,
target_sign,
lane,
message,
dispatch_weight,
fee,
origin,
..
} => {
type Source = Millau;
type Target = Rialto;
let account_ownership_digest = |target_call, source_account_id| {
millau_runtime::rialto_account_ownership_digest(
&target_call,
source_account_id,
Target::RUNTIME_VERSION.spec_version,
)
};
let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD;
let fee = fee.map(|x| x.cast());
let send_message_call = |lane, payload, fee| {
millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message(
lane, payload, fee,
))
};
let source_client = source_chain_client::(source).await?;
let source_sign = Source::source_signing_params(source_sign)?;
let target_sign = Target::target_signing_params(target_sign)?;
let target_call = Target::encode_call(message)?;
let payload = {
let target_call_weight = prepare_call_dispatch_weight(
dispatch_weight,
ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight),
compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()),
);
let source_sender_public: MultiSigner = source_sign.public().into();
let source_account_id = source_sender_public.into_account();
message_payload(
Target::RUNTIME_VERSION.spec_version,
target_call_weight,
match origin {
Origins::Source => CallOrigin::SourceAccount(source_account_id),
Origins::Target => {
let digest = account_ownership_digest(&target_call, source_account_id.clone());
let target_origin_public = target_sign.public();
let digest_signature = target_sign.sign(&digest);
CallOrigin::TargetAccount(
source_account_id,
target_origin_public.into(),
digest_signature.into(),
)
}
},
&target_call,
)
};
let dispatch_weight = payload.weight;
let lane = lane.into();
let fee = get_fee(fee, || {
estimate_message_delivery_and_dispatch_fee(
&source_client,
estimate_message_fee_method,
lane,
payload.clone(),
)
})
.await?;
source_client
.submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| {
let send_message_call = send_message_call(lane, payload, fee);
let signed_source_call = Source::sign_transaction(
*source_client.genesis_hash(),
&source_sign,
transaction_nonce,
send_message_call,
)
.encode();
log::info!(
target: "bridge",
"Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}",
Target::NAME,
signed_source_call.len(),
dispatch_weight,
fee,
);
log::info!(
target: "bridge",
"Signed {} Call: {:?}",
Source::NAME,
HexBytes::encode(&signed_source_call)
);
Bytes(signed_source_call)
})
.await?;
}
cli::SendMessage::RialtoToMillau {
source,
source_sign,
target_sign,
lane,
message,
dispatch_weight,
fee,
origin,
..
} => {
type Source = Rialto;
type Target = Millau;
let account_ownership_digest = |target_call, source_account_id| {
rialto_runtime::millau_account_ownership_digest(
&target_call,
source_account_id,
Target::RUNTIME_VERSION.spec_version,
)
};
let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD;
let fee = fee.map(|x| x.0);
let send_message_call = |lane, payload, fee| {
rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message(
lane, payload, fee,
))
};
let source_client = source_chain_client::(source).await?;
let source_sign = Source::source_signing_params(source_sign)?;
let target_sign = Target::target_signing_params(target_sign)?;
let target_call = Target::encode_call(message)?;
let payload = {
let target_call_weight = prepare_call_dispatch_weight(
dispatch_weight,
ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight),
compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()),
);
let source_sender_public: MultiSigner = source_sign.public().into();
let source_account_id = source_sender_public.into_account();
message_payload(
Target::RUNTIME_VERSION.spec_version,
target_call_weight,
match origin {
Origins::Source => CallOrigin::SourceAccount(source_account_id),
Origins::Target => {
let digest = account_ownership_digest(&target_call, source_account_id.clone());
let target_origin_public = target_sign.public();
let digest_signature = target_sign.sign(&digest);
CallOrigin::TargetAccount(
source_account_id,
target_origin_public.into(),
digest_signature.into(),
)
}
},
&target_call,
)
};
let dispatch_weight = payload.weight;
let lane = lane.into();
let fee = get_fee(fee, || {
estimate_message_delivery_and_dispatch_fee(
&source_client,
estimate_message_fee_method,
lane,
payload.clone(),
)
})
.await?;
source_client
.submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| {
let send_message_call = send_message_call(lane, payload, fee);
let signed_source_call = Source::sign_transaction(
*source_client.genesis_hash(),
&source_sign,
transaction_nonce,
send_message_call,
)
.encode();
log::info!(
target: "bridge",
"Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}",
Target::NAME,
signed_source_call.len(),
dispatch_weight,
fee,
);
log::info!(
target: "bridge",
"Signed {} Call: {:?}",
Source::NAME,
HexBytes::encode(&signed_source_call)
);
Bytes(signed_source_call)
})
.await?;
}
}
Ok(())
}
async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> {
match call {
cli::EncodeCall::Rialto { call } => {
type Source = Rialto;
let call = Source::encode_call(call)?;
println!("{:?}", HexBytes::encode(&call));
}
cli::EncodeCall::Millau { call } => {
type Source = Millau;
let call = Source::encode_call(call)?;
println!("{:?}", HexBytes::encode(&call));
}
}
Ok(())
}
async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> {
match call {
cli::EncodeMessagePayload::RialtoToMillau { payload } => {
type Source = Rialto;
let payload = Source::encode_message(payload)?;
println!("{:?}", HexBytes::encode(&payload));
}
cli::EncodeMessagePayload::MillauToRialto { payload } => {
type Source = Millau;
let payload = Source::encode_message(payload)?;
println!("{:?}", HexBytes::encode(&payload));
}
}
Ok(())
}
async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> {
match cmd {
cli::EstimateFee::RialtoToMillau { source, lane, payload } => {
type Source = Rialto;
type SourceBalance = bp_rialto::Balance;
let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD;
let source_client = source_chain_client::(source).await?;
let lane = lane.into();
let payload = Source::encode_message(payload)?;
let fee: Option =
estimate_message_delivery_and_dispatch_fee(&source_client, estimate_message_fee_method, lane, payload)
.await?;
println!("Fee: {:?}", fee);
}
cli::EstimateFee::MillauToRialto { source, lane, payload } => {
type Source = Millau;
type SourceBalance = bp_millau::Balance;
let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD;
let source_client = source_chain_client::(source).await?;
let lane = lane.into();
let payload = Source::encode_message(payload)?;
let fee: Option =
estimate_message_delivery_and_dispatch_fee(&source_client, estimate_message_fee_method, lane, payload)
.await?;
println!("Fee: {:?}", fee);
}
}
Ok(())
}
async fn estimate_message_delivery_and_dispatch_fee(
client: &relay_substrate_client::Client,
estimate_fee_method: &str,
lane: bp_messages::LaneId,
payload: P,
) -> Result