mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 21:01:02 +00:00
Relay receiving + processing confirmations (#351)
* relay receiving + processing confirmations * fmt && clippy * removed message processing race * remove more traces * generic args names
This commit is contained in:
committed by
Bastian Köcher
parent
5163f62df4
commit
2ae886506d
@@ -31,6 +31,7 @@ mod message_lane;
|
|||||||
mod message_lane_loop;
|
mod message_lane_loop;
|
||||||
mod message_race_delivery;
|
mod message_race_delivery;
|
||||||
mod message_race_loop;
|
mod message_race_loop;
|
||||||
|
mod message_race_receiving;
|
||||||
mod metrics;
|
mod metrics;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
mod rpc_errors;
|
mod rpc_errors;
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
//! One-way message lane types. Within single one-way lane we have three 'races' where we try to:
|
//! One-way message lane types. Within single one-way lane we have three 'races' where we try to:
|
||||||
//!
|
//!
|
||||||
//! 1) relay new messages from source to target node;
|
//! 1) relay new messages from source to target node;
|
||||||
//! 2) relay proof-of-receiving from target to source node;
|
//! 2) relay proof-of-receiving from target to source node.
|
||||||
//! 3) relay proof-of-processing from target no source node.
|
|
||||||
|
|
||||||
use crate::utils::HeaderId;
|
use crate::utils::HeaderId;
|
||||||
|
|
||||||
|
use num_traits::{One, Zero};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// One-way message lane.
|
/// One-way message lane.
|
||||||
@@ -32,10 +32,20 @@ pub trait MessageLane {
|
|||||||
const TARGET_NAME: &'static str;
|
const TARGET_NAME: &'static str;
|
||||||
|
|
||||||
/// Message nonce type.
|
/// Message nonce type.
|
||||||
type MessageNonce: Clone + Copy + Debug + Default + From<u32> + Ord + std::ops::Add<Output = Self::MessageNonce>;
|
type MessageNonce: Clone
|
||||||
|
+ Copy
|
||||||
|
+ Debug
|
||||||
|
+ Default
|
||||||
|
+ From<u32>
|
||||||
|
+ Ord
|
||||||
|
+ std::ops::Add<Output = Self::MessageNonce>
|
||||||
|
+ One
|
||||||
|
+ Zero;
|
||||||
|
|
||||||
/// Messages proof.
|
/// Messages proof.
|
||||||
type MessagesProof: Clone;
|
type MessagesProof: Clone;
|
||||||
|
/// Messages receiving proof.
|
||||||
|
type MessagesReceivingProof: Clone;
|
||||||
|
|
||||||
/// Number of the source header.
|
/// Number of the source header.
|
||||||
type SourceHeaderNumber: Clone + Debug + Default + Ord + PartialEq;
|
type SourceHeaderNumber: Clone + Debug + Default + Ord + PartialEq;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
use crate::message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf};
|
use crate::message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf};
|
||||||
use crate::message_race_delivery::run as run_message_delivery_race;
|
use crate::message_race_delivery::run as run_message_delivery_race;
|
||||||
|
use crate::message_race_receiving::run as run_message_receiving_race;
|
||||||
use crate::utils::{interval, process_future_result, retry_backoff, FailedClient, MaybeConnectionError};
|
use crate::utils::{interval, process_future_result, retry_backoff, FailedClient, MaybeConnectionError};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -52,6 +53,11 @@ pub trait SourceClient<P: MessageLane>: Clone {
|
|||||||
&self,
|
&self,
|
||||||
id: SourceHeaderIdOf<P>,
|
id: SourceHeaderIdOf<P>,
|
||||||
) -> Result<(SourceHeaderIdOf<P>, P::MessageNonce), Self::Error>;
|
) -> Result<(SourceHeaderIdOf<P>, P::MessageNonce), Self::Error>;
|
||||||
|
/// Get nonce of the latest message, which receiving has been confirmed by the target chain.
|
||||||
|
async fn latest_confirmed_received_nonce(
|
||||||
|
&self,
|
||||||
|
id: SourceHeaderIdOf<P>,
|
||||||
|
) -> Result<(SourceHeaderIdOf<P>, P::MessageNonce), Self::Error>;
|
||||||
|
|
||||||
/// Prove messages in inclusive range [begin; end].
|
/// Prove messages in inclusive range [begin; end].
|
||||||
async fn prove_messages(
|
async fn prove_messages(
|
||||||
@@ -59,6 +65,13 @@ pub trait SourceClient<P: MessageLane>: Clone {
|
|||||||
id: SourceHeaderIdOf<P>,
|
id: SourceHeaderIdOf<P>,
|
||||||
nonces: RangeInclusive<P::MessageNonce>,
|
nonces: RangeInclusive<P::MessageNonce>,
|
||||||
) -> Result<(SourceHeaderIdOf<P>, RangeInclusive<P::MessageNonce>, P::MessagesProof), Self::Error>;
|
) -> Result<(SourceHeaderIdOf<P>, RangeInclusive<P::MessageNonce>, P::MessagesProof), Self::Error>;
|
||||||
|
|
||||||
|
/// Submit messages receiving proof.
|
||||||
|
async fn submit_messages_receiving_proof(
|
||||||
|
&self,
|
||||||
|
generated_at_block: TargetHeaderIdOf<P>,
|
||||||
|
proof: P::MessagesReceivingProof,
|
||||||
|
) -> Result<RangeInclusive<P::MessageNonce>, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Target client trait.
|
/// Target client trait.
|
||||||
@@ -73,12 +86,18 @@ pub trait TargetClient<P: MessageLane>: Clone {
|
|||||||
/// Returns state of the client.
|
/// Returns state of the client.
|
||||||
async fn state(&self) -> Result<TargetClientState<P>, Self::Error>;
|
async fn state(&self) -> Result<TargetClientState<P>, Self::Error>;
|
||||||
|
|
||||||
/// Get nonce of latest message, which receival has been confirmed.
|
/// Get nonce of latest received message.
|
||||||
async fn latest_received_nonce(
|
async fn latest_received_nonce(
|
||||||
&self,
|
&self,
|
||||||
id: TargetHeaderIdOf<P>,
|
id: TargetHeaderIdOf<P>,
|
||||||
) -> Result<(TargetHeaderIdOf<P>, P::MessageNonce), Self::Error>;
|
) -> Result<(TargetHeaderIdOf<P>, P::MessageNonce), Self::Error>;
|
||||||
|
|
||||||
|
/// Prove messages receiving at given block.
|
||||||
|
async fn prove_messages_receiving(
|
||||||
|
&self,
|
||||||
|
id: TargetHeaderIdOf<P>,
|
||||||
|
) -> Result<(TargetHeaderIdOf<P>, P::MessagesReceivingProof), Self::Error>;
|
||||||
|
|
||||||
/// Submit messages proof.
|
/// Submit messages proof.
|
||||||
async fn submit_messages_proof(
|
async fn submit_messages_proof(
|
||||||
&self,
|
&self,
|
||||||
@@ -196,6 +215,19 @@ async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: Targ
|
|||||||
)
|
)
|
||||||
.fuse();
|
.fuse();
|
||||||
|
|
||||||
|
let (
|
||||||
|
(receiving_source_state_sender, receiving_source_state_receiver),
|
||||||
|
(receiving_target_state_sender, receiving_target_state_receiver),
|
||||||
|
) = (unbounded(), unbounded());
|
||||||
|
let receiving_race_loop = run_message_receiving_race(
|
||||||
|
source_client.clone(),
|
||||||
|
receiving_source_state_receiver,
|
||||||
|
target_client.clone(),
|
||||||
|
receiving_target_state_receiver,
|
||||||
|
stall_timeout,
|
||||||
|
)
|
||||||
|
.fuse();
|
||||||
|
|
||||||
let exit_signal = exit_signal.fuse();
|
let exit_signal = exit_signal.fuse();
|
||||||
|
|
||||||
futures::pin_mut!(
|
futures::pin_mut!(
|
||||||
@@ -206,6 +238,7 @@ async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: Targ
|
|||||||
target_go_offline_future,
|
target_go_offline_future,
|
||||||
target_tick_stream,
|
target_tick_stream,
|
||||||
delivery_race_loop,
|
delivery_race_loop,
|
||||||
|
receiving_race_loop,
|
||||||
exit_signal
|
exit_signal
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -224,7 +257,8 @@ async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: Targ
|
|||||||
P::SOURCE_NAME,
|
P::SOURCE_NAME,
|
||||||
new_source_state,
|
new_source_state,
|
||||||
);
|
);
|
||||||
let _ = delivery_source_state_sender.unbounded_send(new_source_state);
|
let _ = delivery_source_state_sender.unbounded_send(new_source_state.clone());
|
||||||
|
let _ = receiving_source_state_sender.unbounded_send(new_source_state.clone());
|
||||||
},
|
},
|
||||||
&mut source_go_offline_future,
|
&mut source_go_offline_future,
|
||||||
|delay| async_std::task::sleep(delay),
|
|delay| async_std::task::sleep(delay),
|
||||||
@@ -250,7 +284,8 @@ async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: Targ
|
|||||||
P::TARGET_NAME,
|
P::TARGET_NAME,
|
||||||
new_target_state,
|
new_target_state,
|
||||||
);
|
);
|
||||||
let _ = delivery_target_state_sender.unbounded_send(new_target_state);
|
let _ = delivery_target_state_sender.unbounded_send(new_target_state.clone());
|
||||||
|
let _ = receiving_target_state_sender.unbounded_send(new_target_state.clone());
|
||||||
},
|
},
|
||||||
&mut target_go_offline_future,
|
&mut target_go_offline_future,
|
||||||
|delay| async_std::task::sleep(delay),
|
|delay| async_std::task::sleep(delay),
|
||||||
@@ -270,6 +305,12 @@ async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: Targ
|
|||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
receiving_error = receiving_race_loop => {
|
||||||
|
match receiving_error {
|
||||||
|
Ok(_) => unreachable!("only ends with error; qed"),
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
() = exit_signal => {
|
() = exit_signal => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -304,6 +345,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
pub type TestMessageNonce = u64;
|
pub type TestMessageNonce = u64;
|
||||||
pub type TestMessagesProof = RangeInclusive<TestMessageNonce>;
|
pub type TestMessagesProof = RangeInclusive<TestMessageNonce>;
|
||||||
|
pub type TestMessagesReceivingProof = TestMessageNonce;
|
||||||
|
|
||||||
pub type TestSourceHeaderNumber = u64;
|
pub type TestSourceHeaderNumber = u64;
|
||||||
pub type TestSourceHeaderHash = u64;
|
pub type TestSourceHeaderHash = u64;
|
||||||
@@ -333,7 +375,9 @@ pub(crate) mod tests {
|
|||||||
const TARGET_NAME: &'static str = "TestTarget";
|
const TARGET_NAME: &'static str = "TestTarget";
|
||||||
|
|
||||||
type MessageNonce = TestMessageNonce;
|
type MessageNonce = TestMessageNonce;
|
||||||
|
|
||||||
type MessagesProof = TestMessagesProof;
|
type MessagesProof = TestMessagesProof;
|
||||||
|
type MessagesReceivingProof = TestMessagesReceivingProof;
|
||||||
|
|
||||||
type SourceHeaderNumber = TestSourceHeaderNumber;
|
type SourceHeaderNumber = TestSourceHeaderNumber;
|
||||||
type SourceHeaderHash = TestSourceHeaderHash;
|
type SourceHeaderHash = TestSourceHeaderHash;
|
||||||
@@ -348,6 +392,8 @@ pub(crate) mod tests {
|
|||||||
is_source_reconnected: bool,
|
is_source_reconnected: bool,
|
||||||
source_state: SourceClientState<TestMessageLane>,
|
source_state: SourceClientState<TestMessageLane>,
|
||||||
source_latest_generated_nonce: TestMessageNonce,
|
source_latest_generated_nonce: TestMessageNonce,
|
||||||
|
source_latest_confirmed_received_nonce: TestMessageNonce,
|
||||||
|
submitted_messages_receiving_proofs: Vec<TestMessagesReceivingProof>,
|
||||||
is_target_fails: bool,
|
is_target_fails: bool,
|
||||||
is_target_reconnected: bool,
|
is_target_reconnected: bool,
|
||||||
target_state: SourceClientState<TestMessageLane>,
|
target_state: SourceClientState<TestMessageLane>,
|
||||||
@@ -383,7 +429,6 @@ pub(crate) mod tests {
|
|||||||
Ok(data.source_state.clone())
|
Ok(data.source_state.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get nonce of instance of latest generated message.
|
|
||||||
async fn latest_generated_nonce(
|
async fn latest_generated_nonce(
|
||||||
&self,
|
&self,
|
||||||
id: SourceHeaderIdOf<TestMessageLane>,
|
id: SourceHeaderIdOf<TestMessageLane>,
|
||||||
@@ -396,6 +441,15 @@ pub(crate) mod tests {
|
|||||||
Ok((id, data.source_latest_generated_nonce))
|
Ok((id, data.source_latest_generated_nonce))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn latest_confirmed_received_nonce(
|
||||||
|
&self,
|
||||||
|
id: SourceHeaderIdOf<TestMessageLane>,
|
||||||
|
) -> Result<(SourceHeaderIdOf<TestMessageLane>, TestMessageNonce), Self::Error> {
|
||||||
|
let mut data = self.data.lock();
|
||||||
|
(self.tick)(&mut *data);
|
||||||
|
Ok((id, data.source_latest_confirmed_received_nonce))
|
||||||
|
}
|
||||||
|
|
||||||
async fn prove_messages(
|
async fn prove_messages(
|
||||||
&self,
|
&self,
|
||||||
id: SourceHeaderIdOf<TestMessageLane>,
|
id: SourceHeaderIdOf<TestMessageLane>,
|
||||||
@@ -410,6 +464,18 @@ pub(crate) mod tests {
|
|||||||
> {
|
> {
|
||||||
Ok((id, nonces.clone(), nonces))
|
Ok((id, nonces.clone(), nonces))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn submit_messages_receiving_proof(
|
||||||
|
&self,
|
||||||
|
_generated_at_block: TargetHeaderIdOf<TestMessageLane>,
|
||||||
|
proof: TestMessagesReceivingProof,
|
||||||
|
) -> Result<RangeInclusive<TestMessageNonce>, Self::Error> {
|
||||||
|
let mut data = self.data.lock();
|
||||||
|
(self.tick)(&mut *data);
|
||||||
|
data.submitted_messages_receiving_proofs.push(proof);
|
||||||
|
data.source_latest_confirmed_received_nonce = proof;
|
||||||
|
Ok(proof..=proof)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -452,7 +518,13 @@ pub(crate) mod tests {
|
|||||||
Ok((id, data.target_latest_received_nonce))
|
Ok((id, data.target_latest_received_nonce))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Submit messages proof.
|
async fn prove_messages_receiving(
|
||||||
|
&self,
|
||||||
|
id: TargetHeaderIdOf<TestMessageLane>,
|
||||||
|
) -> Result<(TargetHeaderIdOf<TestMessageLane>, TestMessagesReceivingProof), Self::Error> {
|
||||||
|
Ok((id, self.data.lock().target_latest_received_nonce))
|
||||||
|
}
|
||||||
|
|
||||||
async fn submit_messages_proof(
|
async fn submit_messages_proof(
|
||||||
&self,
|
&self,
|
||||||
_generated_at_header: SourceHeaderIdOf<TestMessageLane>,
|
_generated_at_header: SourceHeaderIdOf<TestMessageLane>,
|
||||||
@@ -570,16 +642,22 @@ pub(crate) mod tests {
|
|||||||
},
|
},
|
||||||
Arc::new(|_: &mut TestClientData| {}),
|
Arc::new(|_: &mut TestClientData| {}),
|
||||||
Arc::new(move |data: &mut TestClientData| {
|
Arc::new(move |data: &mut TestClientData| {
|
||||||
if data.target_state.best_peer.0 < 10 {
|
// syncing source headers -> target chain (by one)
|
||||||
|
if data.target_state.best_peer.0 < data.source_state.best_self.0 {
|
||||||
data.target_state.best_peer =
|
data.target_state.best_peer =
|
||||||
HeaderId(data.target_state.best_peer.0 + 1, data.target_state.best_peer.0 + 1);
|
HeaderId(data.target_state.best_peer.0 + 1, data.target_state.best_peer.0 + 1);
|
||||||
}
|
}
|
||||||
if data
|
// syncing source headers -> target chain (all at once)
|
||||||
.submitted_messages_proofs
|
if data.source_state.best_peer.0 < data.target_state.best_self.0 {
|
||||||
.last()
|
data.source_state.best_peer = data.target_state.best_self;
|
||||||
.map(|last| *last.end() == 10)
|
}
|
||||||
.unwrap_or(false)
|
// if target has received all messages => increase target block so that confirmations may be sent
|
||||||
{
|
if data.target_latest_received_nonce == 10 {
|
||||||
|
data.target_state.best_self =
|
||||||
|
HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.0 + 1);
|
||||||
|
}
|
||||||
|
// if source has received all messages receiving confirmations => increase source block so that confirmations may be sent
|
||||||
|
if data.source_latest_confirmed_received_nonce == 10 {
|
||||||
exit_sender.unbounded_send(()).unwrap();
|
exit_sender.unbounded_send(()).unwrap();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -587,5 +665,6 @@ pub(crate) mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(result.submitted_messages_proofs, vec![1..=4, 5..=8, 9..=10],);
|
assert_eq!(result.submitted_messages_proofs, vec![1..=4, 5..=8, 9..=10],);
|
||||||
|
assert!(!result.submitted_messages_receiving_proofs.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ use crate::message_lane_loop::{
|
|||||||
TargetClientState,
|
TargetClientState,
|
||||||
};
|
};
|
||||||
use crate::message_race_loop::{MessageRace, RaceState, RaceStrategy, SourceClient, TargetClient};
|
use crate::message_race_loop::{MessageRace, RaceState, RaceStrategy, SourceClient, TargetClient};
|
||||||
use crate::utils::FailedClient;
|
use crate::utils::{FailedClient, HeaderId};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::stream::FusedStream;
|
use futures::stream::FusedStream;
|
||||||
|
use num_traits::{One, Zero};
|
||||||
use std::{collections::VecDeque, marker::PhantomData, ops::RangeInclusive, time::Duration};
|
use std::{collections::VecDeque, marker::PhantomData, ops::RangeInclusive, time::Duration};
|
||||||
|
|
||||||
/// Maximal number of messages to relay in single transaction.
|
/// Maximal number of messages to relay in single transaction.
|
||||||
@@ -48,7 +49,7 @@ pub async fn run<P: MessageLane>(
|
|||||||
},
|
},
|
||||||
target_state_updates,
|
target_state_updates,
|
||||||
stall_timeout,
|
stall_timeout,
|
||||||
MessageDeliveryStrategy::<P>::default(),
|
MessageDeliveryStrategy::<P>::new(MAX_MESSAGES_TO_RELAY_IN_SINGLE_TX.into()),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -135,34 +136,60 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Message delivery strategy.
|
/// Messages delivery strategy.
|
||||||
struct MessageDeliveryStrategy<P: MessageLane> {
|
type MessageDeliveryStrategy<P> = DeliveryStrategy<
|
||||||
|
<P as MessageLane>::SourceHeaderNumber,
|
||||||
|
<P as MessageLane>::SourceHeaderHash,
|
||||||
|
<P as MessageLane>::TargetHeaderNumber,
|
||||||
|
<P as MessageLane>::TargetHeaderHash,
|
||||||
|
<P as MessageLane>::MessageNonce,
|
||||||
|
<P as MessageLane>::MessagesProof,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Nonces delivery strategy.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DeliveryStrategy<SourceHeaderNumber, SourceHeaderHash, TargetHeaderNumber, TargetHeaderHash, Nonce, Proof> {
|
||||||
/// All queued nonces.
|
/// All queued nonces.
|
||||||
source_queue: VecDeque<(SourceHeaderIdOf<P>, P::MessageNonce)>,
|
source_queue: VecDeque<(HeaderId<SourceHeaderHash, SourceHeaderNumber>, Nonce)>,
|
||||||
/// Best nonce known to target node.
|
/// Best nonce known to target node.
|
||||||
target_nonce: P::MessageNonce,
|
target_nonce: Nonce,
|
||||||
|
/// Max nonces to relay in single transaction.
|
||||||
|
max_nonces_to_relay_in_single_tx: Nonce,
|
||||||
/// Unused generic types dump.
|
/// Unused generic types dump.
|
||||||
_phantom: PhantomData<P>,
|
_phantom: PhantomData<(TargetHeaderNumber, TargetHeaderHash, Proof)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MessageLane> Default for MessageDeliveryStrategy<P> {
|
impl<SourceHeaderNumber, SourceHeaderHash, TargetHeaderNumber, TargetHeaderHash, Nonce: Default, Proof>
|
||||||
fn default() -> Self {
|
DeliveryStrategy<SourceHeaderNumber, SourceHeaderHash, TargetHeaderNumber, TargetHeaderHash, Nonce, Proof>
|
||||||
MessageDeliveryStrategy {
|
{
|
||||||
|
/// Create new delivery strategy.
|
||||||
|
pub fn new(max_nonces_to_relay_in_single_tx: Nonce) -> Self {
|
||||||
|
DeliveryStrategy {
|
||||||
source_queue: VecDeque::new(),
|
source_queue: VecDeque::new(),
|
||||||
target_nonce: Default::default(),
|
target_nonce: Default::default(),
|
||||||
|
max_nonces_to_relay_in_single_tx,
|
||||||
_phantom: Default::default(),
|
_phantom: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessageNonce, P::MessagesProof>
|
impl<SourceHeaderNumber, SourceHeaderHash, TargetHeaderNumber, TargetHeaderHash, Nonce, Proof>
|
||||||
for MessageDeliveryStrategy<P>
|
RaceStrategy<
|
||||||
|
HeaderId<SourceHeaderHash, SourceHeaderNumber>,
|
||||||
|
HeaderId<TargetHeaderHash, TargetHeaderNumber>,
|
||||||
|
Nonce,
|
||||||
|
Proof,
|
||||||
|
> for DeliveryStrategy<SourceHeaderNumber, SourceHeaderHash, TargetHeaderNumber, TargetHeaderHash, Nonce, Proof>
|
||||||
|
where
|
||||||
|
SourceHeaderHash: Clone,
|
||||||
|
SourceHeaderNumber: Clone + Ord,
|
||||||
|
Nonce: Clone + Copy + From<u32> + Ord + std::ops::Add<Output = Nonce> + One + Zero,
|
||||||
{
|
{
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.source_queue.is_empty()
|
self.source_queue.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_nonce_updated(&mut self, at_block: SourceHeaderIdOf<P>, nonce: P::MessageNonce) {
|
fn source_nonce_updated(&mut self, at_block: HeaderId<SourceHeaderHash, SourceHeaderNumber>, nonce: Nonce) {
|
||||||
if nonce <= self.target_nonce {
|
if nonce <= self.target_nonce {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -178,8 +205,13 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M
|
|||||||
|
|
||||||
fn target_nonce_updated(
|
fn target_nonce_updated(
|
||||||
&mut self,
|
&mut self,
|
||||||
nonce: P::MessageNonce,
|
nonce: Nonce,
|
||||||
race_state: &mut RaceState<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessageNonce, P::MessagesProof>,
|
race_state: &mut RaceState<
|
||||||
|
HeaderId<SourceHeaderHash, SourceHeaderNumber>,
|
||||||
|
HeaderId<TargetHeaderHash, TargetHeaderNumber>,
|
||||||
|
Nonce,
|
||||||
|
Proof,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
if nonce < self.target_nonce {
|
if nonce < self.target_nonce {
|
||||||
return;
|
return;
|
||||||
@@ -216,8 +248,13 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M
|
|||||||
|
|
||||||
fn select_nonces_to_deliver(
|
fn select_nonces_to_deliver(
|
||||||
&mut self,
|
&mut self,
|
||||||
race_state: &RaceState<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessageNonce, P::MessagesProof>,
|
race_state: &RaceState<
|
||||||
) -> Option<RangeInclusive<P::MessageNonce>> {
|
HeaderId<SourceHeaderHash, SourceHeaderNumber>,
|
||||||
|
HeaderId<TargetHeaderHash, TargetHeaderNumber>,
|
||||||
|
Nonce,
|
||||||
|
Proof,
|
||||||
|
>,
|
||||||
|
) -> Option<RangeInclusive<Nonce>> {
|
||||||
// if we have already selected nonces that we want to submit, do nothing
|
// if we have already selected nonces that we want to submit, do nothing
|
||||||
if race_state.nonces_to_submit.is_some() {
|
if race_state.nonces_to_submit.is_some() {
|
||||||
return None;
|
return None;
|
||||||
@@ -229,18 +266,19 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1) we want to deliver all nonces, starting from `target_nonce + 1`
|
// 1) we want to deliver all nonces, starting from `target_nonce + 1`
|
||||||
// 2) we want to deliver at most `MAX_MESSAGES_TO_RELAY_IN_SINGLE_TX` nonces in this batch
|
// 2) we want to deliver at most `self.max_nonces_to_relay_in_single_tx` nonces in this batch
|
||||||
// 3) we can't deliver new nonce until header, that has emitted this nonce, is finalized
|
// 3) we can't deliver new nonce until header, that has emitted this nonce, is finalized
|
||||||
// by target client
|
// by target client
|
||||||
let nonces_begin = self.target_nonce + 1.into();
|
let nonces_begin = self.target_nonce + 1.into();
|
||||||
let best_header_at_target = &race_state.target_state.as_ref()?.best_peer;
|
let best_header_at_target = &race_state.target_state.as_ref()?.best_peer;
|
||||||
let mut nonces_end = None;
|
let mut nonces_end = None;
|
||||||
for i in 0..MAX_MESSAGES_TO_RELAY_IN_SINGLE_TX {
|
let mut i = Zero::zero();
|
||||||
let nonce = nonces_begin + i.into();
|
while i < self.max_nonces_to_relay_in_single_tx {
|
||||||
|
let nonce = nonces_begin + i;
|
||||||
|
|
||||||
// if queue is empty, we don't need to prove anything
|
// if queue is empty, we don't need to prove anything
|
||||||
let (first_queued_at, first_queued_nonce) = match self.source_queue.front() {
|
let (first_queued_at, first_queued_nonce) = match self.source_queue.front() {
|
||||||
Some((first_queued_at, first_queued_nonce)) => (first_queued_at.clone(), *first_queued_nonce),
|
Some((first_queued_at, first_queued_nonce)) => ((*first_queued_at).clone(), *first_queued_nonce),
|
||||||
None => break,
|
None => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -257,6 +295,8 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M
|
|||||||
if nonce == first_queued_nonce {
|
if nonce == first_queued_nonce {
|
||||||
self.source_queue.pop_front();
|
self.source_queue.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i = i + One::one();
|
||||||
}
|
}
|
||||||
|
|
||||||
nonces_end.map(|nonces_end| RangeInclusive::new(nonces_begin, nonces_end))
|
nonces_end.map(|nonces_end| RangeInclusive::new(nonces_begin, nonces_end))
|
||||||
@@ -273,7 +313,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn strategy_is_empty_works() {
|
fn strategy_is_empty_works() {
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
assert_eq!(strategy.is_empty(), true);
|
assert_eq!(strategy.is_empty(), true);
|
||||||
strategy.source_nonce_updated(header_id(1), 1);
|
strategy.source_nonce_updated(header_id(1), 1);
|
||||||
assert_eq!(strategy.is_empty(), false);
|
assert_eq!(strategy.is_empty(), false);
|
||||||
@@ -281,7 +321,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn source_nonce_is_never_lower_than_known_target_nonce() {
|
fn source_nonce_is_never_lower_than_known_target_nonce() {
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
strategy.target_nonce_updated(10, &mut Default::default());
|
strategy.target_nonce_updated(10, &mut Default::default());
|
||||||
strategy.source_nonce_updated(header_id(1), 5);
|
strategy.source_nonce_updated(header_id(1), 5);
|
||||||
assert_eq!(strategy.source_queue, vec![]);
|
assert_eq!(strategy.source_queue, vec![]);
|
||||||
@@ -289,7 +329,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn source_nonce_is_never_lower_than_latest_known_source_nonce() {
|
fn source_nonce_is_never_lower_than_latest_known_source_nonce() {
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
strategy.source_nonce_updated(header_id(1), 5);
|
strategy.source_nonce_updated(header_id(1), 5);
|
||||||
strategy.source_nonce_updated(header_id(2), 3);
|
strategy.source_nonce_updated(header_id(2), 3);
|
||||||
strategy.source_nonce_updated(header_id(2), 5);
|
strategy.source_nonce_updated(header_id(2), 5);
|
||||||
@@ -298,7 +338,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_nonce_is_never_lower_than_latest_known_target_nonce() {
|
fn target_nonce_is_never_lower_than_latest_known_target_nonce() {
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
strategy.target_nonce_updated(10, &mut Default::default());
|
strategy.target_nonce_updated(10, &mut Default::default());
|
||||||
strategy.target_nonce_updated(5, &mut Default::default());
|
strategy.target_nonce_updated(5, &mut Default::default());
|
||||||
assert_eq!(strategy.target_nonce, 10);
|
assert_eq!(strategy.target_nonce, 10);
|
||||||
@@ -306,7 +346,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn updated_target_nonce_removes_queued_entries() {
|
fn updated_target_nonce_removes_queued_entries() {
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
strategy.source_nonce_updated(header_id(1), 5);
|
strategy.source_nonce_updated(header_id(1), 5);
|
||||||
strategy.source_nonce_updated(header_id(2), 10);
|
strategy.source_nonce_updated(header_id(2), 10);
|
||||||
strategy.source_nonce_updated(header_id(3), 15);
|
strategy.source_nonce_updated(header_id(3), 15);
|
||||||
@@ -318,7 +358,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn selected_nonces_are_dropped_on_target_nonce_update() {
|
fn selected_nonces_are_dropped_on_target_nonce_update() {
|
||||||
let mut state = RaceState::default();
|
let mut state = RaceState::default();
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
state.nonces_to_submit = Some((header_id(1), 5..=10, 5..=10));
|
state.nonces_to_submit = Some((header_id(1), 5..=10, 5..=10));
|
||||||
strategy.target_nonce_updated(7, &mut state);
|
strategy.target_nonce_updated(7, &mut state);
|
||||||
assert!(state.nonces_to_submit.is_some());
|
assert!(state.nonces_to_submit.is_some());
|
||||||
@@ -329,7 +369,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn submitted_nonces_are_dropped_on_target_nonce_update() {
|
fn submitted_nonces_are_dropped_on_target_nonce_update() {
|
||||||
let mut state = RaceState::default();
|
let mut state = RaceState::default();
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
state.nonces_submitted = Some(5..=10);
|
state.nonces_submitted = Some(5..=10);
|
||||||
strategy.target_nonce_updated(7, &mut state);
|
strategy.target_nonce_updated(7, &mut state);
|
||||||
assert!(state.nonces_submitted.is_some());
|
assert!(state.nonces_submitted.is_some());
|
||||||
@@ -340,7 +380,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn nothing_is_selected_if_something_is_already_selected() {
|
fn nothing_is_selected_if_something_is_already_selected() {
|
||||||
let mut state = RaceState::default();
|
let mut state = RaceState::default();
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
state.nonces_to_submit = Some((header_id(1), 1..=10, 1..=10));
|
state.nonces_to_submit = Some((header_id(1), 1..=10, 1..=10));
|
||||||
strategy.source_nonce_updated(header_id(1), 10);
|
strategy.source_nonce_updated(header_id(1), 10);
|
||||||
assert_eq!(strategy.select_nonces_to_deliver(&state), None);
|
assert_eq!(strategy.select_nonces_to_deliver(&state), None);
|
||||||
@@ -349,7 +389,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn nothing_is_selected_if_something_is_already_submitted() {
|
fn nothing_is_selected_if_something_is_already_submitted() {
|
||||||
let mut state = RaceState::default();
|
let mut state = RaceState::default();
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
state.nonces_submitted = Some(1..=10);
|
state.nonces_submitted = Some(1..=10);
|
||||||
strategy.source_nonce_updated(header_id(1), 10);
|
strategy.source_nonce_updated(header_id(1), 10);
|
||||||
assert_eq!(strategy.select_nonces_to_deliver(&state), None);
|
assert_eq!(strategy.select_nonces_to_deliver(&state), None);
|
||||||
@@ -358,7 +398,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn select_nonces_to_deliver_works() {
|
fn select_nonces_to_deliver_works() {
|
||||||
let mut state = RaceState::<_, _, TestMessageNonce, TestMessagesProof>::default();
|
let mut state = RaceState::<_, _, TestMessageNonce, TestMessagesProof>::default();
|
||||||
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::default();
|
let mut strategy = MessageDeliveryStrategy::<TestMessageLane>::new(4);
|
||||||
strategy.source_nonce_updated(header_id(1), 1);
|
strategy.source_nonce_updated(header_id(1), 1);
|
||||||
strategy.source_nonce_updated(header_id(2), 2);
|
strategy.source_nonce_updated(header_id(2), 2);
|
||||||
strategy.source_nonce_updated(header_id(3), 6);
|
strategy.source_nonce_updated(header_id(3), 6);
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
use crate::message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf};
|
||||||
|
use crate::message_lane_loop::{
|
||||||
|
SourceClient as MessageLaneSourceClient, SourceClientState, TargetClient as MessageLaneTargetClient,
|
||||||
|
TargetClientState,
|
||||||
|
};
|
||||||
|
use crate::message_race_delivery::DeliveryStrategy;
|
||||||
|
use crate::message_race_loop::{MessageRace, SourceClient, TargetClient};
|
||||||
|
use crate::utils::FailedClient;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use futures::stream::FusedStream;
|
||||||
|
use std::{marker::PhantomData, ops::RangeInclusive, time::Duration};
|
||||||
|
|
||||||
|
/// Message receiving confirmations delivery strategy.
|
||||||
|
type ReceivingConfirmationsDeliveryStrategy<P> = DeliveryStrategy<
|
||||||
|
<P as MessageLane>::TargetHeaderNumber,
|
||||||
|
<P as MessageLane>::TargetHeaderHash,
|
||||||
|
<P as MessageLane>::SourceHeaderNumber,
|
||||||
|
<P as MessageLane>::SourceHeaderHash,
|
||||||
|
<P as MessageLane>::MessageNonce,
|
||||||
|
<P as MessageLane>::MessagesReceivingProof,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Run receiving confirmations race.
|
||||||
|
pub async fn run<P: MessageLane>(
|
||||||
|
source_client: impl MessageLaneSourceClient<P>,
|
||||||
|
source_state_updates: impl FusedStream<Item = SourceClientState<P>>,
|
||||||
|
target_client: impl MessageLaneTargetClient<P>,
|
||||||
|
target_state_updates: impl FusedStream<Item = TargetClientState<P>>,
|
||||||
|
stall_timeout: Duration,
|
||||||
|
) -> Result<(), FailedClient> {
|
||||||
|
crate::message_race_loop::run(
|
||||||
|
ReceivingConfirmationsRaceSource {
|
||||||
|
client: target_client,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
},
|
||||||
|
target_state_updates,
|
||||||
|
ReceivingConfirmationsRaceTarget {
|
||||||
|
client: source_client,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
},
|
||||||
|
source_state_updates,
|
||||||
|
stall_timeout,
|
||||||
|
ReceivingConfirmationsDeliveryStrategy::<P>::new(std::u32::MAX.into()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Messages receiving confirmations race.
|
||||||
|
struct ReceivingConfirmationsRace<P>(std::marker::PhantomData<P>);
|
||||||
|
|
||||||
|
impl<P: MessageLane> MessageRace for ReceivingConfirmationsRace<P> {
|
||||||
|
type SourceHeaderId = TargetHeaderIdOf<P>;
|
||||||
|
type TargetHeaderId = SourceHeaderIdOf<P>;
|
||||||
|
|
||||||
|
type MessageNonce = P::MessageNonce;
|
||||||
|
type Proof = P::MessagesReceivingProof;
|
||||||
|
|
||||||
|
fn source_name() -> String {
|
||||||
|
format!("{}::ReceivingConfirmationsDelivery", P::SOURCE_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_name() -> String {
|
||||||
|
format!("{}::ReceivingConfirmationsDelivery", P::TARGET_NAME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message receiving confirmations race source, which is a target of the lane.
|
||||||
|
struct ReceivingConfirmationsRaceSource<P: MessageLane, C> {
|
||||||
|
client: C,
|
||||||
|
_phantom: PhantomData<P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait(?Send)]
|
||||||
|
impl<P, C> SourceClient<ReceivingConfirmationsRace<P>> for ReceivingConfirmationsRaceSource<P, C>
|
||||||
|
where
|
||||||
|
P: MessageLane,
|
||||||
|
C: MessageLaneTargetClient<P>,
|
||||||
|
{
|
||||||
|
type Error = C::Error;
|
||||||
|
|
||||||
|
async fn latest_nonce(
|
||||||
|
&self,
|
||||||
|
at_block: TargetHeaderIdOf<P>,
|
||||||
|
) -> Result<(TargetHeaderIdOf<P>, P::MessageNonce), Self::Error> {
|
||||||
|
self.client.latest_received_nonce(at_block).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn generate_proof(
|
||||||
|
&self,
|
||||||
|
at_block: TargetHeaderIdOf<P>,
|
||||||
|
nonces: RangeInclusive<P::MessageNonce>,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
TargetHeaderIdOf<P>,
|
||||||
|
RangeInclusive<P::MessageNonce>,
|
||||||
|
P::MessagesReceivingProof,
|
||||||
|
),
|
||||||
|
Self::Error,
|
||||||
|
> {
|
||||||
|
self.client
|
||||||
|
.prove_messages_receiving(at_block)
|
||||||
|
.await
|
||||||
|
.map(|(at_block, proof)| (at_block, nonces, proof))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message receiving confirmations race target, which is a source of the lane.
|
||||||
|
struct ReceivingConfirmationsRaceTarget<P: MessageLane, C> {
|
||||||
|
client: C,
|
||||||
|
_phantom: PhantomData<P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait(?Send)]
|
||||||
|
impl<P, C> TargetClient<ReceivingConfirmationsRace<P>> for ReceivingConfirmationsRaceTarget<P, C>
|
||||||
|
where
|
||||||
|
P: MessageLane,
|
||||||
|
C: MessageLaneSourceClient<P>,
|
||||||
|
{
|
||||||
|
type Error = C::Error;
|
||||||
|
|
||||||
|
async fn latest_nonce(
|
||||||
|
&self,
|
||||||
|
at_block: SourceHeaderIdOf<P>,
|
||||||
|
) -> Result<(SourceHeaderIdOf<P>, P::MessageNonce), Self::Error> {
|
||||||
|
self.client.latest_confirmed_received_nonce(at_block).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn submit_proof(
|
||||||
|
&self,
|
||||||
|
generated_at_block: TargetHeaderIdOf<P>,
|
||||||
|
_nonces: RangeInclusive<P::MessageNonce>,
|
||||||
|
proof: P::MessagesReceivingProof,
|
||||||
|
) -> Result<RangeInclusive<P::MessageNonce>, Self::Error> {
|
||||||
|
self.client
|
||||||
|
.submit_messages_receiving_proof(generated_at_block, proof)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user