// 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 .
//! Substrate-to-substrate relay entrypoint.
#![warn(missing_docs)]
use codec::{Decode, Encode};
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};
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme};
use relay_utils::initialize::initialize_relay;
use sp_core::{Bytes, Pair};
use sp_runtime::traits::IdentifyAccount;
use std::fmt::Debug;
/// Kusama node client.
pub type KusamaClient = relay_substrate_client::Client;
/// Millau node client.
pub type MillauClient = relay_substrate_client::Client;
/// Rialto node client.
pub type RialtoClient = relay_substrate_client::Client;
mod cli;
mod headers_initialize;
mod headers_maintain;
mod headers_pipeline;
mod headers_target;
mod messages_lane;
mod messages_source;
mod messages_target;
mod millau_headers_to_rialto;
mod millau_messages_to_rialto;
mod rialto_headers_to_millau;
mod rialto_messages_to_millau;
fn main() {
initialize_relay();
let result = async_std::task::block_on(run_command(cli::parse_args()));
if let Err(error) = result {
log::error!(target: "bridge", "Failed to start relay: {}", error);
}
}
async fn run_command(command: cli::Command) -> Result<(), String> {
match command {
cli::Command::InitBridge(arg) => run_init_bridge(arg).await,
cli::Command::RelayHeaders(arg) => run_relay_headers(arg).await,
cli::Command::RelayMessages(arg) => run_relay_messages(arg).await,
cli::Command::SendMessage(arg) => run_send_message(arg).await,
cli::Command::EncodeCall(arg) => run_encode_call(arg).await,
cli::Command::EncodeMessagePayload(arg) => run_encode_message_payload(arg).await,
cli::Command::EstimateFee(arg) => run_estimate_fee(arg).await,
cli::Command::DeriveAccount(arg) => run_derive_account(arg).await,
}
}
async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> {
match command {
cli::InitBridge::MillauToRialto {
millau,
rialto,
rialto_sign,
millau_bridge_params,
} => {
let millau_client = millau.into_client().await?;
let rialto_client = rialto.into_client().await?;
let rialto_sign = rialto_sign.parse()?;
let rialto_signer_next_index = rialto_client
.next_account_index(rialto_sign.signer.public().into())
.await?;
headers_initialize::initialize(
millau_client,
rialto_client.clone(),
millau_bridge_params.millau_initial_header,
millau_bridge_params.millau_initial_authorities,
millau_bridge_params.millau_initial_authorities_set_id,
move |initialization_data| {
Ok(Bytes(
Rialto::sign_transaction(
&rialto_client,
&rialto_sign.signer,
rialto_signer_next_index,
rialto_runtime::SudoCall::sudo(Box::new(
rialto_runtime::BridgeMillauCall::initialize(initialization_data).into(),
))
.into(),
)
.encode(),
))
},
)
.await;
}
cli::InitBridge::RialtoToMillau {
rialto,
millau,
millau_sign,
rialto_bridge_params,
} => {
let rialto_client = rialto.into_client().await?;
let millau_client = millau.into_client().await?;
let millau_sign = millau_sign.parse()?;
let millau_signer_next_index = millau_client
.next_account_index(millau_sign.signer.public().into())
.await?;
headers_initialize::initialize(
rialto_client,
millau_client.clone(),
rialto_bridge_params.rialto_initial_header,
rialto_bridge_params.rialto_initial_authorities,
rialto_bridge_params.rialto_initial_authorities_set_id,
move |initialization_data| {
Ok(Bytes(
Millau::sign_transaction(
&millau_client,
&millau_sign.signer,
millau_signer_next_index,
millau_runtime::SudoCall::sudo(Box::new(
millau_runtime::BridgeRialtoCall::initialize(initialization_data).into(),
))
.into(),
)
.encode(),
))
},
)
.await;
}
}
Ok(())
}
async fn run_relay_headers(command: cli::RelayHeaders) -> Result<(), String> {
match command {
cli::RelayHeaders::MillauToRialto {
millau,
rialto,
rialto_sign,
prometheus_params,
} => {
let millau_client = millau.into_client().await?;
let rialto_client = rialto.into_client().await?;
let rialto_sign = rialto_sign.parse()?;
millau_headers_to_rialto::run(millau_client, rialto_client, rialto_sign, prometheus_params.into()).await;
}
cli::RelayHeaders::RialtoToMillau {
rialto,
millau,
millau_sign,
prometheus_params,
} => {
let rialto_client = rialto.into_client().await?;
let millau_client = millau.into_client().await?;
let millau_sign = millau_sign.parse()?;
rialto_headers_to_millau::run(rialto_client, millau_client, millau_sign, prometheus_params.into()).await;
}
}
Ok(())
}
async fn run_relay_messages(command: cli::RelayMessages) -> Result<(), String> {
match command {
cli::RelayMessages::MillauToRialto {
millau,
millau_sign,
rialto,
rialto_sign,
prometheus_params,
lane,
} => {
let millau_client = millau.into_client().await?;
let millau_sign = millau_sign.parse()?;
let rialto_client = rialto.into_client().await?;
let rialto_sign = rialto_sign.parse()?;
millau_messages_to_rialto::run(
millau_client,
millau_sign,
rialto_client,
rialto_sign,
lane.into(),
prometheus_params.into(),
);
}
cli::RelayMessages::RialtoToMillau {
rialto,
rialto_sign,
millau,
millau_sign,
prometheus_params,
lane,
} => {
let rialto_client = rialto.into_client().await?;
let rialto_sign = rialto_sign.parse()?;
let millau_client = millau.into_client().await?;
let millau_sign = millau_sign.parse()?;
rialto_messages_to_millau::run(
rialto_client,
rialto_sign,
millau_client,
millau_sign,
lane.into(),
prometheus_params.into(),
);
}
}
Ok(())
}
async fn run_send_message(command: cli::SendMessage) -> Result<(), String> {
match command {
cli::SendMessage::MillauToRialto {
millau,
millau_sign,
rialto_sign,
lane,
message,
dispatch_weight,
fee,
origin,
..
} => {
let millau_client = millau.into_client().await?;
let millau_sign = millau_sign.parse()?;
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, dispatch_weight);
let dispatch_weight = payload.weight;
let lane = lane.into();
let fee = get_fee(fee, || {
estimate_message_delivery_and_dispatch_fee(
&millau_client,
bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD,
lane,
payload.clone(),
)
})
.await?;
let millau_call = millau_runtime::Call::BridgeRialtoMessageLane(
millau_runtime::MessageLaneCall::send_message(lane, payload, fee),
);
let signed_millau_call = Millau::sign_transaction(
&millau_client,
&millau_sign.signer,
millau_client
.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)).await?;
}
cli::SendMessage::RialtoToMillau {
rialto,
rialto_sign,
millau_sign,
lane,
message,
dispatch_weight,
fee,
origin,
..
} => {
let rialto_client = rialto.into_client().await?;
let rialto_sign = rialto_sign.parse()?;
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, dispatch_weight);
let dispatch_weight = payload.weight;
let lane = lane.into();
let fee = get_fee(fee, || {
estimate_message_delivery_and_dispatch_fee(
&rialto_client,
bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD,
lane,
payload.clone(),
)
})
.await?;
let rialto_call = rialto_runtime::Call::BridgeMillauMessageLane(
rialto_runtime::MessageLaneCall::send_message(lane, payload, fee),
);
let signed_rialto_call = Rialto::sign_transaction(
&rialto_client,
&rialto_sign.signer,
rialto_client
.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)).await?;
}
}
Ok(())
}
async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> {
match call {
cli::EncodeCall::Rialto { call } => {
let call = call.into_call()?;
println!("{:?}", HexBytes::encode(&call));
}
cli::EncodeCall::Millau { call } => {
let call = call.into_call()?;
println!("{:?}", HexBytes::encode(&call));
}
}
Ok(())
}
async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> {
match call {
cli::EncodeMessagePayload::RialtoToMillau { payload } => {
let payload = payload.into_payload()?;
println!("{:?}", HexBytes::encode(&payload));
}
cli::EncodeMessagePayload::MillauToRialto { payload } => {
let payload = payload.into_payload()?;
println!("{:?}", HexBytes::encode(&payload));
}
}
Ok(())
}
async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> {
match cmd {
cli::EstimateFee::RialtoToMillau { rialto, lane, payload } => {
let client = rialto.into_client().await?;
let lane = lane.into();
let payload = payload.into_payload()?;
let fee: Option = estimate_message_delivery_and_dispatch_fee(
&client,
bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD,
lane,
payload,
)
.await?;
println!("Fee: {:?}", fee);
}
cli::EstimateFee::MillauToRialto { millau, lane, payload } => {
let client = millau.into_client().await?;
let lane = lane.into();
let payload = payload.into_payload()?;
let fee: Option = estimate_message_delivery_and_dispatch_fee(
&client,
bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD,
lane,
payload,
)
.await?;
println!("Fee: {:?}", fee);
}
}
Ok(())
}
async fn run_derive_account(cmd: cli::DeriveAccount) -> Result<(), String> {
match cmd {
cli::DeriveAccount::RialtoToMillau { account } => {
let account = account.into_rialto();
let acc = bp_runtime::SourceAccount::Account(account.clone());
let id = bp_millau::derive_account_from_rialto_id(acc);
println!(
"{} (Rialto)\n\nCorresponding (derived) account id:\n-> {} (Millau)",
account, id
)
}
cli::DeriveAccount::MillauToRialto { account } => {
let account = account.into_millau();
let acc = bp_runtime::SourceAccount::Account(account.clone());
let id = bp_rialto::derive_account_from_millau_id(acc);
println!(
"{} (Millau)\n\nCorresponding (derived) account id:\n-> {} (Rialto)",
account, id
)
}
}
Ok(())
}
async fn estimate_message_delivery_and_dispatch_fee(
client: &relay_substrate_client::Client,
estimate_fee_method: &str,
lane: bp_message_lane::LaneId,
payload: P,
) -> Result