Skip to content

Commit 3a658e3

Browse files
authored
Messages relay fixes (#2073)
* removed obsolete check that is superseded by the unblock checks below * if messages race transaction submit has failed, do not restart loop. Instead, wait for new best nonces from target node and retry selection. That's because submit has probably failed because other relayer has submitted same nonces * reset nonces_to_submit and nonces_submitted if at least one of selected/submitted nonces is already at target * removed extra check
1 parent 0022b5a commit 3a658e3

File tree

3 files changed

+66
-52
lines changed

3 files changed

+66
-52
lines changed

relays/messages/src/message_race_delivery.rs

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -343,38 +343,14 @@ where
343343
// There's additional condition in the message delivery race: target would reject messages
344344
// if there are too much unconfirmed messages at the inbound lane.
345345

346-
// The receiving race is responsible to deliver confirmations back to the source chain. So
347-
// if there's a lot of unconfirmed messages, let's wait until it'll be able to do its job.
348-
let latest_received_nonce_at_target = target_nonces.latest_nonce;
349-
let confirmations_missing =
350-
latest_received_nonce_at_target.checked_sub(latest_confirmed_nonce_at_source);
351-
match confirmations_missing {
352-
Some(confirmations_missing)
353-
if confirmations_missing >= self.max_unconfirmed_nonces_at_target =>
354-
{
355-
log::debug!(
356-
target: "bridge",
357-
"Cannot deliver any more messages from {} to {}. Too many unconfirmed nonces \
358-
at target: target.latest_received={:?}, source.latest_confirmed={:?}, max={:?}",
359-
MessageDeliveryRace::<P>::source_name(),
360-
MessageDeliveryRace::<P>::target_name(),
361-
latest_received_nonce_at_target,
362-
latest_confirmed_nonce_at_source,
363-
self.max_unconfirmed_nonces_at_target,
364-
);
365-
366-
return None
367-
},
368-
_ => (),
369-
}
370-
371346
// Ok - we may have new nonces to deliver. But target may still reject new messages, because
372347
// we haven't notified it that (some) messages have been confirmed. So we may want to
373348
// include updated `source.latest_confirmed` in the proof.
374349
//
375350
// Important note: we're including outbound state lane proof whenever there are unconfirmed
376351
// nonces on the target chain. Other strategy is to include it only if it's absolutely
377352
// necessary.
353+
let latest_received_nonce_at_target = target_nonces.latest_nonce;
378354
let latest_confirmed_nonce_at_target = target_nonces.nonces_data.confirmed_nonce;
379355
let outbound_state_proof_required =
380356
latest_confirmed_nonce_at_target < latest_confirmed_nonce_at_source;
@@ -585,6 +561,11 @@ where
585561
self.strategy.source_nonces_updated(at_block, nonces)
586562
}
587563

564+
fn reset_best_target_nonces(&mut self) {
565+
self.target_nonces = None;
566+
self.strategy.reset_best_target_nonces();
567+
}
568+
588569
fn best_target_nonces_updated<RS: RaceState<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>>>(
589570
&mut self,
590571
nonces: TargetClientNonces<DeliveryRaceTargetNoncesData>,
@@ -808,22 +789,6 @@ mod tests {
808789
);
809790
}
810791

811-
#[async_std::test]
812-
async fn message_delivery_strategy_selects_nothing_if_too_many_confirmations_missing() {
813-
let (state, mut strategy) = prepare_strategy();
814-
815-
// if there are already `max_unconfirmed_nonces_at_target` messages on target,
816-
// we need to wait until confirmations will be delivered by receiving race
817-
strategy.latest_confirmed_nonces_at_source = vec![(
818-
header_id(1),
819-
strategy.target_nonces.as_ref().unwrap().latest_nonce -
820-
strategy.max_unconfirmed_nonces_at_target,
821-
)]
822-
.into_iter()
823-
.collect();
824-
assert_eq!(strategy.select_nonces_to_deliver(state).await, None);
825-
}
826-
827792
#[async_std::test]
828793
async fn message_delivery_strategy_includes_outbound_state_proof_when_new_nonces_are_available()
829794
{

relays/messages/src/message_race_loop.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ pub trait RaceStrategy<SourceHeaderId, TargetHeaderId, Proof>: Debug {
195195
at_block: SourceHeaderId,
196196
nonces: SourceClientNonces<Self::SourceNoncesRange>,
197197
);
198+
/// Called when we want to wait until next `best_target_nonces_updated` before selecting
199+
/// any nonces for delivery.
200+
fn reset_best_target_nonces(&mut self);
198201
/// Called when best nonces are updated at target node of the race.
199202
fn best_target_nonces_updated<RS: RaceState<SourceHeaderId, TargetHeaderId>>(
200203
&mut self,
@@ -542,14 +545,22 @@ pub async fn run<P: MessageRace, SC: SourceClient<P>, TC: TargetClient<P>>(
542545
P::target_name(),
543546
);
544547

545-
race_state.reset_nonces_to_submit();
546548
race_state.nonces_submitted = Some(artifacts.nonces);
547549
target_tx_tracker.set(artifacts.tx_tracker.wait().fuse());
548550
},
549551
&mut target_go_offline_future,
550552
async_std::task::sleep,
551553
|| format!("Error submitting proof {}", P::target_name()),
552-
).fail_if_error(FailedClient::Target).map(|_| true)?;
554+
).fail_if_connection_error(FailedClient::Target)?;
555+
556+
// in any case - we don't need to retry submitting the same nonces again until
557+
// we read nonces from the target client
558+
race_state.reset_nonces_to_submit();
559+
// if we have failed to submit transaction AND that is not the connection issue,
560+
// then we need to read best target nonces before selecting nonces again
561+
if !target_client_is_online {
562+
strategy.reset_best_target_nonces();
563+
}
553564
},
554565
target_transaction_status = target_tx_tracker => {
555566
match (target_transaction_status, race_state.nonces_submitted.as_ref()) {
@@ -699,7 +710,13 @@ pub async fn run<P: MessageRace, SC: SourceClient<P>, TC: TargetClient<P>>(
699710
.fuse(),
700711
);
701712
} else if let Some(source_required_header) = source_required_header.clone() {
702-
log::debug!(target: "bridge", "Going to require {} header {:?} at {}", P::source_name(), source_required_header, P::target_name());
713+
log::debug!(
714+
target: "bridge",
715+
"Going to require {} header {:?} at {}",
716+
P::source_name(),
717+
source_required_header,
718+
P::target_name(),
719+
);
703720
target_require_source_header
704721
.set(race_target.require_source_header(source_required_header).fuse());
705722
} else if target_best_nonces_required {

relays/messages/src/message_race_strategy.rs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ impl<
254254
)
255255
}
256256

257+
fn reset_best_target_nonces(&mut self) {
258+
self.best_target_nonce = None;
259+
}
260+
257261
fn best_target_nonces_updated<
258262
RS: RaceState<
259263
HeaderId<SourceHeaderHash, SourceHeaderNumber>,
@@ -266,19 +270,37 @@ impl<
266270
) {
267271
let nonce = nonces.latest_nonce;
268272

273+
// if **some** of nonces that we have selected to submit already present at the
274+
// target chain => select new nonces
269275
let need_to_select_new_nonces = race_state
270276
.nonces_to_submit()
271-
.map(|nonces| *nonces.end() <= nonce)
277+
.map(|nonces| nonce >= *nonces.start())
272278
.unwrap_or(false);
273279
if need_to_select_new_nonces {
280+
log::trace!(
281+
target: "bridge",
282+
"Latest nonce at target is {}. Clearing nonces to submit: {:?}",
283+
nonce,
284+
race_state.nonces_to_submit(),
285+
);
286+
274287
race_state.reset_nonces_to_submit();
275288
}
276289

290+
// if **some** of nonces that we have submitted already present at the
291+
// target chain => select new nonces
277292
let need_new_nonces_to_submit = race_state
278293
.nonces_submitted()
279-
.map(|nonces| *nonces.end() <= nonce)
294+
.map(|nonces| nonce >= *nonces.start())
280295
.unwrap_or(false);
281296
if need_new_nonces_to_submit {
297+
log::trace!(
298+
target: "bridge",
299+
"Latest nonce at target is {}. Clearing submitted nonces: {:?}",
300+
nonce,
301+
race_state.nonces_submitted(),
302+
);
303+
282304
race_state.reset_nonces_submitted();
283305
}
284306

@@ -415,21 +437,31 @@ mod tests {
415437
let mut state = TestRaceStateImpl::default();
416438
let mut strategy = BasicStrategy::<TestMessageLane>::new();
417439
state.nonces_to_submit = Some((header_id(1), 5..=10, (5..=10, None)));
418-
strategy.best_target_nonces_updated(target_nonces(7), &mut state);
440+
// we are going to submit 5..=10, so having latest nonce 4 at target is fine
441+
strategy.best_target_nonces_updated(target_nonces(4), &mut state);
419442
assert!(state.nonces_to_submit.is_some());
420-
strategy.best_target_nonces_updated(target_nonces(10), &mut state);
421-
assert!(state.nonces_to_submit.is_none());
443+
// any nonce larger than 4 invalidates the `nonces_to_submit`
444+
for nonce in 5..=11 {
445+
state.nonces_to_submit = Some((header_id(1), 5..=10, (5..=10, None)));
446+
strategy.best_target_nonces_updated(target_nonces(nonce), &mut state);
447+
assert!(state.nonces_to_submit.is_none());
448+
}
422449
}
423450

424451
#[test]
425452
fn submitted_nonces_are_dropped_on_target_nonce_update() {
426453
let mut state = TestRaceStateImpl::default();
427454
let mut strategy = BasicStrategy::<TestMessageLane>::new();
428455
state.nonces_submitted = Some(5..=10);
429-
strategy.best_target_nonces_updated(target_nonces(7), &mut state);
456+
// we have submitted 5..=10, so having latest nonce 4 at target is fine
457+
strategy.best_target_nonces_updated(target_nonces(4), &mut state);
430458
assert!(state.nonces_submitted.is_some());
431-
strategy.best_target_nonces_updated(target_nonces(10), &mut state);
432-
assert!(state.nonces_submitted.is_none());
459+
// any nonce larger than 4 invalidates the `nonces_submitted`
460+
for nonce in 5..=11 {
461+
state.nonces_submitted = Some(5..=10);
462+
strategy.best_target_nonces_updated(target_nonces(nonce), &mut state);
463+
assert!(state.nonces_submitted.is_none());
464+
}
433465
}
434466

435467
#[async_std::test]

0 commit comments

Comments
 (0)