Move generic CLI logic to different crate (#2885)

* Move generic CLI logic to separate crate

* Move and rename `CliChain` trait definition

Move it to `relay-substrate-client`

* Move generic cli logic to substrate-relay-helper

* Fix docs warnings
This commit is contained in:
Serban Iorga
2024-03-20 09:45:43 +01:00
committed by Bastian Köcher
parent bfce7a250f
commit 3643f721d4
63 changed files with 1746 additions and 1438 deletions
@@ -16,10 +16,13 @@
//! BridgeHubKusama-to-BridgeHubPolkadot messages sync entrypoint. //! BridgeHubKusama-to-BridgeHubPolkadot messages sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_bridge_hub_kusama_client::BridgeHubKusama; use relay_bridge_hub_kusama_client::BridgeHubKusama;
use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; use relay_bridge_hub_polkadot_client::BridgeHubPolkadot;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
/// BridgeHubKusama-to-BridgeHubPolkadot messages bridge. /// BridgeHubKusama-to-BridgeHubPolkadot messages bridge.
pub struct BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge {} pub struct BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge {}
@@ -16,10 +16,13 @@
//! BridgeHubPolkadot-to-BridgeHubKusama messages sync entrypoint. //! BridgeHubPolkadot-to-BridgeHubKusama messages sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_bridge_hub_kusama_client::BridgeHubKusama; use relay_bridge_hub_kusama_client::BridgeHubKusama;
use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; use relay_bridge_hub_polkadot_client::BridgeHubPolkadot;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
/// BridgeHubPolkadot-to-BridgeHubKusama messages bridge. /// BridgeHubPolkadot-to-BridgeHubKusama messages bridge.
pub struct BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge {} pub struct BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge {}
@@ -16,7 +16,7 @@
//! Kusama-to-BridgeHubPolkadot headers sync entrypoint. //! Kusama-to-BridgeHubPolkadot headers sync entrypoint.
use crate::cli::bridge::{ use substrate_relay_helper::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge, CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
}; };
@@ -16,11 +16,11 @@
//! Kusama-to-BridgeHubPolkadot parachains sync entrypoint. //! Kusama-to-BridgeHubPolkadot parachains sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge};
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use relay_substrate_client::{CallOf, HeaderIdOf}; use relay_substrate_client::{CallOf, HeaderIdOf};
use substrate_relay_helper::parachains::{ use substrate_relay_helper::{
SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
parachains::{SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline},
}; };
/// Kusama-to-BridgeHubPolkadot parachain sync description. /// Kusama-to-BridgeHubPolkadot parachain sync description.
@@ -16,7 +16,7 @@
//! Polkadot-to-KusamaBridgeHub headers sync entrypoint. //! Polkadot-to-KusamaBridgeHub headers sync entrypoint.
use crate::cli::bridge::{ use substrate_relay_helper::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge, CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
}; };
@@ -16,11 +16,11 @@
//! Polkadot-to-BridgeHubKusama parachains sync entrypoint. //! Polkadot-to-BridgeHubKusama parachains sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge};
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use relay_substrate_client::{CallOf, HeaderIdOf}; use relay_substrate_client::{CallOf, HeaderIdOf};
use substrate_relay_helper::parachains::{ use substrate_relay_helper::{
SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
parachains::{SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline},
}; };
/// Polkadot-to-BridgeHubKusama parachain sync description. /// Polkadot-to-BridgeHubKusama parachain sync description.
@@ -16,10 +16,13 @@
//! BridgeHubPolkadot-to-PolkadotBulletin messages sync entrypoint. //! BridgeHubPolkadot-to-PolkadotBulletin messages sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; use relay_bridge_hub_polkadot_client::BridgeHubPolkadot;
use relay_polkadot_bulletin_client::PolkadotBulletin; use relay_polkadot_bulletin_client::PolkadotBulletin;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
/// BridgeHubPolkadot-to-PolkadotBulletin messages bridge. /// BridgeHubPolkadot-to-PolkadotBulletin messages bridge.
pub struct BridgeHubPolkadotToPolkadotBulletinMessagesCliBridge {} pub struct BridgeHubPolkadotToPolkadotBulletinMessagesCliBridge {}
@@ -16,11 +16,6 @@
//! PolkadotBulletin-to-BridgeHubPolkadot headers sync entrypoint. //! PolkadotBulletin-to-BridgeHubPolkadot headers sync entrypoint.
use crate::cli::bridge::{
CliBridgeBase, MessagesCliBridge, RelayToRelayEquivocationDetectionCliBridge,
RelayToRelayHeadersCliBridge,
};
use async_trait::async_trait; use async_trait::async_trait;
use substrate_relay_helper::{ use substrate_relay_helper::{
equivocation::SubstrateEquivocationDetectionPipeline, equivocation::SubstrateEquivocationDetectionPipeline,
@@ -28,6 +23,11 @@ use substrate_relay_helper::{
finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline}, finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline},
}; };
use substrate_relay_helper::cli::bridge::{
CliBridgeBase, MessagesCliBridge, RelayToRelayEquivocationDetectionCliBridge,
RelayToRelayHeadersCliBridge,
};
/// Description of `PolkadotBulletin` -> `PolkadotBridgeHub` finalized headers bridge. /// Description of `PolkadotBulletin` -> `PolkadotBridgeHub` finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PolkadotBulletinFinalityToBridgeHubPolkadot; pub struct PolkadotBulletinFinalityToBridgeHubPolkadot;
@@ -16,10 +16,13 @@
//! PolkadotBulletin-to-BridgeHubPolkadot messages sync entrypoint. //! PolkadotBulletin-to-BridgeHubPolkadot messages sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; use relay_bridge_hub_polkadot_client::BridgeHubPolkadot;
use relay_polkadot_bulletin_client::PolkadotBulletin; use relay_polkadot_bulletin_client::PolkadotBulletin;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
/// PolkadotBulletin-to-BridgeHubPolkadot messages bridge. /// PolkadotBulletin-to-BridgeHubPolkadot messages bridge.
pub struct PolkadotBulletinToBridgeHubPolkadotMessagesCliBridge {} pub struct PolkadotBulletinToBridgeHubPolkadotMessagesCliBridge {}
@@ -16,10 +16,6 @@
//! Polkadot-to-PolkadotBulletin headers sync entrypoint. //! Polkadot-to-PolkadotBulletin headers sync entrypoint.
use crate::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
use async_trait::async_trait; use async_trait::async_trait;
use substrate_relay_helper::{ use substrate_relay_helper::{
equivocation::SubstrateEquivocationDetectionPipeline, equivocation::SubstrateEquivocationDetectionPipeline,
@@ -27,6 +23,10 @@ use substrate_relay_helper::{
finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline}, finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline},
}; };
use substrate_relay_helper::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
/// Description of Polkadot -> `PolkadotBulletin` finalized headers bridge. /// Description of Polkadot -> `PolkadotBulletin` finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PolkadotFinalityToPolkadotBulletin; pub struct PolkadotFinalityToPolkadotBulletin;
@@ -16,7 +16,9 @@
//! Polkadot-to-PolkadotBulletin parachains sync entrypoint. //! Polkadot-to-PolkadotBulletin parachains sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; use substrate_relay_helper::cli::bridge::{
CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge,
};
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use bp_runtime::Chain; use bp_runtime::Chain;
@@ -17,9 +17,12 @@
//! BridgeHubRococo-to-RococoBulletin messages sync entrypoint. //! BridgeHubRococo-to-RococoBulletin messages sync entrypoint.
use super::BridgeHubRococoAsBridgeHubPolkadot; use super::BridgeHubRococoAsBridgeHubPolkadot;
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_polkadot_bulletin_client::PolkadotBulletin as RococoBulletin; use relay_polkadot_bulletin_client::PolkadotBulletin as RococoBulletin;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
/// BridgeHubRococo-to-RococoBulletin messages bridge. /// BridgeHubRococo-to-RococoBulletin messages bridge.
pub struct BridgeHubRococoToRococoBulletinMessagesCliBridge {} pub struct BridgeHubRococoToRococoBulletinMessagesCliBridge {}
@@ -16,8 +16,6 @@
//! Declaration of all bridges between Rococo Bulletin Chain and Rococo Bridge Hub. //! Declaration of all bridges between Rococo Bulletin Chain and Rococo Bridge Hub.
use crate::cli::CliChain;
use bp_messages::MessageNonce; use bp_messages::MessageNonce;
use bp_runtime::{ use bp_runtime::{
AccountIdOf, BalanceOf, BlockNumberOf, ChainId, HashOf, HasherOf, HeaderOf, NonceOf, AccountIdOf, BalanceOf, BlockNumberOf, ChainId, HashOf, HasherOf, HeaderOf, NonceOf,
@@ -25,7 +23,8 @@ use bp_runtime::{
}; };
use frame_support::pallet_prelude::Weight; use frame_support::pallet_prelude::Weight;
use relay_substrate_client::{ use relay_substrate_client::{
Error as SubstrateError, SignParam, SimpleRuntimeVersion, UnsignedTransaction, ChainWithRuntimeVersion, Error as SubstrateError, SignParam, SimpleRuntimeVersion,
UnsignedTransaction,
}; };
use sp_core::storage::StorageKey; use sp_core::storage::StorageKey;
use std::time::Duration; use std::time::Duration;
@@ -127,7 +126,7 @@ impl relay_substrate_client::ChainWithTransactions for RococoAsPolkadot {
} }
} }
impl CliChain for RococoAsPolkadot { impl ChainWithRuntimeVersion for RococoAsPolkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> = None; const RUNTIME_VERSION: Option<SimpleRuntimeVersion> = None;
} }
@@ -232,7 +231,7 @@ impl relay_substrate_client::ChainWithMessages for BridgeHubRococoAsBridgeHubPol
relay_bridge_hub_polkadot_client::BridgeHubPolkadot::FROM_CHAIN_MESSAGE_DETAILS_METHOD; relay_bridge_hub_polkadot_client::BridgeHubPolkadot::FROM_CHAIN_MESSAGE_DETAILS_METHOD;
} }
impl CliChain for BridgeHubRococoAsBridgeHubPolkadot { impl ChainWithRuntimeVersion for BridgeHubRococoAsBridgeHubPolkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> = const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_003_000, transaction_version: 3 }); Some(SimpleRuntimeVersion { spec_version: 1_003_000, transaction_version: 3 });
} }
@@ -17,10 +17,6 @@
//! RococoBulletin-to-BridgeHubRococo headers sync entrypoint. //! RococoBulletin-to-BridgeHubRococo headers sync entrypoint.
use super::BridgeHubRococoAsBridgeHubPolkadot; use super::BridgeHubRococoAsBridgeHubPolkadot;
use crate::cli::bridge::{
CliBridgeBase, MessagesCliBridge, RelayToRelayEquivocationDetectionCliBridge,
RelayToRelayHeadersCliBridge,
};
use async_trait::async_trait; use async_trait::async_trait;
use substrate_relay_helper::{ use substrate_relay_helper::{
@@ -29,6 +25,11 @@ use substrate_relay_helper::{
finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline}, finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline},
}; };
use substrate_relay_helper::cli::bridge::{
CliBridgeBase, MessagesCliBridge, RelayToRelayEquivocationDetectionCliBridge,
RelayToRelayHeadersCliBridge,
};
/// Description of `RococoBulletin` -> `RococoBridgeHub` finalized headers bridge. /// Description of `RococoBulletin` -> `RococoBridgeHub` finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RococoBulletinFinalityToBridgeHubRococo; pub struct RococoBulletinFinalityToBridgeHubRococo;
@@ -17,9 +17,12 @@
//! RococoBulletin-to-BridgeHubRococo messages sync entrypoint. //! RococoBulletin-to-BridgeHubRococo messages sync entrypoint.
use super::BridgeHubRococoAsBridgeHubPolkadot; use super::BridgeHubRococoAsBridgeHubPolkadot;
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_polkadot_bulletin_client::PolkadotBulletin as RococoBulletin; use relay_polkadot_bulletin_client::PolkadotBulletin as RococoBulletin;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
/// RococoBulletin-to-BridgeHubRococo messages bridge. /// RococoBulletin-to-BridgeHubRococo messages bridge.
pub struct RococoBulletinToBridgeHubRococoMessagesCliBridge {} pub struct RococoBulletinToBridgeHubRococoMessagesCliBridge {}
@@ -17,9 +17,6 @@
//! Rococo-to-RococoBulletin headers sync entrypoint. //! Rococo-to-RococoBulletin headers sync entrypoint.
use super::RococoAsPolkadot; use super::RococoAsPolkadot;
use crate::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
use async_trait::async_trait; use async_trait::async_trait;
use substrate_relay_helper::{ use substrate_relay_helper::{
@@ -28,6 +25,10 @@ use substrate_relay_helper::{
finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline}, finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline},
}; };
use substrate_relay_helper::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
/// Description of Rococo -> `RococoBulletin` finalized headers bridge. /// Description of Rococo -> `RococoBulletin` finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RococoFinalityToRococoBulletin; pub struct RococoFinalityToRococoBulletin;
@@ -17,12 +17,12 @@
//! Rococo-to-RococoBulletin parachains sync entrypoint. //! Rococo-to-RococoBulletin parachains sync entrypoint.
use super::{BridgeHubRococoAsBridgeHubPolkadot, RococoAsPolkadot}; use super::{BridgeHubRococoAsBridgeHubPolkadot, RococoAsPolkadot};
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge};
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use bp_runtime::Chain; use bp_runtime::Chain;
use relay_substrate_client::{CallOf, HeaderIdOf}; use relay_substrate_client::{CallOf, HeaderIdOf};
use substrate_relay_helper::{ use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
messages_lane::MessagesRelayLimits, messages_lane::MessagesRelayLimits,
parachains::{SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline}, parachains::{SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline},
}; };
@@ -16,10 +16,13 @@
//! BridgeHubRococo-to-BridgeHubWestend messages sync entrypoint. //! BridgeHubRococo-to-BridgeHubWestend messages sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_bridge_hub_rococo_client::BridgeHubRococo; use relay_bridge_hub_rococo_client::BridgeHubRococo;
use relay_bridge_hub_westend_client::BridgeHubWestend; use relay_bridge_hub_westend_client::BridgeHubWestend;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
pub struct BridgeHubRococoToBridgeHubWestendMessagesCliBridge {} pub struct BridgeHubRococoToBridgeHubWestendMessagesCliBridge {}
@@ -16,10 +16,13 @@
//! BridgeHubWestend-to-BridgeHubRococo messages sync entrypoint. //! BridgeHubWestend-to-BridgeHubRococo messages sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
use relay_bridge_hub_rococo_client::BridgeHubRococo; use relay_bridge_hub_rococo_client::BridgeHubRococo;
use relay_bridge_hub_westend_client::BridgeHubWestend; use relay_bridge_hub_westend_client::BridgeHubWestend;
use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; use substrate_relay_helper::{
cli::bridge::{CliBridgeBase, MessagesCliBridge},
messages_lane::SubstrateMessageLane,
UtilityPalletBatchCallBuilder,
};
pub struct BridgeHubWestendToBridgeHubRococoMessagesCliBridge {} pub struct BridgeHubWestendToBridgeHubRococoMessagesCliBridge {}
@@ -16,10 +16,6 @@
//! Rococo-to-Westend bridge hubs headers sync entrypoint. //! Rococo-to-Westend bridge hubs headers sync entrypoint.
use crate::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
use async_trait::async_trait; use async_trait::async_trait;
use substrate_relay_helper::{ use substrate_relay_helper::{
equivocation::SubstrateEquivocationDetectionPipeline, equivocation::SubstrateEquivocationDetectionPipeline,
@@ -27,6 +23,10 @@ use substrate_relay_helper::{
finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline}, finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline},
}; };
use substrate_relay_helper::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
/// Description of Rococo -> Westend finalized headers bridge. /// Description of Rococo -> Westend finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RococoFinalityToBridgeHubWestend; pub struct RococoFinalityToBridgeHubWestend;
@@ -16,11 +16,11 @@
//! Westend-to-Rococo parachains sync entrypoint. //! Westend-to-Rococo parachains sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge};
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use relay_substrate_client::{CallOf, HeaderIdOf}; use relay_substrate_client::{CallOf, HeaderIdOf};
use substrate_relay_helper::parachains::{ use substrate_relay_helper::{
SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
parachains::{SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline},
}; };
/// BridgeHub-to-BridgeHub parachain sync description. /// BridgeHub-to-BridgeHub parachain sync description.
@@ -16,10 +16,6 @@
//! Westend-to-Rococo bridge hubs headers sync entrypoint. //! Westend-to-Rococo bridge hubs headers sync entrypoint.
use crate::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
use async_trait::async_trait; use async_trait::async_trait;
use substrate_relay_helper::{ use substrate_relay_helper::{
equivocation::SubstrateEquivocationDetectionPipeline, equivocation::SubstrateEquivocationDetectionPipeline,
@@ -27,6 +23,10 @@ use substrate_relay_helper::{
finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline}, finality_base::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalityPipeline},
}; };
use substrate_relay_helper::cli::bridge::{
CliBridgeBase, RelayToRelayEquivocationDetectionCliBridge, RelayToRelayHeadersCliBridge,
};
/// Description of Westend -> Rococo finalized headers bridge. /// Description of Westend -> Rococo finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WestendFinalityToBridgeHubRococo; pub struct WestendFinalityToBridgeHubRococo;
@@ -16,11 +16,11 @@
//! Rococo-to-Westend parachains sync entrypoint. //! Rococo-to-Westend parachains sync entrypoint.
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge};
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use relay_substrate_client::{CallOf, HeaderIdOf}; use relay_substrate_client::{CallOf, HeaderIdOf};
use substrate_relay_helper::parachains::{ use substrate_relay_helper::{
SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
parachains::{SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline},
}; };
/// BridgeHub-to-BridgeHub parachain sync description. /// BridgeHub-to-BridgeHub parachain sync description.
@@ -1,32 +0,0 @@
// Copyright 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/>.
//! Kusama + Kusama parachains specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_kusama_client::BridgeHubKusama;
use relay_kusama_client::Kusama;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for Kusama {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_002, transaction_version: 25 });
}
impl CliChain for BridgeHubKusama {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_000, transaction_version: 4 });
}
@@ -1,23 +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/>.
//! Chain-specific relayer configuration.
mod kusama;
mod polkadot;
mod polkadot_bulletin;
mod rococo;
mod westend;
@@ -1,32 +0,0 @@
// Copyright 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/>.
//! Polkadot + Polkadot parachains specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_polkadot_client::BridgeHubPolkadot;
use relay_polkadot_client::Polkadot;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for Polkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_002, transaction_version: 25 });
}
impl CliChain for BridgeHubPolkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_000, transaction_version: 3 });
}
@@ -1,26 +0,0 @@
// Copyright 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/>.
//! Polkadot + Polkadot parachains specification for CLI.
use crate::cli::CliChain;
use relay_polkadot_bulletin_client::PolkadotBulletin;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for PolkadotBulletin {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 100, transaction_version: 1 });
}
@@ -1,32 +0,0 @@
// Copyright 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/>.
//! Rococo + Rococo parachains specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_rococo_client::BridgeHubRococo;
use relay_rococo_client::Rococo;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for Rococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 24 });
}
impl CliChain for BridgeHubRococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 4 });
}
@@ -1,32 +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/>.
//! Westend chain specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_westend_client::BridgeHubWestend;
use relay_substrate_client::SimpleRuntimeVersion;
use relay_westend_client::Westend;
impl CliChain for Westend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 24 });
}
impl CliChain for BridgeHubWestend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 4 });
}
@@ -12,248 +12,12 @@
// GNU General Public License for more details. // GNU General Public License for more details.
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use relay_substrate_client::{AccountKeyPairOf, ChainWithTransactions};
use structopt::StructOpt;
use strum::{EnumString, VariantNames};
use crate::cli::CliChain;
pub use relay_substrate_client::{ChainRuntimeVersion, SimpleRuntimeVersion};
use substrate_relay_helper::TransactionParams;
#[doc = "Runtime version params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)]
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) => {
bp_runtime::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<SimpleRuntimeVersion>,
) -> anyhow::Result<ChainRuntimeVersion> {
Ok(match self.[<$chain_prefix _version_mode>] {
RuntimeVersionType::Auto => ChainRuntimeVersion::Auto,
RuntimeVersionType::Custom => {
let custom_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 custom_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(
SimpleRuntimeVersion {
spec_version: custom_spec_version,
transaction_version: custom_transaction_version
}
)
},
RuntimeVersionType::Bundle => match bundle_runtime_version {
Some(runtime_version) => ChainRuntimeVersion::Custom(runtime_version),
None => {
return Err(anyhow::format_err!("Cannot use bundled runtime version of {}: it is not known to the relay", stringify!($chain_prefix)));
}
},
})
}
}
}
};
}
/// Create chain-specific set of runtime version parameters.
#[macro_export]
macro_rules! declare_chain_connection_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::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(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
)
}
}
}
};
}
/// Create chain-specific set of signing parameters.
#[macro_export]
macro_rules! declare_chain_signing_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::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: ChainWithTransactions>(&self) -> anyhow::Result<AccountKeyPairOf<Chain>> {
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;
AccountKeyPairOf::<Chain>::from_string(
&suri,
suri_password.as_deref()
).map_err(|e| anyhow::format_err!("{:?}", e))
}
/// Return transaction parameters.
#[allow(dead_code)]
pub fn transaction_params<Chain: ChainWithTransactions>(
&self,
) -> anyhow::Result<TransactionParams<AccountKeyPairOf<Chain>>> {
Ok(TransactionParams {
mortality: self.transactions_mortality()?,
signer: self.to_keypair::<Chain>()?,
})
}
}
}
};
}
/// 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);
};
}
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)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use sp_core::Pair; use sp_core::Pair;
use substrate_relay_helper::cli::chain_schema::TargetSigningParams;
#[test] #[test]
fn reads_suri_from_file() { fn reads_suri_from_file() {
@@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::{ use crate::bridges::{
bridges::{
kusama_polkadot::{ kusama_polkadot::{
kusama_headers_to_bridge_hub_polkadot::KusamaToBridgeHubPolkadotCliBridge, kusama_headers_to_bridge_hub_polkadot::KusamaToBridgeHubPolkadotCliBridge,
polkadot_headers_to_bridge_hub_kusama::PolkadotToBridgeHubKusamaCliBridge, polkadot_headers_to_bridge_hub_kusama::PolkadotToBridgeHubKusamaCliBridge,
@@ -24,15 +23,14 @@ use crate::{
rococo_headers_to_bridge_hub_westend::RococoToBridgeHubWestendCliBridge, rococo_headers_to_bridge_hub_westend::RococoToBridgeHubWestendCliBridge,
westend_headers_to_bridge_hub_rococo::WestendToBridgeHubRococoCliBridge, westend_headers_to_bridge_hub_rococo::WestendToBridgeHubRococoCliBridge,
}, },
},
cli::{bridge::*, chain_schema::*, PrometheusParams},
}; };
use async_trait::async_trait;
use relay_substrate_client::ChainWithTransactions;
use structopt::StructOpt; use structopt::StructOpt;
use strum::{EnumString, VariantNames}; use strum::{EnumString, VariantNames};
use substrate_relay_helper::{equivocation, equivocation::SubstrateEquivocationDetectionPipeline};
use substrate_relay_helper::cli::detect_equivocations::{
DetectEquivocationsParams, EquivocationsDetector,
};
/// Start equivocation detection loop. /// Start equivocation detection loop.
#[derive(StructOpt)] #[derive(StructOpt)]
@@ -40,13 +38,7 @@ pub struct DetectEquivocations {
#[structopt(possible_values = DetectEquivocationsBridge::VARIANTS, case_insensitive = true)] #[structopt(possible_values = DetectEquivocationsBridge::VARIANTS, case_insensitive = true)]
bridge: DetectEquivocationsBridge, bridge: DetectEquivocationsBridge,
#[structopt(flatten)] #[structopt(flatten)]
source: SourceConnectionParams, params: DetectEquivocationsParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
} }
#[derive(Debug, EnumString, VariantNames)] #[derive(Debug, EnumString, VariantNames)]
@@ -59,29 +51,6 @@ pub enum DetectEquivocationsBridge {
WestendToBridgeHubRococo, WestendToBridgeHubRococo,
} }
#[async_trait]
trait EquivocationsDetector: RelayToRelayEquivocationDetectionCliBridge
where
Self::Source: ChainWithTransactions,
{
async fn start(data: DetectEquivocations) -> anyhow::Result<()> {
let source_client = data.source.into_client::<Self::Source>().await?;
Self::Equivocation::start_relay_guards(
&source_client,
source_client.can_start_version_guard(),
)
.await?;
equivocation::run::<Self::Equivocation>(
source_client,
data.target.into_client::<Self::Target>().await?,
data.source_sign.transaction_params::<Self::Source>()?,
data.prometheus_params.into_metrics_params()?,
)
.await
}
}
impl EquivocationsDetector for KusamaToBridgeHubPolkadotCliBridge {} impl EquivocationsDetector for KusamaToBridgeHubPolkadotCliBridge {}
impl EquivocationsDetector for PolkadotToBridgeHubKusamaCliBridge {} impl EquivocationsDetector for PolkadotToBridgeHubKusamaCliBridge {}
impl EquivocationsDetector for RococoToBridgeHubWestendCliBridge {} impl EquivocationsDetector for RococoToBridgeHubWestendCliBridge {}
@@ -92,13 +61,13 @@ impl DetectEquivocations {
pub async fn run(self) -> anyhow::Result<()> { pub async fn run(self) -> anyhow::Result<()> {
match self.bridge { match self.bridge {
DetectEquivocationsBridge::KusamaToBridgeHubPolkadot => DetectEquivocationsBridge::KusamaToBridgeHubPolkadot =>
KusamaToBridgeHubPolkadotCliBridge::start(self), KusamaToBridgeHubPolkadotCliBridge::start(self.params),
DetectEquivocationsBridge::PolkadotToBridgeHubKusama => DetectEquivocationsBridge::PolkadotToBridgeHubKusama =>
PolkadotToBridgeHubKusamaCliBridge::start(self), PolkadotToBridgeHubKusamaCliBridge::start(self.params),
DetectEquivocationsBridge::RococoToBridgeHubWestend => DetectEquivocationsBridge::RococoToBridgeHubWestend =>
RococoToBridgeHubWestendCliBridge::start(self), RococoToBridgeHubWestendCliBridge::start(self.params),
DetectEquivocationsBridge::WestendToBridgeHubRococo => DetectEquivocationsBridge::WestendToBridgeHubRococo =>
WestendToBridgeHubRococoCliBridge::start(self), WestendToBridgeHubRococoCliBridge::start(self.params),
} }
.await .await
} }
@@ -14,11 +14,7 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use async_trait::async_trait; use crate::bridges::{
use codec::Encode;
use crate::{
bridges::{
kusama_polkadot::{ kusama_polkadot::{
kusama_headers_to_bridge_hub_polkadot::KusamaToBridgeHubPolkadotCliBridge, kusama_headers_to_bridge_hub_polkadot::KusamaToBridgeHubPolkadotCliBridge,
polkadot_headers_to_bridge_hub_kusama::PolkadotToBridgeHubKusamaCliBridge, polkadot_headers_to_bridge_hub_kusama::PolkadotToBridgeHubKusamaCliBridge,
@@ -35,86 +31,14 @@ use crate::{
rococo_headers_to_bridge_hub_westend::RococoToBridgeHubWestendCliBridge, rococo_headers_to_bridge_hub_westend::RococoToBridgeHubWestendCliBridge,
westend_headers_to_bridge_hub_rococo::WestendToBridgeHubRococoCliBridge, westend_headers_to_bridge_hub_rococo::WestendToBridgeHubRococoCliBridge,
}, },
},
cli::{bridge::CliBridgeBase, chain_schema::*},
}; };
use bp_runtime::Chain as ChainBase; use relay_substrate_client::Chain;
use relay_substrate_client::{AccountKeyPairOf, Chain, UnsignedTransaction};
use sp_core::Pair;
use structopt::StructOpt; use structopt::StructOpt;
use strum::{EnumString, VariantNames}; use strum::{EnumString, VariantNames};
use substrate_relay_helper::finality_base::engine::{Engine, Grandpa as GrandpaFinalityEngine}; use substrate_relay_helper::{
cli::init_bridge::{BridgeInitializer, InitBridgeParams},
/// Initialize bridge pallet. finality_base::engine::{Engine, Grandpa as GrandpaFinalityEngine},
#[derive(StructOpt)] };
pub struct InitBridge {
/// A bridge instance to initialize.
#[structopt(possible_values = InitBridgeName::VARIANTS, case_insensitive = true)]
bridge: InitBridgeName,
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
/// Generates all required data, but does not submit extrinsic
#[structopt(long)]
dry_run: bool,
}
#[derive(Debug, EnumString, VariantNames)]
#[strum(serialize_all = "kebab_case")]
/// Bridge to initialize.
pub enum InitBridgeName {
KusamaToBridgeHubPolkadot,
PolkadotToBridgeHubKusama,
PolkadotToPolkadotBulletin,
PolkadotBulletinToBridgeHubPolkadot,
RococoToRococoBulletin,
RococoBulletinToBridgeHubRococo,
RococoToBridgeHubWestend,
WestendToBridgeHubRococo,
}
#[async_trait]
trait BridgeInitializer: CliBridgeBase
where
<Self::Target as ChainBase>::AccountId: From<<AccountKeyPairOf<Self::Target> as Pair>::Public>,
{
type Engine: Engine<Self::Source>;
/// Get the encoded call to init the bridge.
fn encode_init_bridge(
init_data: <Self::Engine as Engine<Self::Source>>::InitializationData,
) -> <Self::Target as Chain>::Call;
/// Initialize the bridge.
async fn init_bridge(data: InitBridge) -> anyhow::Result<()> {
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 dry_run = data.dry_run;
substrate_relay_helper::finality::initialize::initialize::<Self::Engine, _, _, _>(
source_client,
target_client.clone(),
target_sign,
move |transaction_nonce, initialization_data| {
let call = Self::encode_init_bridge(initialization_data);
log::info!(
target: "bridge",
"Initialize bridge call encoded as hex string: {:?}",
format!("0x{}", hex::encode(call.encode()))
);
Ok(UnsignedTransaction::new(call.into(), transaction_nonce))
},
dry_run,
)
.await;
Ok(())
}
}
impl BridgeInitializer for RococoToBridgeHubWestendCliBridge { impl BridgeInitializer for RococoToBridgeHubWestendCliBridge {
type Engine = GrandpaFinalityEngine<Self::Source>; type Engine = GrandpaFinalityEngine<Self::Source>;
@@ -225,26 +149,50 @@ impl BridgeInitializer for RococoBulletinToBridgeHubRococoCliBridge {
} }
} }
/// Initialize bridge pallet.
#[derive(StructOpt)]
pub struct InitBridge {
/// A bridge instance to initialize.
#[structopt(possible_values = InitBridgeName::VARIANTS, case_insensitive = true)]
bridge: InitBridgeName,
#[structopt(flatten)]
params: InitBridgeParams,
}
#[derive(Debug, EnumString, VariantNames)]
#[strum(serialize_all = "kebab_case")]
/// Bridge to initialize.
pub enum InitBridgeName {
KusamaToBridgeHubPolkadot,
PolkadotToBridgeHubKusama,
PolkadotToPolkadotBulletin,
PolkadotBulletinToBridgeHubPolkadot,
RococoToRococoBulletin,
RococoBulletinToBridgeHubRococo,
RococoToBridgeHubWestend,
WestendToBridgeHubRococo,
}
impl InitBridge { impl InitBridge {
/// Run the command. /// Run the command.
pub async fn run(self) -> anyhow::Result<()> { pub async fn run(self) -> anyhow::Result<()> {
match self.bridge { match self.bridge {
InitBridgeName::KusamaToBridgeHubPolkadot => InitBridgeName::KusamaToBridgeHubPolkadot =>
KusamaToBridgeHubPolkadotCliBridge::init_bridge(self), KusamaToBridgeHubPolkadotCliBridge::init_bridge(self.params),
InitBridgeName::PolkadotToBridgeHubKusama => InitBridgeName::PolkadotToBridgeHubKusama =>
PolkadotToBridgeHubKusamaCliBridge::init_bridge(self), PolkadotToBridgeHubKusamaCliBridge::init_bridge(self.params),
InitBridgeName::PolkadotToPolkadotBulletin => InitBridgeName::PolkadotToPolkadotBulletin =>
PolkadotToPolkadotBulletinCliBridge::init_bridge(self), PolkadotToPolkadotBulletinCliBridge::init_bridge(self.params),
InitBridgeName::PolkadotBulletinToBridgeHubPolkadot => InitBridgeName::PolkadotBulletinToBridgeHubPolkadot =>
PolkadotBulletinToBridgeHubPolkadotCliBridge::init_bridge(self), PolkadotBulletinToBridgeHubPolkadotCliBridge::init_bridge(self.params),
InitBridgeName::RococoToRococoBulletin => InitBridgeName::RococoToRococoBulletin =>
RococoToRococoBulletinCliBridge::init_bridge(self), RococoToRococoBulletinCliBridge::init_bridge(self.params),
InitBridgeName::RococoBulletinToBridgeHubRococo => InitBridgeName::RococoBulletinToBridgeHubRococo =>
RococoBulletinToBridgeHubRococoCliBridge::init_bridge(self), RococoBulletinToBridgeHubRococoCliBridge::init_bridge(self.params),
InitBridgeName::RococoToBridgeHubWestend => InitBridgeName::RococoToBridgeHubWestend =>
RococoToBridgeHubWestendCliBridge::init_bridge(self), RococoToBridgeHubWestendCliBridge::init_bridge(self.params),
InitBridgeName::WestendToBridgeHubRococo => InitBridgeName::WestendToBridgeHubRococo =>
WestendToBridgeHubRococoCliBridge::init_bridge(self), WestendToBridgeHubRococoCliBridge::init_bridge(self.params),
} }
.await .await
} }
+11 -197
View File
@@ -17,18 +17,10 @@
//! Deal with CLI args of substrate-to-substrate relay. //! Deal with CLI args of substrate-to-substrate relay.
use async_std::prelude::*; use async_std::prelude::*;
use codec::{Decode, Encode};
use futures::{select, FutureExt}; use futures::{select, FutureExt};
use rbtag::BuildInfo;
use signal_hook::consts::*; use signal_hook::consts::*;
use signal_hook_async_std::Signals; use signal_hook_async_std::Signals;
use structopt::{clap::arg_enum, StructOpt}; use structopt::StructOpt;
use strum::{EnumString, VariantNames};
use bp_messages::LaneId;
use relay_substrate_client::SimpleRuntimeVersion;
pub(crate) mod bridge;
mod chain_schema; mod chain_schema;
mod detect_equivocations; mod detect_equivocations;
@@ -50,11 +42,17 @@ pub fn parse_args() -> Command {
#[derive(StructOpt)] #[derive(StructOpt)]
#[structopt(about = "Substrate-to-Substrate relay")] #[structopt(about = "Substrate-to-Substrate relay")]
pub enum Command { pub enum Command {
/// Initialize on-chain bridge pallet with current header data.
///
/// Sends initialization transaction to bootstrap the bridge with current finalized block data.
InitBridge(init_bridge::InitBridge),
/// Start headers relay between two chains. /// Start headers relay between two chains.
/// ///
/// The on-chain bridge component should have been already initialized with /// The on-chain bridge component should have been already initialized with
/// `init-bridge` sub-command. /// `init-bridge` sub-command.
RelayHeaders(relay_headers::RelayHeaders), RelayHeaders(relay_headers::RelayHeaders),
/// Relay parachain heads.
RelayParachains(relay_parachains::RelayParachains),
/// Start messages relay between two chains. /// Start messages relay between two chains.
/// ///
/// Ties up to `Messages` pallets on both chains and starts relaying messages. /// Ties up to `Messages` pallets on both chains and starts relaying messages.
@@ -67,12 +65,6 @@ pub enum Command {
/// the message relays - i.e. when there are messages or confirmations that needs to be /// the message relays - i.e. when there are messages or confirmations that needs to be
/// relayed between chains. /// relayed between chains.
RelayHeadersAndMessages(Box<relay_headers_and_messages::RelayHeadersAndMessages>), RelayHeadersAndMessages(Box<relay_headers_and_messages::RelayHeadersAndMessages>),
/// Initialize on-chain bridge pallet with current header data.
///
/// Sends initialization transaction to bootstrap the bridge with current finalized block data.
InitBridge(init_bridge::InitBridge),
/// Relay parachain heads.
RelayParachains(relay_parachains::RelayParachains),
/// Detect and report equivocations. /// Detect and report equivocations.
/// ///
/// Parses the source chain headers that were synchronized with the target chain looking for /// Parses the source chain headers that were synchronized with the target chain looking for
@@ -86,10 +78,10 @@ impl Command {
use relay_utils::initialize::{initialize_logger, initialize_relay}; use relay_utils::initialize::{initialize_logger, initialize_relay};
match self { match self {
Self::InitBridge(_) |
Self::RelayHeaders(_) | Self::RelayHeaders(_) |
Self::RelayMessages(_) | Self::RelayMessages(_) |
Self::RelayHeadersAndMessages(_) | Self::RelayHeadersAndMessages(_) => {
Self::InitBridge(_) => {
initialize_relay(); initialize_relay();
}, },
_ => { _ => {
@@ -101,11 +93,11 @@ impl Command {
/// Run the command. /// Run the command.
async fn do_run(self) -> anyhow::Result<()> { async fn do_run(self) -> anyhow::Result<()> {
match self { match self {
Self::InitBridge(arg) => arg.run().await?,
Self::RelayHeaders(arg) => arg.run().await?, Self::RelayHeaders(arg) => arg.run().await?,
Self::RelayParachains(arg) => arg.run().await?,
Self::RelayMessages(arg) => arg.run().await?, Self::RelayMessages(arg) => arg.run().await?,
Self::RelayHeadersAndMessages(arg) => arg.run().await?, Self::RelayHeadersAndMessages(arg) => arg.run().await?,
Self::InitBridge(arg) => arg.run().await?,
Self::RelayParachains(arg) => arg.run().await?,
Self::DetectEquivocations(arg) => arg.run().await?, Self::DetectEquivocations(arg) => arg.run().await?,
} }
Ok(()) Ok(())
@@ -137,181 +129,3 @@ impl Command {
} }
} }
} }
arg_enum! {
#[derive(Debug)]
/// The origin to use when dispatching the message on the target chain.
///
/// - `Target` uses account existing on the target chain (requires target private key).
/// - `Origin` uses account derived from the source-chain account.
pub enum Origins {
Target,
Source,
}
}
/// Bridge-supported network definition.
///
/// Used to abstract away CLI commands.
pub trait CliChain: relay_substrate_client::Chain {
/// Current version of the chain runtime, known to relay.
///
/// can be `None` if relay is not going to submit transactions to that chain.
const RUNTIME_VERSION: Option<SimpleRuntimeVersion>;
}
/// Lane id.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HexLaneId(pub [u8; 4]);
impl From<HexLaneId> for LaneId {
fn from(lane_id: HexLaneId) -> LaneId {
LaneId(lane_id.0)
}
}
impl std::str::FromStr for HexLaneId {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut lane_id = [0u8; 4];
hex::decode_to_slice(s, &mut lane_id)?;
Ok(HexLaneId(lane_id))
}
}
/// Nicer formatting for raw bytes vectors.
#[derive(Default, Encode, Decode, PartialEq, Eq)]
pub struct HexBytes(pub Vec<u8>);
impl std::str::FromStr for HexBytes {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(hex::decode(s)?))
}
}
impl std::fmt::Debug for HexBytes {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "0x{self}")
}
}
impl std::fmt::Display for HexBytes {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", hex::encode(&self.0))
}
}
/// Prometheus metrics params.
#[derive(Clone, Debug, PartialEq, StructOpt)]
pub struct PrometheusParams {
/// Do not expose a Prometheus metric endpoint.
#[structopt(long)]
pub no_prometheus: bool,
/// Expose Prometheus endpoint at given interface.
#[structopt(long, default_value = "127.0.0.1")]
pub prometheus_host: String,
/// Expose Prometheus endpoint at given port.
#[structopt(long, default_value = "9616")]
pub prometheus_port: u16,
}
/// Struct to get git commit info and build time.
#[derive(BuildInfo)]
struct SubstrateRelayBuildInfo;
impl SubstrateRelayBuildInfo {
/// Get git commit in form `<short-sha-(clean|dirty)>`.
pub fn get_git_commit() -> String {
// on gitlab we use images without git installed, so we can't use `rbtag` there
// locally we don't have `CI_*` env variables, so we can't rely on them
// => we are using `CI_*` env variables or else `rbtag`
let maybe_sha_from_ci = option_env!("CI_COMMIT_SHORT_SHA");
maybe_sha_from_ci
.map(|short_sha| {
// we assume that on CI the copy is always clean
format!("{short_sha}-clean")
})
.unwrap_or_else(|| SubstrateRelayBuildInfo.get_build_commit().into())
}
}
impl PrometheusParams {
/// Tries to convert CLI metrics params into metrics params, used by the relay.
pub fn into_metrics_params(self) -> anyhow::Result<relay_utils::metrics::MetricsParams> {
let metrics_address = if !self.no_prometheus {
Some(relay_utils::metrics::MetricsAddress {
host: self.prometheus_host,
port: self.prometheus_port,
})
} else {
None
};
let relay_version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
let relay_commit = SubstrateRelayBuildInfo::get_git_commit();
relay_utils::metrics::MetricsParams::new(
metrics_address,
relay_version.into(),
relay_commit,
)
.map_err(|e| anyhow::format_err!("{:?}", e))
}
}
/// Either explicit or maximal allowed value.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExplicitOrMaximal<V> {
/// User has explicitly specified argument value.
Explicit(V),
/// Maximal allowed value for this argument.
Maximal,
}
impl<V: std::str::FromStr> std::str::FromStr for ExplicitOrMaximal<V>
where
V::Err: std::fmt::Debug,
{
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.to_lowercase() == "max" {
return Ok(ExplicitOrMaximal::Maximal)
}
V::from_str(s)
.map(ExplicitOrMaximal::Explicit)
.map_err(|e| format!("Failed to parse '{e:?}'. Expected 'max' or explicit value"))
}
}
#[doc = "Runtime version params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)]
pub enum RuntimeVersionType {
/// Auto query version from chain
Auto,
/// Custom `spec_version` and `transaction_version`
Custom,
/// Read version from bundle dependencies directly.
Bundle,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hex_bytes_display_matches_from_str_for_clap() {
// given
let hex = HexBytes(vec![1, 2, 3, 4]);
let display = format!("{hex}");
// when
let hex2: HexBytes = display.parse().unwrap();
// then
assert_eq!(hex.0, hex2.0);
}
}
@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use async_trait::async_trait;
use structopt::StructOpt; use structopt::StructOpt;
use strum::{EnumString, VariantNames}; use strum::{EnumString, VariantNames};
@@ -32,10 +31,8 @@ use crate::bridges::{
rococo_headers_to_rococo_bulletin::RococoToRococoBulletinCliBridge, rococo_headers_to_rococo_bulletin::RococoToRococoBulletinCliBridge,
}, },
}; };
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline;
use crate::cli::{bridge::*, chain_schema::*, PrometheusParams}; use substrate_relay_helper::cli::relay_headers::{HeadersRelayer, RelayHeadersParams};
/// Start headers relayer process. /// Start headers relayer process.
#[derive(StructOpt)] #[derive(StructOpt)]
@@ -43,18 +40,8 @@ pub struct RelayHeaders {
/// A bridge instance to relay headers for. /// A bridge instance to relay headers for.
#[structopt(possible_values = RelayHeadersBridge::VARIANTS, case_insensitive = true)] #[structopt(possible_values = RelayHeadersBridge::VARIANTS, case_insensitive = true)]
bridge: RelayHeadersBridge, bridge: RelayHeadersBridge,
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
/// are relayed.
#[structopt(long)]
only_mandatory_headers: bool,
#[structopt(flatten)] #[structopt(flatten)]
source: SourceConnectionParams, params: RelayHeadersParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
} }
#[derive(Debug, EnumString, VariantNames)] #[derive(Debug, EnumString, VariantNames)]
@@ -69,37 +56,6 @@ pub enum RelayHeadersBridge {
RococoBulletinToBridgeHubRococo, RococoBulletinToBridgeHubRococo,
} }
#[async_trait]
trait HeadersRelayer: RelayToRelayHeadersCliBridge {
/// Relay headers.
async fn relay_headers(data: RelayHeaders) -> anyhow::Result<()> {
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>()?;
let metrics_params: relay_utils::metrics::MetricsParams =
data.prometheus_params.into_metrics_params()?;
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
let target_transactions_params = substrate_relay_helper::TransactionParams {
signer: target_sign,
mortality: target_transactions_mortality,
};
Self::Finality::start_relay_guards(&target_client, target_client.can_start_version_guard())
.await?;
substrate_relay_helper::finality::run::<Self::Finality>(
source_client,
target_client,
data.only_mandatory_headers,
target_transactions_params,
metrics_params,
)
.await
}
}
impl HeadersRelayer for KusamaToBridgeHubPolkadotCliBridge {} impl HeadersRelayer for KusamaToBridgeHubPolkadotCliBridge {}
impl HeadersRelayer for PolkadotToBridgeHubKusamaCliBridge {} impl HeadersRelayer for PolkadotToBridgeHubKusamaCliBridge {}
impl HeadersRelayer for PolkadotToPolkadotBulletinCliBridge {} impl HeadersRelayer for PolkadotToPolkadotBulletinCliBridge {}
@@ -112,17 +68,17 @@ impl RelayHeaders {
pub async fn run(self) -> anyhow::Result<()> { pub async fn run(self) -> anyhow::Result<()> {
match self.bridge { match self.bridge {
RelayHeadersBridge::KusamaToBridgeHubPolkadot => RelayHeadersBridge::KusamaToBridgeHubPolkadot =>
KusamaToBridgeHubPolkadotCliBridge::relay_headers(self), KusamaToBridgeHubPolkadotCliBridge::relay_headers(self.params),
RelayHeadersBridge::PolkadotToBridgeHubKusama => RelayHeadersBridge::PolkadotToBridgeHubKusama =>
PolkadotToBridgeHubKusamaCliBridge::relay_headers(self), PolkadotToBridgeHubKusamaCliBridge::relay_headers(self.params),
RelayHeadersBridge::PolkadotToPolkadotBulletin => RelayHeadersBridge::PolkadotToPolkadotBulletin =>
PolkadotToPolkadotBulletinCliBridge::relay_headers(self), PolkadotToPolkadotBulletinCliBridge::relay_headers(self.params),
RelayHeadersBridge::PolkadotBulletinToBridgeHubPolkadot => RelayHeadersBridge::PolkadotBulletinToBridgeHubPolkadot =>
PolkadotBulletinToBridgeHubPolkadotCliBridge::relay_headers(self), PolkadotBulletinToBridgeHubPolkadotCliBridge::relay_headers(self.params),
RelayHeadersBridge::RococoToRococoBulletin => RelayHeadersBridge::RococoToRococoBulletin =>
RococoToRococoBulletinCliBridge::relay_headers(self), RococoToRococoBulletinCliBridge::relay_headers(self.params),
RelayHeadersBridge::RococoBulletinToBridgeHubRococo => RelayHeadersBridge::RococoBulletinToBridgeHubRococo =>
RococoBulletinToBridgeHubRococoCliBridge::relay_headers(self), RococoBulletinToBridgeHubRococoCliBridge::relay_headers(self.params),
} }
.await .await
} }
@@ -23,22 +23,10 @@
//! `declare_chain_to_parachain_bridge_schema` for the bridge. //! `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. //! 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]
mod relay_to_parachain;
use async_trait::async_trait; use async_trait::async_trait;
use std::{marker::PhantomData, sync::Arc};
use structopt::StructOpt; use structopt::StructOpt;
use futures::{FutureExt, TryFutureExt}; use crate::bridges::{
use relay_to_parachain::*;
use crate::{
bridges::{
kusama_polkadot::{ kusama_polkadot::{
kusama_parachains_to_bridge_hub_polkadot::BridgeHubKusamaToBridgeHubPolkadotCliBridge, kusama_parachains_to_bridge_hub_polkadot::BridgeHubKusamaToBridgeHubPolkadotCliBridge,
polkadot_parachains_to_bridge_hub_kusama::BridgeHubPolkadotToBridgeHubKusamaCliBridge, polkadot_parachains_to_bridge_hub_kusama::BridgeHubPolkadotToBridgeHubKusamaCliBridge,
@@ -56,143 +44,27 @@ use crate::{
rococo_parachains_to_bridge_hub_westend::BridgeHubRococoToBridgeHubWestendCliBridge, rococo_parachains_to_bridge_hub_westend::BridgeHubRococoToBridgeHubWestendCliBridge,
westend_parachains_to_bridge_hub_rococo::BridgeHubWestendToBridgeHubRococoCliBridge, westend_parachains_to_bridge_hub_rococo::BridgeHubWestendToBridgeHubRococoCliBridge,
}, },
}, };
use relay_substrate_client::{
AccountKeyPairOf, ChainRuntimeVersion, ChainWithRuntimeVersion, ChainWithTransactions,
Parachain, SimpleRuntimeVersion,
};
use substrate_relay_helper::{
cli::{ cli::{
bridge::{ bridge::{
CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge, CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge,
RelayToRelayHeadersCliBridge, RelayToRelayHeadersCliBridge,
}, },
chain_schema::*, chain_schema::*,
relay_headers_and_messages::parachain_to_parachain::ParachainToParachainBridge, relay_headers_and_messages::{
CliChain, HexLaneId, PrometheusParams, parachain_to_parachain::ParachainToParachainBridge, relay_to_parachain::*,
BridgeEndCommonParams, Full2WayBridge, Full2WayBridgeCommonParams,
HeadersAndMessagesSharedParams,
}, },
declare_chain_cli_schema, },
declare_chain_cli_schema, declare_parachain_to_parachain_bridge_schema,
declare_relay_to_parachain_bridge_schema, TransactionParams,
}; };
use bp_messages::LaneId;
use bp_runtime::BalanceOf;
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithMessages,
ChainWithTransactions, Client, Parachain,
};
use relay_utils::metrics::MetricsParams;
use sp_core::Pair;
use substrate_relay_helper::{
messages_lane::{MessagesRelayLimits, MessagesRelayParams},
on_demand::OnDemandRelay,
TaggedAccount, TransactionParams,
};
/// 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>,
/// 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,
}
/// 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<Left>,
/// Parameters of the right chain.
pub right: BridgeEndCommonParams<Right>,
/// Common metric parameters.
pub metrics_params: MetricsParams,
}
impl<Left: ChainWithTransactions + CliChain, Right: ChainWithTransactions + CliChain>
Full2WayBridgeCommonParams<Left, Right>
{
/// Creates new bridge parameters from its components.
pub fn new<L2R: MessagesCliBridge<Source = Left, Target = Right>>(
shared: HeadersAndMessagesSharedParams,
left: BridgeEndCommonParams<Left>,
right: BridgeEndCommonParams<Right>,
) -> anyhow::Result<Self> {
// Create metrics registry.
let metrics_params = shared.prometheus_params.clone().into_metrics_params()?;
let metrics_params = relay_utils::relay_metrics(metrics_params).into_params();
Ok(Self { shared, left, right, metrics_params })
}
}
/// Parameters that are associated with one side of the bridge.
pub struct BridgeEndCommonParams<Chain: ChainWithTransactions + CliChain> {
/// Chain client.
pub client: Client<Chain>,
/// Params used for sending transactions to the chain.
pub tx_params: TransactionParams<AccountKeyPairOf<Chain>>,
/// Accounts, which balances are exposed as metrics by the relay process.
pub accounts: Vec<TaggedAccount<AccountIdOf<Chain>>>,
}
/// All data of the bidirectional complex relay.
struct FullBridge<
'a,
Source: ChainWithTransactions + CliChain,
Target: ChainWithTransactions + CliChain,
Bridge: MessagesCliBridge<Source = Source, Target = Target>,
> {
source: &'a mut BridgeEndCommonParams<Source>,
target: &'a mut BridgeEndCommonParams<Target>,
metrics_params: &'a MetricsParams,
_phantom_data: PhantomData<Bridge>,
}
impl<
'a,
Source: ChainWithTransactions + CliChain,
Target: ChainWithTransactions + CliChain,
Bridge: MessagesCliBridge<Source = Source, Target = Target>,
> FullBridge<'a, Source, Target, Bridge>
where
AccountIdOf<Source>: From<<AccountKeyPairOf<Source> as Pair>::Public>,
AccountIdOf<Target>: From<<AccountKeyPairOf<Target> as Pair>::Public>,
BalanceOf<Source>: TryFrom<BalanceOf<Target>> + Into<u128>,
{
/// Construct complex relay given it components.
fn new(
source: &'a mut BridgeEndCommonParams<Source>,
target: &'a mut BridgeEndCommonParams<Target>,
metrics_params: &'a MetricsParams,
) -> Self {
Self { source, target, metrics_params, _phantom_data: Default::default() }
}
/// Returns message relay parameters.
fn messages_relay_params(
&self,
source_to_target_headers_relay: Arc<dyn OnDemandRelay<Source, Target>>,
target_to_source_headers_relay: Arc<dyn OnDemandRelay<Target, Source>>,
lane_id: LaneId,
maybe_limits: Option<MessagesRelayLimits>,
) -> MessagesRelayParams<Bridge::MessagesLane> {
MessagesRelayParams {
source_client: self.source.client.clone(),
source_transaction_params: self.source.tx_params.clone(),
target_client: self.target.client.clone(),
target_transaction_params: self.target.tx_params.clone(),
source_to_target_headers_relay: Some(source_to_target_headers_relay),
target_to_source_headers_relay: Some(target_to_source_headers_relay),
lane_id,
limits: maybe_limits,
metrics_params: self.metrics_params.clone().disable(),
}
}
}
// All supported chains. // All supported chains.
declare_chain_cli_schema!(Rococo, rococo); declare_chain_cli_schema!(Rococo, rococo);
@@ -247,171 +119,6 @@ declare_parachain_to_parachain_bridge_schema!(BridgeHubKusama, Kusama, BridgeHub
declare_relay_to_parachain_bridge_schema!(PolkadotBulletin, BridgeHubPolkadot, Polkadot); declare_relay_to_parachain_bridge_schema!(PolkadotBulletin, BridgeHubPolkadot, Polkadot);
declare_relay_to_parachain_bridge_schema!(RococoBulletin, BridgeHubRococo, Rococo); declare_relay_to_parachain_bridge_schema!(RococoBulletin, BridgeHubRococo, Rococo);
/// 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.
type Params;
/// The left relay chain.
type Left: ChainWithTransactions + CliChain;
/// 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<Self::Left, Self::Right>;
/// Mutable reference to common relay parameters.
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right>;
/// Start on-demand headers relays.
async fn start_on_demand_headers_relayers(
&mut self,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<Self::Left, Self::Right>>,
Arc<dyn OnDemandRelay<Self::Right, Self::Left>>,
)>;
}
/// Bidirectional complex relay.
#[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>,
{
/// Base portion of the bidirectional complex relay.
type Base: Full2WayBridgeBase<Left = Self::Left, Right = Self::Right>;
/// The left relay chain.
type Left: ChainWithTransactions + ChainWithBalances + ChainWithMessages + CliChain;
/// The right relay chain.
type Right: ChainWithTransactions + ChainWithBalances + ChainWithMessages + CliChain;
/// 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>;
/// Construct new bridge.
fn new(params: <Self::Base as Full2WayBridgeBase>::Params) -> anyhow::Result<Self>;
/// 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<Self::Left, Self::Right, Self::L2R> {
let common = self.mut_base().mut_common();
FullBridge::<_, _, Self::L2R>::new(
&mut common.left,
&mut common.right,
&common.metrics_params,
)
}
/// Creates and returns Right to Left complex relay.
fn right_to_left(&mut self) -> FullBridge<Self::Right, Self::Left, Self::R2L> {
let common = self.mut_base().mut_common();
FullBridge::<_, _, Self::R2L>::new(
&mut common.right,
&mut common.left,
&common.metrics_params,
)
}
/// Start complex relay.
async fn run(&mut self) -> anyhow::Result<()> {
// Register standalone metrics.
{
let common = self.mut_base().mut_common();
common.left.accounts.push(TaggedAccount::Messages {
id: common.left.tx_params.signer.public().into(),
bridged_chain: Self::Right::NAME.to_string(),
});
common.right.accounts.push(TaggedAccount::Messages {
id: common.right.tx_params.signer.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 lanes = self
.base()
.common()
.shared
.lane
.iter()
.cloned()
.map(Into::into)
.collect::<Vec<_>>();
{
let common = self.mut_base().mut_common();
substrate_relay_helper::messages_metrics::add_relay_balances_metrics::<_, Self::Right>(
common.left.client.clone(),
&common.metrics_params,
&common.left.accounts,
&lanes,
)
.await?;
substrate_relay_helper::messages_metrics::add_relay_balances_metrics::<_, Self::Left>(
common.right.client.clone(),
&common.metrics_params,
&common.right.accounts,
&lanes,
)
.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 left_to_right_messages = substrate_relay_helper::messages_lane::run::<
<Self::L2R as MessagesCliBridge>::MessagesLane,
>(self.left_to_right().messages_relay_params(
left_to_right_on_demand_headers.clone(),
right_to_left_on_demand_headers.clone(),
lane,
Self::L2R::maybe_messages_limits(),
))
.map_err(|e| anyhow::format_err!("{}", e))
.boxed();
message_relays.push(left_to_right_messages);
let right_to_left_messages = substrate_relay_helper::messages_lane::run::<
<Self::R2L as MessagesCliBridge>::MessagesLane,
>(self.right_to_left().messages_relay_params(
right_to_left_on_demand_headers.clone(),
left_to_right_on_demand_headers.clone(),
lane,
Self::R2L::maybe_messages_limits(),
))
.map_err(|e| anyhow::format_err!("{}", e))
.boxed();
message_relays.push(right_to_left_messages);
}
relay_utils::relay_metrics(self.base().common().metrics_params.clone())
.expose()
.await
.map_err(|e| anyhow::format_err!("{}", e))?;
futures::future::select_all(message_relays).await.0
}
}
/// BridgeHubRococo <> BridgeHubWestend complex relay. /// BridgeHubRococo <> BridgeHubWestend complex relay.
pub struct BridgeHubRococoBridgeHubWestendFull2WayBridge { pub struct BridgeHubRococoBridgeHubWestendFull2WayBridge {
base: <Self as Full2WayBridge>::Base, base: <Self as Full2WayBridge>::Base,
@@ -556,6 +263,7 @@ impl RelayHeadersAndMessages {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use substrate_relay_helper::cli::{HexLaneId, PrometheusParams};
#[test] #[test]
fn should_parse_parachain_to_parachain_options() { fn should_parse_parachain_to_parachain_options() {
@@ -14,10 +14,8 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use async_trait::async_trait;
use sp_core::Pair;
use structopt::StructOpt; use structopt::StructOpt;
use strum::VariantNames; use strum::{EnumString, VariantNames};
use crate::bridges::{ use crate::bridges::{
kusama_polkadot::{ kusama_polkadot::{
@@ -37,10 +35,21 @@ use crate::bridges::{
bridge_hub_westend_messages_to_bridge_hub_rococo::BridgeHubWestendToBridgeHubRococoMessagesCliBridge, bridge_hub_westend_messages_to_bridge_hub_rococo::BridgeHubWestendToBridgeHubRococoMessagesCliBridge,
}, },
}; };
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, BalanceOf, ChainWithTransactions}; use substrate_relay_helper::cli::relay_messages::{MessagesRelayer, RelayMessagesParams};
use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams};
use crate::cli::{bridge::*, chain_schema::*, CliChain, HexLaneId, PrometheusParams}; #[derive(Debug, PartialEq, Eq, EnumString, VariantNames)]
#[strum(serialize_all = "kebab_case")]
/// Supported full bridges (headers + messages).
pub enum FullBridge {
BridgeHubRococoToBridgeHubWestend,
BridgeHubWestendToBridgeHubRococo,
BridgeHubKusamaToBridgeHubPolkadot,
BridgeHubPolkadotToBridgeHubKusama,
PolkadotBulletinToBridgeHubPolkadot,
BridgeHubPolkadotToPolkadotBulletin,
RococoBulletinToBridgeHubRococo,
BridgeHubRococoToRococoBulletin,
}
/// Start messages relayer process. /// Start messages relayer process.
#[derive(StructOpt)] #[derive(StructOpt)]
@@ -48,57 +57,8 @@ pub struct RelayMessages {
/// A bridge instance to relay messages for. /// A bridge instance to relay messages for.
#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)] #[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
bridge: FullBridge, bridge: FullBridge,
/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
#[structopt(flatten)] #[structopt(flatten)]
source: SourceConnectionParams, params: RelayMessagesParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
}
#[async_trait]
trait MessagesRelayer: MessagesCliBridge
where
Self::Source: ChainWithTransactions + CliChain,
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.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.into_client::<Self::Target>().await?;
let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
let target_transactions_mortality = data.target_sign.transactions_mortality()?;
substrate_relay_helper::messages_lane::run::<Self::MessagesLane>(MessagesRelayParams {
source_client,
source_transaction_params: TransactionParams {
signer: source_sign,
mortality: source_transactions_mortality,
},
target_client,
target_transaction_params: TransactionParams {
signer: target_sign,
mortality: target_transactions_mortality,
},
source_to_target_headers_relay: None,
target_to_source_headers_relay: None,
lane_id: data.lane.into(),
limits: Self::maybe_messages_limits(),
metrics_params: data.prometheus_params.into_metrics_params()?,
})
.await
.map_err(|e| anyhow::format_err!("{}", e))
}
} }
impl MessagesRelayer for BridgeHubRococoToBridgeHubWestendMessagesCliBridge {} impl MessagesRelayer for BridgeHubRococoToBridgeHubWestendMessagesCliBridge {}
@@ -115,21 +75,21 @@ impl RelayMessages {
pub async fn run(self) -> anyhow::Result<()> { pub async fn run(self) -> anyhow::Result<()> {
match self.bridge { match self.bridge {
FullBridge::BridgeHubRococoToBridgeHubWestend => FullBridge::BridgeHubRococoToBridgeHubWestend =>
BridgeHubRococoToBridgeHubWestendMessagesCliBridge::relay_messages(self), BridgeHubRococoToBridgeHubWestendMessagesCliBridge::relay_messages(self.params),
FullBridge::BridgeHubWestendToBridgeHubRococo => FullBridge::BridgeHubWestendToBridgeHubRococo =>
BridgeHubWestendToBridgeHubRococoMessagesCliBridge::relay_messages(self), BridgeHubWestendToBridgeHubRococoMessagesCliBridge::relay_messages(self.params),
FullBridge::BridgeHubKusamaToBridgeHubPolkadot => FullBridge::BridgeHubKusamaToBridgeHubPolkadot =>
BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge::relay_messages(self), BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge::relay_messages(self.params),
FullBridge::BridgeHubPolkadotToBridgeHubKusama => FullBridge::BridgeHubPolkadotToBridgeHubKusama =>
BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge::relay_messages(self), BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge::relay_messages(self.params),
FullBridge::PolkadotBulletinToBridgeHubPolkadot => FullBridge::PolkadotBulletinToBridgeHubPolkadot =>
PolkadotBulletinToBridgeHubPolkadotMessagesCliBridge::relay_messages(self), PolkadotBulletinToBridgeHubPolkadotMessagesCliBridge::relay_messages(self.params),
FullBridge::BridgeHubPolkadotToPolkadotBulletin => FullBridge::BridgeHubPolkadotToPolkadotBulletin =>
BridgeHubPolkadotToPolkadotBulletinMessagesCliBridge::relay_messages(self), BridgeHubPolkadotToPolkadotBulletinMessagesCliBridge::relay_messages(self.params),
FullBridge::RococoBulletinToBridgeHubRococo => FullBridge::RococoBulletinToBridgeHubRococo =>
RococoBulletinToBridgeHubRococoMessagesCliBridge::relay_messages(self), RococoBulletinToBridgeHubRococoMessagesCliBridge::relay_messages(self.params),
FullBridge::BridgeHubRococoToRococoBulletin => FullBridge::BridgeHubRococoToRococoBulletin =>
BridgeHubRococoToRococoBulletinMessagesCliBridge::relay_messages(self), BridgeHubRococoToRococoBulletinMessagesCliBridge::relay_messages(self.params),
} }
.await .await
} }
@@ -26,24 +26,9 @@ use crate::bridges::{
westend_parachains_to_bridge_hub_rococo::BridgeHubWestendToBridgeHubRococoCliBridge, westend_parachains_to_bridge_hub_rococo::BridgeHubWestendToBridgeHubRococoCliBridge,
}, },
}; };
use async_std::sync::Mutex;
use async_trait::async_trait;
use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient};
use relay_substrate_client::Parachain;
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
use std::sync::Arc;
use structopt::StructOpt; use structopt::StructOpt;
use strum::{EnumString, VariantNames}; use strum::{EnumString, VariantNames};
use substrate_relay_helper::{ use substrate_relay_helper::cli::relay_parachains::{ParachainsRelayer, RelayParachainsParams};
parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter},
TransactionParams,
};
use crate::cli::{
bridge::{CliBridgeBase, ParachainToRelayHeadersCliBridge},
chain_schema::*,
PrometheusParams,
};
/// Start parachain heads relayer process. /// Start parachain heads relayer process.
#[derive(StructOpt)] #[derive(StructOpt)]
@@ -52,13 +37,7 @@ pub struct RelayParachains {
#[structopt(possible_values = RelayParachainsBridge::VARIANTS, case_insensitive = true)] #[structopt(possible_values = RelayParachainsBridge::VARIANTS, case_insensitive = true)]
bridge: RelayParachainsBridge, bridge: RelayParachainsBridge,
#[structopt(flatten)] #[structopt(flatten)]
source: SourceConnectionParams, params: RelayParachainsParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
} }
/// Parachain heads relay bridge. /// Parachain heads relay bridge.
@@ -73,47 +52,6 @@ pub enum RelayParachainsBridge {
WestendToBridgeHubRococo, WestendToBridgeHubRococo,
} }
#[async_trait]
trait ParachainsRelayer: ParachainToRelayHeadersCliBridge
where
ParachainsSource<Self::ParachainFinality>:
SourceClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
ParachainsTarget<Self::ParachainFinality>:
TargetClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
<Self as CliBridgeBase>::Source: Parachain,
{
async fn relay_parachains(data: RelayParachains) -> anyhow::Result<()> {
let source_client = data.source.into_client::<Self::SourceRelay>().await?;
let source_client = ParachainsSource::<Self::ParachainFinality>::new(
source_client,
Arc::new(Mutex::new(AvailableHeader::Missing)),
);
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.into_client::<Self::Target>().await?;
let target_client = ParachainsTarget::<Self::ParachainFinality>::new(
target_client.clone(),
target_transaction_params,
);
let metrics_params: relay_utils::metrics::MetricsParams =
data.prometheus_params.into_metrics_params()?;
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
parachains_relay::parachains_loop::run(
source_client,
target_client,
metrics_params,
futures::future::pending(),
)
.await
.map_err(|e| anyhow::format_err!("{}", e))
}
}
impl ParachainsRelayer for BridgeHubRococoToBridgeHubWestendCliBridge {} impl ParachainsRelayer for BridgeHubRococoToBridgeHubWestendCliBridge {}
impl ParachainsRelayer for BridgeHubWestendToBridgeHubRococoCliBridge {} impl ParachainsRelayer for BridgeHubWestendToBridgeHubRococoCliBridge {}
impl ParachainsRelayer for BridgeHubKusamaToBridgeHubPolkadotCliBridge {} impl ParachainsRelayer for BridgeHubKusamaToBridgeHubPolkadotCliBridge {}
@@ -126,17 +64,17 @@ impl RelayParachains {
pub async fn run(self) -> anyhow::Result<()> { pub async fn run(self) -> anyhow::Result<()> {
match self.bridge { match self.bridge {
RelayParachainsBridge::RococoToBridgeHubWestend => RelayParachainsBridge::RococoToBridgeHubWestend =>
BridgeHubRococoToBridgeHubWestendCliBridge::relay_parachains(self), BridgeHubRococoToBridgeHubWestendCliBridge::relay_parachains(self.params),
RelayParachainsBridge::WestendToBridgeHubRococo => RelayParachainsBridge::WestendToBridgeHubRococo =>
BridgeHubWestendToBridgeHubRococoCliBridge::relay_parachains(self), BridgeHubWestendToBridgeHubRococoCliBridge::relay_parachains(self.params),
RelayParachainsBridge::KusamaToBridgeHubPolkadot => RelayParachainsBridge::KusamaToBridgeHubPolkadot =>
BridgeHubKusamaToBridgeHubPolkadotCliBridge::relay_parachains(self), BridgeHubKusamaToBridgeHubPolkadotCliBridge::relay_parachains(self.params),
RelayParachainsBridge::PolkadotToBridgeHubKusama => RelayParachainsBridge::PolkadotToBridgeHubKusama =>
BridgeHubPolkadotToBridgeHubKusamaCliBridge::relay_parachains(self), BridgeHubPolkadotToBridgeHubKusamaCliBridge::relay_parachains(self.params),
RelayParachainsBridge::PolkadotToPolkadotBulletin => RelayParachainsBridge::PolkadotToPolkadotBulletin =>
PolkadotToPolkadotBulletinCliBridge::relay_parachains(self), PolkadotToPolkadotBulletinCliBridge::relay_parachains(self.params),
RelayParachainsBridge::RococoToRococoBulletin => RelayParachainsBridge::RococoToRococoBulletin =>
RococoToRococoBulletinCliBridge::relay_parachains(self), RococoToRococoBulletinCliBridge::relay_parachains(self.params),
} }
.await .await
} }
-1
View File
@@ -19,7 +19,6 @@
#![warn(missing_docs)] #![warn(missing_docs)]
mod bridges; mod bridges;
mod chains;
mod cli; mod cli;
fn main() { fn main() {
@@ -23,8 +23,9 @@ use bp_polkadot::SuffixedCommonTransactionExtensionExt;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages,
ChainWithTransactions, ChainWithUtilityPallet, Error as SubstrateError, ChainWithRuntimeVersion, ChainWithTransactions, ChainWithUtilityPallet,
MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, SimpleRuntimeVersion,
UnderlyingChainProvider, UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
@@ -120,3 +121,8 @@ impl ChainWithMessages for BridgeHubKusama {
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
bp_bridge_hub_kusama::FROM_BRIDGE_HUB_KUSAMA_MESSAGE_DETAILS_METHOD; bp_bridge_hub_kusama::FROM_BRIDGE_HUB_KUSAMA_MESSAGE_DETAILS_METHOD;
} }
impl ChainWithRuntimeVersion for BridgeHubKusama {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_000, transaction_version: 4 });
}
@@ -23,8 +23,9 @@ use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages,
ChainWithTransactions, ChainWithUtilityPallet, Error as SubstrateError, ChainWithRuntimeVersion, ChainWithTransactions, ChainWithUtilityPallet,
MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, SimpleRuntimeVersion,
UnderlyingChainProvider, UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
@@ -124,3 +125,8 @@ impl ChainWithMessages for BridgeHubPolkadot {
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
bp_bridge_hub_polkadot::FROM_BRIDGE_HUB_POLKADOT_MESSAGE_DETAILS_METHOD; bp_bridge_hub_polkadot::FROM_BRIDGE_HUB_POLKADOT_MESSAGE_DETAILS_METHOD;
} }
impl ChainWithRuntimeVersion for BridgeHubPolkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_000, transaction_version: 3 });
}
@@ -23,8 +23,9 @@ use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages,
ChainWithTransactions, ChainWithUtilityPallet, Error as SubstrateError, ChainWithRuntimeVersion, ChainWithTransactions, ChainWithUtilityPallet,
MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, SimpleRuntimeVersion,
UnderlyingChainProvider, UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
@@ -122,3 +123,8 @@ impl ChainWithMessages for BridgeHubRococo {
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
bp_bridge_hub_rococo::FROM_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD; bp_bridge_hub_rococo::FROM_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD;
} }
impl ChainWithRuntimeVersion for BridgeHubRococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 4 });
}
@@ -23,8 +23,9 @@ use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages,
ChainWithTransactions, ChainWithUtilityPallet, Error as SubstrateError, ChainWithRuntimeVersion, ChainWithTransactions, ChainWithUtilityPallet,
MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, SimpleRuntimeVersion,
UnderlyingChainProvider, UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
@@ -120,3 +121,8 @@ impl ChainWithMessages for BridgeHubWestend {
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
bp_bridge_hub_westend::FROM_BRIDGE_HUB_WESTEND_MESSAGE_DETAILS_METHOD; bp_bridge_hub_westend::FROM_BRIDGE_HUB_WESTEND_MESSAGE_DETAILS_METHOD;
} }
impl ChainWithRuntimeVersion for BridgeHubWestend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 4 });
}
+8 -2
View File
@@ -22,8 +22,9 @@ use bp_kusama::{AccountInfoStorageMapKeyProvider, KUSAMA_SYNCED_HEADERS_GRANDPA_
use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithTransactions, Error as SubstrateError, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions,
RelayChain, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, RelayChain, SignParam, SimpleRuntimeVersion, UnderlyingChainProvider,
UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
@@ -114,3 +115,8 @@ impl ChainWithTransactions for Kusama {
)) ))
} }
} }
impl ChainWithRuntimeVersion for Kusama {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_002, transaction_version: 25 });
}
@@ -21,8 +21,9 @@ mod codegen_runtime;
use bp_polkadot_bulletin::POLKADOT_BULLETIN_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use bp_polkadot_bulletin::POLKADOT_BULLETIN_SYNCED_HEADERS_GRANDPA_INFO_METHOD;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, ChainWithTransactions, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, ChainWithRuntimeVersion,
Error as SubstrateError, SignParam, UnderlyingChainProvider, UnsignedTransaction, ChainWithTransactions, Error as SubstrateError, SignParam, SimpleRuntimeVersion,
UnderlyingChainProvider, UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
@@ -131,3 +132,8 @@ impl ChainWithTransactions for PolkadotBulletin {
)) ))
} }
} }
impl ChainWithRuntimeVersion for PolkadotBulletin {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 100, transaction_version: 1 });
}
+8 -2
View File
@@ -22,8 +22,9 @@ use bp_polkadot::{AccountInfoStorageMapKeyProvider, POLKADOT_SYNCED_HEADERS_GRAN
use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithTransactions, Error as SubstrateError, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions,
RelayChain, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, RelayChain, SignParam, SimpleRuntimeVersion, UnderlyingChainProvider,
UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
@@ -114,3 +115,8 @@ impl ChainWithTransactions for Polkadot {
)) ))
} }
} }
impl ChainWithRuntimeVersion for Polkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_002, transaction_version: 25 });
}
+8 -2
View File
@@ -22,8 +22,9 @@ use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use bp_rococo::ROCOCO_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use bp_rococo::ROCOCO_SYNCED_HEADERS_GRANDPA_INFO_METHOD;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithTransactions, Error as SubstrateError, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions,
RelayChain, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, RelayChain, SignParam, SimpleRuntimeVersion, UnderlyingChainProvider,
UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
@@ -114,3 +115,8 @@ impl ChainWithTransactions for Rococo {
)) ))
} }
} }
impl ChainWithRuntimeVersion for Rococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 24 });
}
@@ -16,6 +16,7 @@
use crate::calls::UtilityCall; use crate::calls::UtilityCall;
use crate::SimpleRuntimeVersion;
use bp_header_chain::ChainWithGrandpa as ChainWithGrandpaBase; use bp_header_chain::ChainWithGrandpa as ChainWithGrandpaBase;
use bp_messages::ChainWithMessages as ChainWithMessagesBase; use bp_messages::ChainWithMessages as ChainWithMessagesBase;
use bp_runtime::{ use bp_runtime::{
@@ -58,6 +59,16 @@ pub trait Chain: ChainBase + Clone {
type Call: Clone + Codec + Debug + Send + Sync; type Call: Clone + Codec + Debug + Send + Sync;
} }
/// Bridge-supported network definition.
///
/// Used to abstract away CLI commands.
pub trait ChainWithRuntimeVersion: Chain {
/// Current version of the chain runtime, known to relay.
///
/// can be `None` if relay is not going to submit transactions to that chain.
const RUNTIME_VERSION: Option<SimpleRuntimeVersion>;
}
/// Substrate-based relay chain that supports parachains. /// Substrate-based relay chain that supports parachains.
/// ///
/// We assume that the parachains are supported using `runtime_parachains::paras` pallet. /// We assume that the parachains are supported using `runtime_parachains::paras` pallet.
+3 -3
View File
@@ -35,9 +35,9 @@ use std::time::Duration;
pub use crate::{ pub use crate::{
chain::{ chain::{
AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances, AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances,
ChainWithGrandpa, ChainWithMessages, ChainWithTransactions, ChainWithUtilityPallet, ChainWithGrandpa, ChainWithMessages, ChainWithRuntimeVersion, ChainWithTransactions,
FullRuntimeUtilityPallet, MockedRuntimeUtilityPallet, Parachain, RelayChain, SignParam, ChainWithUtilityPallet, FullRuntimeUtilityPallet, MockedRuntimeUtilityPallet, Parachain,
TransactionStatusOf, UnsignedTransaction, UtilityPallet, RelayChain, SignParam, TransactionStatusOf, UnsignedTransaction, UtilityPallet,
}, },
client::{ client::{
is_ancient_block, ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, is_ancient_block, ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet,
+8 -2
View File
@@ -22,8 +22,9 @@ use bp_polkadot_core::SuffixedCommonTransactionExtensionExt;
use bp_westend::WESTEND_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use bp_westend::WESTEND_SYNCED_HEADERS_GRANDPA_INFO_METHOD;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithTransactions, Error as SubstrateError, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions,
RelayChain, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, RelayChain, SignParam, SimpleRuntimeVersion, UnderlyingChainProvider,
UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
@@ -114,3 +115,8 @@ impl ChainWithTransactions for Westend {
)) ))
} }
} }
impl ChainWithRuntimeVersion for Westend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 24 });
}
@@ -10,14 +10,17 @@ workspace = true
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
thiserror = { workspace = true }
async-std = "1.9.0" async-std = "1.9.0"
async-trait = "0.1" async-trait = "0.1"
codec = { package = "parity-scale-codec", version = "3.1.5" } codec = { package = "parity-scale-codec", version = "3.1.5" }
futures = "0.3.30" futures = "0.3.30"
hex = "0.4" hex = "0.4"
num-traits = "0.2"
log = { workspace = true } log = { workspace = true }
num-traits = "0.2"
rbtag = "0.3"
structopt = "0.3"
strum = { version = "0.26.2", features = ["derive"] }
thiserror = { workspace = true }
# Bridge dependencies # Bridge dependencies
@@ -14,38 +14,26 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::cli::CliChain; //! Basic traits for exposing bridges in the CLI.
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{Chain, ChainWithTransactions, Parachain, RelayChain}; use crate::{
use strum::{EnumString, VariantNames};
use substrate_relay_helper::{
equivocation::SubstrateEquivocationDetectionPipeline, equivocation::SubstrateEquivocationDetectionPipeline,
finality::SubstrateFinalitySyncPipeline, finality::SubstrateFinalitySyncPipeline,
messages_lane::{MessagesRelayLimits, SubstrateMessageLane}, messages_lane::{MessagesRelayLimits, SubstrateMessageLane},
parachains::SubstrateParachainsPipeline, parachains::SubstrateParachainsPipeline,
}; };
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
#[derive(Debug, PartialEq, Eq, EnumString, VariantNames)] use relay_substrate_client::{
#[strum(serialize_all = "kebab_case")] Chain, ChainWithRuntimeVersion, ChainWithTransactions, Parachain, RelayChain,
/// Supported full bridges (headers + messages). };
pub enum FullBridge {
BridgeHubRococoToBridgeHubWestend,
BridgeHubWestendToBridgeHubRococo,
BridgeHubKusamaToBridgeHubPolkadot,
BridgeHubPolkadotToBridgeHubKusama,
PolkadotBulletinToBridgeHubPolkadot,
BridgeHubPolkadotToPolkadotBulletin,
RococoBulletinToBridgeHubRococo,
BridgeHubRococoToRococoBulletin,
}
/// Minimal bridge representation that can be used from the CLI. /// Minimal bridge representation that can be used from the CLI.
/// It connects a source chain to a target chain. /// It connects a source chain to a target chain.
pub trait CliBridgeBase: Sized { pub trait CliBridgeBase: Sized {
/// The source chain. /// The source chain.
type Source: Chain + CliChain; type Source: Chain + ChainWithRuntimeVersion;
/// The target chain. /// The target chain.
type Target: ChainWithTransactions + CliChain; type Target: ChainWithTransactions + ChainWithRuntimeVersion;
} }
/// Bridge representation that can be used from the CLI for relaying headers /// Bridge representation that can be used from the CLI for relaying headers
@@ -60,6 +48,7 @@ pub trait RelayToRelayHeadersCliBridge: CliBridgeBase {
/// Convenience trait that adds bounds to `CliBridgeBase`. /// Convenience trait that adds bounds to `CliBridgeBase`.
pub trait RelayToRelayEquivocationDetectionCliBridgeBase: CliBridgeBase { pub trait RelayToRelayEquivocationDetectionCliBridgeBase: CliBridgeBase {
/// The source chain with extra bounds.
type BoundedSource: ChainWithTransactions; type BoundedSource: ChainWithTransactions;
} }
@@ -89,10 +78,10 @@ pub trait ParachainToRelayHeadersCliBridge: CliBridgeBase
where where
Self::Source: Parachain, Self::Source: Parachain,
{ {
// The `CliBridgeBase` type represents the parachain in this situation. /// The `CliBridgeBase` type represents the parachain in this situation.
// We need to add an extra type for the relay chain. /// We need to add an extra type for the relay chain.
type SourceRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher> type SourceRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain + ChainWithRuntimeVersion
+ RelayChain; + RelayChain;
/// Finality proofs synchronization pipeline (source parachain -> target). /// Finality proofs synchronization pipeline (source parachain -> target).
type ParachainFinality: SubstrateParachainsPipeline< type ParachainFinality: SubstrateParachainsPipeline<
@@ -0,0 +1,250 @@
// 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/>.
//! Primitives related to chain CLI options.
use relay_substrate_client::{AccountKeyPairOf, ChainWithTransactions};
use structopt::StructOpt;
use strum::{EnumString, VariantNames};
use relay_substrate_client::{ChainRuntimeVersion, ChainWithRuntimeVersion, SimpleRuntimeVersion};
use crate::TransactionParams;
#[doc = "Runtime version params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)]
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) => {
bp_runtime::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<SimpleRuntimeVersion>,
) -> anyhow::Result<ChainRuntimeVersion> {
Ok(match self.[<$chain_prefix _version_mode>] {
RuntimeVersionType::Auto => ChainRuntimeVersion::Auto,
RuntimeVersionType::Custom => {
let custom_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 custom_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(
SimpleRuntimeVersion {
spec_version: custom_spec_version,
transaction_version: custom_transaction_version
}
)
},
RuntimeVersionType::Bundle => match bundle_runtime_version {
Some(runtime_version) => ChainRuntimeVersion::Custom(runtime_version),
None => {
return Err(anyhow::format_err!("Cannot use bundled runtime version of {}: it is not known to the relay", stringify!($chain_prefix)));
}
},
})
}
}
}
};
}
/// Create chain-specific set of runtime version parameters.
#[macro_export]
macro_rules! declare_chain_connection_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::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: ChainWithRuntimeVersion>(
self,
) -> anyhow::Result<relay_substrate_client::Client<Chain>> {
let chain_runtime_version = self
.[<$chain_prefix _runtime_version>]
.into_runtime_version(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
)
}
}
}
};
}
/// Create chain-specific set of signing parameters.
#[macro_export]
macro_rules! declare_chain_signing_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::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: ChainWithTransactions>(&self) -> anyhow::Result<AccountKeyPairOf<Chain>> {
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;
AccountKeyPairOf::<Chain>::from_string(
&suri,
suri_password.as_deref()
).map_err(|e| anyhow::format_err!("{:?}", e))
}
/// Return transaction parameters.
#[allow(dead_code)]
pub fn transaction_params<Chain: ChainWithTransactions>(
&self,
) -> anyhow::Result<TransactionParams<AccountKeyPairOf<Chain>>> {
Ok(TransactionParams {
mortality: self.transactions_mortality()?,
signer: self.to_keypair::<Chain>()?,
})
}
}
}
};
}
/// 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);
};
}
declare_chain_cli_schema!(Source, source);
declare_chain_cli_schema!(Target, target);
@@ -0,0 +1,65 @@
// Copyright 2019-2023 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/>.
//! Primitives for exposing the equivocation detection functionality in the CLI.
use crate::{
cli::{bridge::*, chain_schema::*, PrometheusParams},
equivocation,
equivocation::SubstrateEquivocationDetectionPipeline,
};
use async_trait::async_trait;
use relay_substrate_client::ChainWithTransactions;
use structopt::StructOpt;
/// Start equivocation detection loop.
#[derive(StructOpt)]
pub struct DetectEquivocationsParams {
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
}
/// Trait used for starting the equivocation detection loop between 2 chains.
#[async_trait]
pub trait EquivocationsDetector: RelayToRelayEquivocationDetectionCliBridge
where
Self::Source: ChainWithTransactions,
{
/// Start the equivocation detection loop.
async fn start(data: DetectEquivocationsParams) -> anyhow::Result<()> {
let source_client = data.source.into_client::<Self::Source>().await?;
Self::Equivocation::start_relay_guards(
&source_client,
source_client.can_start_version_guard(),
)
.await?;
equivocation::run::<Self::Equivocation>(
source_client,
data.target.into_client::<Self::Target>().await?,
data.source_sign.transaction_params::<Self::Source>()?,
data.prometheus_params.into_metrics_params()?,
)
.await
}
}
@@ -0,0 +1,85 @@
// 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/>.
//! Primitives for exposing the bridge initialization functionality in the CLI.
use async_trait::async_trait;
use codec::Encode;
use crate::{
cli::{bridge::CliBridgeBase, chain_schema::*},
finality_base::engine::Engine,
};
use bp_runtime::Chain as ChainBase;
use relay_substrate_client::{AccountKeyPairOf, Chain, UnsignedTransaction};
use sp_core::Pair;
use structopt::StructOpt;
/// Bridge initialization params.
#[derive(StructOpt)]
pub struct InitBridgeParams {
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
/// Generates all required data, but does not submit extrinsic
#[structopt(long)]
dry_run: bool,
}
/// Trait used for bridge initializing.
#[async_trait]
pub trait BridgeInitializer: CliBridgeBase
where
<Self::Target as ChainBase>::AccountId: From<<AccountKeyPairOf<Self::Target> as Pair>::Public>,
{
/// The finality engine used by the source chain.
type Engine: Engine<Self::Source>;
/// Get the encoded call to init the bridge.
fn encode_init_bridge(
init_data: <Self::Engine as Engine<Self::Source>>::InitializationData,
) -> <Self::Target as Chain>::Call;
/// Initialize the bridge.
async fn init_bridge(data: InitBridgeParams) -> anyhow::Result<()> {
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 dry_run = data.dry_run;
crate::finality::initialize::initialize::<Self::Engine, _, _, _>(
source_client,
target_client.clone(),
target_sign,
move |transaction_nonce, initialization_data| {
let call = Self::encode_init_bridge(initialization_data);
log::info!(
target: "bridge",
"Initialize bridge call encoded as hex string: {:?}",
format!("0x{}", hex::encode(call.encode()))
);
Ok(UnsignedTransaction::new(call.into(), transaction_nonce))
},
dry_run,
)
.await;
Ok(())
}
}
@@ -0,0 +1,192 @@
// 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/>.
//! Deal with CLI args of substrate-to-substrate relay.
use codec::{Decode, Encode};
use rbtag::BuildInfo;
use structopt::StructOpt;
use strum::{EnumString, VariantNames};
use bp_messages::LaneId;
pub mod bridge;
pub mod chain_schema;
pub mod detect_equivocations;
pub mod init_bridge;
pub mod relay_headers;
pub mod relay_headers_and_messages;
pub mod relay_messages;
pub mod relay_parachains;
/// The target that will be used when publishing logs related to this pallet.
pub const LOG_TARGET: &str = "bridge";
/// Lane id.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HexLaneId(pub [u8; 4]);
impl From<HexLaneId> for LaneId {
fn from(lane_id: HexLaneId) -> LaneId {
LaneId(lane_id.0)
}
}
impl std::str::FromStr for HexLaneId {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut lane_id = [0u8; 4];
hex::decode_to_slice(s, &mut lane_id)?;
Ok(HexLaneId(lane_id))
}
}
/// Nicer formatting for raw bytes vectors.
#[derive(Default, Encode, Decode, PartialEq, Eq)]
pub struct HexBytes(pub Vec<u8>);
impl std::str::FromStr for HexBytes {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(hex::decode(s)?))
}
}
impl std::fmt::Debug for HexBytes {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "0x{self}")
}
}
impl std::fmt::Display for HexBytes {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", hex::encode(&self.0))
}
}
/// Prometheus metrics params.
#[derive(Clone, Debug, PartialEq, StructOpt)]
pub struct PrometheusParams {
/// Do not expose a Prometheus metric endpoint.
#[structopt(long)]
pub no_prometheus: bool,
/// Expose Prometheus endpoint at given interface.
#[structopt(long, default_value = "127.0.0.1")]
pub prometheus_host: String,
/// Expose Prometheus endpoint at given port.
#[structopt(long, default_value = "9616")]
pub prometheus_port: u16,
}
/// Struct to get git commit info and build time.
#[derive(BuildInfo)]
struct SubstrateRelayBuildInfo;
impl SubstrateRelayBuildInfo {
/// Get git commit in form `<short-sha-(clean|dirty)>`.
pub fn get_git_commit() -> String {
// on gitlab we use images without git installed, so we can't use `rbtag` there
// locally we don't have `CI_*` env variables, so we can't rely on them
// => we are using `CI_*` env variables or else `rbtag`
let maybe_sha_from_ci = option_env!("CI_COMMIT_SHORT_SHA");
maybe_sha_from_ci
.map(|short_sha| {
// we assume that on CI the copy is always clean
format!("{short_sha}-clean")
})
.unwrap_or_else(|| SubstrateRelayBuildInfo.get_build_commit().into())
}
}
impl PrometheusParams {
/// Tries to convert CLI metrics params into metrics params, used by the relay.
pub fn into_metrics_params(self) -> anyhow::Result<relay_utils::metrics::MetricsParams> {
let metrics_address = if !self.no_prometheus {
Some(relay_utils::metrics::MetricsAddress {
host: self.prometheus_host,
port: self.prometheus_port,
})
} else {
None
};
let relay_version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
let relay_commit = SubstrateRelayBuildInfo::get_git_commit();
relay_utils::metrics::MetricsParams::new(
metrics_address,
relay_version.into(),
relay_commit,
)
.map_err(|e| anyhow::format_err!("{:?}", e))
}
}
/// Either explicit or maximal allowed value.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExplicitOrMaximal<V> {
/// User has explicitly specified argument value.
Explicit(V),
/// Maximal allowed value for this argument.
Maximal,
}
impl<V: std::str::FromStr> std::str::FromStr for ExplicitOrMaximal<V>
where
V::Err: std::fmt::Debug,
{
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.to_lowercase() == "max" {
return Ok(ExplicitOrMaximal::Maximal)
}
V::from_str(s)
.map(ExplicitOrMaximal::Explicit)
.map_err(|e| format!("Failed to parse '{e:?}'. Expected 'max' or explicit value"))
}
}
#[doc = "Runtime version params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)]
pub enum RuntimeVersionType {
/// Auto query version from chain
Auto,
/// Custom `spec_version` and `transaction_version`
Custom,
/// Read version from bundle dependencies directly.
Bundle,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hex_bytes_display_matches_from_str_for_clap() {
// given
let hex = HexBytes(vec![1, 2, 3, 4]);
let display = format!("{hex}");
// when
let hex2: HexBytes = display.parse().unwrap();
// then
assert_eq!(hex.0, hex2.0);
}
}
@@ -0,0 +1,76 @@
// 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/>.
//! Primitives for exposing the headers relaying functionality in the CLI.
use async_trait::async_trait;
use structopt::StructOpt;
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
use crate::{
cli::{bridge::*, chain_schema::*, PrometheusParams},
finality::SubstrateFinalitySyncPipeline,
};
/// Chain headers relaying params.
#[derive(StructOpt)]
pub struct RelayHeadersParams {
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
/// are relayed.
#[structopt(long)]
only_mandatory_headers: bool,
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
}
/// Trait used for relaying headers between 2 chains.
#[async_trait]
pub trait HeadersRelayer: RelayToRelayHeadersCliBridge {
/// Relay headers.
async fn relay_headers(data: RelayHeadersParams) -> anyhow::Result<()> {
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>()?;
let metrics_params: relay_utils::metrics::MetricsParams =
data.prometheus_params.into_metrics_params()?;
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
let target_transactions_params = crate::TransactionParams {
signer: target_sign,
mortality: target_transactions_mortality,
};
Self::Finality::start_relay_guards(&target_client, target_client.can_start_version_guard())
.await?;
crate::finality::run::<Self::Finality>(
source_client,
target_client,
data.only_mandatory_headers,
target_transactions_params,
metrics_params,
)
.await
}
}
@@ -0,0 +1,484 @@
// 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]
pub mod parachain_to_parachain;
#[macro_use]
pub mod relay_to_relay;
#[macro_use]
pub mod relay_to_parachain;
use async_trait::async_trait;
use std::{marker::PhantomData, sync::Arc};
use structopt::StructOpt;
use futures::{FutureExt, TryFutureExt};
use crate::{
cli::{bridge::MessagesCliBridge, HexLaneId, PrometheusParams},
messages_lane::{MessagesRelayLimits, MessagesRelayParams},
on_demand::OnDemandRelay,
TaggedAccount, TransactionParams,
};
use bp_messages::LaneId;
use bp_runtime::BalanceOf;
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithMessages,
ChainWithRuntimeVersion, ChainWithTransactions, Client,
};
use relay_utils::metrics::MetricsParams;
use sp_core::Pair;
/// 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>,
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
/// are relayed.
#[structopt(long)]
pub only_mandatory_headers: bool,
#[structopt(flatten)]
/// Prometheus metrics params.
pub prometheus_params: PrometheusParams,
}
/// Bridge parameters, shared by all bridge types.
pub struct Full2WayBridgeCommonParams<
Left: ChainWithTransactions + ChainWithRuntimeVersion,
Right: ChainWithTransactions + ChainWithRuntimeVersion,
> {
/// Shared parameters.
pub shared: HeadersAndMessagesSharedParams,
/// Parameters of the left chain.
pub left: BridgeEndCommonParams<Left>,
/// Parameters of the right chain.
pub right: BridgeEndCommonParams<Right>,
/// Common metric parameters.
pub metrics_params: MetricsParams,
}
impl<
Left: ChainWithTransactions + ChainWithRuntimeVersion,
Right: ChainWithTransactions + ChainWithRuntimeVersion,
> Full2WayBridgeCommonParams<Left, Right>
{
/// Creates new bridge parameters from its components.
pub fn new<L2R: MessagesCliBridge<Source = Left, Target = Right>>(
shared: HeadersAndMessagesSharedParams,
left: BridgeEndCommonParams<Left>,
right: BridgeEndCommonParams<Right>,
) -> anyhow::Result<Self> {
// Create metrics registry.
let metrics_params = shared.prometheus_params.clone().into_metrics_params()?;
let metrics_params = relay_utils::relay_metrics(metrics_params).into_params();
Ok(Self { shared, left, right, metrics_params })
}
}
/// Parameters that are associated with one side of the bridge.
pub struct BridgeEndCommonParams<Chain: ChainWithTransactions + ChainWithRuntimeVersion> {
/// Chain client.
pub client: Client<Chain>,
/// Params used for sending transactions to the chain.
pub tx_params: TransactionParams<AccountKeyPairOf<Chain>>,
/// Accounts, which balances are exposed as metrics by the relay process.
pub accounts: Vec<TaggedAccount<AccountIdOf<Chain>>>,
}
/// All data of the bidirectional complex relay.
pub struct FullBridge<
'a,
Source: ChainWithTransactions + ChainWithRuntimeVersion,
Target: ChainWithTransactions + ChainWithRuntimeVersion,
Bridge: MessagesCliBridge<Source = Source, Target = Target>,
> {
source: &'a mut BridgeEndCommonParams<Source>,
target: &'a mut BridgeEndCommonParams<Target>,
metrics_params: &'a MetricsParams,
_phantom_data: PhantomData<Bridge>,
}
impl<
'a,
Source: ChainWithTransactions + ChainWithRuntimeVersion,
Target: ChainWithTransactions + ChainWithRuntimeVersion,
Bridge: MessagesCliBridge<Source = Source, Target = Target>,
> FullBridge<'a, Source, Target, Bridge>
where
AccountIdOf<Source>: From<<AccountKeyPairOf<Source> as Pair>::Public>,
AccountIdOf<Target>: From<<AccountKeyPairOf<Target> as Pair>::Public>,
BalanceOf<Source>: TryFrom<BalanceOf<Target>> + Into<u128>,
{
/// Construct complex relay given it components.
fn new(
source: &'a mut BridgeEndCommonParams<Source>,
target: &'a mut BridgeEndCommonParams<Target>,
metrics_params: &'a MetricsParams,
) -> Self {
Self { source, target, metrics_params, _phantom_data: Default::default() }
}
/// Returns message relay parameters.
fn messages_relay_params(
&self,
source_to_target_headers_relay: Arc<dyn OnDemandRelay<Source, Target>>,
target_to_source_headers_relay: Arc<dyn OnDemandRelay<Target, Source>>,
lane_id: LaneId,
maybe_limits: Option<MessagesRelayLimits>,
) -> MessagesRelayParams<Bridge::MessagesLane> {
MessagesRelayParams {
source_client: self.source.client.clone(),
source_transaction_params: self.source.tx_params.clone(),
target_client: self.target.client.clone(),
target_transaction_params: self.target.tx_params.clone(),
source_to_target_headers_relay: Some(source_to_target_headers_relay),
target_to_source_headers_relay: Some(target_to_source_headers_relay),
lane_id,
limits: maybe_limits,
metrics_params: self.metrics_params.clone().disable(),
}
}
}
/// 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]
pub trait Full2WayBridgeBase: Sized + Send + Sync {
/// The CLI params for the bridge.
type Params;
/// The left relay chain.
type Left: ChainWithTransactions + ChainWithRuntimeVersion;
/// The right destination chain (it can be a relay or a parachain).
type Right: ChainWithTransactions + ChainWithRuntimeVersion;
/// Reference to common relay parameters.
fn common(&self) -> &Full2WayBridgeCommonParams<Self::Left, Self::Right>;
/// Mutable reference to common relay parameters.
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right>;
/// Start on-demand headers relays.
async fn start_on_demand_headers_relayers(
&mut self,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<Self::Left, Self::Right>>,
Arc<dyn OnDemandRelay<Self::Right, Self::Left>>,
)>;
}
/// Bidirectional complex relay.
#[async_trait]
pub 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>,
{
/// Base portion of the bidirectional complex relay.
type Base: Full2WayBridgeBase<Left = Self::Left, Right = Self::Right>;
/// The left relay chain.
type Left: ChainWithTransactions
+ ChainWithBalances
+ ChainWithMessages
+ ChainWithRuntimeVersion;
/// The right relay chain.
type Right: ChainWithTransactions
+ ChainWithBalances
+ ChainWithMessages
+ ChainWithRuntimeVersion;
/// 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>;
/// Construct new bridge.
fn new(params: <Self::Base as Full2WayBridgeBase>::Params) -> anyhow::Result<Self>;
/// 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<Self::Left, Self::Right, Self::L2R> {
let common = self.mut_base().mut_common();
FullBridge::<_, _, Self::L2R>::new(
&mut common.left,
&mut common.right,
&common.metrics_params,
)
}
/// Creates and returns Right to Left complex relay.
fn right_to_left(&mut self) -> FullBridge<Self::Right, Self::Left, Self::R2L> {
let common = self.mut_base().mut_common();
FullBridge::<_, _, Self::R2L>::new(
&mut common.right,
&mut common.left,
&common.metrics_params,
)
}
/// Start complex relay.
async fn run(&mut self) -> anyhow::Result<()> {
// Register standalone metrics.
{
let common = self.mut_base().mut_common();
common.left.accounts.push(TaggedAccount::Messages {
id: common.left.tx_params.signer.public().into(),
bridged_chain: Self::Right::NAME.to_string(),
});
common.right.accounts.push(TaggedAccount::Messages {
id: common.right.tx_params.signer.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 lanes = self
.base()
.common()
.shared
.lane
.iter()
.cloned()
.map(Into::into)
.collect::<Vec<_>>();
{
let common = self.mut_base().mut_common();
crate::messages_metrics::add_relay_balances_metrics::<_, Self::Right>(
common.left.client.clone(),
&common.metrics_params,
&common.left.accounts,
&lanes,
)
.await?;
crate::messages_metrics::add_relay_balances_metrics::<_, Self::Left>(
common.right.client.clone(),
&common.metrics_params,
&common.right.accounts,
&lanes,
)
.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 left_to_right_messages = crate::messages_lane::run::<
<Self::L2R as MessagesCliBridge>::MessagesLane,
>(self.left_to_right().messages_relay_params(
left_to_right_on_demand_headers.clone(),
right_to_left_on_demand_headers.clone(),
lane,
Self::L2R::maybe_messages_limits(),
))
.map_err(|e| anyhow::format_err!("{}", e))
.boxed();
message_relays.push(left_to_right_messages);
let right_to_left_messages = crate::messages_lane::run::<
<Self::R2L as MessagesCliBridge>::MessagesLane,
>(self.right_to_left().messages_relay_params(
right_to_left_on_demand_headers.clone(),
left_to_right_on_demand_headers.clone(),
lane,
Self::R2L::maybe_messages_limits(),
))
.map_err(|e| anyhow::format_err!("{}", e))
.boxed();
message_relays.push(right_to_left_messages);
}
relay_utils::relay_metrics(self.base().common().metrics_params.clone())
.expose()
.await
.map_err(|e| anyhow::format_err!("{}", e))?;
futures::future::select_all(message_relays).await.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{cli::chain_schema::RuntimeVersionType, declare_chain_cli_schema};
use relay_substrate_client::{ChainRuntimeVersion, Parachain, SimpleRuntimeVersion};
#[test]
// We need `#[allow(dead_code)]` because some of the methods generated by the macros
// are not used.
#[allow(dead_code)]
fn should_parse_parachain_to_parachain_options() {
// Chains.
declare_chain_cli_schema!(Kusama, kusama);
declare_chain_cli_schema!(BridgeHubKusama, bridge_hub_kusama);
declare_chain_cli_schema!(Polkadot, polkadot);
declare_chain_cli_schema!(BridgeHubPolkadot, bridge_hub_polkadot);
// Means to override signers of different layer transactions.
declare_chain_cli_schema!(
KusamaHeadersToBridgeHubPolkadot,
kusama_headers_to_bridge_hub_polkadot
);
declare_chain_cli_schema!(
KusamaParachainsToBridgeHubPolkadot,
kusama_parachains_to_bridge_hub_polkadot
);
declare_chain_cli_schema!(
PolkadotHeadersToBridgeHubKusama,
polkadot_headers_to_bridge_hub_kusama
);
declare_chain_cli_schema!(
PolkadotParachainsToBridgeHubKusama,
polkadot_parachains_to_bridge_hub_kusama
);
// Bridges.
declare_parachain_to_parachain_bridge_schema!(
BridgeHubKusama,
Kusama,
BridgeHubPolkadot,
Polkadot
);
let res = BridgeHubKusamaBridgeHubPolkadotHeadersAndMessages::from_iter(vec![
"bridge-hub-kusama-bridge-hub-polkadot-headers-and-messages",
"--bridge-hub-kusama-host",
"bridge-hub-kusama-node-collator1",
"--bridge-hub-kusama-port",
"9944",
"--bridge-hub-kusama-signer",
"//Iden",
"--bridge-hub-kusama-transactions-mortality",
"64",
"--kusama-host",
"kusama-alice",
"--kusama-port",
"9944",
"--bridge-hub-polkadot-host",
"bridge-hub-polkadot-collator1",
"--bridge-hub-polkadot-port",
"9944",
"--bridge-hub-polkadot-signer",
"//George",
"--bridge-hub-polkadot-transactions-mortality",
"64",
"--polkadot-host",
"polkadot-alice",
"--polkadot-port",
"9944",
"--lane",
"00000000",
"--prometheus-host",
"0.0.0.0",
]);
// then
assert_eq!(
res,
BridgeHubKusamaBridgeHubPolkadotHeadersAndMessages {
shared: HeadersAndMessagesSharedParams {
lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
only_mandatory_headers: false,
prometheus_params: PrometheusParams {
no_prometheus: false,
prometheus_host: "0.0.0.0".into(),
prometheus_port: 9616,
},
},
left: BridgeHubKusamaConnectionParams {
bridge_hub_kusama_host: "bridge-hub-kusama-node-collator1".into(),
bridge_hub_kusama_port: 9944,
bridge_hub_kusama_secure: false,
bridge_hub_kusama_runtime_version: BridgeHubKusamaRuntimeVersionParams {
bridge_hub_kusama_version_mode: RuntimeVersionType::Bundle,
bridge_hub_kusama_spec_version: None,
bridge_hub_kusama_transaction_version: None,
},
},
left_sign: BridgeHubKusamaSigningParams {
bridge_hub_kusama_signer: Some("//Iden".into()),
bridge_hub_kusama_signer_password: None,
bridge_hub_kusama_signer_file: None,
bridge_hub_kusama_signer_password_file: None,
bridge_hub_kusama_transactions_mortality: Some(64),
},
left_relay: KusamaConnectionParams {
kusama_host: "kusama-alice".into(),
kusama_port: 9944,
kusama_secure: false,
kusama_runtime_version: KusamaRuntimeVersionParams {
kusama_version_mode: RuntimeVersionType::Bundle,
kusama_spec_version: None,
kusama_transaction_version: None,
},
},
right: BridgeHubPolkadotConnectionParams {
bridge_hub_polkadot_host: "bridge-hub-polkadot-collator1".into(),
bridge_hub_polkadot_port: 9944,
bridge_hub_polkadot_secure: false,
bridge_hub_polkadot_runtime_version: BridgeHubPolkadotRuntimeVersionParams {
bridge_hub_polkadot_version_mode: RuntimeVersionType::Bundle,
bridge_hub_polkadot_spec_version: None,
bridge_hub_polkadot_transaction_version: None,
},
},
right_sign: BridgeHubPolkadotSigningParams {
bridge_hub_polkadot_signer: Some("//George".into()),
bridge_hub_polkadot_signer_password: None,
bridge_hub_polkadot_signer_file: None,
bridge_hub_polkadot_signer_password_file: None,
bridge_hub_polkadot_transactions_mortality: Some(64),
},
right_relay: PolkadotConnectionParams {
polkadot_host: "polkadot-alice".into(),
polkadot_port: 9944,
polkadot_secure: false,
polkadot_runtime_version: PolkadotRuntimeVersionParams {
polkadot_version_mode: RuntimeVersionType::Bundle,
polkadot_spec_version: None,
polkadot_transaction_version: None,
},
},
}
);
}
}
@@ -14,26 +14,28 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Parachain to parachain relayer CLI primitives.
use async_trait::async_trait; use async_trait::async_trait;
use std::sync::Arc; use std::sync::Arc;
use crate::cli::{ use crate::{
cli::{
bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}, bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
CliChain, },
};
use bp_polkadot_core::parachains::ParaHash;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithTransactions, Client, Parachain,
};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline, finality::SubstrateFinalitySyncPipeline,
on_demand::{ on_demand::{
headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay,
}, },
}; };
use bp_polkadot_core::parachains::ParaHash;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, Client,
Parachain,
};
use sp_core::Pair;
/// A base relay between two parachain from different consensus systems. /// A base relay between two parachain from different consensus systems.
/// ///
@@ -55,6 +57,8 @@ pub struct ParachainToParachainBridge<
pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>, pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>,
} }
/// Create set of configuration objects specific to parachain-to-parachain relayer.
#[macro_export]
macro_rules! declare_parachain_to_parachain_bridge_schema { macro_rules! declare_parachain_to_parachain_bridge_schema {
// left-parachain, relay-chain-of-left-parachain, right-parachain, relay-chain-of-right-parachain // 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) => { ($left_parachain:ident, $left_chain:ident, $right_parachain:ident, $right_chain:ident) => {
@@ -87,20 +91,20 @@ macro_rules! declare_parachain_to_parachain_bridge_schema {
impl [<$left_parachain $right_parachain HeadersAndMessages>] { impl [<$left_parachain $right_parachain HeadersAndMessages>] {
async fn into_bridge< async fn into_bridge<
Left: ChainWithTransactions + CliChain + Parachain, Left: ChainWithTransactions + ChainWithRuntimeVersion + Parachain,
LeftRelay: CliChain, LeftRelay: ChainWithRuntimeVersion,
Right: ChainWithTransactions + CliChain + Parachain, Right: ChainWithTransactions + ChainWithRuntimeVersion + Parachain,
RightRelay: CliChain, RightRelay: ChainWithRuntimeVersion,
L2R: CliBridgeBase<Source = Left, Target = Right> L2R: $crate::cli::bridge::CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge + MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = LeftRelay>, + $crate::cli::bridge::ParachainToRelayHeadersCliBridge<SourceRelay = LeftRelay>,
R2L: CliBridgeBase<Source = Right, Target = Left> R2L: $crate::cli::bridge::CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge + MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>, + $crate::cli::bridge::ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
>( >(
self, self,
) -> anyhow::Result<ParachainToParachainBridge<L2R, R2L>> { ) -> anyhow::Result<$crate::cli::relay_headers_and_messages::parachain_to_parachain::ParachainToParachainBridge<L2R, R2L>> {
Ok(ParachainToParachainBridge { Ok($crate::cli::relay_headers_and_messages::parachain_to_parachain::ParachainToParachainBridge {
common: Full2WayBridgeCommonParams::new::<L2R>( common: Full2WayBridgeCommonParams::new::<L2R>(
self.shared, self.shared,
BridgeEndCommonParams { BridgeEndCommonParams {
@@ -125,12 +129,12 @@ macro_rules! declare_parachain_to_parachain_bridge_schema {
#[async_trait] #[async_trait]
impl< impl<
Left: Chain<Hash = ParaHash> + ChainWithTransactions + CliChain + Parachain, Left: Chain<Hash = ParaHash> + ChainWithTransactions + ChainWithRuntimeVersion + Parachain,
Right: Chain<Hash = ParaHash> + ChainWithTransactions + CliChain + Parachain, Right: Chain<Hash = ParaHash> + ChainWithTransactions + ChainWithRuntimeVersion + Parachain,
LeftRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher> LeftRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain, + ChainWithRuntimeVersion,
RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher> RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain, + ChainWithRuntimeVersion,
L2R: CliBridgeBase<Source = Left, Target = Right> L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge + MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = LeftRelay>, + ParachainToRelayHeadersCliBridge<SourceRelay = LeftRelay>,
@@ -14,29 +14,31 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Relay chain to parachain relayer CLI primitives.
use async_trait::async_trait; use async_trait::async_trait;
use std::sync::Arc; use std::sync::Arc;
use crate::cli::{ use crate::{
cli::{
bridge::{ bridge::{
CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge, CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge,
RelayToRelayHeadersCliBridge, RelayToRelayHeadersCliBridge,
}, },
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
CliChain, },
};
use bp_polkadot_core::parachains::ParaHash;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithTransactions, Client, Parachain,
};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline, finality::SubstrateFinalitySyncPipeline,
on_demand::{ on_demand::{
headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay,
}, },
}; };
use bp_polkadot_core::parachains::ParaHash;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, Client,
Parachain,
};
use sp_core::Pair;
/// A base relay between standalone (relay) chain and a parachain from another consensus system. /// A base relay between standalone (relay) chain and a parachain from another consensus system.
/// ///
@@ -55,6 +57,8 @@ pub struct RelayToParachainBridge<
pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>, pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>,
} }
/// Create set of configuration objects specific to relay-to-parachain relayer.
#[macro_export]
macro_rules! declare_relay_to_parachain_bridge_schema { macro_rules! declare_relay_to_parachain_bridge_schema {
// chain, parachain, relay-chain-of-parachain // chain, parachain, relay-chain-of-parachain
($left_chain:ident, $right_parachain:ident, $right_chain:ident) => { ($left_chain:ident, $right_parachain:ident, $right_chain:ident) => {
@@ -84,9 +88,9 @@ macro_rules! declare_relay_to_parachain_bridge_schema {
impl [<$left_chain $right_parachain HeadersAndMessages>] { impl [<$left_chain $right_parachain HeadersAndMessages>] {
async fn into_bridge< async fn into_bridge<
Left: ChainWithTransactions + CliChain, Left: ChainWithTransactions + ChainWithRuntimeVersion,
Right: ChainWithTransactions + CliChain + Parachain, Right: ChainWithTransactions + ChainWithRuntimeVersion + Parachain,
RightRelay: CliChain, RightRelay: ChainWithRuntimeVersion,
L2R: CliBridgeBase<Source = Left, Target = Right> + MessagesCliBridge + RelayToRelayHeadersCliBridge, L2R: CliBridgeBase<Source = Left, Target = Right> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
R2L: CliBridgeBase<Source = Right, Target = Left> R2L: CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge + MessagesCliBridge
@@ -118,10 +122,10 @@ macro_rules! declare_relay_to_parachain_bridge_schema {
#[async_trait] #[async_trait]
impl< impl<
Left: ChainWithTransactions + CliChain, Left: ChainWithTransactions + ChainWithRuntimeVersion,
Right: Chain<Hash = ParaHash> + ChainWithTransactions + CliChain + Parachain, Right: Chain<Hash = ParaHash> + ChainWithTransactions + ChainWithRuntimeVersion + Parachain,
RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher> RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain, + ChainWithRuntimeVersion,
L2R: CliBridgeBase<Source = Left, Target = Right> L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge + MessagesCliBridge
+ RelayToRelayHeadersCliBridge, + RelayToRelayHeadersCliBridge,
@@ -18,20 +18,23 @@
// future // future
#![allow(unused_macros)] #![allow(unused_macros)]
//! Relay chain to Relay chain relayer CLI primitives.
use async_trait::async_trait; use async_trait::async_trait;
use std::sync::Arc; use std::sync::Arc;
use crate::cli::{ use crate::{
cli::{
bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}, bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge},
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
CliChain, },
};
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, ChainWithTransactions};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline, finality::SubstrateFinalitySyncPipeline,
on_demand::{headers::OnDemandHeadersRelay, OnDemandRelay}, on_demand::{headers::OnDemandHeadersRelay, OnDemandRelay},
}; };
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, ChainWithRuntimeVersion, ChainWithTransactions,
};
use sp_core::Pair;
/// A base relay between two standalone (relay) chains. /// A base relay between two standalone (relay) chains.
/// ///
@@ -45,6 +48,7 @@ pub struct RelayToRelayBridge<
Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>, Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>,
} }
/// Create set of configuration objects specific to relay-to-relay relayer.
macro_rules! declare_relay_to_relay_bridge_schema { macro_rules! declare_relay_to_relay_bridge_schema {
($left_chain:ident, $right_chain:ident) => { ($left_chain:ident, $right_chain:ident) => {
bp_runtime::paste::item! { bp_runtime::paste::item! {
@@ -101,8 +105,8 @@ macro_rules! declare_relay_to_relay_bridge_schema {
#[async_trait] #[async_trait]
impl< impl<
Left: ChainWithTransactions + CliChain, Left: ChainWithTransactions + ChainWithRuntimeVersion,
Right: ChainWithTransactions + CliChain, Right: ChainWithTransactions + ChainWithRuntimeVersion,
L2R: CliBridgeBase<Source = Left, Target = Right> L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge + MessagesCliBridge
+ RelayToRelayHeadersCliBridge, + RelayToRelayHeadersCliBridge,
@@ -0,0 +1,89 @@
// 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/>.
//! Primitives for exposing the messages relaying functionality in the CLI.
use crate::{
cli::{bridge::*, chain_schema::*, HexLaneId, PrometheusParams},
messages_lane::MessagesRelayParams,
TransactionParams,
};
use async_trait::async_trait;
use sp_core::Pair;
use structopt::StructOpt;
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, BalanceOf, ChainWithRuntimeVersion, ChainWithTransactions,
};
/// Messages relaying params.
#[derive(StructOpt)]
pub struct RelayMessagesParams {
/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
}
/// Trait used for relaying messages between 2 chains.
#[async_trait]
pub trait MessagesRelayer: MessagesCliBridge
where
Self::Source: ChainWithTransactions + ChainWithRuntimeVersion,
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>>,
{
/// Start relaying messages.
async fn relay_messages(data: RelayMessagesParams) -> anyhow::Result<()> {
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.into_client::<Self::Target>().await?;
let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
let target_transactions_mortality = data.target_sign.transactions_mortality()?;
crate::messages_lane::run::<Self::MessagesLane>(MessagesRelayParams {
source_client,
source_transaction_params: TransactionParams {
signer: source_sign,
mortality: source_transactions_mortality,
},
target_client,
target_transaction_params: TransactionParams {
signer: target_sign,
mortality: target_transactions_mortality,
},
source_to_target_headers_relay: None,
target_to_source_headers_relay: None,
lane_id: data.lane.into(),
limits: Self::maybe_messages_limits(),
metrics_params: data.prometheus_params.into_metrics_params()?,
})
.await
.map_err(|e| anyhow::format_err!("{}", e))
}
}
@@ -0,0 +1,91 @@
// 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/>.
//! Primitives for exposing the parachains finality relaying functionality in the CLI.
use async_std::sync::Mutex;
use async_trait::async_trait;
use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient};
use relay_substrate_client::Parachain;
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
use std::sync::Arc;
use structopt::StructOpt;
use crate::{
cli::{
bridge::{CliBridgeBase, ParachainToRelayHeadersCliBridge},
chain_schema::*,
PrometheusParams,
},
parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter},
TransactionParams,
};
/// Parachains heads relaying params.
#[derive(StructOpt)]
pub struct RelayParachainsParams {
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
}
/// Trait used for relaying parachains finality between 2 chains.
#[async_trait]
pub trait ParachainsRelayer: ParachainToRelayHeadersCliBridge
where
ParachainsSource<Self::ParachainFinality>:
SourceClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
ParachainsTarget<Self::ParachainFinality>:
TargetClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
<Self as CliBridgeBase>::Source: Parachain,
{
/// Start relaying parachains finality.
async fn relay_parachains(data: RelayParachainsParams) -> anyhow::Result<()> {
let source_client = data.source.into_client::<Self::SourceRelay>().await?;
let source_client = ParachainsSource::<Self::ParachainFinality>::new(
source_client,
Arc::new(Mutex::new(AvailableHeader::Missing)),
);
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.into_client::<Self::Target>().await?;
let target_client = ParachainsTarget::<Self::ParachainFinality>::new(
target_client.clone(),
target_transaction_params,
);
let metrics_params: relay_utils::metrics::MetricsParams =
data.prometheus_params.into_metrics_params()?;
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
parachains_relay::parachains_loop::run(
source_client,
target_client,
metrics_params,
futures::future::pending(),
)
.await
.map_err(|e| anyhow::format_err!("{}", e))
}
}
@@ -22,6 +22,7 @@ use relay_substrate_client::{Chain, ChainWithUtilityPallet, UtilityPallet};
use std::marker::PhantomData; use std::marker::PhantomData;
pub mod cli;
pub mod equivocation; pub mod equivocation;
pub mod error; pub mod error;
pub mod finality; pub mod finality;