From 978de95938aa91f42a98309c734fd720f19f2886 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky <svyatonik@gmail.com> Date: Thu, 22 Apr 2021 17:54:21 +0300 Subject: [PATCH] Fix issue with on-demand headers relay not starting (#921) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * require lane source -> target headers when weknow all headers that have produced messages, but are unable to deliver all messages because of unrewarded relayers vec capacity * Update relays/messages/src/message_race_delivery.rs Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> --- .../relays/messages/src/message_lane_loop.rs | 42 ++++++++------- .../messages/src/message_race_delivery.rs | 53 ++++++++++++++++++- 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index d43fecf9b16..af04bf984e1 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -582,6 +582,9 @@ pub(crate) mod tests { ) -> Result<(), TestError> { let mut data = self.data.lock(); (self.tick)(&mut *data); + data.source_state.best_self = + HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); + data.source_state.best_finalized_self = data.source_state.best_self; data.submitted_messages_receiving_proofs.push(proof); data.source_latest_confirmed_received_nonce = proof; Ok(()) @@ -684,6 +687,7 @@ pub(crate) mod tests { } data.target_state.best_self = HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1); + data.target_state.best_finalized_self = data.target_state.best_self; data.target_latest_received_nonce = *proof.0.end(); if let Some(target_latest_confirmed_received_nonce) = proof.1 { data.target_latest_confirmed_received_nonce = target_latest_confirmed_received_nonce; @@ -812,37 +816,37 @@ pub(crate) mod tests { ..Default::default() }, Arc::new(|data: &mut TestClientData| { + // blocks are produced on every tick + data.source_state.best_self = + HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); + data.source_state.best_finalized_self = data.source_state.best_self; // headers relay must only be started when we need new target headers at source node 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.target_to_source_header_required = None; } + // syncing target headers -> source chain + if let Some(last_requirement) = data.target_to_source_header_requirements.last() { + if *last_requirement != data.source_state.best_finalized_peer_at_best_self { + data.source_state.best_finalized_peer_at_best_self = *last_requirement; + } + } }), Arc::new(move |data: &mut TestClientData| { + // blocks are produced on every tick + data.target_state.best_self = + HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1); + data.target_state.best_finalized_self = data.target_state.best_self; // headers relay must only be started when we need new source headers at target node 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.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 { - data.target_state.best_finalized_peer_at_best_self = data.source_state.best_finalized_self; - } - // syncing source headers -> target chain (all at once) - if data.source_state.best_finalized_peer_at_best_self.0 < data.target_state.best_finalized_self.0 { - data.source_state.best_finalized_peer_at_best_self = data.target_state.best_finalized_self; - } - // if target has received messages batch => increase blocks so that confirmations may be sent - if data.target_latest_received_nonce == 4 - || data.target_latest_received_nonce == 8 - || data.target_latest_received_nonce == 10 - { - data.target_state.best_self = - HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.0 + 1); - data.target_state.best_finalized_self = data.target_state.best_self; - data.source_state.best_self = - 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; + // syncing source headers -> target chain + if let Some(last_requirement) = data.source_to_target_header_requirements.last() { + if *last_requirement != data.target_state.best_finalized_peer_at_best_self { + data.target_state.best_finalized_peer_at_best_self = *last_requirement; + } } // if source has received all messages receiving confirmations => stop if data.source_latest_confirmed_received_nonce == 10 { diff --git a/bridges/relays/messages/src/message_race_delivery.rs b/bridges/relays/messages/src/message_race_delivery.rs index 225c59f23ca..b50b0ffe31b 100644 --- a/bridges/relays/messages/src/message_race_delivery.rs +++ b/bridges/relays/messages/src/message_race_delivery.rs @@ -292,7 +292,16 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M } fn required_source_header_at_target(&self, current_best: &SourceHeaderIdOf<P>) -> Option<SourceHeaderIdOf<P>> { - self.strategy.required_source_header_at_target(current_best) + let header_required_for_messages_delivery = self.strategy.required_source_header_at_target(current_best); + let header_required_for_reward_confirmations_delivery = + self.latest_confirmed_nonces_at_source.back().map(|(id, _)| id.clone()); + match ( + header_required_for_messages_delivery, + header_required_for_reward_confirmations_delivery, + ) { + (Some(id1), Some(id2)) => Some(if id1.0 > id2.0 { id1 } else { id2 }), + (a, b) => a.or(b), + } } fn best_at_source(&self) -> Option<MessageNonce> { @@ -876,4 +885,46 @@ mod tests { Some(((20..=23), proof_parameters(true, 4))) ); } + + #[test] + fn source_header_is_requied_when_confirmations_are_required() { + // let's prepare situation when: + // - all messages [20; 23] have been generated at source block#1; + let (mut state, mut strategy) = prepare_strategy(); + // - messages [20; 21] have been delivered, but messages [11; 20] can't be delivered because of unrewarded + // relayers vector capacity; + strategy.max_unconfirmed_nonces_at_target = 2; + assert_eq!( + strategy.select_nonces_to_deliver(&state), + Some(((20..=21), proof_parameters(false, 2))) + ); + strategy.finalized_target_nonces_updated( + TargetClientNonces { + latest_nonce: 21, + nonces_data: DeliveryRaceTargetNoncesData { + confirmed_nonce: 19, + unrewarded_relayers: UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 2, + total_messages: 2, + }, + }, + }, + &mut state, + ); + assert_eq!(strategy.select_nonces_to_deliver(&state), None); + // - messages [1; 10] receiving confirmation has been delivered at source block#2; + strategy.source_nonces_updated( + header_id(2), + SourceClientNonces { + new_nonces: BTreeMap::new(), + confirmed_nonce: Some(21), + }, + ); + // - so now we'll need to relay source block#11 to be able to accept messages [11; 20]. + assert_eq!( + strategy.required_source_header_at_target(&header_id(1)), + Some(header_id(2)) + ); + } } -- GitLab