mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 07:31:02 +00:00
Millau -> Rialto messages relay (#399)
* Millau messages -> Rialto relay * prepare for custom race strategy of delivery race * custom strategy for delivery race * update TODOs * add reference to issue 457 * impl reconnect * clippy * fix check in test * fmt * removed obsolete TODO * fixed another TODOs * fmt * use MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE const from primitives * Update relays/messages-relay/src/message_lane_loop.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * added SubstrateMessagesProof typedef * fix test * removed comment * additional_proof_required -> ProofParameters * typo * multiline literal * clippy * fix typo * and_then -> await * update_source_latest_confirmed_nonce * Update relays/messages-relay/src/message_race_delivery.rs Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
804ef55146
commit
d4fc7bebdc
@@ -50,6 +50,22 @@ pub enum Command {
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
},
|
||||
/// Serve given lane of Millau -> Rialto messages.
|
||||
MillauMessagesToRialto {
|
||||
#[structopt(flatten)]
|
||||
millau: MillauConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau_sign: MillauSigningParams,
|
||||
#[structopt(flatten)]
|
||||
rialto: RialtoConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
rialto_sign: RialtoSigningParams,
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
/// Hex-encoded id of lane that should be served by relay.
|
||||
#[structopt(long)]
|
||||
lane: HexLaneId,
|
||||
},
|
||||
/// Submit message to given Rialto -> Millau lane.
|
||||
SubmitMillauToRialtoMessage {
|
||||
#[structopt(flatten)]
|
||||
|
||||
@@ -36,7 +36,10 @@ mod cli;
|
||||
mod headers_maintain;
|
||||
mod headers_pipeline;
|
||||
mod headers_target;
|
||||
mod messages_source;
|
||||
mod messages_target;
|
||||
mod millau_headers_to_rialto;
|
||||
mod millau_messages_to_rialto;
|
||||
mod rialto_headers_to_millau;
|
||||
|
||||
fn main() {
|
||||
@@ -94,8 +97,47 @@ async fn run_command(command: cli::Command) -> Result<(), String> {
|
||||
millau_sign.millau_signer_password.as_deref(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to parse millau-signer: {:?}", e))?;
|
||||
|
||||
rialto_headers_to_millau::run(rialto_client, millau_client, millau_sign, prometheus_params.into()).await;
|
||||
}
|
||||
cli::Command::MillauMessagesToRialto {
|
||||
millau,
|
||||
millau_sign,
|
||||
rialto,
|
||||
rialto_sign,
|
||||
prometheus_params,
|
||||
lane,
|
||||
} => {
|
||||
let millau_client = MillauClient::new(ConnectionParams {
|
||||
host: millau.millau_host,
|
||||
port: millau.millau_port,
|
||||
})
|
||||
.await?;
|
||||
let millau_sign = MillauSigningParams::from_suri(
|
||||
&millau_sign.millau_signer,
|
||||
millau_sign.millau_signer_password.as_deref(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to parse millau-signer: {:?}", e))?;
|
||||
let rialto_client = RialtoClient::new(ConnectionParams {
|
||||
host: rialto.rialto_host,
|
||||
port: rialto.rialto_port,
|
||||
})
|
||||
.await?;
|
||||
let rialto_sign = RialtoSigningParams::from_suri(
|
||||
&rialto_sign.rialto_signer,
|
||||
rialto_sign.rialto_signer_password.as_deref(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to parse rialto-signer: {:?}", e))?;
|
||||
|
||||
millau_messages_to_rialto::run(
|
||||
millau_client,
|
||||
millau_sign,
|
||||
rialto_client,
|
||||
rialto_sign,
|
||||
lane.into(),
|
||||
prometheus_params.into(),
|
||||
);
|
||||
}
|
||||
cli::Command::SubmitMillauToRialtoMessage {
|
||||
millau,
|
||||
millau_sign,
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
// Copyright 2019-2020 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/>.
|
||||
|
||||
//! Substrate client as Substrate messages source. The chain we connect to should have
|
||||
//! runtime that implements `<BridgedChainName>HeaderApi` to allow bridging with
|
||||
//! <BridgedName> chain.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_message_lane::{LaneId, MessageNonce};
|
||||
use bp_runtime::InstanceId;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::{
|
||||
message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf},
|
||||
message_lane_loop::{ClientState, SourceClient, SourceClientState},
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf};
|
||||
use relay_utils::HeaderId;
|
||||
use sp_core::Bytes;
|
||||
use sp_runtime::{traits::Header as HeaderT, DeserializeOwned};
|
||||
use sp_trie::StorageProof;
|
||||
use std::{marker::PhantomData, ops::RangeInclusive};
|
||||
|
||||
/// Intermediate message proof returned by the source Substrate node. Includes everything
|
||||
/// required to submit to the target node: cumulative dispatch weight of bundled messages and
|
||||
/// the proof itself.
|
||||
pub type SubstrateMessagesProof<C> = (Weight, (HashOf<C>, StorageProof, LaneId, MessageNonce, MessageNonce));
|
||||
|
||||
/// Substrate client as Substrate messages source.
|
||||
pub struct SubstrateMessagesSource<C: Chain, P, M> {
|
||||
client: Client<C>,
|
||||
tx_maker: M,
|
||||
lane: LaneId,
|
||||
instance: InstanceId,
|
||||
_marker: PhantomData<P>,
|
||||
}
|
||||
|
||||
/// Substrate transactions maker.
|
||||
#[async_trait]
|
||||
pub trait SubstrateTransactionMaker<C: Chain, P: MessageLane>: Clone + Send + Sync {
|
||||
/// Signed transaction type.
|
||||
type SignedTransaction: Send + Sync + Encode;
|
||||
|
||||
/// Make messages receiving proof transaction.
|
||||
async fn make_messages_receiving_proof_transaction(
|
||||
&self,
|
||||
generated_at_block: TargetHeaderIdOf<P>,
|
||||
proof: P::MessagesReceivingProof,
|
||||
) -> Result<Self::SignedTransaction, SubstrateError>;
|
||||
}
|
||||
|
||||
impl<C: Chain, P, M> SubstrateMessagesSource<C, P, M> {
|
||||
/// Create new Substrate headers source.
|
||||
pub fn new(client: Client<C>, tx_maker: M, lane: LaneId, instance: InstanceId) -> Self {
|
||||
SubstrateMessagesSource {
|
||||
client,
|
||||
tx_maker,
|
||||
lane,
|
||||
instance,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Chain, P, M: Clone> Clone for SubstrateMessagesSource<C, P, M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
client: self.client.clone(),
|
||||
tx_maker: self.tx_maker.clone(),
|
||||
lane: self.lane,
|
||||
instance: self.instance,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C, P, M> SourceClient<P> for SubstrateMessagesSource<C, P, M>
|
||||
where
|
||||
C: Chain,
|
||||
C::Header: DeserializeOwned,
|
||||
C::Index: DeserializeOwned,
|
||||
<C::Header as HeaderT>::Number: Into<u64>,
|
||||
P: MessageLane<
|
||||
MessageNonce = MessageNonce,
|
||||
MessagesProof = SubstrateMessagesProof<C>,
|
||||
SourceHeaderNumber = <C::Header as HeaderT>::Number,
|
||||
SourceHeaderHash = <C::Header as HeaderT>::Hash,
|
||||
>,
|
||||
P::TargetHeaderNumber: Decode,
|
||||
P::TargetHeaderHash: Decode,
|
||||
M: SubstrateTransactionMaker<C, P>,
|
||||
{
|
||||
type Error = SubstrateError;
|
||||
|
||||
async fn reconnect(mut self) -> Result<Self, Self::Error> {
|
||||
let new_client = self.client.clone().reconnect().await?;
|
||||
self.client = new_client;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
async fn state(&self) -> Result<SourceClientState<P>, Self::Error> {
|
||||
read_client_state::<_, P::TargetHeaderHash, P::TargetHeaderNumber>(&self.client, P::TARGET_NAME).await
|
||||
}
|
||||
|
||||
async fn latest_generated_nonce(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P>,
|
||||
) -> Result<(SourceHeaderIdOf<P>, P::MessageNonce), Self::Error> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
// TODO: https://github.com/paritytech/parity-bridges-common/issues/457
|
||||
"OutboundLaneApi_latest_generated_nonce".into(),
|
||||
Bytes(self.lane.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
.await?;
|
||||
let latest_generated_nonce: P::MessageNonce =
|
||||
Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?;
|
||||
Ok((id, latest_generated_nonce))
|
||||
}
|
||||
|
||||
async fn latest_confirmed_received_nonce(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P>,
|
||||
) -> Result<(SourceHeaderIdOf<P>, P::MessageNonce), Self::Error> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
// TODO: https://github.com/paritytech/parity-bridges-common/issues/457
|
||||
"OutboundLaneApi_latest_received_nonce".into(),
|
||||
Bytes(self.lane.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
.await?;
|
||||
let latest_received_nonce: P::MessageNonce =
|
||||
Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?;
|
||||
Ok((id, latest_received_nonce))
|
||||
}
|
||||
|
||||
async fn prove_messages(
|
||||
&self,
|
||||
id: SourceHeaderIdOf<P>,
|
||||
nonces: RangeInclusive<P::MessageNonce>,
|
||||
include_outbound_lane_state: bool,
|
||||
) -> Result<(SourceHeaderIdOf<P>, RangeInclusive<P::MessageNonce>, P::MessagesProof), Self::Error> {
|
||||
let (weight, proof) = self
|
||||
.client
|
||||
.prove_messages(
|
||||
self.instance,
|
||||
self.lane,
|
||||
nonces.clone(),
|
||||
include_outbound_lane_state,
|
||||
id.1,
|
||||
)
|
||||
.await?;
|
||||
let proof = (id.1, proof, self.lane, *nonces.start(), *nonces.end());
|
||||
Ok((id, nonces, (weight, proof)))
|
||||
}
|
||||
|
||||
async fn submit_messages_receiving_proof(
|
||||
&self,
|
||||
generated_at_block: TargetHeaderIdOf<P>,
|
||||
proof: P::MessagesReceivingProof,
|
||||
) -> Result<(), Self::Error> {
|
||||
let tx = self
|
||||
.tx_maker
|
||||
.make_messages_receiving_proof_transaction(generated_at_block, proof)
|
||||
.await?;
|
||||
self.client.submit_extrinsic(Bytes(tx.encode())).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_client_state<SelfChain, BridgedHeaderHash, BridgedHeaderNumber>(
|
||||
self_client: &Client<SelfChain>,
|
||||
bridged_chain_name: &str,
|
||||
) -> Result<ClientState<HeaderIdOf<SelfChain>, HeaderId<BridgedHeaderHash, BridgedHeaderNumber>>, SubstrateError>
|
||||
where
|
||||
SelfChain: Chain,
|
||||
SelfChain::Header: DeserializeOwned,
|
||||
SelfChain::Index: DeserializeOwned,
|
||||
BridgedHeaderHash: Decode,
|
||||
BridgedHeaderNumber: Decode,
|
||||
{
|
||||
// let's read our state first: we need best finalized header hash on **this** chain
|
||||
let self_best_finalized_header_hash = self_client.best_finalized_header_hash().await?;
|
||||
let self_best_finalized_header = self_client.header_by_hash(self_best_finalized_header_hash).await?;
|
||||
let self_best_finalized_id = HeaderId(*self_best_finalized_header.number(), self_best_finalized_header_hash);
|
||||
|
||||
// now let's read id of best finalized peer header at our best finalized block
|
||||
let best_finalized_peer_on_self_method = format!("{}HeaderApi_finalized_block", bridged_chain_name);
|
||||
let encoded_best_finalized_peer_on_self = self_client
|
||||
.state_call(
|
||||
best_finalized_peer_on_self_method,
|
||||
Bytes(Vec::new()),
|
||||
Some(self_best_finalized_header_hash),
|
||||
)
|
||||
.await?;
|
||||
let decoded_best_finalized_peer_on_self: (BridgedHeaderNumber, BridgedHeaderHash) =
|
||||
Decode::decode(&mut &encoded_best_finalized_peer_on_self.0[..]).map_err(SubstrateError::ResponseParseFailed)?;
|
||||
let peer_on_self_best_finalized_id = HeaderId(
|
||||
decoded_best_finalized_peer_on_self.0,
|
||||
decoded_best_finalized_peer_on_self.1,
|
||||
);
|
||||
|
||||
Ok(ClientState {
|
||||
best_self: self_best_finalized_id,
|
||||
best_peer: peer_on_self_best_finalized_id,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
// Copyright 2019-2020 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/>.
|
||||
|
||||
//! Substrate client as Substrate messages target. The chain we connect to should have
|
||||
//! runtime that implements `<BridgedChainName>HeaderApi` to allow bridging with
|
||||
//! <BridgedName> chain.
|
||||
|
||||
use crate::messages_source::read_client_state;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_message_lane::{LaneId, MessageNonce};
|
||||
use bp_runtime::InstanceId;
|
||||
use codec::{Decode, Encode};
|
||||
use messages_relay::{
|
||||
message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf},
|
||||
message_lane_loop::{TargetClient, TargetClientState},
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf};
|
||||
use sp_core::Bytes;
|
||||
use sp_runtime::{traits::Header as HeaderT, DeserializeOwned};
|
||||
use sp_trie::StorageProof;
|
||||
use std::{marker::PhantomData, ops::RangeInclusive};
|
||||
|
||||
/// Substrate client as Substrate messages target.
|
||||
pub struct SubstrateMessagesTarget<C: Chain, P, M> {
|
||||
client: Client<C>,
|
||||
tx_maker: M,
|
||||
lane: LaneId,
|
||||
instance: InstanceId,
|
||||
_marker: PhantomData<P>,
|
||||
}
|
||||
|
||||
/// Substrate transactions maker.
|
||||
#[async_trait]
|
||||
pub trait SubstrateTransactionMaker<C: Chain, P: MessageLane>: Clone + Send + Sync {
|
||||
/// Signed transaction type.
|
||||
type SignedTransaction: Send + Sync + Encode;
|
||||
|
||||
/// Make messages delivery transaction.
|
||||
async fn make_messages_delivery_transaction(
|
||||
&self,
|
||||
generated_at_header: SourceHeaderIdOf<P>,
|
||||
nonces: RangeInclusive<P::MessageNonce>,
|
||||
proof: P::MessagesProof,
|
||||
) -> Result<Self::SignedTransaction, SubstrateError>;
|
||||
}
|
||||
|
||||
impl<C: Chain, P, M> SubstrateMessagesTarget<C, P, M> {
|
||||
/// Create new Substrate headers target.
|
||||
pub fn new(client: Client<C>, tx_maker: M, lane: LaneId, instance: InstanceId) -> Self {
|
||||
SubstrateMessagesTarget {
|
||||
client,
|
||||
tx_maker,
|
||||
lane,
|
||||
instance,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Chain, P, M: Clone> Clone for SubstrateMessagesTarget<C, P, M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
client: self.client.clone(),
|
||||
tx_maker: self.tx_maker.clone(),
|
||||
lane: self.lane,
|
||||
instance: self.instance,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C, P, M> TargetClient<P> for SubstrateMessagesTarget<C, P, M>
|
||||
where
|
||||
C: Chain,
|
||||
C::Header: DeserializeOwned,
|
||||
C::Index: DeserializeOwned,
|
||||
<C::Header as HeaderT>::Number: Into<u64>,
|
||||
P: MessageLane<
|
||||
MessageNonce = MessageNonce,
|
||||
MessagesReceivingProof = (HashOf<C>, StorageProof, LaneId),
|
||||
TargetHeaderNumber = <C::Header as HeaderT>::Number,
|
||||
TargetHeaderHash = <C::Header as HeaderT>::Hash,
|
||||
>,
|
||||
P::SourceHeaderNumber: Decode,
|
||||
P::SourceHeaderHash: Decode,
|
||||
M: SubstrateTransactionMaker<C, P>,
|
||||
{
|
||||
type Error = SubstrateError;
|
||||
|
||||
async fn reconnect(mut self) -> Result<Self, Self::Error> {
|
||||
let new_client = self.client.clone().reconnect().await?;
|
||||
self.client = new_client;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
async fn state(&self) -> Result<TargetClientState<P>, Self::Error> {
|
||||
read_client_state::<_, P::SourceHeaderHash, P::SourceHeaderNumber>(&self.client, P::SOURCE_NAME).await
|
||||
}
|
||||
|
||||
async fn latest_received_nonce(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P>,
|
||||
) -> Result<(TargetHeaderIdOf<P>, P::MessageNonce), Self::Error> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
// TODO: https://github.com/paritytech/parity-bridges-common/issues/457
|
||||
"InboundLaneApi_latest_received_nonce".into(),
|
||||
Bytes(self.lane.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
.await?;
|
||||
let latest_received_nonce: P::MessageNonce =
|
||||
Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?;
|
||||
Ok((id, latest_received_nonce))
|
||||
}
|
||||
|
||||
async fn latest_confirmed_received_nonce(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P>,
|
||||
) -> Result<(TargetHeaderIdOf<P>, P::MessageNonce), Self::Error> {
|
||||
let encoded_response = self
|
||||
.client
|
||||
.state_call(
|
||||
// TODO: https://github.com/paritytech/parity-bridges-common/issues/457
|
||||
"OutboundLaneApi_latest_received_nonce".into(),
|
||||
Bytes(self.lane.encode()),
|
||||
Some(id.1),
|
||||
)
|
||||
.await?;
|
||||
let latest_received_nonce: P::MessageNonce =
|
||||
Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?;
|
||||
Ok((id, latest_received_nonce))
|
||||
}
|
||||
|
||||
async fn prove_messages_receiving(
|
||||
&self,
|
||||
id: TargetHeaderIdOf<P>,
|
||||
) -> Result<(TargetHeaderIdOf<P>, P::MessagesReceivingProof), Self::Error> {
|
||||
let proof = self
|
||||
.client
|
||||
.prove_messages_delivery(self.instance, self.lane, id.1)
|
||||
.await?;
|
||||
let proof = (id.1, proof, self.lane);
|
||||
Ok((id, proof))
|
||||
}
|
||||
|
||||
async fn submit_messages_proof(
|
||||
&self,
|
||||
generated_at_header: SourceHeaderIdOf<P>,
|
||||
nonces: RangeInclusive<P::MessageNonce>,
|
||||
proof: P::MessagesProof,
|
||||
) -> Result<RangeInclusive<P::MessageNonce>, Self::Error> {
|
||||
let tx = self
|
||||
.tx_maker
|
||||
.make_messages_delivery_transaction(generated_at_header, nonces.clone(), proof)
|
||||
.await?;
|
||||
self.client.submit_extrinsic(Bytes(tx.encode())).await?;
|
||||
Ok(nonces)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright 2019-2020 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/>.
|
||||
|
||||
//! Millau-to-Rialto messages sync entrypoint.
|
||||
|
||||
use crate::messages_source::{SubstrateMessagesSource, SubstrateTransactionMaker as SubstrateSourceTransactionMaker};
|
||||
use crate::messages_target::{SubstrateMessagesTarget, SubstrateTransactionMaker as SubstrateTargetTransactionMaker};
|
||||
use crate::{MillauClient, RialtoClient};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_message_lane::{LaneId, MessageNonce};
|
||||
use bp_runtime::{MILLAU_BRIDGE_INSTANCE, RIALTO_BRIDGE_INSTANCE};
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_millau_client::{HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams};
|
||||
use relay_rialto_client::{HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_substrate_client::{BlockNumberOf, Error as SubstrateError, HashOf, TransactionSignScheme};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::Pair;
|
||||
use sp_trie::StorageProof;
|
||||
use std::{ops::RangeInclusive, time::Duration};
|
||||
|
||||
/// Millau -> Rialto messages proof:
|
||||
///
|
||||
/// - cumulative dispatch-weight of messages in the batch;
|
||||
/// - proof that we'll actually submit to the Rialto node.
|
||||
type FromMillauMessagesProof = (
|
||||
Weight,
|
||||
(HashOf<Millau>, StorageProof, LaneId, MessageNonce, MessageNonce),
|
||||
);
|
||||
/// Rialto -> Millau messages receiving proof.
|
||||
type FromRialtoMessagesReceivingProof = (HashOf<Rialto>, StorageProof, LaneId);
|
||||
|
||||
/// Millau-to-Rialto messages pipeline.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct MillauMessagesToRialto;
|
||||
|
||||
impl MessageLane for MillauMessagesToRialto {
|
||||
const SOURCE_NAME: &'static str = "Millau";
|
||||
const TARGET_NAME: &'static str = "Rialto";
|
||||
|
||||
type MessageNonce = MessageNonce;
|
||||
type MessagesProof = FromMillauMessagesProof;
|
||||
type MessagesReceivingProof = FromRialtoMessagesReceivingProof;
|
||||
|
||||
type SourceHeaderNumber = BlockNumberOf<Millau>;
|
||||
type SourceHeaderHash = HashOf<Millau>;
|
||||
|
||||
type TargetHeaderNumber = BlockNumberOf<Rialto>;
|
||||
type TargetHeaderHash = HashOf<Rialto>;
|
||||
}
|
||||
|
||||
/// Millau node as messages source.
|
||||
type MillauSourceClient = SubstrateMessagesSource<Millau, MillauMessagesToRialto, MillauTransactionMaker>;
|
||||
|
||||
/// Millau transaction maker.
|
||||
#[derive(Clone)]
|
||||
struct MillauTransactionMaker {
|
||||
client: MillauClient,
|
||||
sign: MillauSigningParams,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SubstrateSourceTransactionMaker<Millau, MillauMessagesToRialto> for MillauTransactionMaker {
|
||||
type SignedTransaction = <Millau as TransactionSignScheme>::SignedTransaction;
|
||||
|
||||
async fn make_messages_receiving_proof_transaction(
|
||||
&self,
|
||||
_generated_at_block: RialtoHeaderId,
|
||||
proof: FromRialtoMessagesReceivingProof,
|
||||
) -> Result<Self::SignedTransaction, SubstrateError> {
|
||||
let account_id = self.sign.signer.public().as_array_ref().clone().into();
|
||||
let nonce = self.client.next_account_index(account_id).await?;
|
||||
let call = millau_runtime::MessageLaneCall::receive_messages_delivery_proof(proof).into();
|
||||
let transaction = Millau::sign_transaction(&self.client, &self.sign.signer, nonce, call);
|
||||
Ok(transaction)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rialto node as messages target.
|
||||
type RialtoTargetClient = SubstrateMessagesTarget<Rialto, MillauMessagesToRialto, RialtoTransactionMaker>;
|
||||
|
||||
/// Rialto transaction maker.
|
||||
#[derive(Clone)]
|
||||
struct RialtoTransactionMaker {
|
||||
client: RialtoClient,
|
||||
relayer_id: bp_millau::AccountId,
|
||||
sign: RialtoSigningParams,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SubstrateTargetTransactionMaker<Rialto, MillauMessagesToRialto> for RialtoTransactionMaker {
|
||||
type SignedTransaction = <Rialto as TransactionSignScheme>::SignedTransaction;
|
||||
|
||||
async fn make_messages_delivery_transaction(
|
||||
&self,
|
||||
_generated_at_header: MillauHeaderId,
|
||||
_nonces: RangeInclusive<MessageNonce>,
|
||||
proof: FromMillauMessagesProof,
|
||||
) -> Result<Self::SignedTransaction, SubstrateError> {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let account_id = self.sign.signer.public().as_array_ref().clone().into();
|
||||
let nonce = self.client.next_account_index(account_id).await?;
|
||||
let call =
|
||||
rialto_runtime::MessageLaneCall::receive_messages_proof(self.relayer_id.clone(), proof, dispatch_weight)
|
||||
.into();
|
||||
let transaction = Rialto::sign_transaction(&self.client, &self.sign.signer, nonce, call);
|
||||
Ok(transaction)
|
||||
}
|
||||
}
|
||||
|
||||
/// Run Millau-to-Rialto messages sync.
|
||||
pub fn run(
|
||||
millau_client: MillauClient,
|
||||
millau_sign: MillauSigningParams,
|
||||
rialto_client: RialtoClient,
|
||||
rialto_sign: RialtoSigningParams,
|
||||
lane: LaneId,
|
||||
metrics_params: Option<MetricsParams>,
|
||||
) {
|
||||
let millau_tick = Duration::from_secs(5);
|
||||
let rialto_tick = Duration::from_secs(5);
|
||||
let reconnect_delay = Duration::from_secs(10);
|
||||
let stall_timeout = Duration::from_secs(5 * 60);
|
||||
let relayer_id = millau_sign.signer.public().as_array_ref().clone().into();
|
||||
|
||||
messages_relay::message_lane_loop::run(
|
||||
messages_relay::message_lane_loop::Params {
|
||||
lane,
|
||||
source_tick: millau_tick,
|
||||
target_tick: rialto_tick,
|
||||
reconnect_delay,
|
||||
stall_timeout,
|
||||
max_unconfirmed_nonces_at_target: bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
},
|
||||
MillauSourceClient::new(
|
||||
millau_client.clone(),
|
||||
MillauTransactionMaker {
|
||||
client: millau_client,
|
||||
sign: millau_sign,
|
||||
},
|
||||
lane,
|
||||
RIALTO_BRIDGE_INSTANCE,
|
||||
),
|
||||
RialtoTargetClient::new(
|
||||
rialto_client.clone(),
|
||||
RialtoTransactionMaker {
|
||||
client: rialto_client,
|
||||
relayer_id,
|
||||
sign: rialto_sign,
|
||||
},
|
||||
lane,
|
||||
MILLAU_BRIDGE_INSTANCE,
|
||||
),
|
||||
metrics_params,
|
||||
futures::future::pending(),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user