mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 21:01:02 +00:00
CLI refactoring
* [CLI] Make bridge definitions more complete * [CLI] Refactor relay_headers_and_messages Signed-off-by: Serban Iorga <serban@parity.io>
This commit is contained in:
committed by
Bastian Köcher
parent
ceefd1b05d
commit
e1fd877b80
@@ -860,7 +860,7 @@ pub mod target {
|
||||
return Err(MessageProofError::Empty)
|
||||
}
|
||||
|
||||
// We only support single lane messages in this schema
|
||||
// We only support single lane messages in this generated_schema
|
||||
let mut proved_messages = ProvedMessages::new();
|
||||
proved_messages.insert(lane, proved_lane_messages);
|
||||
|
||||
|
||||
@@ -15,10 +15,14 @@
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::cli::CliChain;
|
||||
use relay_substrate_client::{AccountKeyPairOf, Chain, TransactionSignScheme};
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
|
||||
use parachains_relay::ParachainsPipeline;
|
||||
use relay_substrate_client::{AccountKeyPairOf, Chain, RelayChain, TransactionSignScheme};
|
||||
use strum::{EnumString, EnumVariantNames};
|
||||
use substrate_relay_helper::{
|
||||
finality::SubstrateFinalitySyncPipeline, messages_lane::SubstrateMessageLane,
|
||||
parachains::SubstrateParachainsPipeline,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, EnumString, EnumVariantNames)]
|
||||
@@ -59,8 +63,9 @@ pub trait CliBridgeBase: Sized {
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Self::Target>>;
|
||||
}
|
||||
|
||||
/// Bridge representation that can be used from the CLI for relaying headers.
|
||||
pub trait HeadersCliBridge: CliBridgeBase {
|
||||
/// Bridge representation that can be used from the CLI for relaying headers
|
||||
/// from a relay chain to a relay chain.
|
||||
pub trait RelayToRelayHeadersCliBridge: CliBridgeBase {
|
||||
/// Finality proofs synchronization pipeline.
|
||||
type Finality: SubstrateFinalitySyncPipeline<
|
||||
SourceChain = Self::Source,
|
||||
@@ -69,6 +74,29 @@ pub trait HeadersCliBridge: CliBridgeBase {
|
||||
>;
|
||||
}
|
||||
|
||||
/// Bridge representation that can be used from the CLI for relaying headers
|
||||
/// from a parachain to a relay chain.
|
||||
pub trait ParachainToRelayHeadersCliBridge: CliBridgeBase {
|
||||
// The `CliBridgeBase` type represents the parachain in this situation.
|
||||
// We need to add an extra type for the relay chain.
|
||||
type SourceRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
|
||||
+ CliChain
|
||||
+ RelayChain;
|
||||
/// Finality proofs synchronization pipeline (source parachain -> target).
|
||||
type ParachainFinality: SubstrateParachainsPipeline<
|
||||
SourceRelayChain = Self::SourceRelay,
|
||||
SourceParachain = Self::Source,
|
||||
TargetChain = Self::Target,
|
||||
TransactionSignScheme = Self::Target,
|
||||
> + ParachainsPipeline<SourceChain = Self::SourceRelay, TargetChain = Self::Target>;
|
||||
/// Finality proofs synchronization pipeline (source relay chain -> target).
|
||||
type RelayFinality: SubstrateFinalitySyncPipeline<
|
||||
SourceChain = Self::SourceRelay,
|
||||
TargetChain = Self::Target,
|
||||
TransactionSignScheme = Self::Target,
|
||||
>;
|
||||
}
|
||||
|
||||
/// Bridge representation that can be used from the CLI for relaying messages.
|
||||
pub trait MessagesCliBridge: CliBridgeBase {
|
||||
/// Name of the runtime method used to estimate the message dispatch and delivery fee for the
|
||||
@@ -80,6 +108,7 @@ pub trait MessagesCliBridge: CliBridgeBase {
|
||||
TargetChain = Self::Target,
|
||||
SourceTransactionSignScheme = Self::Source,
|
||||
TargetTransactionSignScheme = Self::Target,
|
||||
RelayStrategy = MixStrategy,
|
||||
>;
|
||||
}
|
||||
|
||||
@@ -91,7 +120,7 @@ impl CliBridgeBase for MillauToRialtoCliBridge {
|
||||
type Target = relay_rialto_client::Rialto;
|
||||
}
|
||||
|
||||
impl HeadersCliBridge for MillauToRialtoCliBridge {
|
||||
impl RelayToRelayHeadersCliBridge for MillauToRialtoCliBridge {
|
||||
type Finality = crate::chains::millau_headers_to_rialto::MillauFinalityToRialto;
|
||||
}
|
||||
|
||||
@@ -109,7 +138,7 @@ impl CliBridgeBase for RialtoToMillauCliBridge {
|
||||
type Target = relay_millau_client::Millau;
|
||||
}
|
||||
|
||||
impl HeadersCliBridge for RialtoToMillauCliBridge {
|
||||
impl RelayToRelayHeadersCliBridge for RialtoToMillauCliBridge {
|
||||
type Finality = crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau;
|
||||
}
|
||||
|
||||
@@ -127,7 +156,7 @@ impl CliBridgeBase for WestendToMillauCliBridge {
|
||||
type Target = relay_millau_client::Millau;
|
||||
}
|
||||
|
||||
impl HeadersCliBridge for WestendToMillauCliBridge {
|
||||
impl RelayToRelayHeadersCliBridge for WestendToMillauCliBridge {
|
||||
type Finality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau;
|
||||
}
|
||||
|
||||
@@ -139,7 +168,7 @@ impl CliBridgeBase for MillauToRialtoParachainCliBridge {
|
||||
type Target = relay_rialto_parachain_client::RialtoParachain;
|
||||
}
|
||||
|
||||
impl HeadersCliBridge for MillauToRialtoParachainCliBridge {
|
||||
impl RelayToRelayHeadersCliBridge for MillauToRialtoParachainCliBridge {
|
||||
type Finality =
|
||||
crate::chains::millau_headers_to_rialto_parachain::MillauFinalityToRialtoParachain;
|
||||
}
|
||||
@@ -159,6 +188,12 @@ impl CliBridgeBase for RialtoParachainToMillauCliBridge {
|
||||
type Target = relay_millau_client::Millau;
|
||||
}
|
||||
|
||||
impl ParachainToRelayHeadersCliBridge for RialtoParachainToMillauCliBridge {
|
||||
type SourceRelay = relay_rialto_client::Rialto;
|
||||
type ParachainFinality = crate::chains::rialto_parachains_to_millau::RialtoParachainsToMillau;
|
||||
type RelayFinality = crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau;
|
||||
}
|
||||
|
||||
impl MessagesCliBridge for RialtoParachainToMillauCliBridge {
|
||||
const ESTIMATE_MESSAGE_FEE_METHOD: &'static str =
|
||||
bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD;
|
||||
@@ -169,6 +204,12 @@ impl MessagesCliBridge for RialtoParachainToMillauCliBridge {
|
||||
//// `WestendParachain` to `Millau` bridge definition.
|
||||
pub struct WestmintToMillauCliBridge {}
|
||||
|
||||
impl ParachainToRelayHeadersCliBridge for WestmintToMillauCliBridge {
|
||||
type SourceRelay = relay_westend_client::Westend;
|
||||
type ParachainFinality = crate::chains::westend_parachains_to_millau::WestendParachainsToMillau;
|
||||
type RelayFinality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau;
|
||||
}
|
||||
|
||||
impl CliBridgeBase for WestmintToMillauCliBridge {
|
||||
type Source = relay_westend_client::Westmint;
|
||||
type Target = relay_millau_client::Millau;
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
// Copyright 2019-2022 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/>.
|
||||
|
||||
use sp_core::Pair;
|
||||
use structopt::StructOpt;
|
||||
use strum::{EnumString, EnumVariantNames};
|
||||
|
||||
use crate::cli::CliChain;
|
||||
pub use relay_substrate_client::ChainRuntimeVersion;
|
||||
use substrate_relay_helper::TransactionParams;
|
||||
|
||||
#[doc = "Runtime version params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, EnumVariantNames)]
|
||||
pub enum RuntimeVersionType {
|
||||
/// Auto query version from chain
|
||||
Auto,
|
||||
/// Custom `spec_version` and `transaction_version`
|
||||
Custom,
|
||||
/// Read version from bundle dependencies directly.
|
||||
Bundle,
|
||||
}
|
||||
|
||||
/// Create chain-specific set of runtime version parameters.
|
||||
#[macro_export]
|
||||
macro_rules! declare_chain_runtime_version_params_cli_schema {
|
||||
($chain:ident, $chain_prefix:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain " runtime version params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct [<$chain RuntimeVersionParams>] {
|
||||
#[doc = "The type of runtime version for chain " $chain]
|
||||
#[structopt(long, default_value = "Bundle")]
|
||||
pub [<$chain_prefix _version_mode>]: RuntimeVersionType,
|
||||
#[doc = "The custom sepc_version for chain " $chain]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _spec_version>]: Option<u32>,
|
||||
#[doc = "The custom transaction_version for chain " $chain]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _transaction_version>]: Option<u32>,
|
||||
}
|
||||
|
||||
impl [<$chain RuntimeVersionParams>] {
|
||||
/// Converts self into `ChainRuntimeVersion`.
|
||||
pub fn into_runtime_version(
|
||||
self,
|
||||
bundle_runtime_version: Option<sp_version::RuntimeVersion>,
|
||||
) -> anyhow::Result<ChainRuntimeVersion> {
|
||||
Ok(match self.[<$chain_prefix _version_mode>] {
|
||||
RuntimeVersionType::Auto => ChainRuntimeVersion::Auto,
|
||||
RuntimeVersionType::Custom => {
|
||||
let except_spec_version = self.[<$chain_prefix _spec_version>]
|
||||
.ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?;
|
||||
let except_transaction_version = self.[<$chain_prefix _transaction_version>]
|
||||
.ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?;
|
||||
ChainRuntimeVersion::Custom(
|
||||
except_spec_version,
|
||||
except_transaction_version
|
||||
)
|
||||
},
|
||||
RuntimeVersionType::Bundle => match bundle_runtime_version {
|
||||
Some(runtime_version) => ChainRuntimeVersion::Custom(
|
||||
runtime_version.spec_version,
|
||||
runtime_version.transaction_version
|
||||
),
|
||||
None => ChainRuntimeVersion::Auto
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Create chain-specific set of runtime version parameters.
|
||||
#[macro_export]
|
||||
macro_rules! declare_chain_connection_params_cli_schema {
|
||||
($chain:ident, $chain_prefix:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain " connection params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct [<$chain ConnectionParams>] {
|
||||
#[doc = "Connect to " $chain " node at given host."]
|
||||
#[structopt(long, default_value = "127.0.0.1")]
|
||||
pub [<$chain_prefix _host>]: String,
|
||||
#[doc = "Connect to " $chain " node websocket server at given port."]
|
||||
#[structopt(long, default_value = "9944")]
|
||||
pub [<$chain_prefix _port>]: u16,
|
||||
#[doc = "Use secure websocket connection."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _secure>]: bool,
|
||||
#[doc = "Custom runtime version"]
|
||||
#[structopt(flatten)]
|
||||
pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>],
|
||||
}
|
||||
|
||||
impl [<$chain ConnectionParams>] {
|
||||
/// Convert connection params into Substrate client.
|
||||
#[allow(dead_code)]
|
||||
pub async fn into_client<Chain: CliChain>(
|
||||
self,
|
||||
) -> anyhow::Result<relay_substrate_client::Client<Chain>> {
|
||||
let chain_runtime_version = self
|
||||
.[<$chain_prefix _runtime_version>]
|
||||
.into_runtime_version(Some(Chain::RUNTIME_VERSION))?;
|
||||
Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams {
|
||||
host: self.[<$chain_prefix _host>],
|
||||
port: self.[<$chain_prefix _port>],
|
||||
secure: self.[<$chain_prefix _secure>],
|
||||
chain_runtime_version,
|
||||
})
|
||||
.await
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Helper trait to override transaction parameters differently.
|
||||
pub trait TransactionParamsProvider {
|
||||
/// Returns `true` if transaction parameters are defined by this provider.
|
||||
fn is_defined(&self) -> bool;
|
||||
/// Returns transaction parameters.
|
||||
fn transaction_params<Chain: CliChain>(
|
||||
&self,
|
||||
) -> anyhow::Result<TransactionParams<Chain::KeyPair>>;
|
||||
|
||||
/// Returns transaction parameters, defined by `self` provider or, if they're not defined,
|
||||
/// defined by `other` provider.
|
||||
fn transaction_params_or<Chain: CliChain, T: TransactionParamsProvider>(
|
||||
&self,
|
||||
other: &T,
|
||||
) -> anyhow::Result<TransactionParams<Chain::KeyPair>> {
|
||||
if self.is_defined() {
|
||||
self.transaction_params::<Chain>()
|
||||
} else {
|
||||
other.transaction_params::<Chain>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create chain-specific set of signing parameters.
|
||||
#[macro_export]
|
||||
macro_rules! declare_chain_signing_params_cli_schema {
|
||||
($chain:ident, $chain_prefix:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain " signing params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct [<$chain SigningParams>] {
|
||||
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer>]: Option<String>,
|
||||
#[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_password>]: Option<String>,
|
||||
|
||||
#[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_file>]: Option<std::path::PathBuf>,
|
||||
#[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_password_file>]: Option<std::path::PathBuf>,
|
||||
|
||||
#[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _transactions_mortality>]: Option<u32>,
|
||||
}
|
||||
|
||||
impl [<$chain SigningParams>] {
|
||||
/// Return transactions mortality.
|
||||
#[allow(dead_code)]
|
||||
pub fn transactions_mortality(&self) -> anyhow::Result<Option<u32>> {
|
||||
self.[<$chain_prefix _transactions_mortality>]
|
||||
.map(|transactions_mortality| {
|
||||
if !(4..=65536).contains(&transactions_mortality)
|
||||
|| !transactions_mortality.is_power_of_two()
|
||||
{
|
||||
Err(anyhow::format_err!(
|
||||
"Transactions mortality {} is not a power of two in a [4; 65536] range",
|
||||
transactions_mortality,
|
||||
))
|
||||
} else {
|
||||
Ok(transactions_mortality)
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Parse signing params into chain-specific KeyPair.
|
||||
#[allow(dead_code)]
|
||||
pub fn to_keypair<Chain: CliChain>(&self) -> anyhow::Result<Chain::KeyPair> {
|
||||
let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) {
|
||||
(Some(suri), _) => suri.to_owned(),
|
||||
(None, Some(suri_file)) => std::fs::read_to_string(suri_file)
|
||||
.map_err(|err| anyhow::format_err!(
|
||||
"Failed to read SURI from file {:?}: {}",
|
||||
suri_file,
|
||||
err,
|
||||
))?,
|
||||
(None, None) => return Err(anyhow::format_err!(
|
||||
"One of options must be specified: '{}' or '{}'",
|
||||
stringify!([<$chain_prefix _signer>]),
|
||||
stringify!([<$chain_prefix _signer_file>]),
|
||||
)),
|
||||
};
|
||||
|
||||
let suri_password = match (
|
||||
self.[<$chain_prefix _signer_password>].as_ref(),
|
||||
self.[<$chain_prefix _signer_password_file>].as_ref(),
|
||||
) {
|
||||
(Some(suri_password), _) => Some(suri_password.to_owned()),
|
||||
(None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file)
|
||||
.map(Some)
|
||||
.map_err(|err| anyhow::format_err!(
|
||||
"Failed to read SURI password from file {:?}: {}",
|
||||
suri_password_file,
|
||||
err,
|
||||
))?,
|
||||
_ => None,
|
||||
};
|
||||
|
||||
use sp_core::crypto::Pair;
|
||||
|
||||
Chain::KeyPair::from_string(
|
||||
&suri,
|
||||
suri_password.as_deref()
|
||||
).map_err(|e| anyhow::format_err!("{:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl TransactionParamsProvider for [<$chain SigningParams>] {
|
||||
fn is_defined(&self) -> bool {
|
||||
self.[<$chain_prefix _signer>].is_some() || self.[<$chain_prefix _signer_file>].is_some()
|
||||
}
|
||||
|
||||
fn transaction_params<Chain: CliChain>(&self) -> anyhow::Result<TransactionParams<Chain::KeyPair>> {
|
||||
Ok(TransactionParams {
|
||||
mortality: self.transactions_mortality()?,
|
||||
signer: self.to_keypair::<Chain>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Create chain-specific set of messages pallet owner signing parameters.
|
||||
#[macro_export]
|
||||
macro_rules! declare_chain_messages_pallet_owner_signing_params_cli_schema {
|
||||
($chain:ident, $chain_prefix:ident) => {
|
||||
paste::item! {
|
||||
#[doc = "Parameters required to sign transaction on behalf of owner of the messages pallet at " $chain "."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq)]
|
||||
pub struct [<$chain MessagesPalletOwnerSigningParams>] {
|
||||
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _messages_pallet_owner>]: Option<String>,
|
||||
#[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _messages_pallet_owner_password>]: Option<String>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl [<$chain MessagesPalletOwnerSigningParams>] {
|
||||
/// Parse signing params into chain-specific KeyPair.
|
||||
pub fn to_keypair<Chain: CliChain>(&self) -> anyhow::Result<Option<Chain::KeyPair>> {
|
||||
let [<$chain_prefix _messages_pallet_owner>] = match self.[<$chain_prefix _messages_pallet_owner>] {
|
||||
Some(ref messages_pallet_owner) => messages_pallet_owner,
|
||||
None => return Ok(None),
|
||||
};
|
||||
Chain::KeyPair::from_string(
|
||||
[<$chain_prefix _messages_pallet_owner>],
|
||||
self.[<$chain_prefix _messages_pallet_owner_password>].as_deref()
|
||||
).map_err(|e| anyhow::format_err!("{:?}", e)).map(Some)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Create chain-specific set of configuration objects: connection parameters,
|
||||
/// signing parameters and bridge initialization parameters.
|
||||
#[macro_export]
|
||||
macro_rules! declare_chain_cli_schema {
|
||||
($chain:ident, $chain_prefix:ident) => {
|
||||
$crate::declare_chain_runtime_version_params_cli_schema!($chain, $chain_prefix);
|
||||
$crate::declare_chain_connection_params_cli_schema!($chain, $chain_prefix);
|
||||
$crate::declare_chain_signing_params_cli_schema!($chain, $chain_prefix);
|
||||
$crate::declare_chain_messages_pallet_owner_signing_params_cli_schema!(
|
||||
$chain,
|
||||
$chain_prefix
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
declare_chain_cli_schema!(Source, source);
|
||||
declare_chain_cli_schema!(Target, target);
|
||||
declare_chain_cli_schema!(Relaychain, relaychain);
|
||||
declare_chain_cli_schema!(Parachain, parachain);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_core::Pair;
|
||||
|
||||
#[test]
|
||||
fn reads_suri_from_file() {
|
||||
const ALICE: &str = "//Alice";
|
||||
const BOB: &str = "//Bob";
|
||||
const ALICE_PASSWORD: &str = "alice_password";
|
||||
const BOB_PASSWORD: &str = "bob_password";
|
||||
|
||||
let alice: sp_core::sr25519::Pair = Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap();
|
||||
let bob: sp_core::sr25519::Pair = Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap();
|
||||
let bob_with_alice_password =
|
||||
sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap();
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let mut suri_file_path = temp_dir.path().to_path_buf();
|
||||
let mut password_file_path = temp_dir.path().to_path_buf();
|
||||
suri_file_path.push("suri");
|
||||
password_file_path.push("password");
|
||||
std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap();
|
||||
std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap();
|
||||
|
||||
// when both seed and password are read from file
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: Some(ALICE.into()),
|
||||
target_signer_password: Some(ALICE_PASSWORD.into()),
|
||||
|
||||
target_signer_file: None,
|
||||
target_signer_password_file: None,
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(alice.public()),
|
||||
);
|
||||
|
||||
// when both seed and password are read from file
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: None,
|
||||
target_signer_password: None,
|
||||
|
||||
target_signer_file: Some(suri_file_path.clone()),
|
||||
target_signer_password_file: Some(password_file_path.clone()),
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(bob.public()),
|
||||
);
|
||||
|
||||
// when password are is overriden by cli option
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: None,
|
||||
target_signer_password: Some(ALICE_PASSWORD.into()),
|
||||
|
||||
target_signer_file: Some(suri_file_path.clone()),
|
||||
target_signer_password_file: Some(password_file_path.clone()),
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(bob_with_alice_password.public()),
|
||||
);
|
||||
|
||||
// when both seed and password are overriden by cli options
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: Some(ALICE.into()),
|
||||
target_signer_password: Some(ALICE_PASSWORD.into()),
|
||||
|
||||
target_signer_file: Some(suri_file_path),
|
||||
target_signer_password_file: Some(password_file_path),
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(alice.public()),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
use crate::cli::{
|
||||
bridge::{FullBridge, MessagesCliBridge, *},
|
||||
chain_schema::*,
|
||||
relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
Balance, HexBytes, HexLaneId, SourceConnectionParams,
|
||||
Balance, HexBytes, HexLaneId,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use bp_runtime::BalanceOf;
|
||||
@@ -80,7 +81,7 @@ where
|
||||
<Self::Source as ChainBase>::Balance: Display + Into<u128>,
|
||||
{
|
||||
async fn estimate_fee(data: EstimateFee) -> anyhow::Result<()> {
|
||||
let source_client = data.source.to_client::<Self::Source>().await?;
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let lane = data.lane.into();
|
||||
let payload =
|
||||
crate::cli::encode_message::encode_message::<Self::Source, Self::Target>(&data.payload)
|
||||
@@ -239,7 +240,6 @@ async fn do_estimate_message_delivery_and_dispatch_fee<Source: Chain, P: Encode>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams};
|
||||
|
||||
#[test]
|
||||
fn should_parse_cli_options() {
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::cli::{
|
||||
CliBridgeBase, MillauToRialtoCliBridge, MillauToRialtoParachainCliBridge,
|
||||
RialtoToMillauCliBridge, WestendToMillauCliBridge,
|
||||
},
|
||||
SourceConnectionParams, TargetConnectionParams, TargetSigningParams,
|
||||
chain_schema::*,
|
||||
};
|
||||
use bp_runtime::Chain as ChainBase;
|
||||
use codec::Encode;
|
||||
@@ -71,8 +71,8 @@ where
|
||||
|
||||
/// Initialize the bridge.
|
||||
async fn init_bridge(data: InitBridge) -> anyhow::Result<()> {
|
||||
let source_client = data.source.to_client::<Self::Source>().await?;
|
||||
let target_client = data.target.to_client::<Self::Target>().await?;
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let target_client = data.target.into_client::<Self::Target>().await?;
|
||||
let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
|
||||
|
||||
let (spec_version, transaction_version) = target_client.simple_runtime_version().await?;
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use relay_substrate_client::ChainRuntimeVersion;
|
||||
use structopt::{clap::arg_enum, StructOpt};
|
||||
use strum::{EnumString, EnumVariantNames};
|
||||
use substrate_relay_helper::TransactionParams;
|
||||
|
||||
use bp_messages::LaneId;
|
||||
|
||||
@@ -31,6 +29,7 @@ pub(crate) mod encode_message;
|
||||
pub(crate) mod estimate_fee;
|
||||
pub(crate) mod send_message;
|
||||
|
||||
mod chain_schema;
|
||||
mod init_bridge;
|
||||
mod register_parachain;
|
||||
mod relay_headers;
|
||||
@@ -296,283 +295,9 @@ pub enum RuntimeVersionType {
|
||||
Bundle,
|
||||
}
|
||||
|
||||
/// Helper trait to override transaction parameters differently.
|
||||
pub trait TransactionParamsProvider {
|
||||
/// Returns `true` if transaction parameters are defined by this provider.
|
||||
fn is_defined(&self) -> bool;
|
||||
/// Returns transaction parameters.
|
||||
fn transaction_params<Chain: CliChain>(
|
||||
&self,
|
||||
) -> anyhow::Result<TransactionParams<Chain::KeyPair>>;
|
||||
|
||||
/// Returns transaction parameters, defined by `self` provider or, if they're not defined,
|
||||
/// defined by `other` provider.
|
||||
fn transaction_params_or<Chain: CliChain, T: TransactionParamsProvider>(
|
||||
&self,
|
||||
other: &T,
|
||||
) -> anyhow::Result<TransactionParams<Chain::KeyPair>> {
|
||||
if self.is_defined() {
|
||||
self.transaction_params::<Chain>()
|
||||
} else {
|
||||
other.transaction_params::<Chain>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create chain-specific set of configuration objects: connection parameters,
|
||||
/// signing parameters and bridge initialization parameters.
|
||||
#[macro_export]
|
||||
macro_rules! declare_chain_options {
|
||||
($chain:ident, $chain_prefix:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain " connection params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct [<$chain ConnectionParams>] {
|
||||
#[doc = "Connect to " $chain " node at given host."]
|
||||
#[structopt(long, default_value = "127.0.0.1")]
|
||||
pub [<$chain_prefix _host>]: String,
|
||||
#[doc = "Connect to " $chain " node websocket server at given port."]
|
||||
#[structopt(long, default_value = "9944")]
|
||||
pub [<$chain_prefix _port>]: u16,
|
||||
#[doc = "Use secure websocket connection."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _secure>]: bool,
|
||||
#[doc = "Custom runtime version"]
|
||||
#[structopt(flatten)]
|
||||
pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>],
|
||||
}
|
||||
|
||||
#[doc = $chain " runtime version params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct [<$chain RuntimeVersionParams>] {
|
||||
#[doc = "The type of runtime version for chain " $chain]
|
||||
#[structopt(long, default_value = "Bundle")]
|
||||
pub [<$chain_prefix _version_mode>]: RuntimeVersionType,
|
||||
#[doc = "The custom sepc_version for chain " $chain]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _spec_version>]: Option<u32>,
|
||||
#[doc = "The custom transaction_version for chain " $chain]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _transaction_version>]: Option<u32>,
|
||||
}
|
||||
|
||||
#[doc = $chain " signing params."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct [<$chain SigningParams>] {
|
||||
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer>]: Option<String>,
|
||||
#[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_password>]: Option<String>,
|
||||
|
||||
#[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_file>]: Option<std::path::PathBuf>,
|
||||
#[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_password_file>]: Option<std::path::PathBuf>,
|
||||
|
||||
#[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _transactions_mortality>]: Option<u32>,
|
||||
}
|
||||
|
||||
#[doc = "Parameters required to sign transaction on behalf of owner of the messages pallet at " $chain "."]
|
||||
#[derive(StructOpt, Debug, PartialEq, Eq)]
|
||||
pub struct [<$chain MessagesPalletOwnerSigningParams>] {
|
||||
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _messages_pallet_owner>]: Option<String>,
|
||||
#[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _messages_pallet_owner_password>]: Option<String>,
|
||||
}
|
||||
|
||||
impl [<$chain SigningParams>] {
|
||||
/// Return transactions mortality.
|
||||
#[allow(dead_code)]
|
||||
pub fn transactions_mortality(&self) -> anyhow::Result<Option<u32>> {
|
||||
self.[<$chain_prefix _transactions_mortality>]
|
||||
.map(|transactions_mortality| {
|
||||
if !(4..=65536).contains(&transactions_mortality)
|
||||
|| !transactions_mortality.is_power_of_two()
|
||||
{
|
||||
Err(anyhow::format_err!(
|
||||
"Transactions mortality {} is not a power of two in a [4; 65536] range",
|
||||
transactions_mortality,
|
||||
))
|
||||
} else {
|
||||
Ok(transactions_mortality)
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Parse signing params into chain-specific KeyPair.
|
||||
#[allow(dead_code)]
|
||||
pub fn to_keypair<Chain: CliChain>(&self) -> anyhow::Result<Chain::KeyPair> {
|
||||
let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) {
|
||||
(Some(suri), _) => suri.to_owned(),
|
||||
(None, Some(suri_file)) => std::fs::read_to_string(suri_file)
|
||||
.map_err(|err| anyhow::format_err!(
|
||||
"Failed to read SURI from file {:?}: {}",
|
||||
suri_file,
|
||||
err,
|
||||
))?,
|
||||
(None, None) => return Err(anyhow::format_err!(
|
||||
"One of options must be specified: '{}' or '{}'",
|
||||
stringify!([<$chain_prefix _signer>]),
|
||||
stringify!([<$chain_prefix _signer_file>]),
|
||||
)),
|
||||
};
|
||||
|
||||
let suri_password = match (
|
||||
self.[<$chain_prefix _signer_password>].as_ref(),
|
||||
self.[<$chain_prefix _signer_password_file>].as_ref(),
|
||||
) {
|
||||
(Some(suri_password), _) => Some(suri_password.to_owned()),
|
||||
(None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file)
|
||||
.map(Some)
|
||||
.map_err(|err| anyhow::format_err!(
|
||||
"Failed to read SURI password from file {:?}: {}",
|
||||
suri_password_file,
|
||||
err,
|
||||
))?,
|
||||
_ => None,
|
||||
};
|
||||
|
||||
use sp_core::crypto::Pair;
|
||||
|
||||
Chain::KeyPair::from_string(
|
||||
&suri,
|
||||
suri_password.as_deref()
|
||||
).map_err(|e| anyhow::format_err!("{:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl TransactionParamsProvider for [<$chain SigningParams>] {
|
||||
fn is_defined(&self) -> bool {
|
||||
self.[<$chain_prefix _signer>].is_some() || self.[<$chain_prefix _signer_file>].is_some()
|
||||
}
|
||||
|
||||
fn transaction_params<Chain: CliChain>(&self) -> anyhow::Result<TransactionParams<Chain::KeyPair>> {
|
||||
Ok(TransactionParams {
|
||||
mortality: self.transactions_mortality()?,
|
||||
signer: self.to_keypair::<Chain>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl [<$chain MessagesPalletOwnerSigningParams>] {
|
||||
/// Parse signing params into chain-specific KeyPair.
|
||||
pub fn to_keypair<Chain: CliChain>(&self) -> anyhow::Result<Option<Chain::KeyPair>> {
|
||||
use sp_core::crypto::Pair;
|
||||
|
||||
let [<$chain_prefix _messages_pallet_owner>] = match self.[<$chain_prefix _messages_pallet_owner>] {
|
||||
Some(ref messages_pallet_owner) => messages_pallet_owner,
|
||||
None => return Ok(None),
|
||||
};
|
||||
Chain::KeyPair::from_string(
|
||||
[<$chain_prefix _messages_pallet_owner>],
|
||||
self.[<$chain_prefix _messages_pallet_owner_password>].as_deref()
|
||||
).map_err(|e| anyhow::format_err!("{:?}", e)).map(Some)
|
||||
}
|
||||
}
|
||||
|
||||
impl [<$chain ConnectionParams>] {
|
||||
/// Returns `true` if version guard can be started.
|
||||
///
|
||||
/// There's no reason to run version guard when version mode is set to `Auto`. It can
|
||||
/// lead to relay shutdown when chain is upgraded, even though we have explicitly
|
||||
/// said that we don't want to shutdown.
|
||||
#[allow(dead_code)]
|
||||
pub fn can_start_version_guard(&self) -> bool {
|
||||
self.[<$chain_prefix _runtime_version>].[<$chain_prefix _version_mode>] != RuntimeVersionType::Auto
|
||||
}
|
||||
|
||||
/// Convert connection params into Substrate client.
|
||||
pub async fn to_client<Chain: CliChain>(
|
||||
&self,
|
||||
) -> anyhow::Result<relay_substrate_client::Client<Chain>> {
|
||||
let chain_runtime_version = self
|
||||
.[<$chain_prefix _runtime_version>]
|
||||
.into_runtime_version(Some(Chain::RUNTIME_VERSION))?;
|
||||
Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams {
|
||||
host: self.[<$chain_prefix _host>].clone(),
|
||||
port: self.[<$chain_prefix _port>],
|
||||
secure: self.[<$chain_prefix _secure>],
|
||||
chain_runtime_version,
|
||||
})
|
||||
.await
|
||||
)
|
||||
}
|
||||
|
||||
/// Return selected `chain_spec` version.
|
||||
///
|
||||
/// This function only connects to the node if version mode is set to `Auto`.
|
||||
#[allow(dead_code)]
|
||||
pub async fn selected_chain_spec_version<Chain: CliChain>(
|
||||
&self,
|
||||
) -> anyhow::Result<u32> {
|
||||
let chain_runtime_version = self
|
||||
.[<$chain_prefix _runtime_version>]
|
||||
.into_runtime_version(Some(Chain::RUNTIME_VERSION))?;
|
||||
Ok(match chain_runtime_version {
|
||||
ChainRuntimeVersion::Auto => self
|
||||
.to_client::<Chain>()
|
||||
.await?
|
||||
.simple_runtime_version()
|
||||
.await?
|
||||
.0,
|
||||
ChainRuntimeVersion::Custom(spec_version, _) => spec_version,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl [<$chain RuntimeVersionParams>] {
|
||||
/// Converts self into `ChainRuntimeVersion`.
|
||||
pub fn into_runtime_version(
|
||||
self,
|
||||
bundle_runtime_version: Option<sp_version::RuntimeVersion>,
|
||||
) -> anyhow::Result<ChainRuntimeVersion> {
|
||||
Ok(match self.[<$chain_prefix _version_mode>] {
|
||||
RuntimeVersionType::Auto => ChainRuntimeVersion::Auto,
|
||||
RuntimeVersionType::Custom => {
|
||||
let except_spec_version = self.[<$chain_prefix _spec_version>]
|
||||
.ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?;
|
||||
let except_transaction_version = self.[<$chain_prefix _transaction_version>]
|
||||
.ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?;
|
||||
ChainRuntimeVersion::Custom(
|
||||
except_spec_version,
|
||||
except_transaction_version
|
||||
)
|
||||
},
|
||||
RuntimeVersionType::Bundle => match bundle_runtime_version {
|
||||
Some(runtime_version) => ChainRuntimeVersion::Custom(
|
||||
runtime_version.spec_version,
|
||||
runtime_version.transaction_version
|
||||
),
|
||||
None => ChainRuntimeVersion::Auto
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare_chain_options!(Source, source);
|
||||
declare_chain_options!(Target, target);
|
||||
declare_chain_options!(Relaychain, relaychain);
|
||||
declare_chain_options!(Parachain, parachain);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_core::Pair;
|
||||
|
||||
#[test]
|
||||
fn hex_bytes_display_matches_from_str_for_clap() {
|
||||
@@ -586,93 +311,4 @@ mod tests {
|
||||
// then
|
||||
assert_eq!(hex.0, hex2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_suri_from_file() {
|
||||
const ALICE: &str = "//Alice";
|
||||
const BOB: &str = "//Bob";
|
||||
const ALICE_PASSWORD: &str = "alice_password";
|
||||
const BOB_PASSWORD: &str = "bob_password";
|
||||
|
||||
let alice = sp_core::sr25519::Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap();
|
||||
let bob = sp_core::sr25519::Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap();
|
||||
let bob_with_alice_password =
|
||||
sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap();
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let mut suri_file_path = temp_dir.path().to_path_buf();
|
||||
let mut password_file_path = temp_dir.path().to_path_buf();
|
||||
suri_file_path.push("suri");
|
||||
password_file_path.push("password");
|
||||
std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap();
|
||||
std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap();
|
||||
|
||||
// when both seed and password are read from file
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: Some(ALICE.into()),
|
||||
target_signer_password: Some(ALICE_PASSWORD.into()),
|
||||
|
||||
target_signer_file: None,
|
||||
target_signer_password_file: None,
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(alice.public()),
|
||||
);
|
||||
|
||||
// when both seed and password are read from file
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: None,
|
||||
target_signer_password: None,
|
||||
|
||||
target_signer_file: Some(suri_file_path.clone()),
|
||||
target_signer_password_file: Some(password_file_path.clone()),
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(bob.public()),
|
||||
);
|
||||
|
||||
// when password are is overriden by cli option
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: None,
|
||||
target_signer_password: Some(ALICE_PASSWORD.into()),
|
||||
|
||||
target_signer_file: Some(suri_file_path.clone()),
|
||||
target_signer_password_file: Some(password_file_path.clone()),
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(bob_with_alice_password.public()),
|
||||
);
|
||||
|
||||
// when both seed and password are overriden by cli options
|
||||
assert_eq!(
|
||||
TargetSigningParams {
|
||||
target_signer: Some(ALICE.into()),
|
||||
target_signer_password: Some(ALICE_PASSWORD.into()),
|
||||
|
||||
target_signer_file: Some(suri_file_path),
|
||||
target_signer_password_file: Some(password_file_path),
|
||||
|
||||
target_transactions_mortality: None,
|
||||
}
|
||||
.to_keypair::<relay_rialto_client::Rialto>()
|
||||
.map(|p| p.public())
|
||||
.map_err(drop),
|
||||
Ok(alice.public()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::cli::{
|
||||
Balance, ParachainConnectionParams, RelaychainConnectionParams, RelaychainSigningParams,
|
||||
};
|
||||
use crate::cli::{chain_schema::*, Balance};
|
||||
|
||||
use codec::Encode;
|
||||
use frame_support::Twox64Concat;
|
||||
@@ -94,9 +92,9 @@ impl RegisterParachain {
|
||||
/// Run the command.
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
select_bridge!(self.parachain, {
|
||||
let relay_client = self.relay_connection.to_client::<Relaychain>().await?;
|
||||
let relay_client = self.relay_connection.into_client::<Relaychain>().await?;
|
||||
let relay_sign = self.relay_sign.to_keypair::<Relaychain>()?;
|
||||
let para_client = self.para_connection.to_client::<Parachain>().await?;
|
||||
let para_client = self.para_connection.into_client::<Parachain>().await?;
|
||||
|
||||
// hopefully we're the only actor that is registering parachain right now
|
||||
// => read next parachain id
|
||||
@@ -343,9 +341,6 @@ async fn wait_para_state<Relaychain: Chain>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::{
|
||||
ParachainRuntimeVersionParams, RelaychainRuntimeVersionParams, RuntimeVersionType,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn register_rialto_parachain() {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use relay_substrate_client::{AccountKeyPairOf, ChainBase};
|
||||
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf};
|
||||
use sp_core::Pair;
|
||||
use structopt::StructOpt;
|
||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||
@@ -23,10 +23,7 @@ use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
|
||||
use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline;
|
||||
|
||||
use crate::cli::{
|
||||
bridge::*, PrometheusParams, SourceConnectionParams, TargetConnectionParams,
|
||||
TargetSigningParams,
|
||||
};
|
||||
use crate::cli::{bridge::*, chain_schema::*, PrometheusParams};
|
||||
|
||||
/// Start headers relayer process.
|
||||
#[derive(StructOpt)]
|
||||
@@ -59,14 +56,14 @@ pub enum RelayHeadersBridge {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
trait HeadersRelayer: HeadersCliBridge
|
||||
trait HeadersRelayer: RelayToRelayHeadersCliBridge
|
||||
where
|
||||
<Self::Target as ChainBase>::AccountId: From<<AccountKeyPairOf<Self::Target> as Pair>::Public>,
|
||||
AccountIdOf<Self::Target>: From<<AccountKeyPairOf<Self::Target> as Pair>::Public>,
|
||||
{
|
||||
/// Relay headers.
|
||||
async fn relay_headers(data: RelayHeaders) -> anyhow::Result<()> {
|
||||
let source_client = data.source.to_client::<Self::Source>().await?;
|
||||
let target_client = data.target.to_client::<Self::Target>().await?;
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let target_client = data.target.into_client::<Self::Target>().await?;
|
||||
let target_transactions_mortality = data.target_sign.target_transactions_mortality;
|
||||
let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
|
||||
|
||||
@@ -80,7 +77,7 @@ where
|
||||
Self::Finality::start_relay_guards(
|
||||
&target_client,
|
||||
&target_transactions_params,
|
||||
data.target.can_start_version_guard(),
|
||||
target_client.can_start_version_guard(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -1,910 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Complex headers+messages relays support.
|
||||
//!
|
||||
//! To add new complex relay between `ChainA` and `ChainB`, you must:
|
||||
//!
|
||||
//! 1) ensure that there's a `declare_chain_options!(...)` for both chains;
|
||||
//! 2) add `declare_bridge_options!(...)` for the bridge;
|
||||
//! 3) add bridge support to the `select_bridge! { ... }` macro.
|
||||
|
||||
use futures::{FutureExt, TryFutureExt};
|
||||
use structopt::StructOpt;
|
||||
use strum::VariantNames;
|
||||
|
||||
use async_std::sync::Arc;
|
||||
use bp_polkadot_core::parachains::ParaHash;
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, ChainRuntimeVersion, Client,
|
||||
TransactionSignScheme,
|
||||
};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::Pair;
|
||||
use substrate_relay_helper::{
|
||||
finality::SubstrateFinalitySyncPipeline,
|
||||
messages_lane::MessagesRelayParams,
|
||||
on_demand::{
|
||||
headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay,
|
||||
},
|
||||
parachains::SubstrateParachainsPipeline,
|
||||
TaggedAccount, TransactionParams,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
cli::{
|
||||
relay_messages::RelayerMode, CliChain, HexLaneId, PrometheusParams, RuntimeVersionType,
|
||||
TransactionParamsProvider,
|
||||
},
|
||||
declare_chain_options,
|
||||
};
|
||||
|
||||
/// Maximal allowed conversion rate error ratio (abs(real - stored) / stored) that we allow.
|
||||
///
|
||||
/// If it is zero, then transaction will be submitted every time we see difference between
|
||||
/// stored and real conversion rates. If it is large enough (e.g. > than 10 percents, which is 0.1),
|
||||
/// then rational relayers may stop relaying messages because they were submitted using
|
||||
/// lesser conversion rate.
|
||||
pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05;
|
||||
|
||||
/// Start headers+messages relayer process.
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub enum RelayHeadersAndMessages {
|
||||
MillauRialto(MillauRialtoHeadersAndMessages),
|
||||
MillauRialtoParachain(MillauRialtoParachainHeadersAndMessages),
|
||||
}
|
||||
|
||||
/// Parameters that have the same names across all bridges.
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct HeadersAndMessagesSharedParams {
|
||||
/// Hex-encoded lane identifiers that should be served by the complex relay.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
lane: Vec<HexLaneId>,
|
||||
#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
|
||||
relayer_mode: RelayerMode,
|
||||
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
|
||||
/// are relayed.
|
||||
#[structopt(long)]
|
||||
only_mandatory_headers: bool,
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
}
|
||||
|
||||
// The reason behind this macro is that 'normal' relays are using source and target chains
|
||||
// terminology, which is unusable for both-way relays (if you're relaying headers from Rialto to
|
||||
// Millau and from Millau to Rialto, then which chain is source?).
|
||||
macro_rules! declare_bridge_options {
|
||||
// chain, parachain, relay-chain-of-parachain
|
||||
($chain1:ident, $chain2:ident, $chain3:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain1 ", " $chain2 " and " $chain3 " headers+parachains+messages relay params."]
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
#[structopt(flatten)]
|
||||
shared: HeadersAndMessagesSharedParams,
|
||||
#[structopt(flatten)]
|
||||
left: [<$chain1 ConnectionParams>],
|
||||
// default signer, which is always used to sign messages relay transactions on the left chain
|
||||
#[structopt(flatten)]
|
||||
left_sign: [<$chain1 SigningParams>],
|
||||
// override for right_relay->left headers signer
|
||||
#[structopt(flatten)]
|
||||
right_relay_headers_to_left_sign_override: [<$chain3 HeadersTo $chain1 SigningParams>],
|
||||
// override for right->left parachains signer
|
||||
#[structopt(flatten)]
|
||||
right_parachains_to_left_sign_override: [<$chain3 ParachainsTo $chain1 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
left_messages_pallet_owner: [<$chain1 MessagesPalletOwnerSigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right: [<$chain2 ConnectionParams>],
|
||||
// default signer, which is always used to sign messages relay transactions on the right chain
|
||||
#[structopt(flatten)]
|
||||
right_sign: [<$chain2 SigningParams>],
|
||||
// override for left->right headers signer
|
||||
#[structopt(flatten)]
|
||||
left_headers_to_right_sign_override: [<$chain1 HeadersTo $chain2 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_messages_pallet_owner: [<$chain2 MessagesPalletOwnerSigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_relay: [<$chain3 ConnectionParams>],
|
||||
}
|
||||
}
|
||||
|
||||
declare_bridge_options!({ implement }, $chain1, $chain2);
|
||||
};
|
||||
($chain1:ident, $chain2:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain1 " and " $chain2 " headers+messages relay params."]
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
#[structopt(flatten)]
|
||||
shared: HeadersAndMessagesSharedParams,
|
||||
// default signer, which is always used to sign messages relay transactions on the left chain
|
||||
#[structopt(flatten)]
|
||||
left: [<$chain1 ConnectionParams>],
|
||||
// override for right->left headers signer
|
||||
#[structopt(flatten)]
|
||||
right_headers_to_left_sign_override: [<$chain2 HeadersTo $chain1 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
left_sign: [<$chain1 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
left_messages_pallet_owner: [<$chain1 MessagesPalletOwnerSigningParams>],
|
||||
// default signer, which is always used to sign messages relay transactions on the right chain
|
||||
#[structopt(flatten)]
|
||||
right: [<$chain2 ConnectionParams>],
|
||||
// override for left->right headers signer
|
||||
#[structopt(flatten)]
|
||||
left_headers_to_right_sign_override: [<$chain1 HeadersTo $chain2 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_sign: [<$chain2 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_messages_pallet_owner: [<$chain2 MessagesPalletOwnerSigningParams>],
|
||||
}
|
||||
}
|
||||
|
||||
declare_bridge_options!({ implement }, $chain1, $chain2);
|
||||
};
|
||||
({ implement }, $chain1:ident, $chain2:ident) => {
|
||||
paste::item! {
|
||||
impl From<RelayHeadersAndMessages> for [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
fn from(relay_params: RelayHeadersAndMessages) -> [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
match relay_params {
|
||||
RelayHeadersAndMessages::[<$chain1 $chain2>](params) => params,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! select_bridge {
|
||||
($bridge: expr, $generic: tt) => {
|
||||
match $bridge {
|
||||
RelayHeadersAndMessages::MillauRialto(_) => {
|
||||
type Params = MillauRialtoHeadersAndMessages;
|
||||
|
||||
type Left = relay_millau_client::Millau;
|
||||
type Right = relay_rialto_client::Rialto;
|
||||
|
||||
use crate::chains::{
|
||||
millau_messages_to_rialto::MillauMessagesToRialto as LeftToRightMessageLane,
|
||||
rialto_messages_to_millau::RialtoMessagesToMillau as RightToLeftMessageLane,
|
||||
};
|
||||
|
||||
async fn start_on_demand_relays(
|
||||
params: &Params,
|
||||
left_client: Client<Left>,
|
||||
right_client: Client<Right>,
|
||||
at_left_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Left>>>,
|
||||
at_right_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Right>>>,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Left>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Right>>>,
|
||||
)> {
|
||||
start_on_demand_relay_to_relay::<
|
||||
Left,
|
||||
Right,
|
||||
crate::chains::millau_headers_to_rialto::MillauFinalityToRialto,
|
||||
crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau,
|
||||
>(
|
||||
left_client,
|
||||
right_client,
|
||||
params.left_headers_to_right_sign_override.transaction_params_or::<Right, _>(¶ms.right_sign)?,
|
||||
params.right_headers_to_left_sign_override.transaction_params_or::<Left, _>(¶ms.left_sign)?,
|
||||
params.shared.only_mandatory_headers,
|
||||
params.shared.only_mandatory_headers,
|
||||
params.left.can_start_version_guard(),
|
||||
params.right.can_start_version_guard(),
|
||||
at_left_relay_accounts,
|
||||
at_right_relay_accounts,
|
||||
).await
|
||||
}
|
||||
|
||||
$generic
|
||||
},
|
||||
RelayHeadersAndMessages::MillauRialtoParachain(_) => {
|
||||
type Params = MillauRialtoParachainHeadersAndMessages;
|
||||
|
||||
type Left = relay_millau_client::Millau;
|
||||
type Right = relay_rialto_parachain_client::RialtoParachain;
|
||||
|
||||
use crate::chains::{
|
||||
millau_messages_to_rialto_parachain::MillauMessagesToRialtoParachain as LeftToRightMessageLane,
|
||||
rialto_parachain_messages_to_millau::RialtoParachainMessagesToMillau as RightToLeftMessageLane,
|
||||
};
|
||||
|
||||
async fn start_on_demand_relays(
|
||||
params: &Params,
|
||||
left_client: Client<Left>,
|
||||
right_client: Client<Right>,
|
||||
at_left_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Left>>>,
|
||||
at_right_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Right>>>,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Left>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Right>>>,
|
||||
)> {
|
||||
type RightRelayChain = relay_rialto_client::Rialto;
|
||||
let rialto_relay_chain_client = params.right_relay.to_client::<RightRelayChain>().await?;
|
||||
|
||||
start_on_demand_relay_to_parachain::<
|
||||
Left,
|
||||
Right,
|
||||
RightRelayChain,
|
||||
crate::chains::millau_headers_to_rialto_parachain::MillauFinalityToRialtoParachain,
|
||||
crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau,
|
||||
crate::chains::rialto_parachains_to_millau::RialtoParachainsToMillau,
|
||||
>(
|
||||
left_client,
|
||||
right_client,
|
||||
rialto_relay_chain_client,
|
||||
params.left_headers_to_right_sign_override.transaction_params_or::<Right, _>(¶ms.right_sign)?,
|
||||
params.right_relay_headers_to_left_sign_override.transaction_params_or::<Left, _>(¶ms.left_sign)?,
|
||||
params.right_parachains_to_left_sign_override.transaction_params_or::<Left, _>(¶ms.left_sign)?,
|
||||
params.shared.only_mandatory_headers,
|
||||
params.shared.only_mandatory_headers,
|
||||
params.left.can_start_version_guard(),
|
||||
params.right.can_start_version_guard(),
|
||||
at_left_relay_accounts,
|
||||
at_right_relay_accounts,
|
||||
).await
|
||||
}
|
||||
|
||||
$generic
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// All supported chains.
|
||||
declare_chain_options!(Millau, millau);
|
||||
declare_chain_options!(Rialto, rialto);
|
||||
declare_chain_options!(RialtoParachain, rialto_parachain);
|
||||
// Means to override signers of different layer transactions.
|
||||
declare_chain_options!(MillauHeadersToRialto, millau_headers_to_rialto);
|
||||
declare_chain_options!(MillauHeadersToRialtoParachain, millau_headers_to_rialto_parachain);
|
||||
declare_chain_options!(RialtoHeadersToMillau, rialto_headers_to_millau);
|
||||
declare_chain_options!(RialtoParachainsToMillau, rialto_parachains_to_millau);
|
||||
// All supported bridges.
|
||||
declare_bridge_options!(Millau, Rialto);
|
||||
declare_bridge_options!(Millau, RialtoParachain, Rialto);
|
||||
|
||||
impl RelayHeadersAndMessages {
|
||||
/// Run the command.
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
select_bridge!(self, {
|
||||
let params: Params = self.into();
|
||||
|
||||
let left_client = params.left.to_client::<Left>().await?;
|
||||
let left_transactions_mortality = params.left_sign.transactions_mortality()?;
|
||||
let left_sign = params.left_sign.to_keypair::<Left>()?;
|
||||
let left_messages_pallet_owner =
|
||||
params.left_messages_pallet_owner.to_keypair::<Left>()?;
|
||||
let right_client = params.right.to_client::<Right>().await?;
|
||||
let right_transactions_mortality = params.right_sign.transactions_mortality()?;
|
||||
let right_sign = params.right_sign.to_keypair::<Right>()?;
|
||||
let right_messages_pallet_owner =
|
||||
params.right_messages_pallet_owner.to_keypair::<Right>()?;
|
||||
|
||||
let lanes = params.shared.lane.clone();
|
||||
let relayer_mode = params.shared.relayer_mode.into();
|
||||
let relay_strategy = MixStrategy::new(relayer_mode);
|
||||
|
||||
// create metrics registry and register standalone metrics
|
||||
let metrics_params: MetricsParams = params.shared.prometheus_params.clone().into();
|
||||
let metrics_params = relay_utils::relay_metrics(metrics_params).into_params();
|
||||
let left_to_right_metrics =
|
||||
substrate_relay_helper::messages_metrics::standalone_metrics::<
|
||||
LeftToRightMessageLane,
|
||||
>(left_client.clone(), right_client.clone())?;
|
||||
let right_to_left_metrics = left_to_right_metrics.clone().reverse();
|
||||
let mut at_left_relay_accounts = vec![TaggedAccount::Messages {
|
||||
id: left_sign.public().into(),
|
||||
bridged_chain: Right::NAME.to_string(),
|
||||
}];
|
||||
let mut at_right_relay_accounts = vec![TaggedAccount::Messages {
|
||||
id: right_sign.public().into(),
|
||||
bridged_chain: Left::NAME.to_string(),
|
||||
}];
|
||||
|
||||
// start conversion rate update loops for left/right chains
|
||||
if let Some(left_messages_pallet_owner) = left_messages_pallet_owner.clone() {
|
||||
let left_client = left_client.clone();
|
||||
let format_err = || {
|
||||
anyhow::format_err!(
|
||||
"Cannon run conversion rate updater: {} -> {}",
|
||||
Right::NAME,
|
||||
Left::NAME
|
||||
)
|
||||
};
|
||||
substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::<
|
||||
LeftToRightMessageLane,
|
||||
Left,
|
||||
>(
|
||||
left_client,
|
||||
TransactionParams {
|
||||
signer: left_messages_pallet_owner.clone(),
|
||||
mortality: left_transactions_mortality,
|
||||
},
|
||||
left_to_right_metrics
|
||||
.target_to_source_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
left_to_right_metrics
|
||||
.target_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
left_to_right_metrics
|
||||
.source_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
);
|
||||
at_left_relay_accounts.push(TaggedAccount::MessagesPalletOwner {
|
||||
id: left_messages_pallet_owner.public().into(),
|
||||
bridged_chain: Right::NAME.to_string(),
|
||||
});
|
||||
}
|
||||
if let Some(right_messages_pallet_owner) = right_messages_pallet_owner.clone() {
|
||||
let right_client = right_client.clone();
|
||||
let format_err = || {
|
||||
anyhow::format_err!(
|
||||
"Cannon run conversion rate updater: {} -> {}",
|
||||
Left::NAME,
|
||||
Right::NAME
|
||||
)
|
||||
};
|
||||
substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::<
|
||||
RightToLeftMessageLane,
|
||||
Right,
|
||||
>(
|
||||
right_client,
|
||||
TransactionParams {
|
||||
signer: right_messages_pallet_owner.clone(),
|
||||
mortality: right_transactions_mortality,
|
||||
},
|
||||
right_to_left_metrics
|
||||
.target_to_source_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
right_to_left_metrics
|
||||
.target_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
right_to_left_metrics
|
||||
.source_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
);
|
||||
at_right_relay_accounts.push(TaggedAccount::MessagesPalletOwner {
|
||||
id: right_messages_pallet_owner.public().into(),
|
||||
bridged_chain: Left::NAME.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// start on-demand header relays
|
||||
let (left_to_right_on_demand_headers, right_to_left_on_demand_headers) =
|
||||
start_on_demand_relays(
|
||||
¶ms,
|
||||
left_client.clone(),
|
||||
right_client.clone(),
|
||||
&mut at_left_relay_accounts,
|
||||
&mut at_right_relay_accounts,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// add balance-related metrics
|
||||
let metrics_params =
|
||||
substrate_relay_helper::messages_metrics::add_relay_balances_metrics(
|
||||
left_client.clone(),
|
||||
metrics_params,
|
||||
at_left_relay_accounts,
|
||||
)
|
||||
.await?;
|
||||
let metrics_params =
|
||||
substrate_relay_helper::messages_metrics::add_relay_balances_metrics(
|
||||
right_client.clone(),
|
||||
metrics_params,
|
||||
at_right_relay_accounts,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Need 2x capacity since we consider both directions for each lane
|
||||
let mut message_relays = Vec::with_capacity(lanes.len() * 2);
|
||||
for lane in lanes {
|
||||
let lane = lane.into();
|
||||
let left_to_right_messages = substrate_relay_helper::messages_lane::run::<
|
||||
LeftToRightMessageLane,
|
||||
>(MessagesRelayParams {
|
||||
source_client: left_client.clone(),
|
||||
source_transaction_params: TransactionParams {
|
||||
signer: left_sign.clone(),
|
||||
mortality: left_transactions_mortality,
|
||||
},
|
||||
target_client: right_client.clone(),
|
||||
target_transaction_params: TransactionParams {
|
||||
signer: right_sign.clone(),
|
||||
mortality: right_transactions_mortality,
|
||||
},
|
||||
source_to_target_headers_relay: Some(left_to_right_on_demand_headers.clone()),
|
||||
target_to_source_headers_relay: Some(right_to_left_on_demand_headers.clone()),
|
||||
lane_id: lane,
|
||||
metrics_params: metrics_params.clone().disable(),
|
||||
standalone_metrics: Some(left_to_right_metrics.clone()),
|
||||
relay_strategy: relay_strategy.clone(),
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
.boxed();
|
||||
let right_to_left_messages = substrate_relay_helper::messages_lane::run::<
|
||||
RightToLeftMessageLane,
|
||||
>(MessagesRelayParams {
|
||||
source_client: right_client.clone(),
|
||||
source_transaction_params: TransactionParams {
|
||||
signer: right_sign.clone(),
|
||||
mortality: right_transactions_mortality,
|
||||
},
|
||||
target_client: left_client.clone(),
|
||||
target_transaction_params: TransactionParams {
|
||||
signer: left_sign.clone(),
|
||||
mortality: left_transactions_mortality,
|
||||
},
|
||||
source_to_target_headers_relay: Some(right_to_left_on_demand_headers.clone()),
|
||||
target_to_source_headers_relay: Some(left_to_right_on_demand_headers.clone()),
|
||||
lane_id: lane,
|
||||
metrics_params: metrics_params.clone().disable(),
|
||||
standalone_metrics: Some(right_to_left_metrics.clone()),
|
||||
relay_strategy: relay_strategy.clone(),
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
.boxed();
|
||||
|
||||
message_relays.push(left_to_right_messages);
|
||||
message_relays.push(right_to_left_messages);
|
||||
}
|
||||
|
||||
relay_utils::relay_metrics(metrics_params)
|
||||
.expose()
|
||||
.await
|
||||
.map_err(|e| anyhow::format_err!("{}", e))?;
|
||||
|
||||
futures::future::select_all(message_relays).await.0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Start bidirectional on-demand headers <> headers relay.
|
||||
#[allow(clippy::too_many_arguments)] // TODO: https://github.com/paritytech/parity-bridges-common/issues/1415
|
||||
async fn start_on_demand_relay_to_relay<LC, RC, LR, RL>(
|
||||
left_client: Client<LC>,
|
||||
right_client: Client<RC>,
|
||||
left_to_right_transaction_params: TransactionParams<AccountKeyPairOf<RC>>,
|
||||
right_to_left_transaction_params: TransactionParams<AccountKeyPairOf<LC>>,
|
||||
left_to_right_only_mandatory_headers: bool,
|
||||
right_to_left_only_mandatory_headers: bool,
|
||||
left_can_start_version_guard: bool,
|
||||
right_can_start_version_guard: bool,
|
||||
at_left_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<LC>>>,
|
||||
at_right_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<RC>>>,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<LC>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<RC>>>,
|
||||
)>
|
||||
where
|
||||
LC: Chain + TransactionSignScheme<Chain = LC> + CliChain<KeyPair = AccountKeyPairOf<LC>>,
|
||||
RC: Chain + TransactionSignScheme<Chain = RC> + CliChain<KeyPair = AccountKeyPairOf<RC>>,
|
||||
LR: SubstrateFinalitySyncPipeline<
|
||||
SourceChain = LC,
|
||||
TargetChain = RC,
|
||||
TransactionSignScheme = RC,
|
||||
>,
|
||||
RL: SubstrateFinalitySyncPipeline<
|
||||
SourceChain = RC,
|
||||
TargetChain = LC,
|
||||
TransactionSignScheme = LC,
|
||||
>,
|
||||
AccountIdOf<LC>: From<<<LC as TransactionSignScheme>::AccountKeyPair as Pair>::Public>,
|
||||
AccountIdOf<RC>: From<<<RC as TransactionSignScheme>::AccountKeyPair as Pair>::Public>,
|
||||
{
|
||||
at_left_relay_accounts.push(TaggedAccount::Headers {
|
||||
id: right_to_left_transaction_params.signer.public().into(),
|
||||
bridged_chain: RC::NAME.to_string(),
|
||||
});
|
||||
at_right_relay_accounts.push(TaggedAccount::Headers {
|
||||
id: left_to_right_transaction_params.signer.public().into(),
|
||||
bridged_chain: LC::NAME.to_string(),
|
||||
});
|
||||
|
||||
LR::start_relay_guards(
|
||||
&right_client,
|
||||
&left_to_right_transaction_params,
|
||||
right_can_start_version_guard,
|
||||
)
|
||||
.await?;
|
||||
RL::start_relay_guards(
|
||||
&left_client,
|
||||
&right_to_left_transaction_params,
|
||||
left_can_start_version_guard,
|
||||
)
|
||||
.await?;
|
||||
let left_to_right_on_demand_headers = OnDemandHeadersRelay::new::<LR>(
|
||||
left_client.clone(),
|
||||
right_client.clone(),
|
||||
left_to_right_transaction_params,
|
||||
left_to_right_only_mandatory_headers,
|
||||
);
|
||||
let right_to_left_on_demand_headers = OnDemandHeadersRelay::new::<RL>(
|
||||
right_client.clone(),
|
||||
left_client.clone(),
|
||||
right_to_left_transaction_params,
|
||||
right_to_left_only_mandatory_headers,
|
||||
);
|
||||
|
||||
Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_headers)))
|
||||
}
|
||||
|
||||
/// Start bidirectional on-demand headers <> parachains relay.
|
||||
#[allow(clippy::too_many_arguments)] // TODO: https://github.com/paritytech/parity-bridges-common/issues/1415
|
||||
async fn start_on_demand_relay_to_parachain<LC, RC, RRC, LR, RRF, RL>(
|
||||
left_client: Client<LC>,
|
||||
right_client: Client<RC>,
|
||||
right_relay_client: Client<RRC>,
|
||||
left_headers_to_right_transaction_params: TransactionParams<AccountKeyPairOf<RC>>,
|
||||
right_headers_to_left_transaction_params: TransactionParams<AccountKeyPairOf<LC>>,
|
||||
right_parachains_to_left_transaction_params: TransactionParams<AccountKeyPairOf<LC>>,
|
||||
left_to_right_only_mandatory_headers: bool,
|
||||
right_to_left_only_mandatory_headers: bool,
|
||||
left_can_start_version_guard: bool,
|
||||
right_can_start_version_guard: bool,
|
||||
at_left_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<LC>>>,
|
||||
at_right_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<RC>>>,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<LC>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<RC>>>,
|
||||
)>
|
||||
where
|
||||
LC: Chain + TransactionSignScheme<Chain = LC> + CliChain<KeyPair = AccountKeyPairOf<LC>>,
|
||||
RC: Chain<Hash = ParaHash>
|
||||
+ TransactionSignScheme<Chain = RC>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<RC>>,
|
||||
RRC: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
|
||||
+ TransactionSignScheme<Chain = RRC>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<RRC>>,
|
||||
LR: SubstrateFinalitySyncPipeline<
|
||||
SourceChain = LC,
|
||||
TargetChain = RC,
|
||||
TransactionSignScheme = RC,
|
||||
>,
|
||||
RRF: SubstrateFinalitySyncPipeline<
|
||||
SourceChain = RRC,
|
||||
TargetChain = LC,
|
||||
TransactionSignScheme = LC,
|
||||
>,
|
||||
RL: SubstrateParachainsPipeline<
|
||||
SourceRelayChain = RRC,
|
||||
SourceParachain = RC,
|
||||
TargetChain = LC,
|
||||
TransactionSignScheme = LC,
|
||||
>,
|
||||
AccountIdOf<LC>: From<<<LC as TransactionSignScheme>::AccountKeyPair as Pair>::Public>,
|
||||
AccountIdOf<RC>: From<<<RC as TransactionSignScheme>::AccountKeyPair as Pair>::Public>,
|
||||
{
|
||||
at_left_relay_accounts.push(TaggedAccount::Headers {
|
||||
id: right_headers_to_left_transaction_params.signer.public().into(),
|
||||
bridged_chain: RRC::NAME.to_string(),
|
||||
});
|
||||
at_left_relay_accounts.push(TaggedAccount::Parachains {
|
||||
id: right_parachains_to_left_transaction_params.signer.public().into(),
|
||||
bridged_chain: RRC::NAME.to_string(),
|
||||
});
|
||||
at_right_relay_accounts.push(TaggedAccount::Headers {
|
||||
id: left_headers_to_right_transaction_params.signer.public().into(),
|
||||
bridged_chain: LC::NAME.to_string(),
|
||||
});
|
||||
|
||||
LR::start_relay_guards(
|
||||
&right_client,
|
||||
&left_headers_to_right_transaction_params,
|
||||
right_can_start_version_guard,
|
||||
)
|
||||
.await?;
|
||||
RRF::start_relay_guards(
|
||||
&left_client,
|
||||
&right_headers_to_left_transaction_params,
|
||||
left_can_start_version_guard,
|
||||
)
|
||||
.await?;
|
||||
let left_to_right_on_demand_headers = OnDemandHeadersRelay::new::<LR>(
|
||||
left_client.clone(),
|
||||
right_client,
|
||||
left_headers_to_right_transaction_params,
|
||||
left_to_right_only_mandatory_headers,
|
||||
);
|
||||
let right_relay_to_left_on_demand_headers = OnDemandHeadersRelay::new::<RRF>(
|
||||
right_relay_client.clone(),
|
||||
left_client.clone(),
|
||||
right_headers_to_left_transaction_params,
|
||||
right_to_left_only_mandatory_headers,
|
||||
);
|
||||
let right_to_left_on_demand_parachains = OnDemandParachainsRelay::new::<RL>(
|
||||
right_relay_client,
|
||||
left_client,
|
||||
right_parachains_to_left_transaction_params,
|
||||
Arc::new(right_relay_to_left_on_demand_headers),
|
||||
);
|
||||
|
||||
Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_parachains)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_parse_relay_to_relay_options() {
|
||||
// when
|
||||
let res = RelayHeadersAndMessages::from_iter(vec![
|
||||
"relay-headers-and-messages",
|
||||
"millau-rialto",
|
||||
"--millau-host",
|
||||
"millau-node-alice",
|
||||
"--millau-port",
|
||||
"9944",
|
||||
"--millau-signer",
|
||||
"//Charlie",
|
||||
"--millau-messages-pallet-owner",
|
||||
"//Rialto.MessagesOwner",
|
||||
"--millau-transactions-mortality",
|
||||
"64",
|
||||
"--rialto-host",
|
||||
"rialto-node-alice",
|
||||
"--rialto-port",
|
||||
"9944",
|
||||
"--rialto-signer",
|
||||
"//Charlie",
|
||||
"--rialto-messages-pallet-owner",
|
||||
"//Millau.MessagesOwner",
|
||||
"--rialto-transactions-mortality",
|
||||
"64",
|
||||
"--lane",
|
||||
"00000000",
|
||||
"--lane",
|
||||
"73776170",
|
||||
"--prometheus-host",
|
||||
"0.0.0.0",
|
||||
]);
|
||||
|
||||
// then
|
||||
assert_eq!(
|
||||
res,
|
||||
RelayHeadersAndMessages::MillauRialto(MillauRialtoHeadersAndMessages {
|
||||
shared: HeadersAndMessagesSharedParams {
|
||||
lane: vec![
|
||||
HexLaneId([0x00, 0x00, 0x00, 0x00]),
|
||||
HexLaneId([0x73, 0x77, 0x61, 0x70])
|
||||
],
|
||||
relayer_mode: RelayerMode::Rational,
|
||||
only_mandatory_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
prometheus_host: "0.0.0.0".into(),
|
||||
prometheus_port: 9616,
|
||||
},
|
||||
},
|
||||
left: MillauConnectionParams {
|
||||
millau_host: "millau-node-alice".into(),
|
||||
millau_port: 9944,
|
||||
millau_secure: false,
|
||||
millau_runtime_version: MillauRuntimeVersionParams {
|
||||
millau_version_mode: RuntimeVersionType::Bundle,
|
||||
millau_spec_version: None,
|
||||
millau_transaction_version: None,
|
||||
},
|
||||
},
|
||||
left_sign: MillauSigningParams {
|
||||
millau_signer: Some("//Charlie".into()),
|
||||
millau_signer_password: None,
|
||||
millau_signer_file: None,
|
||||
millau_signer_password_file: None,
|
||||
millau_transactions_mortality: Some(64),
|
||||
},
|
||||
left_messages_pallet_owner: MillauMessagesPalletOwnerSigningParams {
|
||||
millau_messages_pallet_owner: Some("//Rialto.MessagesOwner".into()),
|
||||
millau_messages_pallet_owner_password: None,
|
||||
},
|
||||
left_headers_to_right_sign_override: MillauHeadersToRialtoSigningParams {
|
||||
millau_headers_to_rialto_signer: None,
|
||||
millau_headers_to_rialto_signer_password: None,
|
||||
millau_headers_to_rialto_signer_file: None,
|
||||
millau_headers_to_rialto_signer_password_file: None,
|
||||
millau_headers_to_rialto_transactions_mortality: None,
|
||||
},
|
||||
right: RialtoConnectionParams {
|
||||
rialto_host: "rialto-node-alice".into(),
|
||||
rialto_port: 9944,
|
||||
rialto_secure: false,
|
||||
rialto_runtime_version: RialtoRuntimeVersionParams {
|
||||
rialto_version_mode: RuntimeVersionType::Bundle,
|
||||
rialto_spec_version: None,
|
||||
rialto_transaction_version: None,
|
||||
},
|
||||
},
|
||||
right_sign: RialtoSigningParams {
|
||||
rialto_signer: Some("//Charlie".into()),
|
||||
rialto_signer_password: None,
|
||||
rialto_signer_file: None,
|
||||
rialto_signer_password_file: None,
|
||||
rialto_transactions_mortality: Some(64),
|
||||
},
|
||||
right_messages_pallet_owner: RialtoMessagesPalletOwnerSigningParams {
|
||||
rialto_messages_pallet_owner: Some("//Millau.MessagesOwner".into()),
|
||||
rialto_messages_pallet_owner_password: None,
|
||||
},
|
||||
right_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams {
|
||||
rialto_headers_to_millau_signer: None,
|
||||
rialto_headers_to_millau_signer_password: None,
|
||||
rialto_headers_to_millau_signer_file: None,
|
||||
rialto_headers_to_millau_signer_password_file: None,
|
||||
rialto_headers_to_millau_transactions_mortality: None,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_relay_to_parachain_options() {
|
||||
// when
|
||||
let res = RelayHeadersAndMessages::from_iter(vec![
|
||||
"relay-headers-and-messages",
|
||||
"millau-rialto-parachain",
|
||||
"--millau-host",
|
||||
"millau-node-alice",
|
||||
"--millau-port",
|
||||
"9944",
|
||||
"--millau-signer",
|
||||
"//Iden",
|
||||
"--rialto-headers-to-millau-signer",
|
||||
"//Ken",
|
||||
"--millau-messages-pallet-owner",
|
||||
"//RialtoParachain.MessagesOwner",
|
||||
"--millau-transactions-mortality",
|
||||
"64",
|
||||
"--rialto-parachain-host",
|
||||
"rialto-parachain-collator-charlie",
|
||||
"--rialto-parachain-port",
|
||||
"9944",
|
||||
"--rialto-parachain-signer",
|
||||
"//George",
|
||||
"--rialto-parachain-messages-pallet-owner",
|
||||
"//Millau.MessagesOwner",
|
||||
"--rialto-parachain-transactions-mortality",
|
||||
"64",
|
||||
"--rialto-host",
|
||||
"rialto-node-alice",
|
||||
"--rialto-port",
|
||||
"9944",
|
||||
"--lane",
|
||||
"00000000",
|
||||
"--prometheus-host",
|
||||
"0.0.0.0",
|
||||
]);
|
||||
|
||||
// then
|
||||
assert_eq!(
|
||||
res,
|
||||
RelayHeadersAndMessages::MillauRialtoParachain(
|
||||
MillauRialtoParachainHeadersAndMessages {
|
||||
shared: HeadersAndMessagesSharedParams {
|
||||
lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
|
||||
relayer_mode: RelayerMode::Rational,
|
||||
only_mandatory_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
prometheus_host: "0.0.0.0".into(),
|
||||
prometheus_port: 9616,
|
||||
},
|
||||
},
|
||||
left: MillauConnectionParams {
|
||||
millau_host: "millau-node-alice".into(),
|
||||
millau_port: 9944,
|
||||
millau_secure: false,
|
||||
millau_runtime_version: MillauRuntimeVersionParams {
|
||||
millau_version_mode: RuntimeVersionType::Bundle,
|
||||
millau_spec_version: None,
|
||||
millau_transaction_version: None,
|
||||
},
|
||||
},
|
||||
left_sign: MillauSigningParams {
|
||||
millau_signer: Some("//Iden".into()),
|
||||
millau_signer_password: None,
|
||||
millau_signer_file: None,
|
||||
millau_signer_password_file: None,
|
||||
millau_transactions_mortality: Some(64),
|
||||
},
|
||||
left_messages_pallet_owner: MillauMessagesPalletOwnerSigningParams {
|
||||
millau_messages_pallet_owner: Some(
|
||||
"//RialtoParachain.MessagesOwner".into()
|
||||
),
|
||||
millau_messages_pallet_owner_password: None,
|
||||
},
|
||||
left_headers_to_right_sign_override:
|
||||
MillauHeadersToRialtoParachainSigningParams {
|
||||
millau_headers_to_rialto_parachain_signer: None,
|
||||
millau_headers_to_rialto_parachain_signer_password: None,
|
||||
millau_headers_to_rialto_parachain_signer_file: None,
|
||||
millau_headers_to_rialto_parachain_signer_password_file: None,
|
||||
millau_headers_to_rialto_parachain_transactions_mortality: None,
|
||||
},
|
||||
right: RialtoParachainConnectionParams {
|
||||
rialto_parachain_host: "rialto-parachain-collator-charlie".into(),
|
||||
rialto_parachain_port: 9944,
|
||||
rialto_parachain_secure: false,
|
||||
rialto_parachain_runtime_version: RialtoParachainRuntimeVersionParams {
|
||||
rialto_parachain_version_mode: RuntimeVersionType::Bundle,
|
||||
rialto_parachain_spec_version: None,
|
||||
rialto_parachain_transaction_version: None,
|
||||
},
|
||||
},
|
||||
right_sign: RialtoParachainSigningParams {
|
||||
rialto_parachain_signer: Some("//George".into()),
|
||||
rialto_parachain_signer_password: None,
|
||||
rialto_parachain_signer_file: None,
|
||||
rialto_parachain_signer_password_file: None,
|
||||
rialto_parachain_transactions_mortality: Some(64),
|
||||
},
|
||||
right_messages_pallet_owner: RialtoParachainMessagesPalletOwnerSigningParams {
|
||||
rialto_parachain_messages_pallet_owner: Some(
|
||||
"//Millau.MessagesOwner".into()
|
||||
),
|
||||
rialto_parachain_messages_pallet_owner_password: None,
|
||||
},
|
||||
right_relay_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams {
|
||||
rialto_headers_to_millau_signer: Some("//Ken".into()),
|
||||
rialto_headers_to_millau_signer_password: None,
|
||||
rialto_headers_to_millau_signer_file: None,
|
||||
rialto_headers_to_millau_signer_password_file: None,
|
||||
rialto_headers_to_millau_transactions_mortality: None,
|
||||
},
|
||||
right_parachains_to_left_sign_override: RialtoParachainsToMillauSigningParams {
|
||||
rialto_parachains_to_millau_signer: None,
|
||||
rialto_parachains_to_millau_signer_password: None,
|
||||
rialto_parachains_to_millau_signer_file: None,
|
||||
rialto_parachains_to_millau_signer_password_file: None,
|
||||
rialto_parachains_to_millau_transactions_mortality: None,
|
||||
},
|
||||
right_relay: RialtoConnectionParams {
|
||||
rialto_host: "rialto-node-alice".into(),
|
||||
rialto_port: 9944,
|
||||
rialto_secure: false,
|
||||
rialto_runtime_version: RialtoRuntimeVersionParams {
|
||||
rialto_version_mode: RuntimeVersionType::Bundle,
|
||||
rialto_spec_version: None,
|
||||
rialto_transaction_version: None,
|
||||
},
|
||||
},
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
// Copyright 2019-2022 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/>.
|
||||
|
||||
//! Complex 2-ways headers+messages relays support.
|
||||
//!
|
||||
//! To add new complex relay between `ChainA` and `ChainB`, you must:
|
||||
//!
|
||||
//! 1) ensure that there's a `declare_chain_cli_schema!(...)` for both chains.
|
||||
//! 2) add `declare_chain_to_chain_bridge_schema!(...)` or
|
||||
//! `declare_chain_to_parachain_bridge_schema` for the bridge.
|
||||
//! 3) declare a new struct for the added bridge and implement the `Full2WayBridge` trait for it.
|
||||
|
||||
#[macro_use]
|
||||
mod relay_to_relay;
|
||||
#[macro_use]
|
||||
mod relay_to_parachain;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
use structopt::StructOpt;
|
||||
use strum::VariantNames;
|
||||
|
||||
use futures::{FutureExt, TryFutureExt};
|
||||
use relay_to_parachain::*;
|
||||
use relay_to_relay::*;
|
||||
|
||||
use crate::{
|
||||
cli::{
|
||||
bridge::{
|
||||
CliBridgeBase, MessagesCliBridge, MillauToRialtoCliBridge,
|
||||
MillauToRialtoParachainCliBridge, ParachainToRelayHeadersCliBridge,
|
||||
RelayToRelayHeadersCliBridge, RialtoParachainToMillauCliBridge,
|
||||
RialtoToMillauCliBridge,
|
||||
},
|
||||
chain_schema::*,
|
||||
relay_messages::RelayerMode,
|
||||
CliChain, HexLaneId, PrometheusParams,
|
||||
},
|
||||
declare_chain_cli_schema,
|
||||
};
|
||||
use bp_runtime::{BalanceOf, BlockNumberOf};
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, Client, TransactionSignScheme,
|
||||
};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::Pair;
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::MessagesRelayParams, on_demand::OnDemandRelay, TaggedAccount, TransactionParams,
|
||||
};
|
||||
|
||||
/// Maximal allowed conversion rate error ratio (abs(real - stored) / stored) that we allow.
|
||||
///
|
||||
/// If it is zero, then transaction will be submitted every time we see difference between
|
||||
/// stored and real conversion rates. If it is large enough (e.g. > than 10 percents, which is 0.1),
|
||||
/// then rational relayers may stop relaying messages because they were submitted using
|
||||
/// lesser conversion rate.
|
||||
pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05;
|
||||
|
||||
/// Parameters that have the same names across all bridges.
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct HeadersAndMessagesSharedParams {
|
||||
/// Hex-encoded lane identifiers that should be served by the complex relay.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
pub lane: Vec<HexLaneId>,
|
||||
#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
|
||||
pub relayer_mode: RelayerMode,
|
||||
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
|
||||
/// are relayed.
|
||||
#[structopt(long)]
|
||||
pub only_mandatory_headers: bool,
|
||||
#[structopt(flatten)]
|
||||
pub prometheus_params: PrometheusParams,
|
||||
}
|
||||
|
||||
pub struct Full2WayBridgeCommonParams<
|
||||
Left: TransactionSignScheme + CliChain,
|
||||
Right: TransactionSignScheme + CliChain,
|
||||
> {
|
||||
pub shared: HeadersAndMessagesSharedParams,
|
||||
|
||||
pub left: Client<Left>,
|
||||
// default signer, which is always used to sign messages relay transactions on the left chain
|
||||
pub left_sign: AccountKeyPairOf<Left>,
|
||||
pub left_transactions_mortality: Option<u32>,
|
||||
pub left_messages_pallet_owner: Option<AccountKeyPairOf<Left>>,
|
||||
pub at_left_accounts: Vec<TaggedAccount<AccountIdOf<Left>>>,
|
||||
|
||||
pub right: Client<Right>,
|
||||
// default signer, which is always used to sign messages relay transactions on the right chain
|
||||
pub right_sign: AccountKeyPairOf<Right>,
|
||||
pub right_transactions_mortality: Option<u32>,
|
||||
pub right_messages_pallet_owner: Option<AccountKeyPairOf<Right>>,
|
||||
pub at_right_accounts: Vec<TaggedAccount<AccountIdOf<Right>>>,
|
||||
}
|
||||
|
||||
// All supported chains.
|
||||
declare_chain_cli_schema!(Millau, millau);
|
||||
declare_chain_cli_schema!(Rialto, rialto);
|
||||
declare_chain_cli_schema!(RialtoParachain, rialto_parachain);
|
||||
// Means to override signers of different layer transactions.
|
||||
declare_chain_cli_schema!(MillauHeadersToRialto, millau_headers_to_rialto);
|
||||
declare_chain_cli_schema!(MillauHeadersToRialtoParachain, millau_headers_to_rialto_parachain);
|
||||
declare_chain_cli_schema!(RialtoHeadersToMillau, rialto_headers_to_millau);
|
||||
declare_chain_cli_schema!(RialtoParachainsToMillau, rialto_parachains_to_millau);
|
||||
// All supported bridges.
|
||||
declare_relay_to_relay_bridge_schema!(Millau, Rialto);
|
||||
declare_relay_to_parachain_bridge_schema!(Millau, RialtoParachain, Rialto);
|
||||
|
||||
#[async_trait]
|
||||
trait Full2WayBridgeBase: Sized + Send + Sync {
|
||||
/// The CLI params for the bridge.
|
||||
type Params;
|
||||
/// The left relay chain.
|
||||
type Left: TransactionSignScheme<Chain = Self::Left>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Self::Left>>;
|
||||
/// The right destination chain (it can be a relay or a parachain).
|
||||
type Right: TransactionSignScheme<Chain = Self::Right>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Self::Right>>;
|
||||
|
||||
fn common(&self) -> &Full2WayBridgeCommonParams<Self::Left, Self::Right>;
|
||||
|
||||
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right>;
|
||||
|
||||
async fn start_on_demand_headers_relayers(
|
||||
&mut self,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Self::Left>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Self::Right>>>,
|
||||
)>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
trait Full2WayBridge: Sized + Sync
|
||||
where
|
||||
AccountIdOf<Self::Left>: From<<AccountKeyPairOf<Self::Left> as Pair>::Public>,
|
||||
AccountIdOf<Self::Right>: From<<AccountKeyPairOf<Self::Right> as Pair>::Public>,
|
||||
BalanceOf<Self::Left>: TryFrom<BalanceOf<Self::Right>> + Into<u128>,
|
||||
BalanceOf<Self::Right>: TryFrom<BalanceOf<Self::Left>> + Into<u128>,
|
||||
{
|
||||
type Base: Full2WayBridgeBase<Left = Self::Left, Right = Self::Right>;
|
||||
|
||||
/// The left relay chain.
|
||||
type Left: Chain
|
||||
+ ChainWithBalances
|
||||
+ TransactionSignScheme<Chain = Self::Left>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Self::Left>>;
|
||||
/// The right relay chain.
|
||||
type Right: Chain
|
||||
+ ChainWithBalances
|
||||
+ TransactionSignScheme<Chain = Self::Right>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Self::Right>>;
|
||||
|
||||
// Left to Right bridge
|
||||
type L2R: MessagesCliBridge<Source = Self::Left, Target = Self::Right>;
|
||||
// Right to Left bridge
|
||||
type R2L: MessagesCliBridge<Source = Self::Right, Target = Self::Left>;
|
||||
|
||||
fn new(params: <Self::Base as Full2WayBridgeBase>::Params) -> anyhow::Result<Self>;
|
||||
|
||||
fn base(&self) -> &Self::Base;
|
||||
|
||||
fn mut_base(&mut self) -> &mut Self::Base;
|
||||
|
||||
async fn run(&mut self) -> anyhow::Result<()> {
|
||||
let left_client = self.base().common().left.clone();
|
||||
let left_transactions_mortality = self.base().common().left_transactions_mortality;
|
||||
let left_sign = self.base().common().left_sign.clone();
|
||||
let left_messages_pallet_owner = self.base().common().left_messages_pallet_owner.clone();
|
||||
let right_client = self.base().common().right.clone();
|
||||
let right_transactions_mortality = self.base().common().right_transactions_mortality;
|
||||
let right_sign = self.base().common().right_sign.clone();
|
||||
let right_messages_pallet_owner = self.base().common().right_messages_pallet_owner.clone();
|
||||
|
||||
let lanes = self.base().common().shared.lane.clone();
|
||||
let relayer_mode = self.base().common().shared.relayer_mode.into();
|
||||
let relay_strategy = MixStrategy::new(relayer_mode);
|
||||
|
||||
// create metrics registry and register standalone metrics
|
||||
let metrics_params: MetricsParams =
|
||||
self.base().common().shared.prometheus_params.clone().into();
|
||||
let metrics_params = relay_utils::relay_metrics(metrics_params).into_params();
|
||||
let left_to_right_metrics = substrate_relay_helper::messages_metrics::standalone_metrics::<
|
||||
<Self::L2R as MessagesCliBridge>::MessagesLane,
|
||||
>(left_client.clone(), right_client.clone())?;
|
||||
let right_to_left_metrics = left_to_right_metrics.clone().reverse();
|
||||
self.mut_base().mut_common().at_left_accounts.push(TaggedAccount::Messages {
|
||||
id: left_sign.public().into(),
|
||||
bridged_chain: Self::Right::NAME.to_string(),
|
||||
});
|
||||
self.mut_base().mut_common().at_right_accounts.push(TaggedAccount::Messages {
|
||||
id: right_sign.public().into(),
|
||||
bridged_chain: Self::Left::NAME.to_string(),
|
||||
});
|
||||
|
||||
// start conversion rate update loops for left/right chains
|
||||
if let Some(left_messages_pallet_owner) = left_messages_pallet_owner.clone() {
|
||||
let left_client = left_client.clone();
|
||||
let format_err = || {
|
||||
anyhow::format_err!(
|
||||
"Cannon run conversion rate updater: {} -> {}",
|
||||
Self::Right::NAME,
|
||||
Self::Left::NAME
|
||||
)
|
||||
};
|
||||
substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::<
|
||||
<Self::L2R as MessagesCliBridge>::MessagesLane,
|
||||
Self::Left,
|
||||
>(
|
||||
left_client,
|
||||
TransactionParams {
|
||||
signer: left_messages_pallet_owner.clone(),
|
||||
mortality: left_transactions_mortality,
|
||||
},
|
||||
left_to_right_metrics
|
||||
.target_to_source_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
left_to_right_metrics
|
||||
.target_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
left_to_right_metrics
|
||||
.source_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
);
|
||||
self.mut_base().mut_common().at_left_accounts.push(
|
||||
TaggedAccount::MessagesPalletOwner {
|
||||
id: left_messages_pallet_owner.public().into(),
|
||||
bridged_chain: Self::Right::NAME.to_string(),
|
||||
},
|
||||
);
|
||||
}
|
||||
if let Some(right_messages_pallet_owner) = right_messages_pallet_owner.clone() {
|
||||
let right_client = right_client.clone();
|
||||
let format_err = || {
|
||||
anyhow::format_err!(
|
||||
"Cannon run conversion rate updater: {} -> {}",
|
||||
Self::Left::NAME,
|
||||
Self::Right::NAME
|
||||
)
|
||||
};
|
||||
substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::<
|
||||
<Self::R2L as MessagesCliBridge>::MessagesLane,
|
||||
Self::Right,
|
||||
>(
|
||||
right_client,
|
||||
TransactionParams {
|
||||
signer: right_messages_pallet_owner.clone(),
|
||||
mortality: right_transactions_mortality,
|
||||
},
|
||||
right_to_left_metrics
|
||||
.target_to_source_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
right_to_left_metrics
|
||||
.target_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
right_to_left_metrics
|
||||
.source_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
);
|
||||
self.mut_base().mut_common().at_right_accounts.push(
|
||||
TaggedAccount::MessagesPalletOwner {
|
||||
id: right_messages_pallet_owner.public().into(),
|
||||
bridged_chain: Self::Left::NAME.to_string(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// start on-demand header relays
|
||||
let (left_to_right_on_demand_headers, right_to_left_on_demand_headers) =
|
||||
self.mut_base().start_on_demand_headers_relayers().await?;
|
||||
|
||||
// add balance-related metrics
|
||||
let metrics_params = substrate_relay_helper::messages_metrics::add_relay_balances_metrics(
|
||||
left_client.clone(),
|
||||
metrics_params,
|
||||
&self.base().common().at_left_accounts,
|
||||
)
|
||||
.await?;
|
||||
let metrics_params = substrate_relay_helper::messages_metrics::add_relay_balances_metrics(
|
||||
right_client.clone(),
|
||||
metrics_params,
|
||||
&self.base().common().at_right_accounts,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Need 2x capacity since we consider both directions for each lane
|
||||
let mut message_relays = Vec::with_capacity(lanes.len() * 2);
|
||||
for lane in lanes {
|
||||
let lane = lane.into();
|
||||
let left_to_right_messages = substrate_relay_helper::messages_lane::run::<
|
||||
<Self::L2R as MessagesCliBridge>::MessagesLane,
|
||||
>(MessagesRelayParams {
|
||||
source_client: left_client.clone(),
|
||||
source_transaction_params: TransactionParams {
|
||||
signer: left_sign.clone(),
|
||||
mortality: left_transactions_mortality,
|
||||
},
|
||||
target_client: right_client.clone(),
|
||||
target_transaction_params: TransactionParams {
|
||||
signer: right_sign.clone(),
|
||||
mortality: right_transactions_mortality,
|
||||
},
|
||||
source_to_target_headers_relay: Some(left_to_right_on_demand_headers.clone()),
|
||||
target_to_source_headers_relay: Some(right_to_left_on_demand_headers.clone()),
|
||||
lane_id: lane,
|
||||
metrics_params: metrics_params.clone().disable(),
|
||||
standalone_metrics: Some(left_to_right_metrics.clone()),
|
||||
relay_strategy: relay_strategy.clone(),
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
.boxed();
|
||||
let right_to_left_messages = substrate_relay_helper::messages_lane::run::<
|
||||
<Self::R2L as MessagesCliBridge>::MessagesLane,
|
||||
>(MessagesRelayParams {
|
||||
source_client: right_client.clone(),
|
||||
source_transaction_params: TransactionParams {
|
||||
signer: right_sign.clone(),
|
||||
mortality: right_transactions_mortality,
|
||||
},
|
||||
target_client: left_client.clone(),
|
||||
target_transaction_params: TransactionParams {
|
||||
signer: left_sign.clone(),
|
||||
mortality: left_transactions_mortality,
|
||||
},
|
||||
source_to_target_headers_relay: Some(right_to_left_on_demand_headers.clone()),
|
||||
target_to_source_headers_relay: Some(left_to_right_on_demand_headers.clone()),
|
||||
lane_id: lane,
|
||||
metrics_params: metrics_params.clone().disable(),
|
||||
standalone_metrics: Some(right_to_left_metrics.clone()),
|
||||
relay_strategy: relay_strategy.clone(),
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
.boxed();
|
||||
|
||||
message_relays.push(left_to_right_messages);
|
||||
message_relays.push(right_to_left_messages);
|
||||
}
|
||||
|
||||
relay_utils::relay_metrics(metrics_params)
|
||||
.expose()
|
||||
.await
|
||||
.map_err(|e| anyhow::format_err!("{}", e))?;
|
||||
|
||||
futures::future::select_all(message_relays).await.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MillauRialtoFull2WayBridge {
|
||||
base: <Self as Full2WayBridge>::Base,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Full2WayBridge for MillauRialtoFull2WayBridge {
|
||||
type Base = RelayToRelayBridge<Self::L2R, Self::R2L>;
|
||||
type Left = relay_millau_client::Millau;
|
||||
type Right = relay_rialto_client::Rialto;
|
||||
type L2R = MillauToRialtoCliBridge;
|
||||
type R2L = RialtoToMillauCliBridge;
|
||||
|
||||
fn new(base: Self::Base) -> anyhow::Result<Self> {
|
||||
Ok(Self { base })
|
||||
}
|
||||
|
||||
fn base(&self) -> &Self::Base {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn mut_base(&mut self) -> &mut Self::Base {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MillauRialtoParachainFull2WayBridge {
|
||||
base: <Self as Full2WayBridge>::Base,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Full2WayBridge for MillauRialtoParachainFull2WayBridge {
|
||||
type Base = RelayToParachainBridge<Self::L2R, Self::R2L>;
|
||||
type Left = relay_millau_client::Millau;
|
||||
type Right = relay_rialto_parachain_client::RialtoParachain;
|
||||
type L2R = MillauToRialtoParachainCliBridge;
|
||||
type R2L = RialtoParachainToMillauCliBridge;
|
||||
|
||||
fn new(base: Self::Base) -> anyhow::Result<Self> {
|
||||
Ok(Self { base })
|
||||
}
|
||||
|
||||
fn base(&self) -> &Self::Base {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn mut_base(&mut self) -> &mut Self::Base {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
|
||||
/// Start headers+messages relayer process.
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub enum RelayHeadersAndMessages {
|
||||
MillauRialto(MillauRialtoHeadersAndMessages),
|
||||
MillauRialtoParachain(MillauRialtoParachainHeadersAndMessages),
|
||||
}
|
||||
|
||||
impl RelayHeadersAndMessages {
|
||||
/// Run the command.
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
match self {
|
||||
RelayHeadersAndMessages::MillauRialto(params) =>
|
||||
MillauRialtoFull2WayBridge::new(params.into_bridge().await?)?.run().await,
|
||||
RelayHeadersAndMessages::MillauRialtoParachain(params) =>
|
||||
MillauRialtoParachainFull2WayBridge::new(params.into_bridge().await?)?
|
||||
.run()
|
||||
.await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_parse_relay_to_relay_options() {
|
||||
// when
|
||||
let res = RelayHeadersAndMessages::from_iter(vec![
|
||||
"relay-headers-and-messages",
|
||||
"millau-rialto",
|
||||
"--millau-host",
|
||||
"millau-node-alice",
|
||||
"--millau-port",
|
||||
"9944",
|
||||
"--millau-signer",
|
||||
"//Charlie",
|
||||
"--millau-messages-pallet-owner",
|
||||
"//RialtoMessagesOwner",
|
||||
"--millau-transactions-mortality",
|
||||
"64",
|
||||
"--rialto-host",
|
||||
"rialto-node-alice",
|
||||
"--rialto-port",
|
||||
"9944",
|
||||
"--rialto-signer",
|
||||
"//Charlie",
|
||||
"--rialto-messages-pallet-owner",
|
||||
"//MillauMessagesOwner",
|
||||
"--rialto-transactions-mortality",
|
||||
"64",
|
||||
"--lane",
|
||||
"00000000",
|
||||
"--lane",
|
||||
"73776170",
|
||||
"--prometheus-host",
|
||||
"0.0.0.0",
|
||||
]);
|
||||
|
||||
// then
|
||||
assert_eq!(
|
||||
res,
|
||||
RelayHeadersAndMessages::MillauRialto(MillauRialtoHeadersAndMessages {
|
||||
shared: HeadersAndMessagesSharedParams {
|
||||
lane: vec![
|
||||
HexLaneId([0x00, 0x00, 0x00, 0x00]),
|
||||
HexLaneId([0x73, 0x77, 0x61, 0x70])
|
||||
],
|
||||
relayer_mode: RelayerMode::Rational,
|
||||
only_mandatory_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
prometheus_host: "0.0.0.0".into(),
|
||||
prometheus_port: 9616,
|
||||
},
|
||||
},
|
||||
left: MillauConnectionParams {
|
||||
millau_host: "millau-node-alice".into(),
|
||||
millau_port: 9944,
|
||||
millau_secure: false,
|
||||
millau_runtime_version: MillauRuntimeVersionParams {
|
||||
millau_version_mode: RuntimeVersionType::Bundle,
|
||||
millau_spec_version: None,
|
||||
millau_transaction_version: None,
|
||||
},
|
||||
},
|
||||
left_sign: MillauSigningParams {
|
||||
millau_signer: Some("//Charlie".into()),
|
||||
millau_signer_password: None,
|
||||
millau_signer_file: None,
|
||||
millau_signer_password_file: None,
|
||||
millau_transactions_mortality: Some(64),
|
||||
},
|
||||
left_messages_pallet_owner: MillauMessagesPalletOwnerSigningParams {
|
||||
millau_messages_pallet_owner: Some("//RialtoMessagesOwner".into()),
|
||||
millau_messages_pallet_owner_password: None,
|
||||
},
|
||||
left_headers_to_right_sign_override: MillauHeadersToRialtoSigningParams {
|
||||
millau_headers_to_rialto_signer: None,
|
||||
millau_headers_to_rialto_signer_password: None,
|
||||
millau_headers_to_rialto_signer_file: None,
|
||||
millau_headers_to_rialto_signer_password_file: None,
|
||||
millau_headers_to_rialto_transactions_mortality: None,
|
||||
},
|
||||
right: RialtoConnectionParams {
|
||||
rialto_host: "rialto-node-alice".into(),
|
||||
rialto_port: 9944,
|
||||
rialto_secure: false,
|
||||
rialto_runtime_version: RialtoRuntimeVersionParams {
|
||||
rialto_version_mode: RuntimeVersionType::Bundle,
|
||||
rialto_spec_version: None,
|
||||
rialto_transaction_version: None,
|
||||
},
|
||||
},
|
||||
right_sign: RialtoSigningParams {
|
||||
rialto_signer: Some("//Charlie".into()),
|
||||
rialto_signer_password: None,
|
||||
rialto_signer_file: None,
|
||||
rialto_signer_password_file: None,
|
||||
rialto_transactions_mortality: Some(64),
|
||||
},
|
||||
right_messages_pallet_owner: RialtoMessagesPalletOwnerSigningParams {
|
||||
rialto_messages_pallet_owner: Some("//MillauMessagesOwner".into()),
|
||||
rialto_messages_pallet_owner_password: None,
|
||||
},
|
||||
right_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams {
|
||||
rialto_headers_to_millau_signer: None,
|
||||
rialto_headers_to_millau_signer_password: None,
|
||||
rialto_headers_to_millau_signer_file: None,
|
||||
rialto_headers_to_millau_signer_password_file: None,
|
||||
rialto_headers_to_millau_transactions_mortality: None,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_relay_to_parachain_options() {
|
||||
// when
|
||||
let res = RelayHeadersAndMessages::from_iter(vec![
|
||||
"relay-headers-and-messages",
|
||||
"millau-rialto-parachain",
|
||||
"--millau-host",
|
||||
"millau-node-alice",
|
||||
"--millau-port",
|
||||
"9944",
|
||||
"--millau-signer",
|
||||
"//Iden",
|
||||
"--rialto-headers-to-millau-signer",
|
||||
"//Ken",
|
||||
"--millau-messages-pallet-owner",
|
||||
"//RialtoParachainMessagesOwner",
|
||||
"--millau-transactions-mortality",
|
||||
"64",
|
||||
"--rialto-parachain-host",
|
||||
"rialto-parachain-collator-charlie",
|
||||
"--rialto-parachain-port",
|
||||
"9944",
|
||||
"--rialto-parachain-signer",
|
||||
"//George",
|
||||
"--rialto-parachain-messages-pallet-owner",
|
||||
"//MillauMessagesOwner",
|
||||
"--rialto-parachain-transactions-mortality",
|
||||
"64",
|
||||
"--rialto-host",
|
||||
"rialto-node-alice",
|
||||
"--rialto-port",
|
||||
"9944",
|
||||
"--lane",
|
||||
"00000000",
|
||||
"--prometheus-host",
|
||||
"0.0.0.0",
|
||||
]);
|
||||
|
||||
// then
|
||||
assert_eq!(
|
||||
res,
|
||||
RelayHeadersAndMessages::MillauRialtoParachain(
|
||||
MillauRialtoParachainHeadersAndMessages {
|
||||
shared: HeadersAndMessagesSharedParams {
|
||||
lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
|
||||
relayer_mode: RelayerMode::Rational,
|
||||
only_mandatory_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
prometheus_host: "0.0.0.0".into(),
|
||||
prometheus_port: 9616,
|
||||
},
|
||||
},
|
||||
left: MillauConnectionParams {
|
||||
millau_host: "millau-node-alice".into(),
|
||||
millau_port: 9944,
|
||||
millau_secure: false,
|
||||
millau_runtime_version: MillauRuntimeVersionParams {
|
||||
millau_version_mode: RuntimeVersionType::Bundle,
|
||||
millau_spec_version: None,
|
||||
millau_transaction_version: None,
|
||||
},
|
||||
},
|
||||
left_sign: MillauSigningParams {
|
||||
millau_signer: Some("//Iden".into()),
|
||||
millau_signer_password: None,
|
||||
millau_signer_file: None,
|
||||
millau_signer_password_file: None,
|
||||
millau_transactions_mortality: Some(64),
|
||||
},
|
||||
left_messages_pallet_owner: MillauMessagesPalletOwnerSigningParams {
|
||||
millau_messages_pallet_owner: Some("//RialtoParachainMessagesOwner".into()),
|
||||
millau_messages_pallet_owner_password: None,
|
||||
},
|
||||
left_headers_to_right_sign_override:
|
||||
MillauHeadersToRialtoParachainSigningParams {
|
||||
millau_headers_to_rialto_parachain_signer: None,
|
||||
millau_headers_to_rialto_parachain_signer_password: None,
|
||||
millau_headers_to_rialto_parachain_signer_file: None,
|
||||
millau_headers_to_rialto_parachain_signer_password_file: None,
|
||||
millau_headers_to_rialto_parachain_transactions_mortality: None,
|
||||
},
|
||||
right: RialtoParachainConnectionParams {
|
||||
rialto_parachain_host: "rialto-parachain-collator-charlie".into(),
|
||||
rialto_parachain_port: 9944,
|
||||
rialto_parachain_secure: false,
|
||||
rialto_parachain_runtime_version: RialtoParachainRuntimeVersionParams {
|
||||
rialto_parachain_version_mode: RuntimeVersionType::Bundle,
|
||||
rialto_parachain_spec_version: None,
|
||||
rialto_parachain_transaction_version: None,
|
||||
},
|
||||
},
|
||||
right_sign: RialtoParachainSigningParams {
|
||||
rialto_parachain_signer: Some("//George".into()),
|
||||
rialto_parachain_signer_password: None,
|
||||
rialto_parachain_signer_file: None,
|
||||
rialto_parachain_signer_password_file: None,
|
||||
rialto_parachain_transactions_mortality: Some(64),
|
||||
},
|
||||
right_messages_pallet_owner: RialtoParachainMessagesPalletOwnerSigningParams {
|
||||
rialto_parachain_messages_pallet_owner: Some(
|
||||
"//MillauMessagesOwner".into()
|
||||
),
|
||||
rialto_parachain_messages_pallet_owner_password: None,
|
||||
},
|
||||
right_relay_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams {
|
||||
rialto_headers_to_millau_signer: Some("//Ken".into()),
|
||||
rialto_headers_to_millau_signer_password: None,
|
||||
rialto_headers_to_millau_signer_file: None,
|
||||
rialto_headers_to_millau_signer_password_file: None,
|
||||
rialto_headers_to_millau_transactions_mortality: None,
|
||||
},
|
||||
right_parachains_to_left_sign_override: RialtoParachainsToMillauSigningParams {
|
||||
rialto_parachains_to_millau_signer: None,
|
||||
rialto_parachains_to_millau_signer_password: None,
|
||||
rialto_parachains_to_millau_signer_file: None,
|
||||
rialto_parachains_to_millau_signer_password_file: None,
|
||||
rialto_parachains_to_millau_transactions_mortality: None,
|
||||
},
|
||||
right_relay: RialtoConnectionParams {
|
||||
rialto_host: "rialto-node-alice".into(),
|
||||
rialto_port: 9944,
|
||||
rialto_secure: false,
|
||||
rialto_runtime_version: RialtoRuntimeVersionParams {
|
||||
rialto_version_mode: RuntimeVersionType::Bundle,
|
||||
rialto_spec_version: None,
|
||||
rialto_transaction_version: None,
|
||||
},
|
||||
},
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
// Copyright 2019-2022 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/>.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::cli::{
|
||||
bridge::{
|
||||
CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge,
|
||||
RelayToRelayHeadersCliBridge,
|
||||
},
|
||||
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
|
||||
CliChain,
|
||||
};
|
||||
use bp_polkadot_core::parachains::ParaHash;
|
||||
use bp_runtime::BlockNumberOf;
|
||||
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
|
||||
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, Chain, Client, TransactionSignScheme};
|
||||
use sp_core::Pair;
|
||||
use substrate_relay_helper::{
|
||||
finality::SubstrateFinalitySyncPipeline,
|
||||
on_demand::{
|
||||
headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay,
|
||||
},
|
||||
TaggedAccount, TransactionParams,
|
||||
};
|
||||
|
||||
pub struct RelayToParachainBridge<
|
||||
L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge,
|
||||
R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge,
|
||||
> {
|
||||
pub common:
|
||||
Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>,
|
||||
pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>,
|
||||
|
||||
// override for right_relay->left headers signer
|
||||
pub right_headers_to_left_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<<R2L as CliBridgeBase>::Target>>,
|
||||
// override for right->left parachains signer
|
||||
pub right_parachains_to_left_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<<R2L as CliBridgeBase>::Target>>,
|
||||
// override for left->right headers signer
|
||||
pub left_headers_to_right_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<<L2R as CliBridgeBase>::Target>>,
|
||||
}
|
||||
|
||||
macro_rules! declare_relay_to_parachain_bridge_schema {
|
||||
// chain, parachain, relay-chain-of-parachain
|
||||
($left_chain:ident, $right_parachain:ident, $right_chain:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."]
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct [<$left_chain $right_parachain HeadersAndMessages>] {
|
||||
#[structopt(flatten)]
|
||||
shared: HeadersAndMessagesSharedParams,
|
||||
#[structopt(flatten)]
|
||||
left: [<$left_chain ConnectionParams>],
|
||||
// default signer, which is always used to sign messages relay transactions on the left chain
|
||||
#[structopt(flatten)]
|
||||
left_sign: [<$left_chain SigningParams>],
|
||||
// override for right_relay->left headers signer
|
||||
#[structopt(flatten)]
|
||||
right_relay_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>],
|
||||
// override for right->left parachains signer
|
||||
#[structopt(flatten)]
|
||||
right_parachains_to_left_sign_override: [<$right_chain ParachainsTo $left_chain SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
left_messages_pallet_owner: [<$left_chain MessagesPalletOwnerSigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right: [<$right_parachain ConnectionParams>],
|
||||
// default signer, which is always used to sign messages relay transactions on the right chain
|
||||
#[structopt(flatten)]
|
||||
right_sign: [<$right_parachain SigningParams>],
|
||||
// override for left->right headers signer
|
||||
#[structopt(flatten)]
|
||||
left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_parachain SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_messages_pallet_owner: [<$right_parachain MessagesPalletOwnerSigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_relay: [<$right_chain ConnectionParams>],
|
||||
}
|
||||
|
||||
impl [<$left_chain $right_parachain HeadersAndMessages>] {
|
||||
async fn into_bridge<
|
||||
Left: TransactionSignScheme + CliChain<KeyPair = AccountKeyPairOf<Left>>,
|
||||
Right: TransactionSignScheme + CliChain<KeyPair = AccountKeyPairOf<Right>>,
|
||||
RightRelay: TransactionSignScheme + CliChain,
|
||||
L2R: CliBridgeBase<Source = Left, Target = Right> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
|
||||
R2L: CliBridgeBase<Source = Right, Target = Left>
|
||||
+ MessagesCliBridge
|
||||
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
|
||||
>(
|
||||
self,
|
||||
) -> anyhow::Result<RelayToParachainBridge<L2R, R2L>> {
|
||||
Ok(RelayToParachainBridge {
|
||||
common: Full2WayBridgeCommonParams {
|
||||
shared: self.shared,
|
||||
left: self.left.into_client::<Left>().await?,
|
||||
left_sign: self.left_sign.to_keypair::<Left>()?,
|
||||
left_transactions_mortality: self.left_sign.transactions_mortality()?,
|
||||
left_messages_pallet_owner: self.left_messages_pallet_owner.to_keypair::<Left>()?,
|
||||
at_left_accounts: vec![],
|
||||
right: self.right.into_client::<Right>().await?,
|
||||
right_sign: self.right_sign.to_keypair::<Right>()?,
|
||||
right_transactions_mortality: self.right_sign.transactions_mortality()?,
|
||||
right_messages_pallet_owner: self.right_messages_pallet_owner.to_keypair::<Right>()?,
|
||||
at_right_accounts: vec![],
|
||||
},
|
||||
right_relay: self.right_relay.into_client::<RightRelay>().await?,
|
||||
right_headers_to_left_transaction_params: self
|
||||
.right_relay_headers_to_left_sign_override
|
||||
.transaction_params_or::<Left, _>(
|
||||
&self.left_sign,
|
||||
)?,
|
||||
right_parachains_to_left_transaction_params: self
|
||||
.right_parachains_to_left_sign_override
|
||||
.transaction_params_or::<Left, _>(
|
||||
&self.left_sign,
|
||||
)?,
|
||||
left_headers_to_right_transaction_params: self
|
||||
.left_headers_to_right_sign_override
|
||||
.transaction_params_or::<Right, _>(&self.right_sign)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<
|
||||
Left: Chain + TransactionSignScheme<Chain = Left> + CliChain<KeyPair = AccountKeyPairOf<Left>>,
|
||||
Right: Chain<Hash = ParaHash>
|
||||
+ TransactionSignScheme<Chain = Right>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Right>>,
|
||||
RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
|
||||
+ TransactionSignScheme
|
||||
+ CliChain,
|
||||
L2R: CliBridgeBase<Source = Left, Target = Right>
|
||||
+ MessagesCliBridge
|
||||
+ RelayToRelayHeadersCliBridge,
|
||||
R2L: CliBridgeBase<Source = Right, Target = Left>
|
||||
+ MessagesCliBridge
|
||||
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
|
||||
> Full2WayBridgeBase for RelayToParachainBridge<L2R, R2L>
|
||||
where
|
||||
AccountIdOf<Left>: From<<AccountKeyPairOf<Left> as Pair>::Public>,
|
||||
AccountIdOf<Right>: From<<AccountKeyPairOf<Right> as Pair>::Public>,
|
||||
{
|
||||
type Params = RelayToParachainBridge<L2R, R2L>;
|
||||
type Left = Left;
|
||||
type Right = Right;
|
||||
|
||||
fn common(&self) -> &Full2WayBridgeCommonParams<Left, Right> {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right> {
|
||||
&mut self.common
|
||||
}
|
||||
|
||||
async fn start_on_demand_headers_relayers(
|
||||
&mut self,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Self::Left>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Self::Right>>>,
|
||||
)> {
|
||||
self.common.at_left_accounts.push(TaggedAccount::Headers {
|
||||
id: self.right_headers_to_left_transaction_params.signer.public().into(),
|
||||
bridged_chain: RightRelay::NAME.to_string(),
|
||||
});
|
||||
self.common.at_left_accounts.push(TaggedAccount::Parachains {
|
||||
id: self.right_parachains_to_left_transaction_params.signer.public().into(),
|
||||
bridged_chain: RightRelay::NAME.to_string(),
|
||||
});
|
||||
self.common.at_right_accounts.push(TaggedAccount::Headers {
|
||||
id: self.left_headers_to_right_transaction_params.signer.public().into(),
|
||||
bridged_chain: Left::NAME.to_string(),
|
||||
});
|
||||
|
||||
<L2R as RelayToRelayHeadersCliBridge>::Finality::start_relay_guards(
|
||||
&self.common.right,
|
||||
&self.left_headers_to_right_transaction_params,
|
||||
self.common.right.can_start_version_guard(),
|
||||
)
|
||||
.await?;
|
||||
<R2L as ParachainToRelayHeadersCliBridge>::RelayFinality::start_relay_guards(
|
||||
&self.common.left,
|
||||
&self.right_headers_to_left_transaction_params,
|
||||
self.common.left.can_start_version_guard(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let left_to_right_on_demand_headers =
|
||||
OnDemandHeadersRelay::new::<<L2R as RelayToRelayHeadersCliBridge>::Finality>(
|
||||
self.common.left.clone(),
|
||||
self.common.right.clone(),
|
||||
self.left_headers_to_right_transaction_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
);
|
||||
let right_relay_to_left_on_demand_headers =
|
||||
OnDemandHeadersRelay::new::<<R2L as ParachainToRelayHeadersCliBridge>::RelayFinality>(
|
||||
self.right_relay.clone(),
|
||||
self.common.left.clone(),
|
||||
self.right_headers_to_left_transaction_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
);
|
||||
let right_to_left_on_demand_parachains = OnDemandParachainsRelay::new::<
|
||||
<R2L as ParachainToRelayHeadersCliBridge>::ParachainFinality,
|
||||
>(
|
||||
self.right_relay.clone(),
|
||||
self.common.left.clone(),
|
||||
self.right_parachains_to_left_transaction_params.clone(),
|
||||
Arc::new(right_relay_to_left_on_demand_headers),
|
||||
);
|
||||
|
||||
Ok((
|
||||
Arc::new(left_to_right_on_demand_headers),
|
||||
Arc::new(right_to_left_on_demand_parachains),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
// Copyright 2019-2022 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/>.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::cli::{
|
||||
bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge},
|
||||
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
|
||||
CliChain,
|
||||
};
|
||||
use bp_runtime::BlockNumberOf;
|
||||
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, Chain, TransactionSignScheme};
|
||||
use sp_core::Pair;
|
||||
use substrate_relay_helper::{
|
||||
finality::SubstrateFinalitySyncPipeline,
|
||||
on_demand::{headers::OnDemandHeadersRelay, OnDemandRelay},
|
||||
TaggedAccount, TransactionParams,
|
||||
};
|
||||
|
||||
pub struct RelayToRelayBridge<
|
||||
L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge,
|
||||
R2L: MessagesCliBridge + RelayToRelayHeadersCliBridge,
|
||||
> {
|
||||
pub common:
|
||||
Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>,
|
||||
// override for right->left headers signer
|
||||
pub right_to_left_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<<R2L as CliBridgeBase>::Target>>,
|
||||
// override for left->right headers signer
|
||||
pub left_to_right_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<<L2R as CliBridgeBase>::Target>>,
|
||||
}
|
||||
|
||||
macro_rules! declare_relay_to_relay_bridge_schema {
|
||||
($left_chain:ident, $right_chain:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $left_chain " and " $right_chain " headers+messages relay params."]
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct [<$left_chain $right_chain HeadersAndMessages>] {
|
||||
#[structopt(flatten)]
|
||||
shared: HeadersAndMessagesSharedParams,
|
||||
// default signer, which is always used to sign messages relay transactions on the left chain
|
||||
#[structopt(flatten)]
|
||||
left: [<$left_chain ConnectionParams>],
|
||||
// override for right->left headers signer
|
||||
#[structopt(flatten)]
|
||||
right_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
left_sign: [<$left_chain SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
left_messages_pallet_owner: [<$left_chain MessagesPalletOwnerSigningParams>],
|
||||
// default signer, which is always used to sign messages relay transactions on the right chain
|
||||
#[structopt(flatten)]
|
||||
right: [<$right_chain ConnectionParams>],
|
||||
// override for left->right headers signer
|
||||
#[structopt(flatten)]
|
||||
left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_chain SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_sign: [<$right_chain SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right_messages_pallet_owner: [<$right_chain MessagesPalletOwnerSigningParams>],
|
||||
}
|
||||
|
||||
impl [<$left_chain $right_chain HeadersAndMessages>] {
|
||||
async fn into_bridge<
|
||||
Left: TransactionSignScheme + CliChain<KeyPair = AccountKeyPairOf<Left>>,
|
||||
Right: TransactionSignScheme + CliChain<KeyPair = AccountKeyPairOf<Right>>,
|
||||
L2R: CliBridgeBase<Source = Left, Target = Right> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
|
||||
R2L: CliBridgeBase<Source = Right, Target = Left> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
|
||||
>(
|
||||
self,
|
||||
) -> anyhow::Result<RelayToRelayBridge<L2R, R2L>> {
|
||||
Ok(RelayToRelayBridge {
|
||||
common: Full2WayBridgeCommonParams {
|
||||
shared: self.shared,
|
||||
left: self.left.into_client::<Left>().await?,
|
||||
left_sign: self.left_sign.to_keypair::<Left>()?,
|
||||
left_transactions_mortality: self.left_sign.transactions_mortality()?,
|
||||
left_messages_pallet_owner: self.left_messages_pallet_owner.to_keypair::<Left>()?,
|
||||
at_left_accounts: vec![],
|
||||
right: self.right.into_client::<Right>().await?,
|
||||
right_sign: self.right_sign.to_keypair::<Right>()?,
|
||||
right_transactions_mortality: self.right_sign.transactions_mortality()?,
|
||||
right_messages_pallet_owner: self.right_messages_pallet_owner.to_keypair::<Right>()?,
|
||||
at_right_accounts: vec![],
|
||||
},
|
||||
|
||||
right_to_left_transaction_params: self
|
||||
.right_headers_to_left_sign_override
|
||||
.transaction_params_or::<Left, _>(&self.left_sign)?,
|
||||
left_to_right_transaction_params: self
|
||||
.left_headers_to_right_sign_override
|
||||
.transaction_params_or::<Right, _>(&self.right_sign)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<
|
||||
Left: Chain + TransactionSignScheme<Chain = Left> + CliChain<KeyPair = AccountKeyPairOf<Left>>,
|
||||
Right: Chain + TransactionSignScheme<Chain = Right> + CliChain<KeyPair = AccountKeyPairOf<Right>>,
|
||||
L2R: CliBridgeBase<Source = Left, Target = Right>
|
||||
+ MessagesCliBridge
|
||||
+ RelayToRelayHeadersCliBridge,
|
||||
R2L: CliBridgeBase<Source = Right, Target = Left>
|
||||
+ MessagesCliBridge
|
||||
+ RelayToRelayHeadersCliBridge,
|
||||
> Full2WayBridgeBase for RelayToRelayBridge<L2R, R2L>
|
||||
where
|
||||
AccountIdOf<Left>: From<<AccountKeyPairOf<Left> as Pair>::Public>,
|
||||
AccountIdOf<Right>: From<<AccountKeyPairOf<Right> as Pair>::Public>,
|
||||
{
|
||||
type Params = RelayToRelayBridge<L2R, R2L>;
|
||||
type Left = Left;
|
||||
type Right = Right;
|
||||
|
||||
fn common(&self) -> &Full2WayBridgeCommonParams<Left, Right> {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right> {
|
||||
&mut self.common
|
||||
}
|
||||
|
||||
async fn start_on_demand_headers_relayers(
|
||||
&mut self,
|
||||
) -> anyhow::Result<(
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Self::Left>>>,
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<Self::Right>>>,
|
||||
)> {
|
||||
self.common.at_right_accounts.push(TaggedAccount::Headers {
|
||||
id: self.left_to_right_transaction_params.signer.public().into(),
|
||||
bridged_chain: Self::Left::NAME.to_string(),
|
||||
});
|
||||
self.common.at_left_accounts.push(TaggedAccount::Headers {
|
||||
id: self.right_to_left_transaction_params.signer.public().into(),
|
||||
bridged_chain: Self::Right::NAME.to_string(),
|
||||
});
|
||||
|
||||
<L2R as RelayToRelayHeadersCliBridge>::Finality::start_relay_guards(
|
||||
&self.common.right,
|
||||
&self.left_to_right_transaction_params,
|
||||
self.common.right.can_start_version_guard(),
|
||||
)
|
||||
.await?;
|
||||
<R2L as RelayToRelayHeadersCliBridge>::Finality::start_relay_guards(
|
||||
&self.common.left,
|
||||
&self.right_to_left_transaction_params,
|
||||
self.common.left.can_start_version_guard(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let left_to_right_on_demand_headers =
|
||||
OnDemandHeadersRelay::new::<<L2R as RelayToRelayHeadersCliBridge>::Finality>(
|
||||
self.common.left.clone(),
|
||||
self.common.right.clone(),
|
||||
self.left_to_right_transaction_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
);
|
||||
let right_to_left_on_demand_headers =
|
||||
OnDemandHeadersRelay::new::<<R2L as RelayToRelayHeadersCliBridge>::Finality>(
|
||||
self.common.right.clone(),
|
||||
self.common.left.clone(),
|
||||
self.right_to_left_transaction_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
);
|
||||
|
||||
Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_headers)))
|
||||
}
|
||||
}
|
||||
@@ -20,16 +20,10 @@ use structopt::StructOpt;
|
||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_substrate_client::{AccountKeyPairOf, ChainBase, TransactionSignScheme};
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::{MessagesRelayParams, SubstrateMessageLane},
|
||||
TransactionParams,
|
||||
};
|
||||
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, BalanceOf, TransactionSignScheme};
|
||||
use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams};
|
||||
|
||||
use crate::cli::{
|
||||
bridge::*, CliChain, HexLaneId, PrometheusParams, SourceConnectionParams, SourceSigningParams,
|
||||
TargetConnectionParams, TargetSigningParams,
|
||||
};
|
||||
use crate::cli::{bridge::*, chain_schema::*, CliChain, HexLaneId, PrometheusParams};
|
||||
|
||||
/// Relayer operating mode.
|
||||
#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -79,16 +73,15 @@ trait MessagesRelayer: MessagesCliBridge
|
||||
where
|
||||
Self::Source: TransactionSignScheme<Chain = Self::Source>
|
||||
+ CliChain<KeyPair = AccountKeyPairOf<Self::Source>>,
|
||||
<Self::Source as ChainBase>::AccountId: From<<AccountKeyPairOf<Self::Source> as Pair>::Public>,
|
||||
<Self::Target as ChainBase>::AccountId: From<<AccountKeyPairOf<Self::Target> as Pair>::Public>,
|
||||
<Self::Source as ChainBase>::Balance: TryFrom<<Self::Target as ChainBase>::Balance>,
|
||||
Self::MessagesLane: SubstrateMessageLane<RelayStrategy = MixStrategy>,
|
||||
AccountIdOf<Self::Source>: From<<AccountKeyPairOf<Self::Source> as Pair>::Public>,
|
||||
AccountIdOf<Self::Target>: From<<AccountKeyPairOf<Self::Target> as Pair>::Public>,
|
||||
BalanceOf<Self::Source>: TryFrom<BalanceOf<Self::Target>>,
|
||||
{
|
||||
async fn relay_messages(data: RelayMessages) -> anyhow::Result<()> {
|
||||
let source_client = data.source.to_client::<Self::Source>().await?;
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let source_sign = data.source_sign.to_keypair::<Self::Source>()?;
|
||||
let source_transactions_mortality = data.source_sign.transactions_mortality()?;
|
||||
let target_client = data.target.to_client::<Self::Target>().await?;
|
||||
let target_client = data.target.into_client::<Self::Target>().await?;
|
||||
let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
|
||||
let target_transactions_mortality = data.target_sign.transactions_mortality()?;
|
||||
let relayer_mode = data.relayer_mode.into();
|
||||
|
||||
@@ -16,27 +16,22 @@
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_polkadot_core::parachains::ParaId;
|
||||
use pallet_bridge_parachains::RelayBlockNumber;
|
||||
use parachains_relay::{
|
||||
parachains_loop::{ParachainSyncParams, SourceClient, TargetClient},
|
||||
ParachainsPipeline,
|
||||
};
|
||||
use relay_substrate_client::{Chain, RelayChain};
|
||||
use parachains_relay::parachains_loop::{ParachainSyncParams, SourceClient, TargetClient};
|
||||
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
|
||||
use structopt::StructOpt;
|
||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||
use substrate_relay_helper::{
|
||||
parachains::{
|
||||
source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter,
|
||||
SubstrateParachainsPipeline,
|
||||
},
|
||||
parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter},
|
||||
TransactionParams,
|
||||
};
|
||||
|
||||
use crate::cli::{
|
||||
bridge::{CliBridgeBase, RialtoParachainToMillauCliBridge, WestmintToMillauCliBridge},
|
||||
CliChain, PrometheusParams, SourceConnectionParams, TargetConnectionParams,
|
||||
TargetSigningParams,
|
||||
bridge::{
|
||||
ParachainToRelayHeadersCliBridge, RialtoParachainToMillauCliBridge,
|
||||
WestmintToMillauCliBridge,
|
||||
},
|
||||
chain_schema::*,
|
||||
PrometheusParams,
|
||||
};
|
||||
|
||||
/// Start parachain heads relayer process.
|
||||
@@ -64,29 +59,23 @@ pub enum RelayParachainsBridge {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
trait ParachainsRelayer: CliBridgeBase
|
||||
trait ParachainsRelayer: ParachainToRelayHeadersCliBridge
|
||||
where
|
||||
ParachainsSource<Self::Pipeline>: SourceClient<ParachainsPipelineAdapter<Self::Pipeline>>,
|
||||
ParachainsTarget<Self::Pipeline>: TargetClient<ParachainsPipelineAdapter<Self::Pipeline>>,
|
||||
ParachainsSource<Self::ParachainFinality>:
|
||||
SourceClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
|
||||
ParachainsTarget<Self::ParachainFinality>:
|
||||
TargetClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
|
||||
{
|
||||
type SourceRelay: Chain<BlockNumber = RelayBlockNumber> + CliChain + RelayChain;
|
||||
type Pipeline: SubstrateParachainsPipeline<
|
||||
SourceParachain = Self::Source,
|
||||
TargetChain = Self::Target,
|
||||
SourceRelayChain = Self::SourceRelay,
|
||||
TransactionSignScheme = Self::Target,
|
||||
> + ParachainsPipeline<SourceChain = Self::SourceRelay, TargetChain = Self::Target>;
|
||||
|
||||
async fn relay_headers(data: RelayParachains) -> anyhow::Result<()> {
|
||||
let source_client = data.source.to_client::<Self::SourceRelay>().await?;
|
||||
let source_client = ParachainsSource::<Self::Pipeline>::new(source_client, None);
|
||||
let source_client = data.source.into_client::<Self::SourceRelay>().await?;
|
||||
let source_client = ParachainsSource::<Self::ParachainFinality>::new(source_client, None);
|
||||
|
||||
let target_transaction_params = TransactionParams {
|
||||
signer: data.target_sign.to_keypair::<Self::Target>()?,
|
||||
mortality: data.target_sign.target_transactions_mortality,
|
||||
};
|
||||
let target_client = data.target.to_client::<Self::Target>().await?;
|
||||
let target_client = ParachainsTarget::<Self::Pipeline>::new(
|
||||
let target_client = data.target.into_client::<Self::Target>().await?;
|
||||
let target_client = ParachainsTarget::<Self::ParachainFinality>::new(
|
||||
target_client.clone(),
|
||||
target_transaction_params,
|
||||
);
|
||||
@@ -110,15 +99,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl ParachainsRelayer for RialtoParachainToMillauCliBridge {
|
||||
type SourceRelay = relay_rialto_client::Rialto;
|
||||
type Pipeline = crate::chains::rialto_parachains_to_millau::RialtoParachainsToMillau;
|
||||
}
|
||||
impl ParachainsRelayer for RialtoParachainToMillauCliBridge {}
|
||||
|
||||
impl ParachainsRelayer for WestmintToMillauCliBridge {
|
||||
type SourceRelay = relay_westend_client::Westend;
|
||||
type Pipeline = crate::chains::westend_parachains_to_millau::WestendParachainsToMillau;
|
||||
}
|
||||
impl ParachainsRelayer for WestmintToMillauCliBridge {}
|
||||
|
||||
impl RelayParachains {
|
||||
/// Run the command.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::cli::{Balance, TargetConnectionParams, TargetSigningParams};
|
||||
use crate::cli::{chain_schema::*, Balance};
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use num_traits::{One, Zero};
|
||||
@@ -102,7 +102,7 @@ impl ResubmitTransactions {
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
select_bridge!(self.chain, {
|
||||
let relay_loop_name = format!("ResubmitTransactions{}", Target::NAME);
|
||||
let client = self.target.to_client::<Target>().await?;
|
||||
let client = self.target.into_client::<Target>().await?;
|
||||
let transaction_params = TransactionParams {
|
||||
signer: self.target_sign.to_keypair::<Target>()?,
|
||||
mortality: self.target_sign.target_transactions_mortality,
|
||||
|
||||
@@ -16,15 +16,16 @@
|
||||
|
||||
use crate::cli::{
|
||||
bridge::{FullBridge, MessagesCliBridge, *},
|
||||
chain_schema::*,
|
||||
encode_message::{self, CliEncodeMessage},
|
||||
estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride},
|
||||
Balance, CliChain, HexBytes, HexLaneId, SourceConnectionParams, SourceSigningParams,
|
||||
Balance, CliChain, HexBytes, HexLaneId,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use bp_runtime::AccountIdOf;
|
||||
use codec::Encode;
|
||||
use relay_substrate_client::{
|
||||
AccountKeyPairOf, Chain, ChainBase, SignParam, TransactionSignScheme, UnsignedTransaction,
|
||||
AccountIdOf, AccountKeyPairOf, Chain, ChainBase, SignParam, TransactionSignScheme,
|
||||
UnsignedTransaction,
|
||||
};
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_runtime::AccountId32;
|
||||
@@ -95,7 +96,7 @@ where
|
||||
async fn send_message(data: SendMessage) -> anyhow::Result<()> {
|
||||
let payload = encode_message::encode_message::<Self::Source, Self::Target>(&data.message)?;
|
||||
|
||||
let source_client = data.source.to_client::<Self::Source>().await?;
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let source_sign = data.source_sign.to_keypair::<Self::Source>()?;
|
||||
|
||||
let lane = data.lane.clone().into();
|
||||
|
||||
@@ -756,6 +756,15 @@ impl<C: Chain> Client<C> {
|
||||
let client = self.client.clone();
|
||||
self.tokio.spawn(async move { make_jsonrpsee_future(client).await }).await?
|
||||
}
|
||||
|
||||
/// Returns `true` if version guard can be started.
|
||||
///
|
||||
/// There's no reason to run version guard when version mode is set to `Auto`. It can
|
||||
/// lead to relay shutdown when chain is upgraded, even though we have explicitly
|
||||
/// said that we don't want to shutdown.
|
||||
pub fn can_start_version_guard(&self) -> bool {
|
||||
!matches!(self.chain_runtime_version, ChainRuntimeVersion::Auto)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> Subscription<T> {
|
||||
|
||||
@@ -274,7 +274,7 @@ pub fn standalone_metrics<P: SubstrateMessageLane>(
|
||||
pub async fn add_relay_balances_metrics<C: ChainWithBalances>(
|
||||
client: Client<C>,
|
||||
metrics: MetricsParams,
|
||||
relay_accounts: Vec<TaggedAccount<AccountIdOf<C>>>,
|
||||
relay_accounts: &Vec<TaggedAccount<AccountIdOf<C>>>,
|
||||
) -> anyhow::Result<MetricsParams>
|
||||
where
|
||||
BalanceOf<C>: Into<u128> + std::fmt::Debug,
|
||||
|
||||
Reference in New Issue
Block a user