From 9da22df16b1eb866b4f9fb24951cfd8399af2b18 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 22 Nov 2022 11:48:20 +0300 Subject: [PATCH] Complex parachain <> parachain relay (#1637) * complex parachain <> parachain relay * spelling --- .../src/cli/relay_headers_and_messages/mod.rs | 44 ++- .../parachain_to_parachain.rs | 281 ++++++++++++++++++ .../relay_to_parachain.rs | 43 ++- .../relay_to_relay.rs | 8 +- 4 files changed, 357 insertions(+), 19 deletions(-) create mode 100644 bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs index 49e9c5aa1560..bdc92f984daf 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs @@ -23,6 +23,8 @@ //! `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 parachain_to_parachain; #[macro_use] mod relay_to_relay; #[macro_use] @@ -78,20 +80,26 @@ pub struct HeadersAndMessagesSharedParams { pub prometheus_params: PrometheusParams, } +/// Bridge parameters, shared by all bridge types. pub struct Full2WayBridgeCommonParams< Left: ChainWithTransactions + CliChain, Right: ChainWithTransactions + CliChain, > { + /// Shared parameters. pub shared: HeadersAndMessagesSharedParams, + /// Parameters of the left chain. pub left: BridgeEndCommonParams, + /// Parameters of the right chain. pub right: BridgeEndCommonParams, + /// Common metric parameters. pub metrics_params: MetricsParams, } impl Full2WayBridgeCommonParams { + /// Creates new bridge parameters from its components. pub fn new>( shared: HeadersAndMessagesSharedParams, left: BridgeEndCommonParams, @@ -105,14 +113,21 @@ impl { + /// Chain client. pub client: Client, + /// Transactions signer. pub sign: AccountKeyPairOf, + /// Transactions mortality. pub transactions_mortality: Option, + /// Account that "owns" messages pallet. pub messages_pallet_owner: Option>, + /// Accounts, which balances are exposed as metrics by the relay process. pub accounts: Vec>>, } +/// All data of the bidirectional complex relay. struct FullBridge< 'a, Source: ChainWithTransactions + CliChain, @@ -136,6 +151,7 @@ where AccountIdOf: From< as Pair>::Public>, BalanceOf: TryFrom> + Into, { + /// Construct complex relay given it components. fn new( source: &'a mut BridgeEndCommonParams, target: &'a mut BridgeEndCommonParams, @@ -144,6 +160,7 @@ where Self { source, target, metrics_params, _phantom_data: Default::default() } } + /// Returns message relay parameters. fn messages_relay_params( &self, source_to_target_headers_relay: Arc>>, @@ -182,6 +199,12 @@ declare_chain_cli_schema!(RialtoParachainsToMillau, rialto_parachains_to_millau) declare_relay_to_relay_bridge_schema!(Millau, Rialto); declare_relay_to_parachain_bridge_schema!(Millau, RialtoParachain, Rialto); +/// Base portion of the bidirectional complex relay. +/// +/// This main purpose of extracting this trait is that in different relays the implementation +/// of `start_on_demand_headers_relayers` method will be different. But the number of +/// implementations is limited to relay <> relay, parachain <> relay and parachain <> parachain. +/// This trait allows us to reuse these implementations in different bridges. #[async_trait] trait Full2WayBridgeBase: Sized + Send + Sync { /// The CLI params for the bridge. @@ -191,10 +214,13 @@ trait Full2WayBridgeBase: Sized + Send + Sync { /// The right destination chain (it can be a relay or a parachain). type Right: ChainWithTransactions + CliChain>; + /// Reference to common relay parameters. fn common(&self) -> &Full2WayBridgeCommonParams; + /// Mutable reference to common relay parameters. fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams; + /// Start on-demand headers relays. async fn start_on_demand_headers_relayers( &mut self, ) -> anyhow::Result<( @@ -203,6 +229,7 @@ trait Full2WayBridgeBase: Sized + Send + Sync { )>; } +/// Bidirectional complex relay. #[async_trait] trait Full2WayBridge: Sized + Sync where @@ -211,6 +238,7 @@ where BalanceOf: TryFrom> + Into, BalanceOf: TryFrom> + Into, { + /// Base portion of the bidirectional complex relay. type Base: Full2WayBridgeBase; /// The left relay chain. @@ -222,17 +250,21 @@ where + ChainWithBalances + CliChain>; - // Left to Right bridge + /// Left to Right bridge. type L2R: MessagesCliBridge; - // Right to Left bridge + /// Right to Left bridge type R2L: MessagesCliBridge; + /// Construct new bridge. fn new(params: ::Params) -> anyhow::Result; + /// Reference to the base relay portion. fn base(&self) -> &Self::Base; + /// Mutable reference to the base relay portion. fn mut_base(&mut self) -> &mut Self::Base; + /// Creates and returns Left to Right complex relay. fn left_to_right(&mut self) -> FullBridge { let common = self.mut_base().mut_common(); FullBridge::<_, _, Self::L2R>::new( @@ -242,6 +274,7 @@ where ) } + /// Creates and returns Right to Left complex relay. fn right_to_left(&mut self) -> FullBridge { let common = self.mut_base().mut_common(); FullBridge::<_, _, Self::R2L>::new( @@ -251,6 +284,7 @@ where ) } + /// Start complex relay. async fn run(&mut self) -> anyhow::Result<()> { // Register standalone metrics. { @@ -324,6 +358,7 @@ where } } +/// Millau <> Rialto complex relay. pub struct MillauRialtoFull2WayBridge { base: ::Base, } @@ -349,6 +384,7 @@ impl Full2WayBridge for MillauRialtoFull2WayBridge { } } +/// Millau <> RialtoParachain complex relay. pub struct MillauRialtoParachainFull2WayBridge { base: ::Base, } @@ -374,10 +410,12 @@ impl Full2WayBridge for MillauRialtoParachainFull2WayBridge { } } -/// Start headers+messages relayer process. +/// Complex headers+messages relay. #[derive(Debug, PartialEq, StructOpt)] pub enum RelayHeadersAndMessages { + /// Millau <> Rialto relay. MillauRialto(MillauRialtoHeadersAndMessages), + /// Millau <> RialtoParachain relay. MillauRialtoParachain(MillauRialtoParachainHeadersAndMessages), } diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs new file mode 100644 index 000000000000..9adc8fd66243 --- /dev/null +++ b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs @@ -0,0 +1,281 @@ +// 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 . + +#![allow(unused_macros)] // TODO (https://github.com/paritytech/parity-bridges-common/issues/1629): remove me + +use async_trait::async_trait; +use std::sync::Arc; + +use crate::cli::{ + bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}, + 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, ChainWithTransactions, Client}; +use sp_core::Pair; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, + on_demand::{ + headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, + }, + TaggedAccount, TransactionParams, +}; + +/// A base relay between two parachain from different consensus systems. +/// +/// Such relay starts 2 messages relay. It also starts 2 on-demand header relays and 2 on-demand +/// parachain heads relay. +pub struct ParachainToParachainBridge< + L2R: MessagesCliBridge + ParachainToRelayHeadersCliBridge, + R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge, +> { + /// Parameters that are shared by all bridge types. + pub common: + Full2WayBridgeCommonParams<::Target, ::Target>, + /// Client of the left relay chain. + pub left_relay: Client<::SourceRelay>, + /// Client of the right relay chain. + pub right_relay: Client<::SourceRelay>, + + /// Override for right_relay->left headers signer. + pub right_headers_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for left_relay->right headers signer. + pub left_headers_to_right_transaction_params: + TransactionParams::Target>>, + + /// Override for right->left parachains signer. + pub right_parachains_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for left->right parachains signer. + pub left_parachains_to_right_transaction_params: + TransactionParams::Target>>, +} + +macro_rules! declare_parachain_to_parachain_bridge_schema { + // left-parachain, relay-chain-of-left-parachain, right-parachain, relay-chain-of-right-parachain + ($left_parachain:ident, $left_chain:ident, $right_parachain:ident, $right_chain:ident) => { + bp_runtime::paste::item! { + #[doc = $left_parachain ", " $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."] + #[derive(Debug, PartialEq, StructOpt)] + pub struct [<$left_parachain $right_parachain HeadersAndMessages>] { + // shared parameters + #[structopt(flatten)] + shared: HeadersAndMessagesSharedParams, + + #[structopt(flatten)] + left: [<$left_parachain ConnectionParams>], + #[structopt(flatten)] + left_relay: [<$left_chain ConnectionParams>], + + // default signer, which is always used to sign messages relay transactions on the left chain + #[structopt(flatten)] + left_sign: [<$left_parachain SigningParams>], + // signer used to sign parameter update transactions at the left parachain + #[structopt(flatten)] + left_messages_pallet_owner: [<$left_parachain MessagesPalletOwnerSigningParams>], + + #[structopt(flatten)] + right: [<$right_parachain ConnectionParams>], + #[structopt(flatten)] + right_relay: [<$right_chain ConnectionParams>], + + // default signer, which is always used to sign messages relay transactions on the right chain + #[structopt(flatten)] + right_sign: [<$right_parachain SigningParams>], + // signer used to sign parameter update transactions at the right parachain + #[structopt(flatten)] + right_messages_pallet_owner: [<$right_parachain MessagesPalletOwnerSigningParams>], + + // override for right_relay->left-parachain headers signer + #[structopt(flatten)] + right_relay_headers_to_left_sign_override: [<$right_chain HeadersTo $left_parachain SigningParams>], + // override for left_relay->right-parachain headers signer + #[structopt(flatten)] + left_relay_headers_to_right_sign_override: [<$left_chain HeadersTo $right_parachain SigningParams>], + + // override for right->left parachains signer + #[structopt(flatten)] + right_parachains_to_left_sign_override: [<$right_chain ParachainsTo $left_parachain SigningParams>], + // override for left->right parachains signer + #[structopt(flatten)] + left_parachains_to_right_sign_override: [<$left_chain ParachainsTo $right_parachain SigningParams>], + } + + impl [<$left_chain $right_parachain HeadersAndMessages>] { + async fn into_bridge< + Left: ChainWithTransactions + CliChain>, + LeftRelay: CliChain, + Right: ChainWithTransactions + CliChain>, + RightRelay: CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + >( + self, + ) -> anyhow::Result> { + Ok(ParachainToParachainBridge { + common: Full2WayBridgeCommonParams::new::( + self.shared, + BridgeEndCommonParams { + client: self.left.into_client::().await?, + sign: self.left_sign.to_keypair::()?, + transactions_mortality: self.left_sign.transactions_mortality()?, + messages_pallet_owner: self.left_messages_pallet_owner.to_keypair::()?, + accounts: vec![], + }, + BridgeEndCommonParams { + client: self.right.into_client::().await?, + sign: self.right_sign.to_keypair::()?, + transactions_mortality: self.right_sign.transactions_mortality()?, + messages_pallet_owner: self.right_messages_pallet_owner.to_keypair::()?, + accounts: vec![], + }, + )?, + left_relay: self.left_relay.into_client::().await?, + right_relay: self.right_relay.into_client::().await?, + right_headers_to_left_transaction_params: self + .right_relay_headers_to_left_sign_override + .transaction_params_or::(&self.left_sign)?, + left_headers_to_right_transaction_params: self + .left_relay_headers_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + right_parachains_to_left_transaction_params: self + .right_parachains_to_left_sign_override + .transaction_params_or::(&self.left_sign)?, + left_parachains_to_right_transaction_params: self + .left_parachains_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + }) + } + } + } + }; +} + +#[async_trait] +impl< + Left: Chain + ChainWithTransactions + CliChain>, + Right: Chain + + ChainWithTransactions + + CliChain>, + LeftRelay: Chain + + CliChain, + RightRelay: Chain + + CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + > Full2WayBridgeBase for ParachainToParachainBridge +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, +{ + type Params = ParachainToParachainBridge; + type Left = Left; + type Right = Right; + + fn common(&self) -> &Full2WayBridgeCommonParams { + &self.common + } + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams { + &mut self.common + } + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>>, + Arc>>, + )> { + self.common.left.accounts.push(TaggedAccount::Headers { + id: self.right_headers_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.left.accounts.push(TaggedAccount::Parachains { + id: self.right_parachains_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.right.accounts.push(TaggedAccount::Headers { + id: self.left_headers_to_right_transaction_params.signer.public().into(), + bridged_chain: Left::NAME.to_string(), + }); + self.common.right.accounts.push(TaggedAccount::Parachains { + id: self.left_parachains_to_right_transaction_params.signer.public().into(), + bridged_chain: LeftRelay::NAME.to_string(), + }); + + ::RelayFinality::start_relay_guards( + &self.common.right.client, + &self.left_headers_to_right_transaction_params, + self.common.right.client.can_start_version_guard(), + ) + .await?; + ::RelayFinality::start_relay_guards( + &self.common.left.client, + &self.right_headers_to_left_transaction_params, + self.common.left.client.can_start_version_guard(), + ) + .await?; + + let left_relay_to_right_on_demand_headers = + OnDemandHeadersRelay::new::<::RelayFinality>( + self.left_relay.clone(), + self.common.right.client.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::<::RelayFinality>( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_headers_to_left_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + ); + + let left_to_right_on_demand_parachains = OnDemandParachainsRelay::new::< + ::ParachainFinality, + >( + self.left_relay.clone(), + self.common.right.client.clone(), + self.left_parachains_to_right_transaction_params.clone(), + Arc::new(left_relay_to_right_on_demand_headers), + ); + let right_to_left_on_demand_parachains = OnDemandParachainsRelay::new::< + ::ParachainFinality, + >( + self.right_relay.clone(), + self.common.left.client.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_parachains), + Arc::new(right_to_left_on_demand_parachains), + )) + } +} diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs index 0990a2d21758..4070783df09b 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs @@ -38,21 +38,27 @@ use substrate_relay_helper::{ TaggedAccount, TransactionParams, }; +/// A base relay between standalone (relay) chain and a parachain from another consensus system. +/// +/// Such relay starts 2 messages relay. It also starts 2 on-demand header relays and 1 on-demand +/// parachain heads relay. pub struct RelayToParachainBridge< L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge, R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge, > { + /// Parameters that are shared by all bridge types. pub common: Full2WayBridgeCommonParams<::Target, ::Target>, + /// Client of the right relay chain. pub right_relay: Client<::SourceRelay>, - // override for right_relay->left headers signer + /// Override for right_relay->left headers signer. pub right_headers_to_left_transaction_params: TransactionParams::Target>>, - // override for right->left parachains signer + /// Override for right->left parachains signer. pub right_parachains_to_left_transaction_params: TransactionParams::Target>>, - // override for left->right headers signer + /// Override for left->right headers signer. pub left_headers_to_right_transaction_params: TransactionParams::Target>>, } @@ -64,40 +70,50 @@ macro_rules! declare_relay_to_parachain_bridge_schema { #[doc = $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."] #[derive(Debug, PartialEq, StructOpt)] pub struct [<$left_chain $right_parachain HeadersAndMessages>] { + // shared parameters #[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>], + // signer used to sign parameter update transactions at the left chain #[structopt(flatten)] left_messages_pallet_owner: [<$left_chain MessagesPalletOwnerSigningParams>], + #[structopt(flatten)] right: [<$right_parachain ConnectionParams>], + #[structopt(flatten)] + right_relay: [<$right_chain ConnectionParams>], + // default signer, which is always used to sign messages relay transactions on the right chain #[structopt(flatten)] right_sign: [<$right_parachain SigningParams>], + // signer used to sign parameter update transactions at the left chain + #[structopt(flatten)] + right_messages_pallet_owner: [<$right_parachain MessagesPalletOwnerSigningParams>], + + + // override for right_relay->left headers signer + #[structopt(flatten)] + right_relay_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>], // override for left->right headers signer #[structopt(flatten)] left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_parachain SigningParams>], + + // override for right->left parachains signer #[structopt(flatten)] - right_messages_pallet_owner: [<$right_parachain MessagesPalletOwnerSigningParams>], - #[structopt(flatten)] - right_relay: [<$right_chain ConnectionParams>], + right_parachains_to_left_sign_override: [<$right_chain ParachainsTo $left_chain SigningParams>], } impl [<$left_chain $right_parachain HeadersAndMessages>] { async fn into_bridge< Left: ChainWithTransactions + CliChain>, Right: ChainWithTransactions + CliChain>, - RightRelay: ChainWithTransactions + CliChain, + RightRelay: CliChain, L2R: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, R2L: CliBridgeBase + MessagesCliBridge @@ -151,7 +167,6 @@ impl< + ChainWithTransactions + CliChain>, RightRelay: Chain - + ChainWithTransactions + CliChain, L2R: CliBridgeBase + MessagesCliBridge diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs index fb33fab8b785..bda532a2afd6 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs @@ -31,16 +31,20 @@ use substrate_relay_helper::{ TaggedAccount, TransactionParams, }; +/// A base relay between two standalone (relay) chains. +/// +/// Such relay starts 2 messages relay and 2 on-demand header relays. pub struct RelayToRelayBridge< L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge, R2L: MessagesCliBridge + RelayToRelayHeadersCliBridge, > { + /// Parameters that are shared by all bridge types. pub common: Full2WayBridgeCommonParams<::Target, ::Target>, - // override for right->left headers signer + /// Override for right->left headers signer. pub right_to_left_transaction_params: TransactionParams::Target>>, - // override for left->right headers signer + /// Override for left->right headers signer. pub left_to_right_transaction_params: TransactionParams::Target>>, }