Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bridge: add subcommand to relay messages delivery confirmation #4453

Merged
merged 8 commits into from
May 27, 2024
51 changes: 51 additions & 0 deletions bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,24 @@ pub struct RelayMessagesRangeParams {
target_sign: TargetSigningParams,
}

/// Messages delivery confirmation relaying params.
#[derive(StructOpt)]
pub struct RelayMessagesDeliveryConfirmationParams {
/// Number of the target chain header that we will use to prepare a messages
/// delivery proof. This header must be previously proved to the source chain.
#[structopt(long)]
at_target_block: u128,
/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target: TargetConnectionParams,
}

/// Trait used for relaying messages between 2 chains.
#[async_trait]
pub trait MessagesRelayer: MessagesCliBridge
Expand Down Expand Up @@ -154,4 +172,37 @@ where
)
.await
}

/// Relay a messages delivery confirmation.
async fn relay_messages_delivery_confirmation(
data: RelayMessagesDeliveryConfirmationParams,
) -> anyhow::Result<()> {
let source_client = data.source.into_client::<Self::Source>().await?;
let target_client = data.target.into_client::<Self::Target>().await?;
let source_sign = data.source_sign.to_keypair::<Self::Source>()?;
let source_transactions_mortality = data.source_sign.transactions_mortality()?;

let at_target_block = target_client
.header_by_number(data.at_target_block.unique_saturated_into())
.await
.map_err(|e| {
log::trace!(
target: "bridge",
"Failed to read {} header with number {}: {e:?}",
Self::Target::NAME,
data.at_target_block,
);
anyhow::format_err!("The command has failed")
})?
.id();

crate::messages_lane::relay_messages_delivery_confirmation::<Self::MessagesLane>(
source_client,
target_client,
TransactionParams { signer: source_sign, mortality: source_transactions_mortality },
at_target_block,
data.lane.into(),
)
.await
}
}
42 changes: 40 additions & 2 deletions bridges/relays/lib-substrate-relay/src/messages_lane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ where
source_client,
params.lane_id,
relayer_id_at_source,
params.target_transaction_params,
Some(params.target_transaction_params),
params.source_to_target_headers_relay,
),
{
Expand Down Expand Up @@ -307,7 +307,7 @@ where
source_client,
lane_id,
relayer_id_at_source,
target_transaction_params,
Some(target_transaction_params),
None,
),
at_source_block,
Expand All @@ -318,6 +318,44 @@ where
.map_err(|_| anyhow::format_err!("The command has failed"))
}

/// Relay messages delivery confirmation of Substrate-to-Substrate messages.
/// No checks are made to ensure that transaction will succeed.
pub async fn relay_messages_delivery_confirmation<P: SubstrateMessageLane>(
source_client: Client<P::SourceChain>,
target_client: Client<P::TargetChain>,
source_transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
at_target_block: HeaderIdOf<P::TargetChain>,
lane_id: LaneId,
) -> anyhow::Result<()>
where
AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>,
BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
{
let relayer_id_at_source: AccountIdOf<P::SourceChain> =
source_transaction_params.signer.public().into();
messages_relay::relay_messages_delivery_confirmation(
SubstrateMessagesSource::<P>::new(
source_client.clone(),
target_client.clone(),
lane_id,
source_transaction_params,
None,
),
SubstrateMessagesTarget::<P>::new(
target_client,
source_client,
lane_id,
relayer_id_at_source,
None,
None,
),
at_target_block,
)
.await
.map_err(|_| anyhow::format_err!("The command has failed"))
}

/// 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
Expand Down
19 changes: 13 additions & 6 deletions bridges/relays/lib-substrate-relay/src/messages_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ use messages_relay::{
message_lane_loop::{NoncesSubmitArtifacts, TargetClient, TargetClientState},
};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, BalanceOf, CallOf, Client, Error as SubstrateError, HashOf,
TransactionEra, TransactionTracker, UnsignedTransaction,
AccountIdOf, AccountKeyPairOf, BalanceOf, CallOf, Chain, Client, Error as SubstrateError,
HashOf, TransactionEra, TransactionTracker, UnsignedTransaction,
};
use relay_utils::relay_loop::Client as RelayClient;
use sp_core::Pair;
Expand All @@ -57,7 +57,7 @@ pub struct SubstrateMessagesTarget<P: SubstrateMessageLane> {
source_client: Client<P::SourceChain>,
lane_id: LaneId,
relayer_id_at_source: AccountIdOf<P::SourceChain>,
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
transaction_params: Option<TransactionParams<AccountKeyPairOf<P::TargetChain>>>,
source_to_target_headers_relay: Option<Arc<dyn OnDemandRelay<P::SourceChain, P::TargetChain>>>,
}

Expand All @@ -68,7 +68,7 @@ impl<P: SubstrateMessageLane> SubstrateMessagesTarget<P> {
source_client: Client<P::SourceChain>,
lane_id: LaneId,
relayer_id_at_source: AccountIdOf<P::SourceChain>,
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
transaction_params: Option<TransactionParams<AccountKeyPairOf<P::TargetChain>>>,
source_to_target_headers_relay: Option<
Arc<dyn OnDemandRelay<P::SourceChain, P::TargetChain>>,
>,
Expand Down Expand Up @@ -249,11 +249,18 @@ where
None => messages_proof_call,
};

let transaction_params = self.transaction_params.clone();
let transaction_params = self.transaction_params.clone().map(Ok).unwrap_or_else(|| {
// this error shall never happen in practice, so it not deserves
// a separate error variant
Err(SubstrateError::Custom(format!(
"Cannot sign transaction of {} chain",
P::TargetChain::NAME,
)))
})?;
let tx_tracker = self
.target_client
.submit_and_watch_signed_extrinsic(
&self.transaction_params.signer,
&transaction_params.signer,
move |best_block_id, transaction_nonce| {
Ok(UnsignedTransaction::new(final_call.into(), transaction_nonce)
.era(TransactionEra::new(best_block_id, transaction_params.mortality)))
Expand Down
1 change: 1 addition & 0 deletions bridges/relays/messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ mod message_race_receiving;
mod message_race_strategy;

pub use message_race_delivery::relay_messages_range;
pub use message_race_receiving::relay_messages_delivery_confirmation;
39 changes: 38 additions & 1 deletion bridges/relays/messages/src/message_race_receiving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
use async_trait::async_trait;
use bp_messages::MessageNonce;
use futures::stream::FusedStream;
use relay_utils::FailedClient;
use relay_utils::{FailedClient, TrackedTransactionStatus, TransactionTracker};
use std::{marker::PhantomData, ops::RangeInclusive};

/// Message receiving confirmations delivery strategy.
Expand Down Expand Up @@ -69,6 +69,43 @@ pub async fn run<P: MessageLane>(
.await
}

/// Relay messages delivery confirmation.
pub async fn relay_messages_delivery_confirmation<P: MessageLane>(
source_client: impl MessageLaneSourceClient<P>,
target_client: impl MessageLaneTargetClient<P>,
at: TargetHeaderIdOf<P>,
) -> Result<(), ()> {
// prepare messages delivery proof
let (at, proof) = target_client.prove_messages_receiving(at.clone()).await.map_err(|e| {
log::error!(
target: "bridge",
"Failed to generate messages delivery proof at {:?}: {:?}",
at,
e,
);
})?;
// submit messages delivery proof to the source node
let tx_tracker =
source_client
.submit_messages_receiving_proof(None, at, proof)
.await
.map_err(|e| {
log::error!(
target: "bridge",
"Failed to submit messages delivery proof: {:?}",
e,
);
})?;

match tx_tracker.wait().await {
TrackedTransactionStatus::Finalized(_) => Ok(()),
TrackedTransactionStatus::Lost => {
log::error!("Transaction with messages delivery proof is considered lost");
Err(())
},
}
}

/// Messages receiving confirmations race.
struct ReceivingConfirmationsRace<P>(std::marker::PhantomData<P>);

Expand Down
Loading