@@ -318,16 +318,31 @@ where
318318 & self ,
319319 current_best : & SourceHeaderIdOf < P > ,
320320 ) -> Option < SourceHeaderIdOf < P > > {
321+ let has_nonces_to_deliver = !self . strategy . is_empty ( ) ;
321322 let header_required_for_messages_delivery =
322323 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 ( ) ) ;
325329 match (
330+ has_nonces_to_deliver,
326331 header_required_for_messages_delivery,
327332 header_required_for_reward_confirmations_delivery,
328333 ) {
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 ,
331346 }
332347 }
333348
@@ -926,38 +941,58 @@ mod tests {
926941 // - all messages [20; 23] have been generated at source block#1;
927942 let ( mut state, mut strategy) = prepare_strategy ( ) ;
928943 //
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
932945 assert_eq ! (
933946 strategy. select_nonces_to_deliver( state. clone( ) ) . await ,
934- Some ( ( ( 20 ..=21 ) , proof_parameters( false , 2 ) ) )
947+ Some ( ( ( 20 ..=23 ) , proof_parameters( false , 4 ) ) )
935948 ) ;
936949 strategy. finalized_target_nonces_updated (
937950 TargetClientNonces {
938- latest_nonce : 21 ,
951+ latest_nonce : 23 ,
939952 nonces_data : DeliveryRaceTargetNoncesData {
940953 confirmed_nonce : 19 ,
941954 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 ,
946959 } ,
947960 } ,
948961 } ,
949962 & mut state,
950963 ) ;
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 ) ) ;
958970 //
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 ) ;
960973 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 ) ;
961996 }
962997
963998 #[ async_std:: test]
@@ -985,4 +1020,38 @@ mod tests {
9851020 Some ( ( ( 20 ..=24 ) , proof_parameters( false , 5 ) ) )
9861021 ) ;
9871022 }
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+ }
9881057}
0 commit comments