mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 23:21:02 +00:00
Complex headers+messages Millau<->Rialto relay (#878)
* complex headers+messages relay * post-merge fix * fix + test issue with on-demand not starting
This commit is contained in:
committed by
Bastian Köcher
parent
0d60f42b5e
commit
e2131724fb
@@ -33,6 +33,7 @@ pub(crate) mod send_message;
|
||||
mod derive_account;
|
||||
mod init_bridge;
|
||||
mod relay_headers;
|
||||
mod relay_headers_and_messages;
|
||||
mod relay_messages;
|
||||
|
||||
/// Parse relay CLI args.
|
||||
@@ -54,6 +55,13 @@ pub enum Command {
|
||||
/// Ties up to `Messages` pallets on both chains and starts relaying messages.
|
||||
/// Requires the header relay to be already running.
|
||||
RelayMessages(relay_messages::RelayMessages),
|
||||
/// Start headers and messages relay between two Substrate chains.
|
||||
///
|
||||
/// This high-level relay internally starts four low-level relays: two `RelayHeaders`
|
||||
/// and two `RelayMessages` relays. Headers are only relayed when they are required by
|
||||
/// the message relays - i.e. when there are messages or confirmations that needs to be
|
||||
/// relayed between chains.
|
||||
RelayHeadersAndMessages(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.
|
||||
@@ -86,6 +94,7 @@ impl Command {
|
||||
match self {
|
||||
Self::RelayHeaders(arg) => arg.run().await?,
|
||||
Self::RelayMessages(arg) => arg.run().await?,
|
||||
Self::RelayHeadersAndMessages(arg) => arg.run().await?,
|
||||
Self::InitBridge(arg) => arg.run().await?,
|
||||
Self::SendMessage(arg) => arg.run().await?,
|
||||
Self::EncodeCall(arg) => arg.run().await?,
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Complex headers+messages relays support.
|
||||
//!
|
||||
//! To add new complex relay between `ChainA` and `ChainB`, you must:
|
||||
//!
|
||||
//! 1) ensure that there's a `declare_chain_options!(...)` for both chains;
|
||||
//! 2) add `declare_bridge_options!(...)` for the bridge;
|
||||
//! 3) add bridge support to the `select_bridge! { ... }` macro.
|
||||
|
||||
use crate::cli::{CliChain, HexLaneId, PrometheusParams};
|
||||
use crate::declare_chain_options;
|
||||
use crate::messages_lane::MessagesRelayParams;
|
||||
use crate::on_demand_headers::OnDemandHeadersRelay;
|
||||
|
||||
use futures::{FutureExt, TryFutureExt};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// Start headers+messages relayer process.
|
||||
#[derive(StructOpt)]
|
||||
pub enum RelayHeadersAndMessages {
|
||||
MillauRialto(MillauRialtoHeadersAndMessages),
|
||||
}
|
||||
|
||||
/// Parameters that have the same names across all bridges.
|
||||
#[derive(StructOpt)]
|
||||
pub struct HeadersAndMessagesSharedParams {
|
||||
/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
lane: HexLaneId,
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
}
|
||||
|
||||
// The reason behind this macro is that 'normal' relays are using source and target chains terminology,
|
||||
// which is unusable for both-way relays (if you're relaying headers from Rialto to Millau and from
|
||||
// Millau to Rialto, then which chain is source?).
|
||||
macro_rules! declare_bridge_options {
|
||||
($chain1:ident, $chain2:ident) => {
|
||||
paste::item! {
|
||||
#[doc = $chain1 " and " $chain2 " headers+messages relay params."]
|
||||
#[derive(StructOpt)]
|
||||
pub struct [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
#[structopt(flatten)]
|
||||
shared: HeadersAndMessagesSharedParams,
|
||||
#[structopt(flatten)]
|
||||
left: [<$chain1 ConnectionParams>],
|
||||
#[structopt(flatten)]
|
||||
left_sign: [<$chain1 SigningParams>],
|
||||
#[structopt(flatten)]
|
||||
right: [<$chain2 ConnectionParams>],
|
||||
#[structopt(flatten)]
|
||||
right_sign: [<$chain2 SigningParams>],
|
||||
}
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
impl From<RelayHeadersAndMessages> for [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
fn from(relay_params: RelayHeadersAndMessages) -> [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
match relay_params {
|
||||
RelayHeadersAndMessages::[<$chain1 $chain2>](params) => params,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! select_bridge {
|
||||
($bridge: expr, $generic: tt) => {
|
||||
match $bridge {
|
||||
RelayHeadersAndMessages::MillauRialto(_) => {
|
||||
type Params = MillauRialtoHeadersAndMessages;
|
||||
|
||||
type Left = relay_millau_client::Millau;
|
||||
type Right = relay_rialto_client::Rialto;
|
||||
|
||||
type LeftToRightFinality = crate::rialto_millau::millau_headers_to_rialto::MillauFinalityToRialto;
|
||||
type RightToLeftFinality = crate::rialto_millau::rialto_headers_to_millau::RialtoFinalityToMillau;
|
||||
|
||||
type LeftToRightMessages = crate::rialto_millau::millau_messages_to_rialto::MillauMessagesToRialto;
|
||||
type RightToLeftMessages = crate::rialto_millau::rialto_messages_to_millau::RialtoMessagesToMillau;
|
||||
|
||||
use crate::rialto_millau::millau_messages_to_rialto::run as left_to_right_messages;
|
||||
use crate::rialto_millau::rialto_messages_to_millau::run as right_to_left_messages;
|
||||
|
||||
$generic
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// All supported chains.
|
||||
declare_chain_options!(Millau, millau);
|
||||
declare_chain_options!(Rialto, rialto);
|
||||
// All supported bridges.
|
||||
declare_bridge_options!(Millau, Rialto);
|
||||
|
||||
impl RelayHeadersAndMessages {
|
||||
/// Run the command.
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
select_bridge!(self, {
|
||||
let params: Params = self.into();
|
||||
|
||||
let left_client = params.left.to_client::<Left>().await?;
|
||||
let left_sign = params.left_sign.to_keypair::<Left>()?;
|
||||
let right_client = params.right.to_client::<Right>().await?;
|
||||
let right_sign = params.right_sign.to_keypair::<Right>()?;
|
||||
|
||||
let lane = params.shared.lane.into();
|
||||
|
||||
let metrics_params: MetricsParams = params.shared.prometheus_params.into();
|
||||
let metrics_params = relay_utils::relay_metrics(None, metrics_params).into_params();
|
||||
|
||||
let left_to_right_on_demand_headers = OnDemandHeadersRelay::new(
|
||||
left_client.clone(),
|
||||
right_client.clone(),
|
||||
LeftToRightFinality::new(right_client.clone(), right_sign.clone()),
|
||||
);
|
||||
let right_to_left_on_demand_headers = OnDemandHeadersRelay::new(
|
||||
right_client.clone(),
|
||||
left_client.clone(),
|
||||
RightToLeftFinality::new(left_client.clone(), left_sign.clone()),
|
||||
);
|
||||
|
||||
let left_to_right_messages = left_to_right_messages(MessagesRelayParams {
|
||||
source_client: left_client.clone(),
|
||||
source_sign: left_sign.clone(),
|
||||
target_client: right_client.clone(),
|
||||
target_sign: right_sign.clone(),
|
||||
source_to_target_headers_relay: Some(left_to_right_on_demand_headers.clone()),
|
||||
target_to_source_headers_relay: Some(right_to_left_on_demand_headers.clone()),
|
||||
lane_id: lane,
|
||||
metrics_params: metrics_params
|
||||
.clone()
|
||||
.disable()
|
||||
.metrics_prefix(messages_relay::message_lane_loop::metrics_prefix::<LeftToRightMessages>(&lane)),
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
.boxed();
|
||||
let right_to_left_messages = right_to_left_messages(MessagesRelayParams {
|
||||
source_client: right_client,
|
||||
source_sign: right_sign,
|
||||
target_client: left_client.clone(),
|
||||
target_sign: left_sign.clone(),
|
||||
source_to_target_headers_relay: Some(right_to_left_on_demand_headers),
|
||||
target_to_source_headers_relay: Some(left_to_right_on_demand_headers),
|
||||
lane_id: lane,
|
||||
metrics_params: metrics_params
|
||||
.clone()
|
||||
.disable()
|
||||
.metrics_prefix(messages_relay::message_lane_loop::metrics_prefix::<RightToLeftMessages>(&lane)),
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
.boxed();
|
||||
|
||||
relay_utils::relay_metrics(None, metrics_params)
|
||||
.expose()
|
||||
.await
|
||||
.map_err(|e| anyhow::format_err!("{}", e))?;
|
||||
|
||||
futures::future::select(left_to_right_messages, right_to_left_messages)
|
||||
.await
|
||||
.factor_first()
|
||||
.0
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,9 @@ use crate::cli::{
|
||||
HexLaneId, PrometheusParams, SourceConnectionParams, SourceSigningParams, TargetConnectionParams,
|
||||
TargetSigningParams,
|
||||
};
|
||||
use crate::messages_lane::MessagesRelayParams;
|
||||
use crate::select_full_bridge;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// Start messages relayer process.
|
||||
@@ -52,14 +54,16 @@ impl RelayMessages {
|
||||
let target_client = self.target.to_client::<Target>().await?;
|
||||
let target_sign = self.target_sign.to_keypair::<Target>()?;
|
||||
|
||||
relay_messages(
|
||||
relay_messages(MessagesRelayParams {
|
||||
source_client,
|
||||
source_sign,
|
||||
target_client,
|
||||
target_sign,
|
||||
self.lane.into(),
|
||||
self.prometheus_params.into(),
|
||||
)
|
||||
source_to_target_headers_relay: None,
|
||||
target_to_source_headers_relay: None,
|
||||
lane_id: self.lane.into(),
|
||||
metrics_params: self.prometheus_params.into(),
|
||||
})
|
||||
.await
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
})
|
||||
|
||||
@@ -27,6 +27,7 @@ mod headers_initialize;
|
||||
mod messages_lane;
|
||||
mod messages_source;
|
||||
mod messages_target;
|
||||
mod on_demand_headers;
|
||||
|
||||
mod rialto_millau;
|
||||
|
||||
|
||||
@@ -16,15 +16,36 @@
|
||||
|
||||
use crate::messages_source::SubstrateMessagesProof;
|
||||
use crate::messages_target::SubstrateMessagesReceivingProof;
|
||||
use crate::on_demand_headers::OnDemandHeadersRelay;
|
||||
|
||||
use bp_messages::MessageNonce;
|
||||
use bp_messages::{LaneId, MessageNonce};
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf};
|
||||
use relay_substrate_client::{BlockNumberOf, Chain, Client, HashOf};
|
||||
use relay_utils::BlockNumberBase;
|
||||
use relay_utils::{metrics::MetricsParams, BlockNumberBase};
|
||||
use sp_core::Bytes;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
/// Substrate <-> Substrate messages relay parameters.
|
||||
pub struct MessagesRelayParams<SC: Chain, SS, TC: Chain, TS> {
|
||||
/// Messages source client.
|
||||
pub source_client: Client<SC>,
|
||||
/// Sign parameters for messages source chain.
|
||||
pub source_sign: SS,
|
||||
/// Messages target client.
|
||||
pub target_client: Client<TC>,
|
||||
/// Sign parameters for messages target chain.
|
||||
pub target_sign: TS,
|
||||
/// Optional on-demand source to target headers relay.
|
||||
pub source_to_target_headers_relay: Option<OnDemandHeadersRelay<SC>>,
|
||||
/// Optional on-demand target to source headers relay.
|
||||
pub target_to_source_headers_relay: Option<OnDemandHeadersRelay<TC>>,
|
||||
/// Identifier of lane that needs to be served.
|
||||
pub lane_id: LaneId,
|
||||
/// Metrics parameters.
|
||||
pub metrics_params: MetricsParams,
|
||||
}
|
||||
|
||||
/// Message sync pipeline for Substrate <-> Substrate relays.
|
||||
pub trait SubstrateMessageLane: MessageLane {
|
||||
/// Name of the runtime method that returns dispatch weight of outbound messages at the source chain.
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
//! <BridgedName> chain.
|
||||
|
||||
use crate::messages_lane::SubstrateMessageLane;
|
||||
use crate::on_demand_headers::OnDemandHeadersRelay;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{LaneId, MessageNonce};
|
||||
@@ -45,22 +46,30 @@ use std::{marker::PhantomData, ops::RangeInclusive};
|
||||
pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<HashOf<C>>);
|
||||
|
||||
/// Substrate client as Substrate messages source.
|
||||
pub struct SubstrateMessagesSource<C: Chain, P, R, I> {
|
||||
pub struct SubstrateMessagesSource<C: Chain, P: SubstrateMessageLane, R, I> {
|
||||
client: Client<C>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
instance: InstanceId,
|
||||
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
|
||||
_phantom: PhantomData<(R, I)>,
|
||||
}
|
||||
|
||||
impl<C: Chain, P, R, I> SubstrateMessagesSource<C, P, R, I> {
|
||||
impl<C: Chain, P: SubstrateMessageLane, R, I> SubstrateMessagesSource<C, P, R, I> {
|
||||
/// Create new Substrate headers source.
|
||||
pub fn new(client: Client<C>, lane: P, lane_id: LaneId, instance: InstanceId) -> Self {
|
||||
pub fn new(
|
||||
client: Client<C>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
instance: InstanceId,
|
||||
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
|
||||
) -> Self {
|
||||
SubstrateMessagesSource {
|
||||
client,
|
||||
lane,
|
||||
lane_id,
|
||||
instance,
|
||||
target_to_source_headers_relay,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -73,6 +82,7 @@ impl<C: Chain, P: SubstrateMessageLane, R, I> Clone for SubstrateMessagesSource<
|
||||
lane: self.lane.clone(),
|
||||
lane_id: self.lane_id,
|
||||
instance: self.instance,
|
||||
target_to_source_headers_relay: self.target_to_source_headers_relay.clone(),
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -106,6 +116,7 @@ where
|
||||
SourceHeaderHash = <C::Header as HeaderT>::Hash,
|
||||
SourceChain = C,
|
||||
>,
|
||||
P::TargetChain: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
|
||||
P::TargetHeaderNumber: Decode,
|
||||
P::TargetHeaderHash: Decode,
|
||||
R: Send + Sync + MessagesConfig<I>,
|
||||
@@ -226,7 +237,11 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn activate_target_to_source_headers_relay(&self, _activate: bool) {}
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<P>) {
|
||||
if let Some(ref target_to_source_headers_relay) = self.target_to_source_headers_relay {
|
||||
target_to_source_headers_relay.require_finalized_header(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_client_state<SelfChain, BridgedHeaderHash, BridgedHeaderNumber>(
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
use crate::messages_lane::SubstrateMessageLane;
|
||||
use crate::messages_source::read_client_state;
|
||||
use crate::on_demand_headers::OnDemandHeadersRelay;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState};
|
||||
@@ -45,22 +46,30 @@ pub type SubstrateMessagesReceivingProof<C> = (
|
||||
);
|
||||
|
||||
/// Substrate client as Substrate messages target.
|
||||
pub struct SubstrateMessagesTarget<C: Chain, P, R, I> {
|
||||
pub struct SubstrateMessagesTarget<C: Chain, P: SubstrateMessageLane, R, I> {
|
||||
client: Client<C>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
instance: InstanceId,
|
||||
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
|
||||
_phantom: PhantomData<(R, I)>,
|
||||
}
|
||||
|
||||
impl<C: Chain, P, R, I> SubstrateMessagesTarget<C, P, R, I> {
|
||||
impl<C: Chain, P: SubstrateMessageLane, R, I> SubstrateMessagesTarget<C, P, R, I> {
|
||||
/// Create new Substrate headers target.
|
||||
pub fn new(client: Client<C>, lane: P, lane_id: LaneId, instance: InstanceId) -> Self {
|
||||
pub fn new(
|
||||
client: Client<C>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
instance: InstanceId,
|
||||
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
|
||||
) -> Self {
|
||||
SubstrateMessagesTarget {
|
||||
client,
|
||||
lane,
|
||||
lane_id,
|
||||
instance,
|
||||
source_to_target_headers_relay,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -73,6 +82,7 @@ impl<C: Chain, P: SubstrateMessageLane, R, I> Clone for SubstrateMessagesTarget<
|
||||
lane: self.lane.clone(),
|
||||
lane_id: self.lane_id,
|
||||
instance: self.instance,
|
||||
source_to_target_headers_relay: self.source_to_target_headers_relay.clone(),
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -106,6 +116,7 @@ where
|
||||
TargetHeaderNumber = <C::Header as HeaderT>::Number,
|
||||
TargetHeaderHash = <C::Header as HeaderT>::Hash,
|
||||
>,
|
||||
P::SourceChain: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber>,
|
||||
P::SourceHeaderNumber: Decode,
|
||||
P::SourceHeaderHash: Decode,
|
||||
R: Send + Sync + MessagesConfig<I>,
|
||||
@@ -213,5 +224,9 @@ where
|
||||
Ok(nonces)
|
||||
}
|
||||
|
||||
async fn activate_source_to_target_headers_relay(&self, _activate: bool) {}
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<P>) {
|
||||
if let Some(ref source_to_target_headers_relay) = self.source_to_target_headers_relay {
|
||||
source_to_target_headers_relay.require_finalized_header(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
// 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/>.
|
||||
|
||||
//! On-demand Substrate -> Substrate headers relay.
|
||||
|
||||
use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
use crate::finality_target::SubstrateFinalityTarget;
|
||||
|
||||
use bp_header_chain::justification::GrandpaJustification;
|
||||
use finality_relay::TargetClient as FinalityTargetClient;
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
select, FutureExt, StreamExt,
|
||||
};
|
||||
use num_traits::Zero;
|
||||
use relay_substrate_client::{BlockNumberOf, Chain, Client, HashOf, HeaderIdOf, SyncHeader};
|
||||
use relay_utils::{metrics::MetricsParams, BlockNumberBase, HeaderId};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// On-demand Substrate <-> Substrate headers relay.
|
||||
///
|
||||
/// This relay may be started by messages whenever some other relay (e.g. messages relay) needs more
|
||||
/// headers to be relayed to continue its regular work. When enough headers are relayed, on-demand
|
||||
/// relay may be deactivated.
|
||||
#[derive(Clone)]
|
||||
pub struct OnDemandHeadersRelay<SourceChain: Chain> {
|
||||
/// Background task name.
|
||||
background_task_name: String,
|
||||
/// Required headers to background sender.
|
||||
required_header_tx: mpsc::Sender<HeaderId<SourceChain::Hash, SourceChain::BlockNumber>>,
|
||||
}
|
||||
|
||||
impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
|
||||
/// Create new on-demand headers relay.
|
||||
pub fn new<TargetChain: Chain, TargetSign>(
|
||||
source_client: Client<SourceChain>,
|
||||
target_client: Client<TargetChain>,
|
||||
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
||||
) -> Self
|
||||
where
|
||||
SourceChain: Chain + Debug,
|
||||
SourceChain::BlockNumber: BlockNumberBase,
|
||||
TargetChain: Chain + Debug,
|
||||
TargetChain::BlockNumber: BlockNumberBase,
|
||||
TargetSign: Clone + Send + Sync + 'static,
|
||||
SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>: SubstrateFinalitySyncPipeline<
|
||||
Hash = HashOf<SourceChain>,
|
||||
Number = BlockNumberOf<SourceChain>,
|
||||
Header = SyncHeader<SourceChain::Header>,
|
||||
FinalityProof = GrandpaJustification<SourceChain::Header>,
|
||||
TargetChain = TargetChain,
|
||||
>,
|
||||
SubstrateFinalityTarget<TargetChain, SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>:
|
||||
FinalityTargetClient<SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>,
|
||||
{
|
||||
let (required_header_tx, required_header_rx) = mpsc::channel(1);
|
||||
async_std::task::spawn(async move {
|
||||
background_task(source_client, target_client, pipeline, required_header_rx).await;
|
||||
});
|
||||
|
||||
let background_task_name = format!(
|
||||
"{}-background",
|
||||
on_demand_headers_relay_name::<SourceChain, TargetChain>()
|
||||
);
|
||||
OnDemandHeadersRelay {
|
||||
background_task_name,
|
||||
required_header_tx,
|
||||
}
|
||||
}
|
||||
|
||||
/// Someone is asking us to relay given finalized header.
|
||||
pub fn require_finalized_header(&self, header_id: HeaderIdOf<SourceChain>) {
|
||||
if let Err(error) = self.required_header_tx.clone().try_send(header_id) {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Failed to send require header id {:?} to {:?}: {:?}",
|
||||
header_id,
|
||||
self.background_task_name,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Background task that is responsible for starting and stopping headers relay when required.
|
||||
async fn background_task<SourceChain, TargetChain, TargetSign>(
|
||||
source_client: Client<SourceChain>,
|
||||
target_client: Client<TargetChain>,
|
||||
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
||||
mut required_header_rx: mpsc::Receiver<HeaderIdOf<SourceChain>>,
|
||||
) where
|
||||
SourceChain: Chain + Debug,
|
||||
SourceChain::BlockNumber: BlockNumberBase,
|
||||
TargetChain: Chain + Debug,
|
||||
TargetChain::BlockNumber: BlockNumberBase,
|
||||
TargetSign: Clone + Send + Sync + 'static,
|
||||
SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>: SubstrateFinalitySyncPipeline<
|
||||
Hash = HashOf<SourceChain>,
|
||||
Number = BlockNumberOf<SourceChain>,
|
||||
Header = SyncHeader<SourceChain::Header>,
|
||||
FinalityProof = GrandpaJustification<SourceChain::Header>,
|
||||
TargetChain = TargetChain,
|
||||
>,
|
||||
SubstrateFinalityTarget<TargetChain, SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>:
|
||||
FinalityTargetClient<SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>,
|
||||
{
|
||||
let relay_task_name = on_demand_headers_relay_name::<SourceChain, TargetChain>();
|
||||
let finality_target = SubstrateFinalityTarget::new(target_client.clone(), pipeline.clone());
|
||||
|
||||
let mut active_headers_relay = None;
|
||||
let mut required_header_number = Zero::zero();
|
||||
let mut relay_exited_rx = futures::future::pending().left_future();
|
||||
|
||||
loop {
|
||||
// wait for next target block or for new required header
|
||||
select! {
|
||||
_ = async_std::task::sleep(TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {},
|
||||
required_header_id = required_header_rx.next() => {
|
||||
match required_header_id {
|
||||
Some(required_header_id) => {
|
||||
if required_header_id.0 > required_header_number {
|
||||
required_header_number = required_header_id.0;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// that's the only way to exit background task - to drop `required_header_tx`
|
||||
break
|
||||
},
|
||||
}
|
||||
},
|
||||
_ = relay_exited_rx => {
|
||||
// there could be a situation when we're receiving exit signals after we
|
||||
// have already stopped relay or when we have already started new relay.
|
||||
// but it isn't critical, because even if we'll accidentally stop new relay
|
||||
// we'll restart it almost immediately
|
||||
stop_on_demand_headers_relay(active_headers_relay.take()).await;
|
||||
},
|
||||
}
|
||||
|
||||
// read best finalized source block from target
|
||||
let available_header_number = match finality_target.best_finalized_source_block_number().await {
|
||||
Ok(available_header_number) => available_header_number,
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Failed to read best finalized {} header from {} in {} relay: {:?}",
|
||||
SourceChain::NAME,
|
||||
TargetChain::NAME,
|
||||
relay_task_name,
|
||||
error,
|
||||
);
|
||||
|
||||
// we don't know what's happening with target client, so better to stop on-demand relay than
|
||||
// submit unneeded transactions
|
||||
// => assume that required header is known to the target node
|
||||
required_header_number
|
||||
}
|
||||
};
|
||||
|
||||
// start or stop headers relay if required
|
||||
let activate = required_header_number > available_header_number;
|
||||
match (activate, active_headers_relay.is_some()) {
|
||||
(true, false) => {
|
||||
let (relay_exited_tx, new_relay_exited_rx) = oneshot::channel();
|
||||
active_headers_relay = start_on_demand_headers_relay(
|
||||
relay_task_name.clone(),
|
||||
relay_exited_tx,
|
||||
source_client.clone(),
|
||||
target_client.clone(),
|
||||
pipeline.clone(),
|
||||
);
|
||||
if active_headers_relay.is_some() {
|
||||
relay_exited_rx = new_relay_exited_rx.right_future();
|
||||
}
|
||||
}
|
||||
(false, true) => {
|
||||
stop_on_demand_headers_relay(active_headers_relay.take()).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// On-demand headers relay task name.
|
||||
fn on_demand_headers_relay_name<SourceChain: Chain, TargetChain: Chain>() -> String {
|
||||
format!("on-demand-{}-to-{}", SourceChain::NAME, TargetChain::NAME)
|
||||
}
|
||||
|
||||
/// Start on-demand headers relay task.
|
||||
fn start_on_demand_headers_relay<SourceChain: Chain, TargetChain: Chain, TargetSign>(
|
||||
task_name: String,
|
||||
relay_exited_tx: oneshot::Sender<()>,
|
||||
source_client: Client<SourceChain>,
|
||||
target_client: Client<TargetChain>,
|
||||
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
||||
) -> Option<async_std::task::JoinHandle<()>>
|
||||
where
|
||||
SourceChain::BlockNumber: BlockNumberBase,
|
||||
SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>: SubstrateFinalitySyncPipeline<
|
||||
Hash = HashOf<SourceChain>,
|
||||
Number = BlockNumberOf<SourceChain>,
|
||||
Header = SyncHeader<SourceChain::Header>,
|
||||
FinalityProof = GrandpaJustification<SourceChain::Header>,
|
||||
TargetChain = TargetChain,
|
||||
>,
|
||||
TargetSign: 'static,
|
||||
{
|
||||
let headers_relay_future =
|
||||
crate::finality_pipeline::run(pipeline, source_client, target_client, MetricsParams::disabled());
|
||||
let closure_task_name = task_name.clone();
|
||||
async_std::task::Builder::new()
|
||||
.name(task_name.clone())
|
||||
.spawn(async move {
|
||||
log::info!(target: "bridge", "Starting {} headers relay", closure_task_name);
|
||||
let result = headers_relay_future.await;
|
||||
log::trace!(target: "bridge", "{} headers relay has exited. Result: {:?}", closure_task_name, result);
|
||||
let _ = relay_exited_tx.send(());
|
||||
})
|
||||
.map_err(|error| {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Failed to start {} relay: {:?}",
|
||||
task_name,
|
||||
error,
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// Stop on-demand headers relay task.
|
||||
async fn stop_on_demand_headers_relay(task: Option<async_std::task::JoinHandle<()>>) {
|
||||
if let Some(task) = task {
|
||||
let task_name = task
|
||||
.task()
|
||||
.name()
|
||||
.expect("on-demand tasks are always started with name; qed")
|
||||
.to_string();
|
||||
log::trace!(target: "bridge", "Cancelling {} headers relay", task_name);
|
||||
task.cancel().await;
|
||||
log::info!(target: "bridge", "Cancelled {} headers relay", task_name);
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
//! Millau-to-Rialto messages sync entrypoint.
|
||||
|
||||
use super::{MillauClient, RialtoClient};
|
||||
use crate::messages_lane::{select_delivery_transaction_limits, SubstrateMessageLane, SubstrateMessageLaneToSubstrate};
|
||||
use crate::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
};
|
||||
use crate::messages_source::SubstrateMessagesSource;
|
||||
use crate::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
use bp_messages::{LaneId, MessageNonce};
|
||||
use bp_messages::MessageNonce;
|
||||
use bp_runtime::{MILLAU_BRIDGE_INSTANCE, RIALTO_BRIDGE_INSTANCE};
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use codec::Encode;
|
||||
@@ -33,12 +34,12 @@ use relay_substrate_client::{
|
||||
metrics::{FloatStorageValueMetric, StorageProofOverheadMetric},
|
||||
Chain, TransactionSignScheme,
|
||||
};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::{Bytes, Pair};
|
||||
use std::{ops::RangeInclusive, time::Duration};
|
||||
|
||||
/// Millau-to-Rialto message lane.
|
||||
type MillauMessagesToRialto = SubstrateMessageLaneToSubstrate<Millau, MillauSigningParams, Rialto, RialtoSigningParams>;
|
||||
pub type MillauMessagesToRialto =
|
||||
SubstrateMessageLaneToSubstrate<Millau, MillauSigningParams, Rialto, RialtoSigningParams>;
|
||||
|
||||
impl SubstrateMessageLane for MillauMessagesToRialto {
|
||||
const OUTBOUND_LANE_MESSAGES_DISPATCH_WEIGHT_METHOD: &'static str =
|
||||
@@ -143,21 +144,18 @@ type RialtoTargetClient = SubstrateMessagesTarget<
|
||||
|
||||
/// Run Millau-to-Rialto messages sync.
|
||||
pub async fn run(
|
||||
millau_client: MillauClient,
|
||||
millau_sign: MillauSigningParams,
|
||||
rialto_client: RialtoClient,
|
||||
rialto_sign: RialtoSigningParams,
|
||||
lane_id: LaneId,
|
||||
metrics_params: MetricsParams,
|
||||
params: MessagesRelayParams<Millau, MillauSigningParams, Rialto, RialtoSigningParams>,
|
||||
) -> Result<(), String> {
|
||||
let stall_timeout = Duration::from_secs(5 * 60);
|
||||
let relayer_id_at_millau = (*millau_sign.public().as_array_ref()).into();
|
||||
let relayer_id_at_millau = (*params.source_sign.public().as_array_ref()).into();
|
||||
|
||||
let lane_id = params.lane_id;
|
||||
let source_client = params.source_client;
|
||||
let lane = MillauMessagesToRialto {
|
||||
source_client: millau_client.clone(),
|
||||
source_sign: millau_sign,
|
||||
target_client: rialto_client.clone(),
|
||||
target_sign: rialto_sign,
|
||||
source_client: source_client.clone(),
|
||||
source_sign: params.source_sign,
|
||||
target_client: params.target_client.clone(),
|
||||
target_sign: params.target_sign,
|
||||
relayer_id_at_source: relayer_id_at_millau,
|
||||
};
|
||||
|
||||
@@ -198,24 +196,48 @@ pub async fn run(
|
||||
max_messages_size_in_single_batch,
|
||||
},
|
||||
},
|
||||
MillauSourceClient::new(millau_client.clone(), lane.clone(), lane_id, RIALTO_BRIDGE_INSTANCE),
|
||||
RialtoTargetClient::new(rialto_client, lane, lane_id, MILLAU_BRIDGE_INSTANCE),
|
||||
MillauSourceClient::new(
|
||||
source_client.clone(),
|
||||
lane.clone(),
|
||||
lane_id,
|
||||
RIALTO_BRIDGE_INSTANCE,
|
||||
params.target_to_source_headers_relay,
|
||||
),
|
||||
RialtoTargetClient::new(
|
||||
params.target_client,
|
||||
lane,
|
||||
lane_id,
|
||||
MILLAU_BRIDGE_INSTANCE,
|
||||
params.source_to_target_headers_relay,
|
||||
),
|
||||
relay_utils::relay_metrics(
|
||||
messages_relay::message_lane_loop::metrics_prefix::<MillauMessagesToRialto>(&lane_id),
|
||||
metrics_params.address,
|
||||
Some(messages_relay::message_lane_loop::metrics_prefix::<
|
||||
MillauMessagesToRialto,
|
||||
>(&lane_id)),
|
||||
params.metrics_params,
|
||||
)
|
||||
.standalone_metric(StorageProofOverheadMetric::new(
|
||||
millau_client.clone(),
|
||||
"millau_storage_proof_overhead".into(),
|
||||
"Millau storage proof overhead".into(),
|
||||
))?
|
||||
.standalone_metric(FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
millau_client,
|
||||
sp_core::storage::StorageKey(millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec()),
|
||||
Some(millau_runtime::rialto_messages::INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE),
|
||||
"millau_rialto_to_millau_conversion_rate".into(),
|
||||
"Rialto to Millau tokens conversion rate (used by Rialto)".into(),
|
||||
))?
|
||||
.standalone_metric(|registry, prefix| {
|
||||
StorageProofOverheadMetric::new(
|
||||
registry,
|
||||
prefix,
|
||||
source_client.clone(),
|
||||
"millau_storage_proof_overhead".into(),
|
||||
"Millau storage proof overhead".into(),
|
||||
)
|
||||
})?
|
||||
.standalone_metric(|registry, prefix| {
|
||||
FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
registry,
|
||||
prefix,
|
||||
source_client,
|
||||
sp_core::storage::StorageKey(
|
||||
millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec(),
|
||||
),
|
||||
Some(millau_runtime::rialto_messages::INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE),
|
||||
"millau_rialto_to_millau_conversion_rate".into(),
|
||||
"Rialto to Millau tokens conversion rate (used by Rialto)".into(),
|
||||
)
|
||||
})?
|
||||
.into_params(),
|
||||
futures::future::pending(),
|
||||
)
|
||||
|
||||
@@ -22,11 +22,6 @@ pub mod rialto_headers_to_millau;
|
||||
pub mod rialto_messages_to_millau;
|
||||
pub mod westend_headers_to_millau;
|
||||
|
||||
/// Millau node client.
|
||||
pub type MillauClient = relay_substrate_client::Client<Millau>;
|
||||
/// Rialto node client.
|
||||
pub type RialtoClient = relay_substrate_client::Client<Rialto>;
|
||||
|
||||
use crate::cli::{
|
||||
bridge,
|
||||
encode_call::{self, Call, CliEncodeCall},
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
//! Rialto-to-Millau messages sync entrypoint.
|
||||
|
||||
use super::{MillauClient, RialtoClient};
|
||||
use crate::messages_lane::{select_delivery_transaction_limits, SubstrateMessageLane, SubstrateMessageLaneToSubstrate};
|
||||
use crate::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
};
|
||||
use crate::messages_source::SubstrateMessagesSource;
|
||||
use crate::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
use bp_messages::{LaneId, MessageNonce};
|
||||
use bp_messages::MessageNonce;
|
||||
use bp_runtime::{MILLAU_BRIDGE_INSTANCE, RIALTO_BRIDGE_INSTANCE};
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use codec::Encode;
|
||||
@@ -33,12 +34,12 @@ use relay_substrate_client::{
|
||||
metrics::{FloatStorageValueMetric, StorageProofOverheadMetric},
|
||||
Chain, TransactionSignScheme,
|
||||
};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::{Bytes, Pair};
|
||||
use std::{ops::RangeInclusive, time::Duration};
|
||||
|
||||
/// Rialto-to-Millau message lane.
|
||||
type RialtoMessagesToMillau = SubstrateMessageLaneToSubstrate<Rialto, RialtoSigningParams, Millau, MillauSigningParams>;
|
||||
pub type RialtoMessagesToMillau =
|
||||
SubstrateMessageLaneToSubstrate<Rialto, RialtoSigningParams, Millau, MillauSigningParams>;
|
||||
|
||||
impl SubstrateMessageLane for RialtoMessagesToMillau {
|
||||
const OUTBOUND_LANE_MESSAGES_DISPATCH_WEIGHT_METHOD: &'static str =
|
||||
@@ -143,21 +144,18 @@ type MillauTargetClient = SubstrateMessagesTarget<
|
||||
|
||||
/// Run Rialto-to-Millau messages sync.
|
||||
pub async fn run(
|
||||
rialto_client: RialtoClient,
|
||||
rialto_sign: RialtoSigningParams,
|
||||
millau_client: MillauClient,
|
||||
millau_sign: MillauSigningParams,
|
||||
lane_id: LaneId,
|
||||
metrics_params: MetricsParams,
|
||||
params: MessagesRelayParams<Rialto, RialtoSigningParams, Millau, MillauSigningParams>,
|
||||
) -> Result<(), String> {
|
||||
let stall_timeout = Duration::from_secs(5 * 60);
|
||||
let relayer_id_at_rialto = (*rialto_sign.public().as_array_ref()).into();
|
||||
let relayer_id_at_rialto = (*params.source_sign.public().as_array_ref()).into();
|
||||
|
||||
let lane_id = params.lane_id;
|
||||
let source_client = params.source_client;
|
||||
let lane = RialtoMessagesToMillau {
|
||||
source_client: rialto_client.clone(),
|
||||
source_sign: rialto_sign,
|
||||
target_client: millau_client.clone(),
|
||||
target_sign: millau_sign,
|
||||
source_client: source_client.clone(),
|
||||
source_sign: params.source_sign,
|
||||
target_client: params.target_client.clone(),
|
||||
target_sign: params.target_sign,
|
||||
relayer_id_at_source: relayer_id_at_rialto,
|
||||
};
|
||||
|
||||
@@ -197,24 +195,48 @@ pub async fn run(
|
||||
max_messages_size_in_single_batch,
|
||||
},
|
||||
},
|
||||
RialtoSourceClient::new(rialto_client.clone(), lane.clone(), lane_id, MILLAU_BRIDGE_INSTANCE),
|
||||
MillauTargetClient::new(millau_client, lane, lane_id, RIALTO_BRIDGE_INSTANCE),
|
||||
RialtoSourceClient::new(
|
||||
source_client.clone(),
|
||||
lane.clone(),
|
||||
lane_id,
|
||||
MILLAU_BRIDGE_INSTANCE,
|
||||
params.target_to_source_headers_relay,
|
||||
),
|
||||
MillauTargetClient::new(
|
||||
params.target_client,
|
||||
lane,
|
||||
lane_id,
|
||||
RIALTO_BRIDGE_INSTANCE,
|
||||
params.source_to_target_headers_relay,
|
||||
),
|
||||
relay_utils::relay_metrics(
|
||||
messages_relay::message_lane_loop::metrics_prefix::<RialtoMessagesToMillau>(&lane_id),
|
||||
metrics_params.address,
|
||||
Some(messages_relay::message_lane_loop::metrics_prefix::<
|
||||
RialtoMessagesToMillau,
|
||||
>(&lane_id)),
|
||||
params.metrics_params,
|
||||
)
|
||||
.standalone_metric(StorageProofOverheadMetric::new(
|
||||
rialto_client.clone(),
|
||||
"rialto_storage_proof_overhead".into(),
|
||||
"Rialto storage proof overhead".into(),
|
||||
))?
|
||||
.standalone_metric(FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
rialto_client,
|
||||
sp_core::storage::StorageKey(rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec()),
|
||||
Some(rialto_runtime::millau_messages::INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE),
|
||||
"rialto_millau_to_rialto_conversion_rate".into(),
|
||||
"Millau to Rialto tokens conversion rate (used by Millau)".into(),
|
||||
))?
|
||||
.standalone_metric(|registry, prefix| {
|
||||
StorageProofOverheadMetric::new(
|
||||
registry,
|
||||
prefix,
|
||||
source_client.clone(),
|
||||
"rialto_storage_proof_overhead".into(),
|
||||
"Rialto storage proof overhead".into(),
|
||||
)
|
||||
})?
|
||||
.standalone_metric(|registry, prefix| {
|
||||
FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
registry,
|
||||
prefix,
|
||||
source_client,
|
||||
sp_core::storage::StorageKey(
|
||||
rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec(),
|
||||
),
|
||||
Some(rialto_runtime::millau_messages::INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE),
|
||||
"rialto_millau_to_rialto_conversion_rate".into(),
|
||||
"Millau to Rialto tokens conversion rate (used by Millau)".into(),
|
||||
)
|
||||
})?
|
||||
.into_params(),
|
||||
futures::future::pending(),
|
||||
)
|
||||
|
||||
@@ -36,22 +36,30 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau {
|
||||
|
||||
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
|
||||
Ok(
|
||||
relay_utils::relay_metrics(finality_relay::metrics_prefix::<Self>(), params.address)
|
||||
relay_utils::relay_metrics(Some(finality_relay::metrics_prefix::<Self>()), params)
|
||||
// Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama
|
||||
// relays, but we want to test metrics/dashboards in advance
|
||||
.standalone_metric(FloatJsonValueMetric::new(
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=Polkadot&vs_currencies=usd".into(),
|
||||
"$.polkadot.usd".into(),
|
||||
"polkadot_price".into(),
|
||||
"Polkadot price in USD".into(),
|
||||
))
|
||||
.standalone_metric(|registry, prefix| {
|
||||
FloatJsonValueMetric::new(
|
||||
registry,
|
||||
prefix,
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=Polkadot&vs_currencies=usd".into(),
|
||||
"$.polkadot.usd".into(),
|
||||
"polkadot_price".into(),
|
||||
"Polkadot price in USD".into(),
|
||||
)
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))?
|
||||
.standalone_metric(FloatJsonValueMetric::new(
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=Kusama&vs_currencies=usd".into(),
|
||||
"$.kusama.usd".into(),
|
||||
"kusama_price".into(),
|
||||
"Kusama price in USD".into(),
|
||||
))
|
||||
.standalone_metric(|registry, prefix| {
|
||||
FloatJsonValueMetric::new(
|
||||
registry,
|
||||
prefix,
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=Kusama&vs_currencies=usd".into(),
|
||||
"$.kusama.usd".into(),
|
||||
"kusama_price".into(),
|
||||
"Kusama price in USD".into(),
|
||||
)
|
||||
})
|
||||
.map_err(|e| anyhow::format_err!("{}", e))?
|
||||
.into_params(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user