@@ -1437,7 +1437,7 @@ impl<'a> CandidateRouteHop<'a> {
1437
1437
}
1438
1438
}
1439
1439
1440
- #[ inline]
1440
+ #[ inline( always ) ]
1441
1441
fn src_node_counter ( & self ) -> u32 {
1442
1442
match self {
1443
1443
CandidateRouteHop :: FirstHop ( hop) => hop. payer_node_counter ,
@@ -1772,6 +1772,14 @@ struct PathBuildingHop<'a> {
1772
1772
/// decrease as well. Thus, we have to explicitly track which nodes have been processed and
1773
1773
/// avoid processing them again.
1774
1774
was_processed : bool ,
1775
+ /// When processing a node as the next best-score candidate, we want to quickly check if it is
1776
+ /// a direct counterparty of ours, using our local channel information immediately if we can.
1777
+ ///
1778
+ /// In order to do so efficiently, we cache whether a node is a direct counterparty here at the
1779
+ /// start of a route-finding pass. Unlike all other fields in this struct, this field is never
1780
+ /// updated after being initialized - it is set at the start of a route-finding pass and only
1781
+ /// read thereafter.
1782
+ is_first_hop_target : bool ,
1775
1783
/// Used to compare channels when choosing the for routing.
1776
1784
/// Includes paying for the use of a hop and the following hops, as well as
1777
1785
/// an estimated cost of reaching this hop.
@@ -1810,6 +1818,7 @@ impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
1810
1818
. field ( "source_node_id" , & self . candidate . source ( ) )
1811
1819
. field ( "target_node_id" , & self . candidate . target ( ) )
1812
1820
. field ( "short_channel_id" , & self . candidate . short_channel_id ( ) )
1821
+ . field ( "is_first_hop_target" , & self . is_first_hop_target )
1813
1822
. field ( "total_fee_msat" , & self . total_fee_msat )
1814
1823
. field ( "next_hops_fee_msat" , & self . next_hops_fee_msat )
1815
1824
. field ( "hop_use_fee_msat" , & self . hop_use_fee_msat )
@@ -2383,6 +2392,8 @@ where L::Target: Logger {
2383
2392
// if the amount being transferred over this path is lower.
2384
2393
// We do this for now, but this is a subject for removal.
2385
2394
if let Some ( mut available_value_contribution_msat) = htlc_maximum_msat. checked_sub( $next_hops_fee_msat) {
2395
+ let cltv_expiry_delta = $candidate. cltv_expiry_delta( ) ;
2396
+ let htlc_minimum_msat = $candidate. htlc_minimum_msat( ) ;
2386
2397
let used_liquidity_msat = used_liquidities
2387
2398
. get( & $candidate. id( ) )
2388
2399
. map_or( 0 , |used_liquidity_msat| {
@@ -2406,7 +2417,7 @@ where L::Target: Logger {
2406
2417
. checked_sub( 2 * MEDIAN_HOP_CLTV_EXPIRY_DELTA )
2407
2418
. unwrap_or( payment_params. max_total_cltv_expiry_delta - final_cltv_expiry_delta) ;
2408
2419
let hop_total_cltv_delta = ( $next_hops_cltv_delta as u32 )
2409
- . saturating_add( $candidate . cltv_expiry_delta( ) ) ;
2420
+ . saturating_add( cltv_expiry_delta) ;
2410
2421
let exceeds_cltv_delta_limit = hop_total_cltv_delta > max_total_cltv_expiry_delta;
2411
2422
2412
2423
let value_contribution_msat = cmp:: min( available_value_contribution_msat, $next_hops_value_contribution) ;
@@ -2417,13 +2428,13 @@ where L::Target: Logger {
2417
2428
None => unreachable!( ) ,
2418
2429
} ;
2419
2430
#[ allow( unused_comparisons) ] // $next_hops_path_htlc_minimum_msat is 0 in some calls so rustc complains
2420
- let over_path_minimum_msat = amount_to_transfer_over_msat >= $candidate . htlc_minimum_msat( ) &&
2431
+ let over_path_minimum_msat = amount_to_transfer_over_msat >= htlc_minimum_msat &&
2421
2432
amount_to_transfer_over_msat >= $next_hops_path_htlc_minimum_msat;
2422
2433
2423
2434
#[ allow( unused_comparisons) ] // $next_hops_path_htlc_minimum_msat is 0 in some calls so rustc complains
2424
2435
let may_overpay_to_meet_path_minimum_msat =
2425
- ( ( amount_to_transfer_over_msat < $candidate . htlc_minimum_msat( ) &&
2426
- recommended_value_msat >= $candidate . htlc_minimum_msat( ) ) ||
2436
+ ( ( amount_to_transfer_over_msat < htlc_minimum_msat &&
2437
+ recommended_value_msat >= htlc_minimum_msat) ||
2427
2438
( amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
2428
2439
recommended_value_msat >= $next_hops_path_htlc_minimum_msat) ) ;
2429
2440
@@ -2493,12 +2504,14 @@ where L::Target: Logger {
2493
2504
// payment path (upstream to the payee). To avoid that, we recompute
2494
2505
// path fees knowing the final path contribution after constructing it.
2495
2506
let curr_min = cmp:: max(
2496
- $next_hops_path_htlc_minimum_msat, $candidate . htlc_minimum_msat( )
2507
+ $next_hops_path_htlc_minimum_msat, htlc_minimum_msat
2497
2508
) ;
2498
- let path_htlc_minimum_msat = compute_fees_saturating( curr_min, $candidate. fees( ) )
2509
+ let candidate_fees = $candidate. fees( ) ;
2510
+ let src_node_counter = $candidate. src_node_counter( ) ;
2511
+ let path_htlc_minimum_msat = compute_fees_saturating( curr_min, candidate_fees)
2499
2512
. saturating_add( curr_min) ;
2500
2513
2501
- let dist_entry = & mut dist[ $candidate . src_node_counter( ) as usize ] ;
2514
+ let dist_entry = & mut dist[ src_node_counter as usize ] ;
2502
2515
let old_entry = if let Some ( hop) = dist_entry {
2503
2516
hop
2504
2517
} else {
@@ -2516,6 +2529,7 @@ where L::Target: Logger {
2516
2529
path_htlc_minimum_msat,
2517
2530
path_penalty_msat: u64 :: max_value( ) ,
2518
2531
was_processed: false ,
2532
+ is_first_hop_target: false ,
2519
2533
#[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2520
2534
value_contribution_msat,
2521
2535
} ) ;
@@ -2540,7 +2554,7 @@ where L::Target: Logger {
2540
2554
if src_node_id != our_node_id {
2541
2555
// Note that `u64::max_value` means we'll always fail the
2542
2556
// `old_entry.total_fee_msat > total_fee_msat` check below
2543
- hop_use_fee_msat = compute_fees_saturating( amount_to_transfer_over_msat, $candidate . fees ( ) ) ;
2557
+ hop_use_fee_msat = compute_fees_saturating( amount_to_transfer_over_msat, candidate_fees ) ;
2544
2558
total_fee_msat = total_fee_msat. saturating_add( hop_use_fee_msat) ;
2545
2559
}
2546
2560
@@ -2679,12 +2693,14 @@ where L::Target: Logger {
2679
2693
let fee_to_target_msat;
2680
2694
let next_hops_path_htlc_minimum_msat;
2681
2695
let next_hops_path_penalty_msat;
2696
+ let is_first_hop_target;
2682
2697
let skip_node = if let Some ( elem) = & mut dist[ $node. node_counter as usize ] {
2683
2698
let was_processed = elem. was_processed;
2684
2699
elem. was_processed = true ;
2685
2700
fee_to_target_msat = elem. total_fee_msat;
2686
2701
next_hops_path_htlc_minimum_msat = elem. path_htlc_minimum_msat;
2687
2702
next_hops_path_penalty_msat = elem. path_penalty_msat;
2703
+ is_first_hop_target = elem. is_first_hop_target;
2688
2704
was_processed
2689
2705
} else {
2690
2706
// Entries are added to dist in add_entry!() when there is a channel from a node.
@@ -2695,21 +2711,24 @@ where L::Target: Logger {
2695
2711
fee_to_target_msat = 0 ;
2696
2712
next_hops_path_htlc_minimum_msat = 0 ;
2697
2713
next_hops_path_penalty_msat = 0 ;
2714
+ is_first_hop_target = false ;
2698
2715
false
2699
2716
} ;
2700
2717
2701
2718
if !skip_node {
2702
- if let Some ( ( first_channels, peer_node_counter) ) = first_hop_targets. get( & $node_id) {
2703
- for details in first_channels {
2704
- debug_assert_eq!( * peer_node_counter, $node. node_counter) ;
2705
- let candidate = CandidateRouteHop :: FirstHop ( FirstHopCandidate {
2706
- details, payer_node_id: & our_node_id, payer_node_counter,
2707
- target_node_counter: $node. node_counter,
2708
- } ) ;
2709
- add_entry!( & candidate, fee_to_target_msat,
2710
- $next_hops_value_contribution,
2711
- next_hops_path_htlc_minimum_msat, next_hops_path_penalty_msat,
2712
- $next_hops_cltv_delta, $next_hops_path_length) ;
2719
+ if is_first_hop_target {
2720
+ if let Some ( ( first_channels, peer_node_counter) ) = first_hop_targets. get( & $node_id) {
2721
+ for details in first_channels {
2722
+ debug_assert_eq!( * peer_node_counter, $node. node_counter) ;
2723
+ let candidate = CandidateRouteHop :: FirstHop ( FirstHopCandidate {
2724
+ details, payer_node_id: & our_node_id, payer_node_counter,
2725
+ target_node_counter: $node. node_counter,
2726
+ } ) ;
2727
+ add_entry!( & candidate, fee_to_target_msat,
2728
+ $next_hops_value_contribution,
2729
+ next_hops_path_htlc_minimum_msat, next_hops_path_penalty_msat,
2730
+ $next_hops_cltv_delta, $next_hops_path_length) ;
2731
+ }
2713
2732
}
2714
2733
}
2715
2734
@@ -2756,6 +2775,32 @@ where L::Target: Logger {
2756
2775
for e in dist. iter_mut ( ) {
2757
2776
* e = None ;
2758
2777
}
2778
+ for ( _, ( chans, peer_node_counter) ) in first_hop_targets. iter ( ) {
2779
+ // In order to avoid looking up whether each node is a first-hop target, we store a
2780
+ // dummy entry in dist for each first-hop target, allowing us to do this lookup for
2781
+ // free since we're already looking at the `was_processed` flag.
2782
+ //
2783
+ // Note that all the fields (except `is_first_hop_target`) will be overwritten whenever
2784
+ // we find a path to the target, so are left as dummies here.
2785
+ dist[ * peer_node_counter as usize ] = Some ( PathBuildingHop {
2786
+ candidate : CandidateRouteHop :: FirstHop ( FirstHopCandidate {
2787
+ details : & chans[ 0 ] ,
2788
+ payer_node_id : & our_node_id,
2789
+ target_node_counter : u32:: max_value ( ) ,
2790
+ payer_node_counter : u32:: max_value ( ) ,
2791
+ } ) ,
2792
+ fee_msat : 0 ,
2793
+ next_hops_fee_msat : u64:: max_value ( ) ,
2794
+ hop_use_fee_msat : u64:: max_value ( ) ,
2795
+ total_fee_msat : u64:: max_value ( ) ,
2796
+ path_htlc_minimum_msat : u64:: max_value ( ) ,
2797
+ path_penalty_msat : u64:: max_value ( ) ,
2798
+ was_processed : false ,
2799
+ is_first_hop_target : true ,
2800
+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
2801
+ value_contribution_msat : 0 ,
2802
+ } ) ;
2803
+ }
2759
2804
hit_minimum_limit = false ;
2760
2805
2761
2806
// If first hop is a private channel and the only way to reach the payee, this is the only
0 commit comments