@@ -194,6 +194,12 @@ struct PathBuildingHop {
194
194
/// we don't fall below the minimum. Should not be updated manually and
195
195
/// generally should not be accessed.
196
196
htlc_minimum_msat : u64 ,
197
+ /// Keeps track of the minimum value we have to hit on this hop. It is useful for routing,
198
+ /// so that we don't accidentally choose the next hop to be cheaper-but-underpaying-minimum.
199
+ /// The value which has to hit this is hop_use_fee_msat + value_contribution_msat, where
200
+ /// hop_use_fee_msat pays for the following hops, but is deducted on this one.
201
+ /// Should not be updated manually and generally should not be accessed.
202
+ effective_htlc_minimum_msat : u64 ,
197
203
}
198
204
199
205
impl PathBuildingHop {
@@ -508,15 +514,15 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
508
514
// Can't overflow due to how the values were computed right above.
509
515
None => unreachable!( ) ,
510
516
} ;
511
- let over_path_minimum_msat = amount_to_transfer_over_msat >= $directional_info. htlc_minimum_msat &&
512
- amount_to_transfer_over_msat >= $incl_fee_next_hops_htlc_minimum_msat;
513
517
514
518
// If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
515
519
// bother considering this channel.
516
520
// Since we're choosing amount_to_transfer_over_msat as maximum possible, it can
517
521
// be only reduced later (not increased), so this channel should just be skipped
518
522
// as not sufficient.
519
523
// TODO: Explore simply adding fee to hit htlc_minimum_msat
524
+ let effective_htlc_minimum_msat = cmp:: max( $directional_info. htlc_minimum_msat, $incl_fee_next_hops_htlc_minimum_msat) ;
525
+ let over_path_minimum_msat = amount_to_transfer_over_msat >= effective_htlc_minimum_msat;
520
526
if contributes_sufficient_value && over_path_minimum_msat {
521
527
let hm_entry = dist. entry( & $src_node_id) ;
522
528
let old_entry = hm_entry. or_insert_with( || {
@@ -549,6 +555,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
549
555
hop_use_fee_msat: u64 :: max_value( ) ,
550
556
total_fee_msat: u64 :: max_value( ) ,
551
557
htlc_minimum_msat: $directional_info. htlc_minimum_msat,
558
+ effective_htlc_minimum_msat,
552
559
}
553
560
} ) ;
554
561
@@ -638,7 +645,8 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
638
645
old_entry. channel_fees = $directional_info. fees;
639
646
// It's probably fine to replace the old entry, because the new one
640
647
// passed the htlc_minimum-related checks above.
641
- old_entry. htlc_minimum_msat = $directional_info. htlc_minimum_msat;
648
+ old_entry. htlc_minimum_msat = cmp:: max( $directional_info. htlc_minimum_msat, old_entry. htlc_minimum_msat) ;
649
+ old_entry. effective_htlc_minimum_msat = effective_htlc_minimum_msat;
642
650
}
643
651
}
644
652
}
@@ -812,7 +820,35 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
812
820
}
813
821
814
822
new_entry = match dist. remove ( & ordered_hops. last ( ) . unwrap ( ) . route_hop . pubkey ) {
815
- Some ( payment_hop) => payment_hop,
823
+ Some ( payment_hop) => {
824
+ if new_entry. hop_use_fee_msat + value_contribution_msat <
825
+ ordered_hops. last_mut ( ) . unwrap ( ) . effective_htlc_minimum_msat {
826
+ // This could happen if a mismatch happened in add_entry! when
827
+ // there is a path fork: e.g. source-A-B-payee and source-A-C-payee.
828
+ // The mismatch of htlc_min could happen if B is the cheapest path,
829
+ // but while adding A-for-B, A can't hit htlc_minimum_msat.
830
+ // Then, we add A-for-C because it does hit htlc_minimum msat.
831
+ //
832
+ // This block would trigger if after this we choose A-for-C
833
+ // as a way to reach B, and we break from the loop because this
834
+ // path would be invalid otherwise.
835
+ //
836
+ // The actual problem would happen when we propagate fees one hop
837
+ // backward (see below), the A-for-C is not sufficient to hit
838
+ // htlc_minimum_msat anymore.
839
+ //
840
+ // This check here attempts to check the compatibility:
841
+ // (fine if A-for-C just matches following C or overpays for D).
842
+ //
843
+ // TODO. this is a safe approach. It indeed avoids invalid paths,
844
+ // but it also could drop valid ones. Ideally, we should prevent
845
+ // the latter too. Although dropping is rare, because in the example
846
+ // above, C would be dropped from candidates, and then we just have
847
+ // to implement hitting htlc_minimum_msat for B in add_entry.
848
+ break ' paths_collection;
849
+ }
850
+ payment_hop
851
+ }
816
852
None => {
817
853
// If we can't reach a given node, something went wrong
818
854
// during path traverse.
0 commit comments