@@ -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 to that node. This should never happen, but with multiple codepaths
1789
+ /// processing channels we've had issues here in the past, so in debug-mode we track it and
1790
+ /// 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
///
@@ -2425,6 +2431,19 @@ where L::Target: Logger {
2425
2431
// We "return" whether we updated the path at the end, and how much we can route via
2426
2432
// this channel, via this:
2427
2433
let mut hop_contribution_amt_msat = None ;
2434
+
2435
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2436
+ if let Some ( counter) = $candidate. target_node_counter( ) {
2437
+ // Once we are adding paths backwards from a given target, we've sepected the best
2438
+ // path from that target to the destination and it should no longer change. We thus
2439
+ // set the best-path selected flag and check that it doesn't change below.
2440
+ if let Some ( node) = & mut dist[ counter as usize ] {
2441
+ node. best_path_from_hop_selected = true ;
2442
+ } else if counter != payee_node_counter {
2443
+ panic!( "No dist entry for target node counter {}" , counter) ;
2444
+ }
2445
+ }
2446
+
2428
2447
// Channels to self should not be used. This is more of belt-and-suspenders, because in
2429
2448
// practice these cases should be caught earlier:
2430
2449
// - for regular channels at channel announcement (TODO)
@@ -2589,6 +2608,8 @@ where L::Target: Logger {
2589
2608
was_processed: false ,
2590
2609
is_first_hop_target: false ,
2591
2610
is_last_hop_target: false ,
2611
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2612
+ best_path_from_hop_selected: false ,
2592
2613
value_contribution_msat,
2593
2614
} ) ;
2594
2615
dist_entry. as_mut( ) . unwrap( )
@@ -2669,6 +2690,11 @@ where L::Target: Logger {
2669
2690
|| ( new_cost == old_cost && old_entry. value_contribution_msat < value_contribution_msat) ;
2670
2691
2671
2692
if !old_entry. was_processed && should_replace {
2693
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2694
+ {
2695
+ assert!( !old_entry. best_path_from_hop_selected) ;
2696
+ }
2697
+
2672
2698
let new_graph_node = RouteGraphNode {
2673
2699
node_id: src_node_id,
2674
2700
node_counter: src_node_counter,
@@ -2872,6 +2898,8 @@ where L::Target: Logger {
2872
2898
is_first_hop_target : true ,
2873
2899
is_last_hop_target : false ,
2874
2900
value_contribution_msat : 0 ,
2901
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2902
+ best_path_from_hop_selected : false ,
2875
2903
} ) ;
2876
2904
}
2877
2905
for ( target_node_counter, candidates) in last_hop_candidates. iter ( ) {
@@ -2899,6 +2927,8 @@ where L::Target: Logger {
2899
2927
is_first_hop_target : false ,
2900
2928
is_last_hop_target : true ,
2901
2929
value_contribution_msat : 0 ,
2930
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2931
+ best_path_from_hop_selected : false ,
2902
2932
} ) ;
2903
2933
}
2904
2934
}
0 commit comments