@@ -318,16 +318,31 @@ where
318
318
& self ,
319
319
current_best : & SourceHeaderIdOf < P > ,
320
320
) -> Option < SourceHeaderIdOf < P > > {
321
+ let has_nonces_to_deliver = !self . strategy . is_empty ( ) ;
321
322
let header_required_for_messages_delivery =
322
323
self . strategy . required_source_header_at_target ( current_best) ;
323
- let header_required_for_reward_confirmations_delivery =
324
- self . latest_confirmed_nonces_at_source . back ( ) . map ( |( id, _) | id. clone ( ) ) ;
324
+ let header_required_for_reward_confirmations_delivery = self
325
+ . latest_confirmed_nonces_at_source
326
+ . back ( )
327
+ . filter ( |( id, nonce) | * nonce != 0 && id. 0 > current_best. 0 )
328
+ . map ( |( id, _) | id. clone ( ) ) ;
325
329
match (
330
+ has_nonces_to_deliver,
326
331
header_required_for_messages_delivery,
327
332
header_required_for_reward_confirmations_delivery,
328
333
) {
329
- ( Some ( id1) , Some ( id2) ) => Some ( if id1. 0 > id2. 0 { id1 } else { id2 } ) ,
330
- ( a, b) => a. or ( b) ,
334
+ // if we need to delver messages and proof-of-delivery-confirmations, then we need to
335
+ // select the most recent header to avoid extra roundtrips
336
+ ( true , Some ( id1) , Some ( id2) ) => Some ( if id1. 0 > id2. 0 { id1 } else { id2 } ) ,
337
+ // if we only need to deliver messages - fine, let's require some source header
338
+ //
339
+ // if we need new header for proof-of-delivery-confirmations - let's also ask for that.
340
+ // Even though it may require additional header, we'll be sure that we won't block the
341
+ // lane (sometimes we can't deliver messages without proof-of-delivery-confirmations)
342
+ ( true , a, b) => a. or ( b) ,
343
+ // we never submit delivery transaction without messages, so if `has_nonces_to_deliver`
344
+ // if `false`, we don't need any source headers at target
345
+ ( false , _, _) => None ,
331
346
}
332
347
}
333
348
@@ -926,38 +941,58 @@ mod tests {
926
941
// - all messages [20; 23] have been generated at source block#1;
927
942
let ( mut state, mut strategy) = prepare_strategy ( ) ;
928
943
//
929
- // - messages [20; 21] have been delivered, but messages [11; 20] can't be delivered because
930
- // of unrewarded relayers vector capacity;
931
- strategy. max_unconfirmed_nonces_at_target = 2 ;
944
+ // - messages [20; 23] have been delivered
932
945
assert_eq ! (
933
946
strategy. select_nonces_to_deliver( state. clone( ) ) . await ,
934
- Some ( ( ( 20 ..=21 ) , proof_parameters( false , 2 ) ) )
947
+ Some ( ( ( 20 ..=23 ) , proof_parameters( false , 4 ) ) )
935
948
) ;
936
949
strategy. finalized_target_nonces_updated (
937
950
TargetClientNonces {
938
- latest_nonce : 21 ,
951
+ latest_nonce : 23 ,
939
952
nonces_data : DeliveryRaceTargetNoncesData {
940
953
confirmed_nonce : 19 ,
941
954
unrewarded_relayers : UnrewardedRelayersState {
942
- unrewarded_relayer_entries : 2 ,
943
- messages_in_oldest_entry : 2 ,
944
- total_messages : 2 ,
945
- last_delivered_nonce : 19 ,
955
+ unrewarded_relayer_entries : 1 ,
956
+ messages_in_oldest_entry : 4 ,
957
+ total_messages : 4 ,
958
+ last_delivered_nonce : 23 ,
946
959
} ,
947
960
} ,
948
961
} ,
949
962
& mut state,
950
963
) ;
951
- assert_eq ! ( strategy. select_nonces_to_deliver( state) . await , None ) ;
952
- //
953
- // - messages [1; 10] receiving confirmation has been delivered at source block#2;
954
- strategy. source_nonces_updated (
955
- header_id ( 2 ) ,
956
- SourceClientNonces { new_nonces : MessageDetailsMap :: new ( ) , confirmed_nonce : Some ( 21 ) } ,
957
- ) ;
964
+ // nothing needs to be delivered now and we don't need any new headers
965
+ assert_eq ! ( strategy. select_nonces_to_deliver( state. clone( ) ) . await , None ) ;
966
+ assert_eq ! ( strategy. required_source_header_at_target( & header_id( 1 ) ) , None ) ;
967
+
968
+ // now let's generate two more nonces [24; 25] at the soruce;
969
+ strategy. source_nonces_updated ( header_id ( 2 ) , source_nonces ( 24 ..=25 , 19 , 0 ) ) ;
958
970
//
959
- // - so now we'll need to relay source block#11 to be able to accept messages [11; 20].
971
+ // - so now we'll need to relay source block#2 to be able to accept messages [24; 25].
972
+ assert_eq ! ( strategy. select_nonces_to_deliver( state. clone( ) ) . await , None ) ;
960
973
assert_eq ! ( strategy. required_source_header_at_target( & header_id( 1 ) ) , Some ( header_id( 2 ) ) ) ;
974
+
975
+ // let's relay source block#2
976
+ state. best_finalized_source_header_id_at_source = Some ( header_id ( 2 ) ) ;
977
+ state. best_finalized_source_header_id_at_best_target = Some ( header_id ( 2 ) ) ;
978
+ state. best_target_header_id = Some ( header_id ( 2 ) ) ;
979
+ state. best_finalized_target_header_id = Some ( header_id ( 2 ) ) ;
980
+
981
+ // and ask strategy again => still nothing to deliver, because parallel confirmations
982
+ // race need to be pushed further
983
+ assert_eq ! ( strategy. select_nonces_to_deliver( state. clone( ) ) . await , None ) ;
984
+ assert_eq ! ( strategy. required_source_header_at_target( & header_id( 2 ) ) , None ) ;
985
+
986
+ // let's confirm messages [20; 23]
987
+ strategy. source_nonces_updated ( header_id ( 2 ) , source_nonces ( 24 ..=25 , 23 , 0 ) ) ;
988
+
989
+ // and ask strategy again => now we have everything required to deliver remaining
990
+ // [24; 25] nonces and proof of [20; 23] confirmation
991
+ assert_eq ! (
992
+ strategy. select_nonces_to_deliver( state) . await ,
993
+ Some ( ( ( 24 ..=25 ) , proof_parameters( true , 2 ) ) ) ,
994
+ ) ;
995
+ assert_eq ! ( strategy. required_source_header_at_target( & header_id( 2 ) ) , None ) ;
961
996
}
962
997
963
998
#[ async_std:: test]
@@ -985,4 +1020,38 @@ mod tests {
985
1020
Some ( ( ( 20 ..=24 ) , proof_parameters( false , 5 ) ) )
986
1021
) ;
987
1022
}
1023
+
1024
+ #[ test]
1025
+ #[ allow( clippy:: reversed_empty_ranges) ]
1026
+ fn no_source_headers_required_at_target_if_lanes_are_empty ( ) {
1027
+ let mut strategy = TestStrategy {
1028
+ max_unrewarded_relayer_entries_at_target : 4 ,
1029
+ max_unconfirmed_nonces_at_target : 4 ,
1030
+ max_messages_in_single_batch : 4 ,
1031
+ max_messages_weight_in_single_batch : Weight :: from_ref_time ( 4 ) ,
1032
+ max_messages_size_in_single_batch : 4 ,
1033
+ latest_confirmed_nonces_at_source : VecDeque :: new ( ) ,
1034
+ lane_source_client : TestSourceClient :: default ( ) ,
1035
+ lane_target_client : TestTargetClient :: default ( ) ,
1036
+ metrics_msg : None ,
1037
+ target_nonces : None ,
1038
+ strategy : BasicStrategy :: new ( ) ,
1039
+ } ;
1040
+
1041
+ let source_header_id = header_id ( 10 ) ;
1042
+ strategy. source_nonces_updated (
1043
+ source_header_id,
1044
+ // MessageDeliveryRaceSource::nonces returns Some(0), because that's how it is
1045
+ // represented in memory (there's no Options in OutboundLaneState)
1046
+ source_nonces ( 1u64 ..=0u64 , 0 , 0 ) ,
1047
+ ) ;
1048
+
1049
+ // even though `latest_confirmed_nonces_at_source` is not empty, new headers are not
1050
+ // requested
1051
+ assert_eq ! (
1052
+ strategy. latest_confirmed_nonces_at_source,
1053
+ VecDeque :: from( [ ( source_header_id, 0 ) ] )
1054
+ ) ;
1055
+ assert_eq ! ( strategy. required_source_header_at_target( & source_header_id) , None ) ;
1056
+ }
988
1057
}
0 commit comments