mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Complex headers+messages Millau<->Rialto relay (#878)
* complex headers+messages relay * post-merge fix * fix + test issue with on-demand not starting
This commit is contained in:
committed by
Bastian Köcher
parent
0d60f42b5e
commit
e2131724fb
@@ -140,8 +140,8 @@ pub trait SourceClient<P: MessageLane>: RelayClient {
|
||||
proof: P::MessagesReceivingProof,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Activate (or deactivate) headers relay that relays target headers to source node.
|
||||
async fn activate_target_to_source_headers_relay(&self, activate: bool);
|
||||
/// We need given finalized target header on source to continue synchronization.
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<P>);
|
||||
}
|
||||
|
||||
/// Target client trait.
|
||||
@@ -181,8 +181,8 @@ pub trait TargetClient<P: MessageLane>: RelayClient {
|
||||
proof: P::MessagesProof,
|
||||
) -> Result<RangeInclusive<MessageNonce>, Self::Error>;
|
||||
|
||||
/// Activate (or deactivate) headers relay that relays source headers to target node.
|
||||
async fn activate_source_to_target_headers_relay(&self, activate: bool);
|
||||
/// We need given finalized source header on target to continue synchronization.
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<P>);
|
||||
}
|
||||
|
||||
/// State of the client.
|
||||
@@ -232,9 +232,9 @@ pub async fn run<P: MessageLane>(
|
||||
let exit_signal = exit_signal.shared();
|
||||
relay_utils::relay_loop(source_client, target_client)
|
||||
.reconnect_delay(params.reconnect_delay)
|
||||
.with_metrics(metrics_prefix::<P>(¶ms.lane), metrics_params)
|
||||
.loop_metric(MessageLaneLoopMetrics::default())?
|
||||
.standalone_metric(GlobalMetrics::default())?
|
||||
.with_metrics(Some(metrics_prefix::<P>(¶ms.lane)), metrics_params)
|
||||
.loop_metric(|registry, prefix| MessageLaneLoopMetrics::new(registry, prefix))?
|
||||
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
||||
.expose()
|
||||
.await?
|
||||
.run(|source_client, target_client, metrics| {
|
||||
@@ -475,8 +475,10 @@ pub(crate) mod tests {
|
||||
target_latest_received_nonce: MessageNonce,
|
||||
target_latest_confirmed_received_nonce: MessageNonce,
|
||||
submitted_messages_proofs: Vec<TestMessagesProof>,
|
||||
is_target_to_source_headers_relay_activated: bool,
|
||||
is_source_to_target_headers_relay_activated: bool,
|
||||
target_to_source_header_required: Option<TestTargetHeaderId>,
|
||||
target_to_source_header_requirements: Vec<TestTargetHeaderId>,
|
||||
source_to_target_header_required: Option<TestSourceHeaderId>,
|
||||
source_to_target_header_requirements: Vec<TestSourceHeaderId>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -582,9 +584,10 @@ pub(crate) mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn activate_target_to_source_headers_relay(&self, activate: bool) {
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<TestMessageLane>) {
|
||||
let mut data = self.data.lock();
|
||||
data.is_target_to_source_headers_relay_activated = activate;
|
||||
data.target_to_source_header_required = Some(id);
|
||||
data.target_to_source_header_requirements.push(id);
|
||||
(self.tick)(&mut *data);
|
||||
}
|
||||
}
|
||||
@@ -686,9 +689,10 @@ pub(crate) mod tests {
|
||||
Ok(nonces)
|
||||
}
|
||||
|
||||
async fn activate_source_to_target_headers_relay(&self, activate: bool) {
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<TestMessageLane>) {
|
||||
let mut data = self.data.lock();
|
||||
data.is_source_to_target_headers_relay_activated = activate;
|
||||
data.source_to_target_header_required = Some(id);
|
||||
data.source_to_target_header_requirements.push(id);
|
||||
(self.tick)(&mut *data);
|
||||
}
|
||||
}
|
||||
@@ -806,16 +810,16 @@ pub(crate) mod tests {
|
||||
},
|
||||
Arc::new(|data: &mut TestClientData| {
|
||||
// headers relay must only be started when we need new target headers at source node
|
||||
if data.is_target_to_source_headers_relay_activated {
|
||||
if data.target_to_source_header_required.is_some() {
|
||||
assert!(data.source_state.best_finalized_peer_at_best_self.0 < data.target_state.best_self.0);
|
||||
data.is_target_to_source_headers_relay_activated = false;
|
||||
data.target_to_source_header_required = None;
|
||||
}
|
||||
}),
|
||||
Arc::new(move |data: &mut TestClientData| {
|
||||
// headers relay must only be started when we need new source headers at target node
|
||||
if data.is_target_to_source_headers_relay_activated {
|
||||
if data.source_to_target_header_required.is_some() {
|
||||
assert!(data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_self.0);
|
||||
data.is_target_to_source_headers_relay_activated = false;
|
||||
data.source_to_target_header_required = None;
|
||||
}
|
||||
// syncing source headers -> target chain (all at once)
|
||||
if data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_finalized_self.0 {
|
||||
@@ -837,7 +841,7 @@ pub(crate) mod tests {
|
||||
HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.0 + 1);
|
||||
data.source_state.best_finalized_self = data.source_state.best_self;
|
||||
}
|
||||
// if source has received all messages receiving confirmations => increase source block so that confirmations may be sent
|
||||
// if source has received all messages receiving confirmations => stop
|
||||
if data.source_latest_confirmed_received_nonce == 10 {
|
||||
exit_sender.unbounded_send(()).unwrap();
|
||||
}
|
||||
@@ -853,5 +857,9 @@ pub(crate) mod tests {
|
||||
assert_eq!(result.submitted_messages_proofs[1].0, 5..=8);
|
||||
assert_eq!(result.submitted_messages_proofs[2].0, 9..=10);
|
||||
assert!(!result.submitted_messages_receiving_proofs.is_empty());
|
||||
|
||||
// check that we have at least once required new source->target or target->source headers
|
||||
assert!(!result.target_to_source_header_requirements.is_empty());
|
||||
assert!(!result.source_to_target_header_requirements.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +166,8 @@ where
|
||||
type Error = C::Error;
|
||||
type TargetNoncesData = DeliveryRaceTargetNoncesData;
|
||||
|
||||
async fn require_more_source_headers(&self, activate: bool) {
|
||||
self.client.activate_source_to_target_headers_relay(activate).await
|
||||
async fn require_source_header(&self, id: SourceHeaderIdOf<P>) {
|
||||
self.client.require_source_header_on_target(id).await
|
||||
}
|
||||
|
||||
async fn nonces(
|
||||
@@ -291,6 +291,10 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M
|
||||
self.strategy.is_empty()
|
||||
}
|
||||
|
||||
fn required_source_header_at_target(&self, current_best: &SourceHeaderIdOf<P>) -> Option<SourceHeaderIdOf<P>> {
|
||||
self.strategy.required_source_header_at_target(current_best)
|
||||
}
|
||||
|
||||
fn best_at_source(&self) -> Option<MessageNonce> {
|
||||
self.strategy.best_at_source()
|
||||
}
|
||||
|
||||
@@ -123,8 +123,9 @@ pub trait TargetClient<P: MessageRace> {
|
||||
/// Type of the additional data from the target client, used by the race.
|
||||
type TargetNoncesData: std::fmt::Debug;
|
||||
|
||||
/// Ask headers relay to relay more headers from race source to race target.
|
||||
async fn require_more_source_headers(&self, activate: bool);
|
||||
/// Ask headers relay to relay finalized headers up to (and including) given header
|
||||
/// from race source to race target.
|
||||
async fn require_source_header(&self, id: P::SourceHeaderId);
|
||||
|
||||
/// Return nonces that are known to the target client.
|
||||
async fn nonces(
|
||||
@@ -152,6 +153,8 @@ pub trait RaceStrategy<SourceHeaderId, TargetHeaderId, Proof>: Debug {
|
||||
|
||||
/// Should return true if nothing has to be synced.
|
||||
fn is_empty(&self) -> bool;
|
||||
/// Return id of source header that is required to be on target to continue synchronization.
|
||||
fn required_source_header_at_target(&self, current_best: &SourceHeaderId) -> Option<SourceHeaderId>;
|
||||
/// Return best nonce at source node.
|
||||
///
|
||||
/// `Some` is returned only if we are sure that the value is greater or equal
|
||||
@@ -219,7 +222,6 @@ pub async fn run<P: MessageRace, SC: SourceClient<P>, TC: TargetClient<P>>(
|
||||
TargetNoncesData = TC::TargetNoncesData,
|
||||
>,
|
||||
) -> Result<(), FailedClient> {
|
||||
let mut is_strategy_empty = true;
|
||||
let mut progress_context = Instant::now();
|
||||
let mut race_state = RaceState::default();
|
||||
let mut stall_countdown = Instant::now();
|
||||
@@ -307,6 +309,15 @@ pub async fn run<P: MessageRace, SC: SourceClient<P>, TC: TargetClient<P>>(
|
||||
async_std::task::sleep,
|
||||
|| format!("Error retrieving nonces from {}", P::source_name()),
|
||||
).fail_if_connection_error(FailedClient::Source)?;
|
||||
|
||||
// ask for more headers if we have nonces to deliver and required headers are missing
|
||||
let required_source_header_id = race_state
|
||||
.best_finalized_source_header_id_at_best_target
|
||||
.as_ref()
|
||||
.and_then(|best|strategy.required_source_header_at_target(best));
|
||||
if let Some(required_source_header_id) = required_source_header_id {
|
||||
race_target.require_source_header(required_source_header_id).await;
|
||||
}
|
||||
},
|
||||
nonces = target_best_nonces => {
|
||||
target_best_nonces_required = false;
|
||||
@@ -408,13 +419,6 @@ pub async fn run<P: MessageRace, SC: SourceClient<P>, TC: TargetClient<P>>(
|
||||
|
||||
progress_context = print_race_progress::<P, _>(progress_context, &strategy);
|
||||
|
||||
// ask for more headers if we have nonces to deliver
|
||||
let prev_is_strategy_empty = is_strategy_empty;
|
||||
is_strategy_empty = strategy.is_empty();
|
||||
if is_strategy_empty != prev_is_strategy_empty {
|
||||
race_target.require_more_source_headers(!is_strategy_empty).await;
|
||||
}
|
||||
|
||||
if stall_countdown.elapsed() > stall_timeout {
|
||||
log::warn!(
|
||||
target: "bridge",
|
||||
|
||||
@@ -159,8 +159,8 @@ where
|
||||
type Error = C::Error;
|
||||
type TargetNoncesData = ();
|
||||
|
||||
async fn require_more_source_headers(&self, activate: bool) {
|
||||
self.client.activate_target_to_source_headers_relay(activate).await
|
||||
async fn require_source_header(&self, id: TargetHeaderIdOf<P>) {
|
||||
self.client.require_target_header_on_source(id).await
|
||||
}
|
||||
|
||||
async fn nonces(
|
||||
|
||||
@@ -162,6 +162,15 @@ where
|
||||
self.source_queue.is_empty()
|
||||
}
|
||||
|
||||
fn required_source_header_at_target(
|
||||
&self,
|
||||
current_best: &HeaderId<SourceHeaderHash, SourceHeaderNumber>,
|
||||
) -> Option<HeaderId<SourceHeaderHash, SourceHeaderNumber>> {
|
||||
self.source_queue
|
||||
.back()
|
||||
.and_then(|(h, _)| if h.0 > current_best.0 { Some(h.clone()) } else { None })
|
||||
}
|
||||
|
||||
fn best_at_source(&self) -> Option<MessageNonce> {
|
||||
let best_in_queue = self.source_queue.back().map(|(_, range)| range.end());
|
||||
match (best_in_queue, self.best_target_nonce) {
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::message_lane::MessageLane;
|
||||
use crate::message_lane_loop::{SourceClientState, TargetClientState};
|
||||
|
||||
use bp_messages::MessageNonce;
|
||||
use relay_utils::metrics::{register, GaugeVec, Metrics, Opts, Registry, U64};
|
||||
use relay_utils::metrics::{metric_name, register, GaugeVec, Opts, PrometheusError, Registry, U64};
|
||||
|
||||
/// Message lane relay metrics.
|
||||
///
|
||||
@@ -34,25 +34,28 @@ pub struct MessageLaneLoopMetrics {
|
||||
lane_state_nonces: GaugeVec<U64>,
|
||||
}
|
||||
|
||||
impl Metrics for MessageLaneLoopMetrics {
|
||||
fn register(&self, registry: &Registry) -> Result<(), String> {
|
||||
register(self.best_block_numbers.clone(), registry).map_err(|e| e.to_string())?;
|
||||
register(self.lane_state_nonces.clone(), registry).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MessageLaneLoopMetrics {
|
||||
fn default() -> Self {
|
||||
MessageLaneLoopMetrics {
|
||||
best_block_numbers: GaugeVec::new(
|
||||
Opts::new("best_block_numbers", "Best finalized block numbers"),
|
||||
&["type"],
|
||||
)
|
||||
.expect("metric is static and thus valid; qed"),
|
||||
lane_state_nonces: GaugeVec::new(Opts::new("lane_state_nonces", "Nonces of the lane state"), &["type"])
|
||||
.expect("metric is static and thus valid; qed"),
|
||||
}
|
||||
impl MessageLaneLoopMetrics {
|
||||
/// Create and register messages loop metrics.
|
||||
pub fn new(registry: &Registry, prefix: Option<&str>) -> Result<Self, PrometheusError> {
|
||||
Ok(MessageLaneLoopMetrics {
|
||||
best_block_numbers: register(
|
||||
GaugeVec::new(
|
||||
Opts::new(
|
||||
metric_name(prefix, "best_block_numbers"),
|
||||
"Best finalized block numbers",
|
||||
),
|
||||
&["type"],
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
lane_state_nonces: register(
|
||||
GaugeVec::new(
|
||||
Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"),
|
||||
&["type"],
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user