// 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 .
//! Deal with CLI args of substrate-to-substrate relay.
use async_std::prelude::*;
use futures::{select, FutureExt};
use signal_hook::consts::*;
use signal_hook_async_std::Signals;
use structopt::StructOpt;
mod chain_schema;
mod detect_equivocations;
mod init_bridge;
mod relay_headers;
mod relay_headers_and_messages;
mod relay_messages;
mod relay_parachains;
/// The target that will be used when publishing logs related to this pallet.
pub const LOG_TARGET: &str = "bridge";
/// Parse relay CLI args.
pub fn parse_args() -> Command {
Command::from_args()
}
/// Substrate-to-Substrate bridge utilities.
#[derive(StructOpt)]
#[structopt(about = "Substrate-to-Substrate relay")]
pub enum Command {
/// Initialize on-chain bridge pallet with current header data.
///
/// Sends initialization transaction to bootstrap the bridge with current finalized block data.
InitBridge(init_bridge::InitBridge),
/// Start headers relay between two chains.
///
/// The on-chain bridge component should have been already initialized with
/// `init-bridge` sub-command.
RelayHeaders(relay_headers::RelayHeaders),
/// Relay parachain heads.
RelayParachains(relay_parachains::RelayParachains),
/// Start messages relay between two chains.
///
/// Ties up to `Messages` pallets on both chains and starts relaying messages.
/// Requires the header relay to be already running.
RelayMessages(relay_messages::RelayMessages),
/// Start headers and messages relay between two Substrate chains.
///
/// This high-level relay internally starts four low-level relays: two `RelayHeaders`
/// and two `RelayMessages` relays. Headers are only relayed when they are required by
/// the message relays - i.e. when there are messages or confirmations that needs to be
/// relayed between chains.
RelayHeadersAndMessages(Box),
/// Detect and report equivocations.
///
/// Parses the source chain headers that were synchronized with the target chain looking for
/// equivocations. If any equivocation is found, it is reported to the source chain.
DetectEquivocations(detect_equivocations::DetectEquivocations),
}
impl Command {
// Initialize logger depending on the command.
fn init_logger(&self) {
use relay_utils::initialize::{initialize_logger, initialize_relay};
match self {
Self::InitBridge(_) |
Self::RelayHeaders(_) |
Self::RelayMessages(_) |
Self::RelayHeadersAndMessages(_) => {
initialize_relay();
},
_ => {
initialize_logger(false);
},
}
}
/// Run the command.
async fn do_run(self) -> anyhow::Result<()> {
match self {
Self::InitBridge(arg) => arg.run().await?,
Self::RelayHeaders(arg) => arg.run().await?,
Self::RelayParachains(arg) => arg.run().await?,
Self::RelayMessages(arg) => arg.run().await?,
Self::RelayHeadersAndMessages(arg) => arg.run().await?,
Self::DetectEquivocations(arg) => arg.run().await?,
}
Ok(())
}
/// Run the command.
pub async fn run(self) {
self.init_logger();
let exit_signals = match Signals::new([SIGINT, SIGTERM]) {
Ok(signals) => signals,
Err(e) => {
log::error!(target: LOG_TARGET, "Could not register exit signals: {}", e);
return
},
};
let run = self.do_run().fuse();
futures::pin_mut!(exit_signals, run);
select! {
signal = exit_signals.next().fuse() => {
log::info!(target: LOG_TARGET, "Received exit signal {:?}", signal);
},
result = run => {
if let Err(e) = result {
log::error!(target: LOG_TARGET, "substrate-relay: {}", e);
}
},
}
}
}