@@ -1784,6 +1784,12 @@ struct PathBuildingHop<'a> {
1784
1784
/// decrease as well. Thus, we have to explicitly track which nodes have been processed and
1785
1785
/// avoid processing them again.
1786
1786
was_processed : bool ,
1787
+ /// If we've already processed a channel backwards from a target node, we shouldn't update our
1788
+ /// selected best path from that node to the destination. This should never happen, but with
1789
+ /// multiple codepaths processing channels we've had issues here in the past, so in debug-mode
1790
+ /// we track it and assert on it when processing a node.
1791
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
1792
+ best_path_from_hop_selected : bool ,
1787
1793
/// When processing a node as the next best-score candidate, we want to quickly check if it is
1788
1794
/// a direct counterparty of ours, using our local channel information immediately if we can.
1789
1795
///
@@ -2427,6 +2433,19 @@ where L::Target: Logger {
2427
2433
// We "return" whether we updated the path at the end, and how much we can route via
2428
2434
// this channel, via this:
2429
2435
let mut hop_contribution_amt_msat = None ;
2436
+
2437
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2438
+ if let Some ( counter) = $candidate. target_node_counter( ) {
2439
+ // Once we are adding paths backwards from a given target, we've selected the best
2440
+ // path from that target to the destination and it should no longer change. We thus
2441
+ // set the best-path selected flag and check that it doesn't change below.
2442
+ if let Some ( node) = & mut dist[ counter as usize ] {
2443
+ node. best_path_from_hop_selected = true ;
2444
+ } else if counter != payee_node_counter {
2445
+ panic!( "No dist entry for target node counter {}" , counter) ;
2446
+ }
2447
+ }
2448
+
2430
2449
// Channels to self should not be used. This is more of belt-and-suspenders, because in
2431
2450
// practice these cases should be caught earlier:
2432
2451
// - for regular channels at channel announcement (TODO)
@@ -2591,6 +2610,8 @@ where L::Target: Logger {
2591
2610
was_processed: false ,
2592
2611
is_first_hop_target: false ,
2593
2612
is_last_hop_target: false ,
2613
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2614
+ best_path_from_hop_selected: false ,
2594
2615
value_contribution_msat,
2595
2616
} ) ;
2596
2617
dist_entry. as_mut( ) . unwrap( )
@@ -2671,6 +2692,11 @@ where L::Target: Logger {
2671
2692
|| ( new_cost == old_cost && old_entry. value_contribution_msat < value_contribution_msat) ;
2672
2693
2673
2694
if !old_entry. was_processed && should_replace {
2695
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2696
+ {
2697
+ assert!( !old_entry. best_path_from_hop_selected) ;
2698
+ }
2699
+
2674
2700
let new_graph_node = RouteGraphNode {
2675
2701
node_id: src_node_id,
2676
2702
node_counter: src_node_counter,
@@ -2884,6 +2910,8 @@ where L::Target: Logger {
2884
2910
is_first_hop_target : true ,
2885
2911
is_last_hop_target : false ,
2886
2912
value_contribution_msat : 0 ,
2913
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2914
+ best_path_from_hop_selected : false ,
2887
2915
} ) ;
2888
2916
}
2889
2917
for ( target_node_counter, candidates) in last_hop_candidates. iter ( ) {
@@ -2911,6 +2939,8 @@ where L::Target: Logger {
2911
2939
is_first_hop_target : false ,
2912
2940
is_last_hop_target : true ,
2913
2941
value_contribution_msat : 0 ,
2942
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2943
+ best_path_from_hop_selected : false ,
2914
2944
} ) ;
2915
2945
}
2916
2946
}
0 commit comments