mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 18:41:03 +00:00
Refactor message relay helpers (#1234)
* refactor message relay helpers * single standalone_metrics function * fixed tests * clippy + fmt * removed commented code * add calls tracing * fix spelling * cargo fmt * -commented code * fix build again * post-merge build fix * clippy + fmt
This commit is contained in:
committed by
Bastian Köcher
parent
90f2b3c365
commit
4cdd959057
@@ -42,6 +42,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
|
||||
|
||||
[dev-dependencies]
|
||||
bp-millau = { path = "../../primitives/chain-millau" }
|
||||
bp-rialto = { path = "../../primitives/chain-rialto" }
|
||||
bp-rococo = { path = "../../primitives/chain-rococo" }
|
||||
bp-wococo = { path = "../../primitives/chain-wococo" }
|
||||
relay-rococo-client = { path = "../client-rococo" }
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
//! Types and functions intended to ease adding of new Substrate -> Substrate
|
||||
//! finality proofs synchronization pipelines.
|
||||
|
||||
use crate::{finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget};
|
||||
use crate::{
|
||||
finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget,
|
||||
TransactionParams,
|
||||
};
|
||||
|
||||
use bp_header_chain::justification::GrandpaJustification;
|
||||
use finality_relay::FinalitySyncPipeline;
|
||||
@@ -36,15 +39,6 @@ use std::{fmt::Debug, marker::PhantomData};
|
||||
/// Substrate+GRANDPA based chains (good to know).
|
||||
pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096;
|
||||
|
||||
/// Submit-finality-proofs transaction creation parameters.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TransactionParams<TS> {
|
||||
/// Transactions author.
|
||||
pub transactions_signer: TS,
|
||||
/// Transactions mortality.
|
||||
pub transactions_mortality: Option<u32>,
|
||||
}
|
||||
|
||||
/// Substrate -> Substrate finality proofs synchronization pipeline.
|
||||
pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync {
|
||||
/// Headers of this chain are submitted to the `TargetChain`.
|
||||
@@ -67,7 +61,7 @@ pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync {
|
||||
|
||||
/// Adapter that allows all `SubstrateFinalitySyncPipeline` to act as `FinalitySyncPipeline`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FinalitySyncPipelineAdapter<P: SubstrateFinalitySyncPipeline> {
|
||||
pub(crate) struct FinalitySyncPipelineAdapter<P: SubstrateFinalitySyncPipeline> {
|
||||
_phantom: PhantomData<P>,
|
||||
}
|
||||
|
||||
@@ -179,7 +173,7 @@ where
|
||||
),
|
||||
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
|
||||
stall_timeout: transaction_stall_timeout(
|
||||
transaction_params.transactions_mortality,
|
||||
transaction_params.mortality,
|
||||
P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
||||
crate::STALL_TIMEOUT,
|
||||
),
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
//! bridge GRANDPA pallet deployed and provide `<BridgedChainName>FinalityApi` to allow bridging
|
||||
//! with <BridgedName> chain.
|
||||
|
||||
use crate::finality_pipeline::{
|
||||
FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
||||
use crate::{
|
||||
finality_pipeline::{
|
||||
FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
||||
},
|
||||
TransactionParams,
|
||||
};
|
||||
|
||||
@@ -103,16 +105,13 @@ where
|
||||
P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof);
|
||||
self.client
|
||||
.submit_signed_extrinsic(
|
||||
self.transaction_params.transactions_signer.public().into(),
|
||||
self.transaction_params.signer.public().into(),
|
||||
move |best_block_id, transaction_nonce| {
|
||||
Bytes(
|
||||
P::TransactionSignScheme::sign_transaction(
|
||||
genesis_hash,
|
||||
&transaction_params.transactions_signer,
|
||||
TransactionEra::new(
|
||||
best_block_id,
|
||||
transaction_params.transactions_mortality,
|
||||
),
|
||||
&transaction_params.signer,
|
||||
TransactionEra::new(best_block_id, transaction_params.mortality),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
)
|
||||
.encode(),
|
||||
|
||||
@@ -28,6 +28,7 @@ pub mod finality_target;
|
||||
pub mod headers_initialize;
|
||||
pub mod helpers;
|
||||
pub mod messages_lane;
|
||||
pub mod messages_metrics;
|
||||
pub mod messages_source;
|
||||
pub mod messages_target;
|
||||
pub mod on_demand_headers;
|
||||
@@ -40,3 +41,12 @@ pub mod on_demand_headers;
|
||||
/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine
|
||||
/// transaction, or remove it from the pool.
|
||||
pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60);
|
||||
|
||||
/// Transaction creation parameters.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TransactionParams<TS> {
|
||||
/// Transactions author.
|
||||
pub signer: TS,
|
||||
/// Transactions mortality.
|
||||
pub mortality: Option<u32>,
|
||||
}
|
||||
|
||||
@@ -17,194 +17,396 @@
|
||||
//! Tools for supporting message lanes between two Substrate-based chains.
|
||||
|
||||
use crate::{
|
||||
messages_source::SubstrateMessagesProof, messages_target::SubstrateMessagesReceivingProof,
|
||||
messages_metrics::StandaloneMessagesMetrics,
|
||||
messages_source::{SubstrateMessagesProof, SubstrateMessagesSource},
|
||||
messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget},
|
||||
on_demand_headers::OnDemandHeadersRelay,
|
||||
TransactionParams, STALL_TIMEOUT,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{LaneId, MessageNonce};
|
||||
use bp_runtime::{AccountIdOf, IndexOf};
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::{
|
||||
message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf},
|
||||
relay_strategy::RelayStrategy,
|
||||
use bp_runtime::{AccountIdOf, Chain as _};
|
||||
use bridge_runtime_common::messages::{
|
||||
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_support::weights::{GetDispatchInfo, Weight};
|
||||
use messages_relay::{message_lane::MessageLane, relay_strategy::RelayStrategy};
|
||||
use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig};
|
||||
use relay_substrate_client::{
|
||||
metrics::{FloatStorageValueMetric, StorageProofOverheadMetric},
|
||||
BlockNumberOf, Chain, Client, HashOf,
|
||||
AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithMessages, Client, HashOf,
|
||||
TransactionSignScheme,
|
||||
};
|
||||
use relay_utils::{
|
||||
metrics::{
|
||||
FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric,
|
||||
},
|
||||
BlockNumberBase,
|
||||
};
|
||||
use sp_core::{storage::StorageKey, Bytes};
|
||||
use sp_runtime::FixedU128;
|
||||
use std::ops::RangeInclusive;
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::Pair;
|
||||
use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
|
||||
|
||||
/// Substrate -> Substrate messages synchronization pipeline.
|
||||
pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync {
|
||||
/// Name of the source -> target tokens conversion rate parameter name.
|
||||
///
|
||||
/// The parameter is stored at the target chain and the storage key is computed using
|
||||
/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
|
||||
/// to be 1.
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>;
|
||||
/// Name of the target -> source tokens conversion rate parameter name.
|
||||
///
|
||||
/// The parameter is stored at the source chain and the storage key is computed using
|
||||
/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
|
||||
/// to be 1.
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>;
|
||||
|
||||
/// Messages of this chain are relayed to the `TargetChain`.
|
||||
type SourceChain: ChainWithMessages;
|
||||
/// Messages from the `SourceChain` are dispatched on this chain.
|
||||
type TargetChain: ChainWithMessages;
|
||||
|
||||
/// Scheme used to sign source chain transactions.
|
||||
type SourceTransactionSignScheme: TransactionSignScheme;
|
||||
/// Scheme used to sign target chain transactions.
|
||||
type TargetTransactionSignScheme: TransactionSignScheme;
|
||||
|
||||
/// How receive messages proof call is built?
|
||||
type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder<Self>;
|
||||
/// How receive messages delivery proof call is built?
|
||||
type ReceiveMessagesDeliveryProofCallBuilder: ReceiveMessagesDeliveryProofCallBuilder<Self>;
|
||||
|
||||
/// Message relay strategy.
|
||||
type RelayStrategy: RelayStrategy;
|
||||
}
|
||||
|
||||
/// Adapter that allows all `SubstrateMessageLane` to act as `MessageLane`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MessageLaneAdapter<P: SubstrateMessageLane> {
|
||||
_phantom: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<P: SubstrateMessageLane> MessageLane for MessageLaneAdapter<P> {
|
||||
const SOURCE_NAME: &'static str = P::SourceChain::NAME;
|
||||
const TARGET_NAME: &'static str = P::TargetChain::NAME;
|
||||
|
||||
type MessagesProof = SubstrateMessagesProof<P::SourceChain>;
|
||||
type MessagesReceivingProof = SubstrateMessagesDeliveryProof<P::TargetChain>;
|
||||
|
||||
type SourceChainBalance = BalanceOf<P::SourceChain>;
|
||||
type SourceHeaderNumber = BlockNumberOf<P::SourceChain>;
|
||||
type SourceHeaderHash = HashOf<P::SourceChain>;
|
||||
|
||||
type TargetHeaderNumber = BlockNumberOf<P::TargetChain>;
|
||||
type TargetHeaderHash = HashOf<P::TargetChain>;
|
||||
}
|
||||
|
||||
/// Substrate <-> Substrate messages relay parameters.
|
||||
pub struct MessagesRelayParams<SC: Chain, SS, TC: Chain, TS, Strategy: RelayStrategy> {
|
||||
pub struct MessagesRelayParams<P: SubstrateMessageLane> {
|
||||
/// Messages source client.
|
||||
pub source_client: Client<SC>,
|
||||
/// Sign parameters for messages source chain.
|
||||
pub source_sign: SS,
|
||||
/// Mortality of source transactions.
|
||||
pub source_transactions_mortality: Option<u32>,
|
||||
pub source_client: Client<P::SourceChain>,
|
||||
/// Source transaction params.
|
||||
pub source_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<P::SourceTransactionSignScheme>>,
|
||||
/// Messages target client.
|
||||
pub target_client: Client<TC>,
|
||||
/// Sign parameters for messages target chain.
|
||||
pub target_sign: TS,
|
||||
/// Mortality of target transactions.
|
||||
pub target_transactions_mortality: Option<u32>,
|
||||
pub target_client: Client<P::TargetChain>,
|
||||
/// Target transaction params.
|
||||
pub target_transaction_params:
|
||||
TransactionParams<AccountKeyPairOf<P::TargetTransactionSignScheme>>,
|
||||
/// Optional on-demand source to target headers relay.
|
||||
pub source_to_target_headers_relay: Option<OnDemandHeadersRelay<SC>>,
|
||||
pub source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
|
||||
/// Optional on-demand target to source headers relay.
|
||||
pub target_to_source_headers_relay: Option<OnDemandHeadersRelay<TC>>,
|
||||
pub target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
|
||||
/// Identifier of lane that needs to be served.
|
||||
pub lane_id: LaneId,
|
||||
/// Metrics parameters.
|
||||
pub metrics_params: MetricsParams,
|
||||
/// Pre-registered standalone metrics.
|
||||
pub standalone_metrics: Option<StandaloneMessagesMetrics<SC, TC>>,
|
||||
/// Relay strategy
|
||||
pub relay_strategy: Strategy,
|
||||
pub standalone_metrics: Option<StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>>,
|
||||
/// Relay strategy.
|
||||
pub relay_strategy: P::RelayStrategy,
|
||||
}
|
||||
|
||||
/// Message sync pipeline for Substrate <-> Substrate relays.
|
||||
#[async_trait]
|
||||
pub trait SubstrateMessageLane: 'static + Clone + Send + Sync {
|
||||
/// Underlying generic message lane.
|
||||
type MessageLane: MessageLane;
|
||||
|
||||
/// Name of the runtime method that returns dispatch weight of outbound messages at the source
|
||||
/// chain.
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str;
|
||||
/// Name of the runtime method that returns latest generated nonce at the source chain.
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str;
|
||||
/// Name of the runtime method that returns latest received (confirmed) nonce at the the source
|
||||
/// chain.
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str;
|
||||
|
||||
/// Name of the runtime method that returns latest received nonce at the target chain.
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str;
|
||||
/// Name of the runtime method that returns the latest confirmed (reward-paid) nonce at the
|
||||
/// target chain.
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str;
|
||||
/// Number of the runtime method that returns state of "unrewarded relayers" set at the target
|
||||
/// chain.
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str;
|
||||
|
||||
/// Name of the runtime method that returns id of best finalized source header at target chain.
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str;
|
||||
/// Name of the runtime method that returns id of best finalized target header at source chain.
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str;
|
||||
|
||||
/// Name of the messages pallet as it is declared in the `construct_runtime!()` at source chain.
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str;
|
||||
/// Name of the messages pallet as it is declared in the `construct_runtime!()` at target chain.
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str;
|
||||
|
||||
/// Extra weight of the delivery transaction at the target chain, that is paid to cover
|
||||
/// dispatch fee payment.
|
||||
///
|
||||
/// If dispatch fee is paid at the source chain, then this weight is refunded by the
|
||||
/// delivery transaction.
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight;
|
||||
|
||||
/// Source chain.
|
||||
type SourceChain: Chain;
|
||||
/// Target chain.
|
||||
type TargetChain: Chain;
|
||||
|
||||
/// Returns id of account that we're using to sign transactions at target chain (messages
|
||||
/// proof).
|
||||
fn target_transactions_author(&self) -> AccountIdOf<Self::TargetChain>;
|
||||
|
||||
/// Make messages delivery transaction.
|
||||
fn make_messages_delivery_transaction(
|
||||
&self,
|
||||
best_block_id: TargetHeaderIdOf<Self::MessageLane>,
|
||||
transaction_nonce: IndexOf<Self::TargetChain>,
|
||||
generated_at_header: SourceHeaderIdOf<Self::MessageLane>,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes;
|
||||
|
||||
/// Returns id of account that we're using to sign transactions at source chain (delivery
|
||||
/// proof).
|
||||
fn source_transactions_author(&self) -> AccountIdOf<Self::SourceChain>;
|
||||
|
||||
/// Make messages receiving proof transaction.
|
||||
fn make_messages_receiving_proof_transaction(
|
||||
&self,
|
||||
best_block_id: SourceHeaderIdOf<Self::MessageLane>,
|
||||
transaction_nonce: IndexOf<Self::SourceChain>,
|
||||
generated_at_header: TargetHeaderIdOf<Self::MessageLane>,
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesReceivingProof,
|
||||
) -> Bytes;
|
||||
}
|
||||
|
||||
/// Substrate-to-Substrate message lane.
|
||||
#[derive(Debug)]
|
||||
pub struct SubstrateMessageLaneToSubstrate<
|
||||
Source: Chain,
|
||||
SourceSignParams,
|
||||
Target: Chain,
|
||||
TargetSignParams,
|
||||
> {
|
||||
/// Client for the source Substrate chain.
|
||||
pub source_client: Client<Source>,
|
||||
/// Parameters required to sign transactions for source chain.
|
||||
pub source_sign: SourceSignParams,
|
||||
/// Source transactions mortality.
|
||||
pub source_transactions_mortality: Option<u32>,
|
||||
/// Client for the target Substrate chain.
|
||||
pub target_client: Client<Target>,
|
||||
/// Parameters required to sign transactions for target chain.
|
||||
pub target_sign: TargetSignParams,
|
||||
/// Target transactions mortality.
|
||||
pub target_transactions_mortality: Option<u32>,
|
||||
/// Account id of relayer at the source chain.
|
||||
pub relayer_id_at_source: Source::AccountId,
|
||||
}
|
||||
|
||||
impl<Source: Chain, SourceSignParams: Clone, Target: Chain, TargetSignParams: Clone> Clone
|
||||
for SubstrateMessageLaneToSubstrate<Source, SourceSignParams, Target, TargetSignParams>
|
||||
/// Run Substrate-to-Substrate messages sync loop.
|
||||
pub async fn run<P: SubstrateMessageLane>(params: MessagesRelayParams<P>) -> anyhow::Result<()>
|
||||
where
|
||||
AccountIdOf<P::SourceChain>:
|
||||
From<<AccountKeyPairOf<P::SourceTransactionSignScheme> as Pair>::Public>,
|
||||
AccountIdOf<P::TargetChain>:
|
||||
From<<AccountKeyPairOf<P::TargetTransactionSignScheme> as Pair>::Public>,
|
||||
BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
|
||||
P::SourceTransactionSignScheme: TransactionSignScheme<Chain = P::SourceChain>,
|
||||
P::TargetTransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
source_client: self.source_client.clone(),
|
||||
source_sign: self.source_sign.clone(),
|
||||
source_transactions_mortality: self.source_transactions_mortality,
|
||||
target_client: self.target_client.clone(),
|
||||
target_sign: self.target_sign.clone(),
|
||||
target_transactions_mortality: self.target_transactions_mortality,
|
||||
relayer_id_at_source: self.relayer_id_at_source.clone(),
|
||||
let source_client = params.source_client;
|
||||
let target_client = params.target_client;
|
||||
let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout(
|
||||
params.source_transaction_params.mortality,
|
||||
params.target_transaction_params.mortality,
|
||||
P::SourceChain::AVERAGE_BLOCK_INTERVAL,
|
||||
P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
||||
STALL_TIMEOUT,
|
||||
);
|
||||
let relayer_id_at_source: AccountIdOf<P::SourceChain> =
|
||||
params.source_transaction_params.signer.public().into();
|
||||
|
||||
// 2/3 is reserved for proofs and tx overhead
|
||||
let max_messages_size_in_single_batch = P::TargetChain::max_extrinsic_size() / 3;
|
||||
// we don't know exact weights of the Polkadot runtime. So to guess weights we'll be using
|
||||
// weights from Rialto and then simply dividing it by x2.
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
crate::messages_lane::select_delivery_transaction_limits::<
|
||||
<P::TargetChain as ChainWithMessages>::WeightInfo,
|
||||
>(
|
||||
P::TargetChain::max_extrinsic_weight(),
|
||||
P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
|
||||
|
||||
let standalone_metrics = params.standalone_metrics.map(Ok).unwrap_or_else(|| {
|
||||
crate::messages_metrics::standalone_metrics::<P>(
|
||||
source_client.clone(),
|
||||
target_client.clone(),
|
||||
)
|
||||
})?;
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Starting {} -> {} messages relay.\n\t\
|
||||
{} relayer account id: {:?}\n\t\
|
||||
Max messages in single transaction: {}\n\t\
|
||||
Max messages size in single transaction: {}\n\t\
|
||||
Max messages weight in single transaction: {}\n\t\
|
||||
Tx mortality: {:?}/{:?}\n\t\
|
||||
Stall timeout: {:?}",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
relayer_id_at_source,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
params.source_transaction_params.mortality,
|
||||
params.target_transaction_params.mortality,
|
||||
stall_timeout,
|
||||
);
|
||||
|
||||
messages_relay::message_lane_loop::run(
|
||||
messages_relay::message_lane_loop::Params {
|
||||
lane: params.lane_id,
|
||||
source_tick: P::SourceChain::AVERAGE_BLOCK_INTERVAL,
|
||||
target_tick: P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target:
|
||||
P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
|
||||
max_unconfirmed_nonces_at_target:
|
||||
P::SourceChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
relay_strategy: params.relay_strategy,
|
||||
},
|
||||
},
|
||||
SubstrateMessagesSource::<P>::new(
|
||||
source_client,
|
||||
params.lane_id,
|
||||
params.source_transaction_params,
|
||||
params.target_to_source_headers_relay,
|
||||
),
|
||||
SubstrateMessagesTarget::<P>::new(
|
||||
target_client,
|
||||
params.lane_id,
|
||||
relayer_id_at_source,
|
||||
params.target_transaction_params,
|
||||
standalone_metrics.clone(),
|
||||
params.source_to_target_headers_relay,
|
||||
),
|
||||
standalone_metrics.register_and_spawn(params.metrics_params)?,
|
||||
futures::future::pending(),
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Different ways of building `receive_messages_proof` calls.
|
||||
pub trait ReceiveMessagesProofCallBuilder<P: SubstrateMessageLane> {
|
||||
/// Given messages proof, build call of `receive_messages_proof` function of bridge
|
||||
/// messages module at the target chain.
|
||||
fn build_receive_messages_proof_call(
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
proof: SubstrateMessagesProof<P::SourceChain>,
|
||||
messages_count: u32,
|
||||
dispatch_weight: Weight,
|
||||
trace_call: bool,
|
||||
) -> CallOf<P::TargetChain>;
|
||||
}
|
||||
|
||||
/// Building `receive_messages_proof` call when you have direct access to the target
|
||||
/// chain runtime.
|
||||
pub struct DirectReceiveMessagesProofCallBuilder<P, R, I> {
|
||||
_phantom: PhantomData<(P, R, I)>,
|
||||
}
|
||||
|
||||
impl<P, R, I> ReceiveMessagesProofCallBuilder<P> for DirectReceiveMessagesProofCallBuilder<P, R, I>
|
||||
where
|
||||
P: SubstrateMessageLane,
|
||||
R: BridgeMessagesConfig<I, InboundRelayer = AccountIdOf<P::SourceChain>>,
|
||||
I: 'static,
|
||||
R::SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain<
|
||||
R::InboundMessageFee,
|
||||
MessagesProof = FromBridgedChainMessagesProof<HashOf<P::SourceChain>>,
|
||||
>,
|
||||
CallOf<P::TargetChain>: From<BridgeMessagesCall<R, I>> + GetDispatchInfo,
|
||||
{
|
||||
fn build_receive_messages_proof_call(
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
proof: SubstrateMessagesProof<P::SourceChain>,
|
||||
messages_count: u32,
|
||||
dispatch_weight: Weight,
|
||||
trace_call: bool,
|
||||
) -> CallOf<P::TargetChain> {
|
||||
let call: CallOf<P::TargetChain> = BridgeMessagesCall::<R, I>::receive_messages_proof {
|
||||
relayer_id_at_bridged_chain: relayer_id_at_source,
|
||||
proof: proof.1,
|
||||
messages_count,
|
||||
dispatch_weight,
|
||||
}
|
||||
.into();
|
||||
if trace_call {
|
||||
// this trace isn't super-accurate, because limits are for transactions and we
|
||||
// have a call here, but it provides required information
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Prepared {} -> {} messages delivery call. Weight: {}/{}, size: {}/{}",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
call.get_dispatch_info().weight,
|
||||
P::TargetChain::max_extrinsic_weight(),
|
||||
call.encode().len(),
|
||||
P::TargetChain::max_extrinsic_size(),
|
||||
);
|
||||
}
|
||||
call
|
||||
}
|
||||
}
|
||||
|
||||
impl<Source: Chain, SourceSignParams, Target: Chain, TargetSignParams> MessageLane
|
||||
for SubstrateMessageLaneToSubstrate<Source, SourceSignParams, Target, TargetSignParams>
|
||||
/// Macro that generates `ReceiveMessagesProofCallBuilder` implementation for the case when
|
||||
/// you only have an access to the mocked version of target chain runtime. In this case you
|
||||
/// should provide "name" of the call variant for the bridge messages calls and the "name" of
|
||||
/// the variant for the `receive_messages_proof` call within that first option.
|
||||
#[rustfmt::skip]
|
||||
#[macro_export]
|
||||
macro_rules! generate_mocked_receive_message_proof_call_builder {
|
||||
($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_proof:path) => {
|
||||
pub struct $mocked_builder;
|
||||
|
||||
impl $crate::messages_lane::ReceiveMessagesProofCallBuilder<$pipeline>
|
||||
for $mocked_builder
|
||||
{
|
||||
fn build_receive_messages_proof_call(
|
||||
relayer_id_at_source: relay_substrate_client::AccountIdOf<
|
||||
<$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain
|
||||
>,
|
||||
proof: $crate::messages_source::SubstrateMessagesProof<
|
||||
<$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain
|
||||
>,
|
||||
messages_count: u32,
|
||||
dispatch_weight: Weight,
|
||||
_trace_call: bool,
|
||||
) -> relay_substrate_client::CallOf<
|
||||
<$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain
|
||||
> {
|
||||
$bridge_messages($receive_messages_proof(
|
||||
relayer_id_at_source,
|
||||
proof.1,
|
||||
messages_count,
|
||||
dispatch_weight,
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Different ways of building `receive_messages_delivery_proof` calls.
|
||||
pub trait ReceiveMessagesDeliveryProofCallBuilder<P: SubstrateMessageLane> {
|
||||
/// Given messages delivery proof, build call of `receive_messages_delivery_proof` function of
|
||||
/// bridge messages module at the source chain.
|
||||
fn build_receive_messages_delivery_proof_call(
|
||||
proof: SubstrateMessagesDeliveryProof<P::TargetChain>,
|
||||
trace_call: bool,
|
||||
) -> CallOf<P::SourceChain>;
|
||||
}
|
||||
|
||||
/// Building `receive_messages_delivery_proof` call when you have direct access to the source
|
||||
/// chain runtime.
|
||||
pub struct DirectReceiveMessagesDeliveryProofCallBuilder<P, R, I> {
|
||||
_phantom: PhantomData<(P, R, I)>,
|
||||
}
|
||||
|
||||
impl<P, R, I> ReceiveMessagesDeliveryProofCallBuilder<P>
|
||||
for DirectReceiveMessagesDeliveryProofCallBuilder<P, R, I>
|
||||
where
|
||||
SourceSignParams: Clone + Send + Sync + 'static,
|
||||
TargetSignParams: Clone + Send + Sync + 'static,
|
||||
BlockNumberOf<Source>: BlockNumberBase,
|
||||
BlockNumberOf<Target>: BlockNumberBase,
|
||||
P: SubstrateMessageLane,
|
||||
R: BridgeMessagesConfig<I>,
|
||||
I: 'static,
|
||||
R::TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain<
|
||||
R::OutboundPayload,
|
||||
R::AccountId,
|
||||
MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof<HashOf<P::TargetChain>>,
|
||||
>,
|
||||
CallOf<P::SourceChain>: From<BridgeMessagesCall<R, I>> + GetDispatchInfo,
|
||||
{
|
||||
const SOURCE_NAME: &'static str = Source::NAME;
|
||||
const TARGET_NAME: &'static str = Target::NAME;
|
||||
fn build_receive_messages_delivery_proof_call(
|
||||
proof: SubstrateMessagesDeliveryProof<P::TargetChain>,
|
||||
trace_call: bool,
|
||||
) -> CallOf<P::SourceChain> {
|
||||
let call: CallOf<P::SourceChain> =
|
||||
BridgeMessagesCall::<R, I>::receive_messages_delivery_proof {
|
||||
proof: proof.1,
|
||||
relayers_state: proof.0,
|
||||
}
|
||||
.into();
|
||||
if trace_call {
|
||||
// this trace isn't super-accurate, because limits are for transactions and we
|
||||
// have a call here, but it provides required information
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Prepared {} -> {} delivery confirmation transaction. Weight: {}/{}, size: {}/{}",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
call.get_dispatch_info().weight,
|
||||
P::SourceChain::max_extrinsic_weight(),
|
||||
call.encode().len(),
|
||||
P::SourceChain::max_extrinsic_size(),
|
||||
);
|
||||
}
|
||||
call
|
||||
}
|
||||
}
|
||||
|
||||
type MessagesProof = SubstrateMessagesProof<Source>;
|
||||
type MessagesReceivingProof = SubstrateMessagesReceivingProof<Target>;
|
||||
/// Macro that generates `ReceiveMessagesDeliveryProofCallBuilder` implementation for the case when
|
||||
/// you only have an access to the mocked version of source chain runtime. In this case you
|
||||
/// should provide "name" of the call variant for the bridge messages calls and the "name" of
|
||||
/// the variant for the `receive_messages_delivery_proof` call within that first option.
|
||||
#[rustfmt::skip]
|
||||
#[macro_export]
|
||||
macro_rules! generate_mocked_receive_message_delivery_proof_call_builder {
|
||||
($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_delivery_proof:path) => {
|
||||
pub struct $mocked_builder;
|
||||
|
||||
type SourceChainBalance = Source::Balance;
|
||||
type SourceHeaderNumber = BlockNumberOf<Source>;
|
||||
type SourceHeaderHash = HashOf<Source>;
|
||||
|
||||
type TargetHeaderNumber = BlockNumberOf<Target>;
|
||||
type TargetHeaderHash = HashOf<Target>;
|
||||
impl $crate::messages_lane::ReceiveMessagesDeliveryProofCallBuilder<$pipeline>
|
||||
for $mocked_builder
|
||||
{
|
||||
fn build_receive_messages_delivery_proof_call(
|
||||
proof: $crate::messages_target::SubstrateMessagesDeliveryProof<
|
||||
<$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain
|
||||
>,
|
||||
_trace_call: bool,
|
||||
) -> relay_substrate_client::CallOf<
|
||||
<$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain
|
||||
> {
|
||||
$bridge_messages($receive_messages_delivery_proof(proof.1, proof.0))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns maximal number of messages and their maximal cumulative dispatch weight, based
|
||||
@@ -245,155 +447,10 @@ pub fn select_delivery_transaction_limits<W: pallet_bridge_messages::WeightInfoE
|
||||
(max_number_of_messages, weight_for_messages_dispatch)
|
||||
}
|
||||
|
||||
/// Shared references to the standalone metrics of the message lane relay loop.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandaloneMessagesMetrics<SC: Chain, TC: Chain> {
|
||||
/// Global metrics.
|
||||
pub global: GlobalMetrics,
|
||||
/// Storage chain proof overhead metric.
|
||||
pub source_storage_proof_overhead: StorageProofOverheadMetric<SC>,
|
||||
/// Target chain proof overhead metric.
|
||||
pub target_storage_proof_overhead: StorageProofOverheadMetric<TC>,
|
||||
/// Source tokens to base conversion rate metric.
|
||||
pub source_to_base_conversion_rate: Option<FloatJsonValueMetric>,
|
||||
/// Target tokens to base conversion rate metric.
|
||||
pub target_to_base_conversion_rate: Option<FloatJsonValueMetric>,
|
||||
/// Source tokens to target tokens conversion rate metric. This rate is stored by the target
|
||||
/// chain.
|
||||
pub source_to_target_conversion_rate:
|
||||
Option<FloatStorageValueMetric<TC, sp_runtime::FixedU128>>,
|
||||
/// Target tokens to source tokens conversion rate metric. This rate is stored by the source
|
||||
/// chain.
|
||||
pub target_to_source_conversion_rate:
|
||||
Option<FloatStorageValueMetric<SC, sp_runtime::FixedU128>>,
|
||||
}
|
||||
|
||||
impl<SC: Chain, TC: Chain> StandaloneMessagesMetrics<SC, TC> {
|
||||
/// Swap source and target sides.
|
||||
pub fn reverse(self) -> StandaloneMessagesMetrics<TC, SC> {
|
||||
StandaloneMessagesMetrics {
|
||||
global: self.global,
|
||||
source_storage_proof_overhead: self.target_storage_proof_overhead,
|
||||
target_storage_proof_overhead: self.source_storage_proof_overhead,
|
||||
source_to_base_conversion_rate: self.target_to_base_conversion_rate,
|
||||
target_to_base_conversion_rate: self.source_to_base_conversion_rate,
|
||||
source_to_target_conversion_rate: self.target_to_source_conversion_rate,
|
||||
target_to_source_conversion_rate: self.source_to_target_conversion_rate,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register all metrics in the registry.
|
||||
pub fn register_and_spawn(
|
||||
self,
|
||||
metrics: MetricsParams,
|
||||
) -> Result<MetricsParams, PrometheusError> {
|
||||
self.global.register_and_spawn(&metrics.registry)?;
|
||||
self.source_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
|
||||
self.target_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
|
||||
if let Some(m) = self.source_to_base_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_to_base_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_to_source_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
Ok(metrics)
|
||||
}
|
||||
|
||||
/// Return conversion rate from target to source tokens.
|
||||
pub async fn target_to_source_conversion_rate(&self) -> Option<f64> {
|
||||
Self::compute_target_to_source_conversion_rate(
|
||||
*self.target_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await,
|
||||
*self.source_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await,
|
||||
)
|
||||
}
|
||||
|
||||
/// Return conversion rate from target to source tokens, given conversion rates from
|
||||
/// target/source tokens to some base token.
|
||||
fn compute_target_to_source_conversion_rate(
|
||||
target_to_base_conversion_rate: Option<f64>,
|
||||
source_to_base_conversion_rate: Option<f64>,
|
||||
) -> Option<f64> {
|
||||
Some(source_to_base_conversion_rate? / target_to_base_conversion_rate?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create standalone metrics for the message lane relay loop.
|
||||
///
|
||||
/// All metrics returned by this function are exposed by loops that are serving given lane (`P`)
|
||||
/// and by loops that are serving reverse lane (`P` with swapped `TargetChain` and `SourceChain`).
|
||||
pub fn standalone_metrics<SC: Chain, TC: Chain>(
|
||||
source_client: Client<SC>,
|
||||
target_client: Client<TC>,
|
||||
source_chain_token_id: Option<&str>,
|
||||
target_chain_token_id: Option<&str>,
|
||||
source_to_target_conversion_rate_params: Option<(StorageKey, FixedU128)>,
|
||||
target_to_source_conversion_rate_params: Option<(StorageKey, FixedU128)>,
|
||||
) -> anyhow::Result<StandaloneMessagesMetrics<SC, TC>> {
|
||||
Ok(StandaloneMessagesMetrics {
|
||||
global: GlobalMetrics::new()?,
|
||||
source_storage_proof_overhead: StorageProofOverheadMetric::new(
|
||||
source_client.clone(),
|
||||
format!("{}_storage_proof_overhead", SC::NAME.to_lowercase()),
|
||||
format!("{} storage proof overhead", SC::NAME),
|
||||
)?,
|
||||
target_storage_proof_overhead: StorageProofOverheadMetric::new(
|
||||
target_client.clone(),
|
||||
format!("{}_storage_proof_overhead", TC::NAME.to_lowercase()),
|
||||
format!("{} storage proof overhead", TC::NAME),
|
||||
)?,
|
||||
source_to_base_conversion_rate: source_chain_token_id
|
||||
.map(|source_chain_token_id| {
|
||||
crate::helpers::token_price_metric(source_chain_token_id).map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_to_base_conversion_rate: target_chain_token_id
|
||||
.map(|target_chain_token_id| {
|
||||
crate::helpers::token_price_metric(target_chain_token_id).map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
source_to_target_conversion_rate: source_to_target_conversion_rate_params
|
||||
.map(|(key, rate)| {
|
||||
FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
target_client,
|
||||
key,
|
||||
Some(rate),
|
||||
format!("{}_{}_to_{}_conversion_rate", TC::NAME, SC::NAME, TC::NAME),
|
||||
format!(
|
||||
"{} to {} tokens conversion rate (used by {})",
|
||||
SC::NAME,
|
||||
TC::NAME,
|
||||
TC::NAME
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_to_source_conversion_rate: target_to_source_conversion_rate_params
|
||||
.map(|(key, rate)| {
|
||||
FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
source_client,
|
||||
key,
|
||||
Some(rate),
|
||||
format!("{}_{}_to_{}_conversion_rate", SC::NAME, TC::NAME, SC::NAME),
|
||||
format!(
|
||||
"{} to {} tokens conversion rate (used by {})",
|
||||
TC::NAME,
|
||||
SC::NAME,
|
||||
SC::NAME
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bp_runtime::Chain;
|
||||
|
||||
type RialtoToMillauMessagesWeights =
|
||||
pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>;
|
||||
@@ -402,8 +459,8 @@ mod tests {
|
||||
fn select_delivery_transaction_limits_works() {
|
||||
let (max_count, max_weight) =
|
||||
select_delivery_transaction_limits::<RialtoToMillauMessagesWeights>(
|
||||
bp_millau::max_extrinsic_weight(),
|
||||
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
bp_millau::Millau::max_extrinsic_weight(),
|
||||
bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
|
||||
);
|
||||
assert_eq!(
|
||||
(max_count, max_weight),
|
||||
@@ -415,12 +472,4 @@ mod tests {
|
||||
(782, 216_583_333_334),
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn target_to_source_conversion_rate_works() {
|
||||
assert_eq!(
|
||||
StandaloneMessagesMetrics::<relay_rococo_client::Rococo, relay_wococo_client::Wococo>::compute_target_to_source_conversion_rate(Some(183.15), Some(12.32)),
|
||||
Some(12.32 / 183.15),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
// 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/>.
|
||||
|
||||
//! Tools for supporting message lanes between two Substrate-based chains.
|
||||
|
||||
use crate::messages_lane::SubstrateMessageLane;
|
||||
|
||||
use num_traits::One;
|
||||
use relay_substrate_client::{
|
||||
metrics::{FloatStorageValueMetric, StorageProofOverheadMetric},
|
||||
Chain, Client,
|
||||
};
|
||||
use relay_utils::metrics::{
|
||||
FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric,
|
||||
};
|
||||
use sp_runtime::FixedU128;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Shared references to the standalone metrics of the message lane relay loop.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandaloneMessagesMetrics<SC: Chain, TC: Chain> {
|
||||
/// Global metrics.
|
||||
pub global: GlobalMetrics,
|
||||
/// Storage chain proof overhead metric.
|
||||
pub source_storage_proof_overhead: StorageProofOverheadMetric<SC>,
|
||||
/// Target chain proof overhead metric.
|
||||
pub target_storage_proof_overhead: StorageProofOverheadMetric<TC>,
|
||||
/// Source tokens to base conversion rate metric.
|
||||
pub source_to_base_conversion_rate: Option<FloatJsonValueMetric>,
|
||||
/// Target tokens to base conversion rate metric.
|
||||
pub target_to_base_conversion_rate: Option<FloatJsonValueMetric>,
|
||||
/// Source tokens to target tokens conversion rate metric. This rate is stored by the target
|
||||
/// chain.
|
||||
pub source_to_target_conversion_rate:
|
||||
Option<FloatStorageValueMetric<TC, sp_runtime::FixedU128>>,
|
||||
/// Target tokens to source tokens conversion rate metric. This rate is stored by the source
|
||||
/// chain.
|
||||
pub target_to_source_conversion_rate:
|
||||
Option<FloatStorageValueMetric<SC, sp_runtime::FixedU128>>,
|
||||
}
|
||||
|
||||
impl<SC: Chain, TC: Chain> StandaloneMessagesMetrics<SC, TC> {
|
||||
/// Swap source and target sides.
|
||||
pub fn reverse(self) -> StandaloneMessagesMetrics<TC, SC> {
|
||||
StandaloneMessagesMetrics {
|
||||
global: self.global,
|
||||
source_storage_proof_overhead: self.target_storage_proof_overhead,
|
||||
target_storage_proof_overhead: self.source_storage_proof_overhead,
|
||||
source_to_base_conversion_rate: self.target_to_base_conversion_rate,
|
||||
target_to_base_conversion_rate: self.source_to_base_conversion_rate,
|
||||
source_to_target_conversion_rate: self.target_to_source_conversion_rate,
|
||||
target_to_source_conversion_rate: self.source_to_target_conversion_rate,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register all metrics in the registry.
|
||||
pub fn register_and_spawn(
|
||||
self,
|
||||
metrics: MetricsParams,
|
||||
) -> Result<MetricsParams, PrometheusError> {
|
||||
self.global.register_and_spawn(&metrics.registry)?;
|
||||
self.source_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
|
||||
self.target_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
|
||||
if let Some(m) = self.source_to_base_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_to_base_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_to_source_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
Ok(metrics)
|
||||
}
|
||||
|
||||
/// Return conversion rate from target to source tokens.
|
||||
pub async fn target_to_source_conversion_rate(&self) -> Option<f64> {
|
||||
Self::compute_target_to_source_conversion_rate(
|
||||
*self.target_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await,
|
||||
*self.source_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await,
|
||||
)
|
||||
}
|
||||
|
||||
/// Return conversion rate from target to source tokens, given conversion rates from
|
||||
/// target/source tokens to some base token.
|
||||
fn compute_target_to_source_conversion_rate(
|
||||
target_to_base_conversion_rate: Option<f64>,
|
||||
source_to_base_conversion_rate: Option<f64>,
|
||||
) -> Option<f64> {
|
||||
Some(source_to_base_conversion_rate? / target_to_base_conversion_rate?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create standalone metrics for the message lane relay loop.
|
||||
///
|
||||
/// All metrics returned by this function are exposed by loops that are serving given lane (`P`)
|
||||
/// and by loops that are serving reverse lane (`P` with swapped `TargetChain` and `SourceChain`).
|
||||
/// We assume that either conversion rate parameters have values in the storage, or they are
|
||||
/// initialized with 1:1.
|
||||
pub fn standalone_metrics<P: SubstrateMessageLane>(
|
||||
source_client: Client<P::SourceChain>,
|
||||
target_client: Client<P::TargetChain>,
|
||||
) -> anyhow::Result<StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>> {
|
||||
Ok(StandaloneMessagesMetrics {
|
||||
global: GlobalMetrics::new()?,
|
||||
source_storage_proof_overhead: StorageProofOverheadMetric::new(
|
||||
source_client.clone(),
|
||||
format!("{}_storage_proof_overhead", P::SourceChain::NAME.to_lowercase()),
|
||||
format!("{} storage proof overhead", P::SourceChain::NAME),
|
||||
)?,
|
||||
target_storage_proof_overhead: StorageProofOverheadMetric::new(
|
||||
target_client.clone(),
|
||||
format!("{}_storage_proof_overhead", P::TargetChain::NAME.to_lowercase()),
|
||||
format!("{} storage proof overhead", P::TargetChain::NAME),
|
||||
)?,
|
||||
source_to_base_conversion_rate: P::SourceChain::TOKEN_ID
|
||||
.map(|source_chain_token_id| {
|
||||
crate::helpers::token_price_metric(source_chain_token_id).map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_to_base_conversion_rate: P::TargetChain::TOKEN_ID
|
||||
.map(|target_chain_token_id| {
|
||||
crate::helpers::token_price_metric(target_chain_token_id).map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
source_to_target_conversion_rate: P::SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME
|
||||
.map(bp_runtime::storage_parameter_key)
|
||||
.map(|key| {
|
||||
FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
target_client,
|
||||
key,
|
||||
Some(FixedU128::one()),
|
||||
format!(
|
||||
"{}_{}_to_{}_conversion_rate",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME
|
||||
),
|
||||
format!(
|
||||
"{} to {} tokens conversion rate (used by {})",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
P::TargetChain::NAME
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_to_source_conversion_rate: P::TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME
|
||||
.map(bp_runtime::storage_parameter_key)
|
||||
.map(|key| {
|
||||
FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new(
|
||||
source_client,
|
||||
key,
|
||||
Some(FixedU128::one()),
|
||||
format!(
|
||||
"{}_{}_to_{}_conversion_rate",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME
|
||||
),
|
||||
format!(
|
||||
"{} to {} tokens conversion rate (used by {})",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
P::SourceChain::NAME
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[async_std::test]
|
||||
async fn target_to_source_conversion_rate_works() {
|
||||
assert_eq!(
|
||||
StandaloneMessagesMetrics::<relay_rococo_client::Rococo, relay_wococo_client::Wococo>::compute_target_to_source_conversion_rate(Some(183.15), Some(12.32)),
|
||||
Some(12.32 / 183.15),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,12 @@
|
||||
//! <BridgedName> chain.
|
||||
|
||||
use crate::{
|
||||
messages_lane::SubstrateMessageLane, messages_target::SubstrateMessagesReceivingProof,
|
||||
messages_lane::{
|
||||
MessageLaneAdapter, ReceiveMessagesDeliveryProofCallBuilder, SubstrateMessageLane,
|
||||
},
|
||||
messages_target::SubstrateMessagesDeliveryProof,
|
||||
on_demand_headers::OnDemandHeadersRelay,
|
||||
TransactionParams,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
@@ -39,15 +43,13 @@ use messages_relay::{
|
||||
};
|
||||
use num_traits::{Bounded, Zero};
|
||||
use relay_substrate_client::{
|
||||
BalanceOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf, HeaderOf,
|
||||
IndexOf,
|
||||
};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId};
|
||||
use sp_core::Bytes;
|
||||
use sp_runtime::{
|
||||
traits::{AtLeast32BitUnsigned, Header as HeaderT},
|
||||
DeserializeOwned,
|
||||
AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithMessages, Client,
|
||||
Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, TransactionEra, TransactionSignScheme,
|
||||
UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_runtime::{traits::Header as HeaderT, DeserializeOwned};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
/// Intermediate message proof returned by the source Substrate node. Includes everything
|
||||
@@ -58,8 +60,8 @@ pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<Hash
|
||||
/// Substrate client as Substrate messages source.
|
||||
pub struct SubstrateMessagesSource<P: SubstrateMessageLane> {
|
||||
client: Client<P::SourceChain>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::SourceTransactionSignScheme>>,
|
||||
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
|
||||
}
|
||||
|
||||
@@ -67,11 +69,16 @@ impl<P: SubstrateMessageLane> SubstrateMessagesSource<P> {
|
||||
/// Create new Substrate headers source.
|
||||
pub fn new(
|
||||
client: Client<P::SourceChain>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::SourceTransactionSignScheme>>,
|
||||
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
|
||||
) -> Self {
|
||||
SubstrateMessagesSource { client, lane, lane_id, target_to_source_headers_relay }
|
||||
SubstrateMessagesSource {
|
||||
client,
|
||||
lane_id,
|
||||
transaction_params,
|
||||
target_to_source_headers_relay,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,8 +86,8 @@ impl<P: SubstrateMessageLane> Clone for SubstrateMessagesSource<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
client: self.client.clone(),
|
||||
lane: self.lane.clone(),
|
||||
lane_id: self.lane_id,
|
||||
transaction_params: self.transaction_params.clone(),
|
||||
target_to_source_headers_relay: self.target_to_source_headers_relay.clone(),
|
||||
}
|
||||
}
|
||||
@@ -96,53 +103,33 @@ impl<P: SubstrateMessageLane> RelayClient for SubstrateMessagesSource<P> {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<P> SourceClient<P::MessageLane> for SubstrateMessagesSource<P>
|
||||
impl<P: SubstrateMessageLane> SourceClient<MessageLaneAdapter<P>> for SubstrateMessagesSource<P>
|
||||
where
|
||||
P: SubstrateMessageLane,
|
||||
P::SourceChain: Chain<
|
||||
Hash = <P::MessageLane as MessageLane>::SourceHeaderHash,
|
||||
BlockNumber = <P::MessageLane as MessageLane>::SourceHeaderNumber,
|
||||
Balance = <P::MessageLane as MessageLane>::SourceChainBalance,
|
||||
>,
|
||||
BalanceOf<P::SourceChain>: Decode + Bounded,
|
||||
IndexOf<P::SourceChain>: DeserializeOwned,
|
||||
HashOf<P::SourceChain>: Copy,
|
||||
BlockNumberOf<P::SourceChain>: BlockNumberBase + Copy,
|
||||
HeaderOf<P::SourceChain>: DeserializeOwned,
|
||||
P::TargetChain: Chain<
|
||||
Hash = <P::MessageLane as MessageLane>::TargetHeaderHash,
|
||||
BlockNumber = <P::MessageLane as MessageLane>::TargetHeaderNumber,
|
||||
>,
|
||||
|
||||
P::MessageLane: MessageLane<
|
||||
MessagesProof = SubstrateMessagesProof<P::SourceChain>,
|
||||
MessagesReceivingProof = SubstrateMessagesReceivingProof<P::TargetChain>,
|
||||
>,
|
||||
<P::MessageLane as MessageLane>::TargetHeaderNumber: Decode,
|
||||
<P::MessageLane as MessageLane>::TargetHeaderHash: Decode,
|
||||
<P::MessageLane as MessageLane>::SourceChainBalance: AtLeast32BitUnsigned,
|
||||
AccountIdOf<P::SourceChain>:
|
||||
From<<AccountKeyPairOf<P::SourceTransactionSignScheme> as Pair>::Public>,
|
||||
P::SourceTransactionSignScheme: TransactionSignScheme<Chain = P::SourceChain>,
|
||||
{
|
||||
async fn state(&self) -> Result<SourceClientState<P::MessageLane>, SubstrateError> {
|
||||
async fn state(&self) -> Result<SourceClientState<MessageLaneAdapter<P>>, SubstrateError> {
|
||||
// we can't continue to deliver confirmations if source node is out of sync, because
|
||||
// it may have already received confirmations that we're going to deliver
|
||||
self.client.ensure_synced().await?;
|
||||
|
||||
read_client_state::<
|
||||
_,
|
||||
<P::MessageLane as MessageLane>::TargetHeaderHash,
|
||||
<P::MessageLane as MessageLane>::TargetHeaderNumber,
|
||||
>(&self.client, P::BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE)
|
||||
<MessageLaneAdapter<P> as MessageLane>::TargetHeaderHash,
|
||||
<MessageLaneAdapter<P> as MessageLane>::TargetHeaderNumber,
|
||||
>(&self.client, P::TargetChain::BEST_FINALIZED_HEADER_ID_METHOD)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn latest_generated_nonce(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P::MessageLane>,
|
||||
) -> Result<(SourceHeaderIdOf<P::MessageLane>, MessageNonce), SubstrateError> {
|
||||
id: SourceHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
) -> Result<(SourceHeaderIdOf<MessageLaneAdapter<P>>, MessageNonce), SubstrateError> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
P::OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD.into(),
|
||||
P::TargetChain::TO_CHAIN_LATEST_GENERATED_NONCE_METHOD.into(),
|
||||
Bytes(self.lane_id.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
@@ -154,12 +141,12 @@ where
|
||||
|
||||
async fn latest_confirmed_received_nonce(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P::MessageLane>,
|
||||
) -> Result<(SourceHeaderIdOf<P::MessageLane>, MessageNonce), SubstrateError> {
|
||||
id: SourceHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
) -> Result<(SourceHeaderIdOf<MessageLaneAdapter<P>>, MessageNonce), SubstrateError> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
P::OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD.into(),
|
||||
P::TargetChain::TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD.into(),
|
||||
Bytes(self.lane_id.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
@@ -171,16 +158,16 @@ where
|
||||
|
||||
async fn generated_message_details(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P::MessageLane>,
|
||||
id: SourceHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
) -> Result<
|
||||
MessageDetailsMap<<P::MessageLane as MessageLane>::SourceChainBalance>,
|
||||
MessageDetailsMap<<MessageLaneAdapter<P> as MessageLane>::SourceChainBalance>,
|
||||
SubstrateError,
|
||||
> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
P::OUTBOUND_LANE_MESSAGE_DETAILS_METHOD.into(),
|
||||
P::TargetChain::TO_CHAIN_MESSAGE_DETAILS_METHOD.into(),
|
||||
Bytes((self.lane_id, nonces.start(), nonces.end()).encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
@@ -195,14 +182,14 @@ where
|
||||
|
||||
async fn prove_messages(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P::MessageLane>,
|
||||
id: SourceHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
proof_parameters: MessageProofParameters,
|
||||
) -> Result<
|
||||
(
|
||||
SourceHeaderIdOf<P::MessageLane>,
|
||||
SourceHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
RangeInclusive<MessageNonce>,
|
||||
<P::MessageLane as MessageLane>::MessagesProof,
|
||||
<MessageLaneAdapter<P> as MessageLane>::MessagesProof,
|
||||
),
|
||||
SubstrateError,
|
||||
> {
|
||||
@@ -211,7 +198,7 @@ where
|
||||
let mut message_nonce = *nonces.start();
|
||||
while message_nonce <= *nonces.end() {
|
||||
let message_key = pallet_bridge_messages::storage_keys::message_key(
|
||||
P::MESSAGE_PALLET_NAME_AT_SOURCE,
|
||||
P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
|
||||
&self.lane_id,
|
||||
message_nonce,
|
||||
);
|
||||
@@ -220,7 +207,7 @@ where
|
||||
}
|
||||
if proof_parameters.outbound_state_proof_required {
|
||||
storage_keys.push(pallet_bridge_messages::storage_keys::outbound_lane_data_key(
|
||||
P::MESSAGE_PALLET_NAME_AT_SOURCE,
|
||||
P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
|
||||
&self.lane_id,
|
||||
));
|
||||
}
|
||||
@@ -238,19 +225,22 @@ where
|
||||
|
||||
async fn submit_messages_receiving_proof(
|
||||
&self,
|
||||
generated_at_block: TargetHeaderIdOf<P::MessageLane>,
|
||||
proof: <P::MessageLane as MessageLane>::MessagesReceivingProof,
|
||||
_generated_at_block: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
proof: <MessageLaneAdapter<P> as MessageLane>::MessagesReceivingProof,
|
||||
) -> Result<(), SubstrateError> {
|
||||
let lane = self.lane.clone();
|
||||
let genesis_hash = *self.client.genesis_hash();
|
||||
let transaction_params = self.transaction_params.clone();
|
||||
self.client
|
||||
.submit_signed_extrinsic(
|
||||
self.lane.source_transactions_author(),
|
||||
self.transaction_params.signer.public().into(),
|
||||
move |best_block_id, transaction_nonce| {
|
||||
lane.make_messages_receiving_proof_transaction(
|
||||
make_messages_delivery_proof_transaction::<P>(
|
||||
&genesis_hash,
|
||||
&transaction_params,
|
||||
best_block_id,
|
||||
transaction_nonce,
|
||||
generated_at_block,
|
||||
proof,
|
||||
true,
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -258,7 +248,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<P::MessageLane>) {
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<MessageLaneAdapter<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).await;
|
||||
}
|
||||
@@ -266,13 +256,15 @@ where
|
||||
|
||||
async fn estimate_confirmation_transaction(
|
||||
&self,
|
||||
) -> <P::MessageLane as MessageLane>::SourceChainBalance {
|
||||
) -> <MessageLaneAdapter<P> as MessageLane>::SourceChainBalance {
|
||||
self.client
|
||||
.estimate_extrinsic_fee(self.lane.make_messages_receiving_proof_transaction(
|
||||
.estimate_extrinsic_fee(make_messages_delivery_proof_transaction::<P>(
|
||||
self.client.genesis_hash(),
|
||||
&self.transaction_params,
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Zero::zero(),
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
prepare_dummy_messages_delivery_proof::<P::SourceChain, P::TargetChain>(),
|
||||
false,
|
||||
))
|
||||
.await
|
||||
.map(|fee| fee.inclusion_fee())
|
||||
@@ -280,12 +272,39 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Make messages delivery proof transaction from given proof.
|
||||
fn make_messages_delivery_proof_transaction<P: SubstrateMessageLane>(
|
||||
source_genesis_hash: &HashOf<P::SourceChain>,
|
||||
source_transaction_params: &TransactionParams<AccountKeyPairOf<P::SourceTransactionSignScheme>>,
|
||||
source_best_block_id: HeaderIdOf<P::SourceChain>,
|
||||
transaction_nonce: IndexOf<P::SourceChain>,
|
||||
proof: SubstrateMessagesDeliveryProof<P::TargetChain>,
|
||||
trace_call: bool,
|
||||
) -> Bytes
|
||||
where
|
||||
P::SourceTransactionSignScheme: TransactionSignScheme<Chain = P::SourceChain>,
|
||||
{
|
||||
let call =
|
||||
P::ReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call(
|
||||
proof, trace_call,
|
||||
);
|
||||
Bytes(
|
||||
P::SourceTransactionSignScheme::sign_transaction(
|
||||
*source_genesis_hash,
|
||||
&source_transaction_params.signer,
|
||||
TransactionEra::new(source_best_block_id, source_transaction_params.mortality),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction.
|
||||
///
|
||||
/// We don't care about proof actually being the valid proof, because its validity doesn't
|
||||
/// affect the call weight - we only care about its size.
|
||||
fn prepare_dummy_messages_delivery_proof<SC: Chain, TC: Chain>(
|
||||
) -> SubstrateMessagesReceivingProof<TC> {
|
||||
) -> SubstrateMessagesDeliveryProof<TC> {
|
||||
let single_message_confirmation_size = bp_messages::InboundLaneData::<()>::encoded_size_hint(
|
||||
SC::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE,
|
||||
1,
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
//! <BridgedName> chain.
|
||||
|
||||
use crate::{
|
||||
messages_lane::{StandaloneMessagesMetrics, SubstrateMessageLane},
|
||||
messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane},
|
||||
messages_metrics::StandaloneMessagesMetrics,
|
||||
messages_source::{read_client_state, SubstrateMessagesProof},
|
||||
on_demand_headers::OnDemandHeadersRelay,
|
||||
TransactionParams,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState};
|
||||
|
||||
use bridge_runtime_common::messages::{
|
||||
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||
};
|
||||
@@ -38,23 +39,25 @@ use messages_relay::{
|
||||
};
|
||||
use num_traits::{Bounded, Zero};
|
||||
use relay_substrate_client::{
|
||||
BalanceOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, HeaderOf, IndexOf,
|
||||
WeightToFeeOf,
|
||||
AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithMessages, Client,
|
||||
Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, TransactionEra, TransactionSignScheme,
|
||||
UnsignedTransaction, WeightToFeeOf,
|
||||
};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId};
|
||||
use sp_core::Bytes;
|
||||
use sp_runtime::{traits::Saturating, DeserializeOwned, FixedPointNumber, FixedU128};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
|
||||
use std::{convert::TryFrom, ops::RangeInclusive};
|
||||
|
||||
/// Message receiving proof returned by the target Substrate node.
|
||||
pub type SubstrateMessagesReceivingProof<C> =
|
||||
pub type SubstrateMessagesDeliveryProof<C> =
|
||||
(UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof<HashOf<C>>);
|
||||
|
||||
/// Substrate client as Substrate messages target.
|
||||
pub struct SubstrateMessagesTarget<P: SubstrateMessageLane> {
|
||||
client: Client<P::TargetChain>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetTransactionSignScheme>>,
|
||||
metric_values: StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>,
|
||||
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
|
||||
}
|
||||
@@ -63,15 +66,17 @@ impl<P: SubstrateMessageLane> SubstrateMessagesTarget<P> {
|
||||
/// Create new Substrate headers target.
|
||||
pub fn new(
|
||||
client: Client<P::TargetChain>,
|
||||
lane: P,
|
||||
lane_id: LaneId,
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetTransactionSignScheme>>,
|
||||
metric_values: StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>,
|
||||
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
|
||||
) -> Self {
|
||||
SubstrateMessagesTarget {
|
||||
client,
|
||||
lane,
|
||||
lane_id,
|
||||
relayer_id_at_source,
|
||||
transaction_params,
|
||||
metric_values,
|
||||
source_to_target_headers_relay,
|
||||
}
|
||||
@@ -82,8 +87,9 @@ impl<P: SubstrateMessageLane> Clone for SubstrateMessagesTarget<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
client: self.client.clone(),
|
||||
lane: self.lane.clone(),
|
||||
lane_id: self.lane_id,
|
||||
relayer_id_at_source: self.relayer_id_at_source.clone(),
|
||||
transaction_params: self.transaction_params.clone(),
|
||||
metric_values: self.metric_values.clone(),
|
||||
source_to_target_headers_relay: self.source_to_target_headers_relay.clone(),
|
||||
}
|
||||
@@ -100,52 +106,34 @@ impl<P: SubstrateMessageLane> RelayClient for SubstrateMessagesTarget<P> {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<P> TargetClient<P::MessageLane> for SubstrateMessagesTarget<P>
|
||||
impl<P: SubstrateMessageLane> TargetClient<MessageLaneAdapter<P>> for SubstrateMessagesTarget<P>
|
||||
where
|
||||
P: SubstrateMessageLane,
|
||||
P::SourceChain: Chain<
|
||||
Hash = <P::MessageLane as MessageLane>::SourceHeaderHash,
|
||||
BlockNumber = <P::MessageLane as MessageLane>::SourceHeaderNumber,
|
||||
Balance = <P::MessageLane as MessageLane>::SourceChainBalance,
|
||||
>,
|
||||
BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>> + Bounded,
|
||||
P::TargetChain: Chain<
|
||||
Hash = <P::MessageLane as MessageLane>::TargetHeaderHash,
|
||||
BlockNumber = <P::MessageLane as MessageLane>::TargetHeaderNumber,
|
||||
>,
|
||||
IndexOf<P::TargetChain>: DeserializeOwned,
|
||||
HashOf<P::TargetChain>: Copy,
|
||||
BlockNumberOf<P::TargetChain>: Copy,
|
||||
HeaderOf<P::TargetChain>: DeserializeOwned,
|
||||
BlockNumberOf<P::TargetChain>: BlockNumberBase,
|
||||
P::MessageLane: MessageLane<
|
||||
MessagesProof = SubstrateMessagesProof<P::SourceChain>,
|
||||
MessagesReceivingProof = SubstrateMessagesReceivingProof<P::TargetChain>,
|
||||
>,
|
||||
<P::MessageLane as MessageLane>::SourceHeaderNumber: Decode,
|
||||
<P::MessageLane as MessageLane>::SourceHeaderHash: Decode,
|
||||
AccountIdOf<P::TargetChain>:
|
||||
From<<AccountKeyPairOf<P::TargetTransactionSignScheme> as Pair>::Public>,
|
||||
P::TargetTransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
|
||||
BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
|
||||
{
|
||||
async fn state(&self) -> Result<TargetClientState<P::MessageLane>, SubstrateError> {
|
||||
async fn state(&self) -> Result<TargetClientState<MessageLaneAdapter<P>>, SubstrateError> {
|
||||
// we can't continue to deliver messages if target node is out of sync, because
|
||||
// it may have already received (some of) messages that we're going to deliver
|
||||
self.client.ensure_synced().await?;
|
||||
|
||||
read_client_state::<
|
||||
_,
|
||||
<P::MessageLane as MessageLane>::SourceHeaderHash,
|
||||
<P::MessageLane as MessageLane>::SourceHeaderNumber,
|
||||
>(&self.client, P::BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET)
|
||||
<MessageLaneAdapter<P> as MessageLane>::SourceHeaderHash,
|
||||
<MessageLaneAdapter<P> as MessageLane>::SourceHeaderNumber,
|
||||
>(&self.client, P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn latest_received_nonce(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P::MessageLane>,
|
||||
) -> Result<(TargetHeaderIdOf<P::MessageLane>, MessageNonce), SubstrateError> {
|
||||
id: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
) -> Result<(TargetHeaderIdOf<MessageLaneAdapter<P>>, MessageNonce), SubstrateError> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
P::INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD.into(),
|
||||
P::SourceChain::FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD.into(),
|
||||
Bytes(self.lane_id.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
@@ -157,12 +145,12 @@ where
|
||||
|
||||
async fn latest_confirmed_received_nonce(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P::MessageLane>,
|
||||
) -> Result<(TargetHeaderIdOf<P::MessageLane>, MessageNonce), SubstrateError> {
|
||||
id: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
) -> Result<(TargetHeaderIdOf<MessageLaneAdapter<P>>, MessageNonce), SubstrateError> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
P::INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD.into(),
|
||||
P::SourceChain::FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD.into(),
|
||||
Bytes(self.lane_id.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
@@ -174,12 +162,13 @@ where
|
||||
|
||||
async fn unrewarded_relayers_state(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P::MessageLane>,
|
||||
) -> Result<(TargetHeaderIdOf<P::MessageLane>, UnrewardedRelayersState), SubstrateError> {
|
||||
id: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
) -> Result<(TargetHeaderIdOf<MessageLaneAdapter<P>>, UnrewardedRelayersState), SubstrateError>
|
||||
{
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
P::INBOUND_LANE_UNREWARDED_RELAYERS_STATE.into(),
|
||||
P::SourceChain::FROM_CHAIN_UNREWARDED_RELAYERS_STATE.into(),
|
||||
Bytes(self.lane_id.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
@@ -192,14 +181,17 @@ where
|
||||
|
||||
async fn prove_messages_receiving(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P::MessageLane>,
|
||||
id: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
) -> Result<
|
||||
(TargetHeaderIdOf<P::MessageLane>, <P::MessageLane as MessageLane>::MessagesReceivingProof),
|
||||
(
|
||||
TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
<MessageLaneAdapter<P> as MessageLane>::MessagesReceivingProof,
|
||||
),
|
||||
SubstrateError,
|
||||
> {
|
||||
let (id, relayers_state) = self.unrewarded_relayers_state(id).await?;
|
||||
let inbound_data_key = pallet_bridge_messages::storage_keys::inbound_lane_data_key(
|
||||
P::MESSAGE_PALLET_NAME_AT_TARGET,
|
||||
P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
|
||||
&self.lane_id,
|
||||
);
|
||||
let proof = self
|
||||
@@ -218,22 +210,27 @@ where
|
||||
|
||||
async fn submit_messages_proof(
|
||||
&self,
|
||||
generated_at_header: SourceHeaderIdOf<P::MessageLane>,
|
||||
_generated_at_header: SourceHeaderIdOf<MessageLaneAdapter<P>>,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
proof: <P::MessageLane as MessageLane>::MessagesProof,
|
||||
proof: <MessageLaneAdapter<P> as MessageLane>::MessagesProof,
|
||||
) -> Result<RangeInclusive<MessageNonce>, SubstrateError> {
|
||||
let lane = self.lane.clone();
|
||||
let genesis_hash = *self.client.genesis_hash();
|
||||
let transaction_params = self.transaction_params.clone();
|
||||
let relayer_id_at_source = self.relayer_id_at_source.clone();
|
||||
let nonces_clone = nonces.clone();
|
||||
self.client
|
||||
.submit_signed_extrinsic(
|
||||
self.lane.target_transactions_author(),
|
||||
self.transaction_params.signer.public().into(),
|
||||
move |best_block_id, transaction_nonce| {
|
||||
lane.make_messages_delivery_transaction(
|
||||
make_messages_delivery_transaction::<P>(
|
||||
&genesis_hash,
|
||||
&transaction_params,
|
||||
best_block_id,
|
||||
transaction_nonce,
|
||||
generated_at_header,
|
||||
relayer_id_at_source,
|
||||
nonces_clone,
|
||||
proof,
|
||||
true,
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -241,7 +238,7 @@ where
|
||||
Ok(nonces)
|
||||
}
|
||||
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<P::MessageLane>) {
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<MessageLaneAdapter<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).await;
|
||||
}
|
||||
@@ -253,7 +250,7 @@ where
|
||||
total_prepaid_nonces: MessageNonce,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> Result<<P::MessageLane as MessageLane>::SourceChainBalance, SubstrateError> {
|
||||
) -> Result<<MessageLaneAdapter<P> as MessageLane>::SourceChainBalance, SubstrateError> {
|
||||
let conversion_rate =
|
||||
self.metric_values.target_to_source_conversion_rate().await.ok_or_else(|| {
|
||||
SubstrateError::Custom(format!(
|
||||
@@ -264,16 +261,19 @@ where
|
||||
})?;
|
||||
|
||||
// Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight.
|
||||
let delivery_tx = self.lane.make_messages_delivery_transaction(
|
||||
let delivery_tx = make_messages_delivery_transaction::<P>(
|
||||
self.client.genesis_hash(),
|
||||
&self.transaction_params,
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Zero::zero(),
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Default::default(),
|
||||
nonces.clone(),
|
||||
prepare_dummy_messages_proof::<P::SourceChain>(
|
||||
nonces.clone(),
|
||||
total_dispatch_weight,
|
||||
total_size,
|
||||
),
|
||||
false,
|
||||
);
|
||||
let delivery_tx_fee = self.client.estimate_extrinsic_fee(delivery_tx).await?;
|
||||
let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee();
|
||||
@@ -300,20 +300,23 @@ where
|
||||
let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE);
|
||||
let larger_delivery_tx_fee = self
|
||||
.client
|
||||
.estimate_extrinsic_fee(self.lane.make_messages_delivery_transaction(
|
||||
.estimate_extrinsic_fee(make_messages_delivery_transaction::<P>(
|
||||
self.client.genesis_hash(),
|
||||
&self.transaction_params,
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Zero::zero(),
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Default::default(),
|
||||
nonces.clone(),
|
||||
prepare_dummy_messages_proof::<P::SourceChain>(
|
||||
nonces.clone(),
|
||||
larger_dispatch_weight,
|
||||
total_size,
|
||||
),
|
||||
false,
|
||||
))
|
||||
.await?;
|
||||
|
||||
compute_prepaid_messages_refund::<P>(
|
||||
compute_prepaid_messages_refund::<P::TargetChain>(
|
||||
total_prepaid_nonces,
|
||||
compute_fee_multiplier::<P::TargetChain>(
|
||||
delivery_tx_fee.adjusted_weight_fee,
|
||||
@@ -359,6 +362,41 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Make messages delivery transaction from given proof.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn make_messages_delivery_transaction<P: SubstrateMessageLane>(
|
||||
target_genesis_hash: &HashOf<P::TargetChain>,
|
||||
target_transaction_params: &TransactionParams<AccountKeyPairOf<P::TargetTransactionSignScheme>>,
|
||||
target_best_block_id: HeaderIdOf<P::TargetChain>,
|
||||
transaction_nonce: IndexOf<P::TargetChain>,
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
proof: SubstrateMessagesProof<P::SourceChain>,
|
||||
trace_call: bool,
|
||||
) -> Bytes
|
||||
where
|
||||
P::TargetTransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
|
||||
{
|
||||
let messages_count = nonces.end() - nonces.start() + 1;
|
||||
let dispatch_weight = proof.0;
|
||||
let call = P::ReceiveMessagesProofCallBuilder::build_receive_messages_proof_call(
|
||||
relayer_id_at_source,
|
||||
proof,
|
||||
messages_count as _,
|
||||
dispatch_weight,
|
||||
trace_call,
|
||||
);
|
||||
Bytes(
|
||||
P::TargetTransactionSignScheme::sign_transaction(
|
||||
*target_genesis_hash,
|
||||
&target_transaction_params.signer,
|
||||
TransactionEra::new(target_best_block_id, target_transaction_params.mortality),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Prepare 'dummy' messages proof that will compose the delivery transaction.
|
||||
///
|
||||
/// We don't care about proof actually being the valid proof, because its validity doesn't
|
||||
@@ -425,80 +463,20 @@ fn compute_fee_multiplier<C: Chain>(
|
||||
|
||||
/// Compute fee that will be refunded to the relayer because dispatch of `total_prepaid_nonces`
|
||||
/// messages has been paid at the source chain.
|
||||
fn compute_prepaid_messages_refund<P: SubstrateMessageLane>(
|
||||
fn compute_prepaid_messages_refund<C: ChainWithMessages>(
|
||||
total_prepaid_nonces: MessageNonce,
|
||||
fee_multiplier: FixedU128,
|
||||
) -> BalanceOf<P::TargetChain> {
|
||||
fee_multiplier.saturating_mul_int(WeightToFeeOf::<P::TargetChain>::calc(
|
||||
&P::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN.saturating_mul(total_prepaid_nonces),
|
||||
) -> BalanceOf<C> {
|
||||
fee_multiplier.saturating_mul_int(WeightToFeeOf::<C>::calc(
|
||||
&C::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN.saturating_mul(total_prepaid_nonces),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams};
|
||||
use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TestSubstrateMessageLane;
|
||||
|
||||
impl SubstrateMessageLane for TestSubstrateMessageLane {
|
||||
type MessageLane = crate::messages_lane::SubstrateMessageLaneToSubstrate<
|
||||
Rococo,
|
||||
RococoSigningParams,
|
||||
Wococo,
|
||||
WococoSigningParams,
|
||||
>;
|
||||
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = "";
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = "";
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = "";
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = "";
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = "";
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = "";
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = "";
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = "";
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = "";
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = "";
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = 100_000;
|
||||
|
||||
type SourceChain = Rococo;
|
||||
type TargetChain = Wococo;
|
||||
|
||||
fn source_transactions_author(&self) -> bp_rococo::AccountId {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn make_messages_receiving_proof_transaction(
|
||||
&self,
|
||||
_best_block_id: SourceHeaderIdOf<Self::MessageLane>,
|
||||
_transaction_nonce: IndexOf<Rococo>,
|
||||
_generated_at_block: TargetHeaderIdOf<Self::MessageLane>,
|
||||
_proof: <Self::MessageLane as MessageLane>::MessagesReceivingProof,
|
||||
) -> Bytes {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn target_transactions_author(&self) -> bp_wococo::AccountId {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn make_messages_delivery_transaction(
|
||||
&self,
|
||||
_best_block_id: TargetHeaderIdOf<Self::MessageLane>,
|
||||
_transaction_nonce: IndexOf<Wococo>,
|
||||
_generated_at_header: SourceHeaderIdOf<Self::MessageLane>,
|
||||
_nonces: RangeInclusive<MessageNonce>,
|
||||
_proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
use relay_rococo_client::Rococo;
|
||||
use relay_wococo_client::Wococo;
|
||||
|
||||
#[test]
|
||||
fn prepare_dummy_messages_proof_works() {
|
||||
@@ -556,11 +534,10 @@ mod tests {
|
||||
#[test]
|
||||
fn compute_prepaid_messages_refund_returns_sane_results() {
|
||||
assert!(
|
||||
compute_prepaid_messages_refund::<TestSubstrateMessageLane>(
|
||||
compute_prepaid_messages_refund::<Wococo>(
|
||||
10,
|
||||
FixedU128::saturating_from_rational(110, 100),
|
||||
) > (10 * TestSubstrateMessageLane::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN)
|
||||
.into()
|
||||
) > (10 * Wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN).into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,10 @@ use relay_utils::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
finality_pipeline::{
|
||||
SubstrateFinalitySyncPipeline, TransactionParams, RECENT_FINALITY_PROOFS_LIMIT,
|
||||
},
|
||||
finality_pipeline::{SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT},
|
||||
finality_source::{RequiredHeaderNumberRef, SubstrateFinalitySource},
|
||||
finality_target::SubstrateFinalityTarget,
|
||||
STALL_TIMEOUT,
|
||||
TransactionParams, STALL_TIMEOUT,
|
||||
};
|
||||
|
||||
/// On-demand Substrate <-> Substrate headers relay.
|
||||
@@ -116,7 +114,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
|
||||
P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
|
||||
{
|
||||
let relay_task_name = on_demand_headers_relay_name::<P::SourceChain, P::TargetChain>();
|
||||
let target_transactions_mortality = target_transaction_params.transactions_mortality;
|
||||
let target_transactions_mortality = target_transaction_params.mortality;
|
||||
let mut finality_source = SubstrateFinalitySource::<P>::new(
|
||||
source_client.clone(),
|
||||
Some(required_header_number.clone()),
|
||||
|
||||
Reference in New Issue
Block a user