@@ -1442,27 +1442,38 @@ where L::Target: Logger {
1442
1442
// when we want to stop looking for new paths.
1443
1443
let mut already_collected_value_msat = 0 ;
1444
1444
1445
+ macro_rules! sort_first_hop_channels {
1446
+ ( $channels: expr) => {
1447
+ // Sort the first_hops channels to the same node(s) in priority order of which channel we'd
1448
+ // most like to use.
1449
+ //
1450
+ // First, if channels are below `recommended_value_msat`, sort them in descending order,
1451
+ // preferring larger channels to avoid splitting the payment into more MPP parts than is
1452
+ // required.
1453
+ //
1454
+ // Second, because simply always sorting in descending order would always use our largest
1455
+ // available outbound capacity, needlessly fragmenting our available channel capacities,
1456
+ // sort channels above `recommended_value_msat` in ascending order, preferring channels
1457
+ // which have enough, but not too much, capacity for the payment.
1458
+ $channels. sort_unstable_by( |chan_a, chan_b| {
1459
+ let chan_a_outbound_limit_msat = chan_a. next_outbound_htlc_limit_msat
1460
+ . saturating_sub( * used_channel_liquidities. get( & ( chan_a. get_outbound_payment_scid( ) . unwrap( ) ,
1461
+ our_node_pubkey < & chan_a. counterparty. node_id) ) . unwrap_or( & 0 ) ) ;
1462
+ let chan_b_outbound_limit_msat = chan_b. next_outbound_htlc_limit_msat
1463
+ . saturating_sub( * used_channel_liquidities. get( & ( chan_b. get_outbound_payment_scid( ) . unwrap( ) ,
1464
+ our_node_pubkey < & chan_b. counterparty. node_id) ) . unwrap_or( & 0 ) ) ;
1465
+ if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat {
1466
+ // Sort in descending order
1467
+ chan_b_outbound_limit_msat. cmp( & chan_a_outbound_limit_msat)
1468
+ } else {
1469
+ // Sort in ascending order
1470
+ chan_a_outbound_limit_msat. cmp( & chan_b_outbound_limit_msat)
1471
+ }
1472
+ } ) ;
1473
+ }
1474
+ }
1445
1475
for ( _, channels) in first_hop_targets. iter_mut ( ) {
1446
- // Sort the first_hops channels to the same node(s) in priority order of which channel we'd
1447
- // most like to use.
1448
- //
1449
- // First, if channels are below `recommended_value_msat`, sort them in descending order,
1450
- // preferring larger channels to avoid splitting the payment into more MPP parts than is
1451
- // required.
1452
- //
1453
- // Second, because simply always sorting in descending order would always use our largest
1454
- // available outbound capacity, needlessly fragmenting our available channel capacities,
1455
- // sort channels above `recommended_value_msat` in ascending order, preferring channels
1456
- // which have enough, but not too much, capacity for the payment.
1457
- channels. sort_unstable_by ( |chan_a, chan_b| {
1458
- if chan_b. next_outbound_htlc_limit_msat < recommended_value_msat || chan_a. next_outbound_htlc_limit_msat < recommended_value_msat {
1459
- // Sort in descending order
1460
- chan_b. next_outbound_htlc_limit_msat . cmp ( & chan_a. next_outbound_htlc_limit_msat )
1461
- } else {
1462
- // Sort in ascending order
1463
- chan_a. next_outbound_htlc_limit_msat . cmp ( & chan_b. next_outbound_htlc_limit_msat )
1464
- }
1465
- } ) ;
1476
+ sort_first_hop_channels ! ( channels) ;
1466
1477
}
1467
1478
1468
1479
log_trace ! ( logger, "Building path from {} to payer {} for value {} msat." ,
@@ -1871,7 +1882,8 @@ where L::Target: Logger {
1871
1882
. saturating_add ( 1 ) ;
1872
1883
1873
1884
// Searching for a direct channel between last checked hop and first_hop_targets
1874
- if let Some ( first_channels) = first_hop_targets. get ( & NodeId :: from_pubkey ( & prev_hop_id) ) {
1885
+ if let Some ( first_channels) = first_hop_targets. get_mut ( & NodeId :: from_pubkey ( & prev_hop_id) ) {
1886
+ sort_first_hop_channels ! ( first_channels) ;
1875
1887
for details in first_channels {
1876
1888
let first_hop_candidate = CandidateRouteHop :: FirstHop { details } ;
1877
1889
add_entry ! ( first_hop_candidate, our_node_id, NodeId :: from_pubkey( & prev_hop_id) ,
@@ -1910,7 +1922,8 @@ where L::Target: Logger {
1910
1922
// Note that we *must* check if the last hop was added as `add_entry`
1911
1923
// always assumes that the third argument is a node to which we have a
1912
1924
// path.
1913
- if let Some ( first_channels) = first_hop_targets. get ( & NodeId :: from_pubkey ( & hop. src_node_id ) ) {
1925
+ if let Some ( first_channels) = first_hop_targets. get_mut ( & NodeId :: from_pubkey ( & hop. src_node_id ) ) {
1926
+ sort_first_hop_channels ! ( first_channels) ;
1914
1927
for details in first_channels {
1915
1928
let first_hop_candidate = CandidateRouteHop :: FirstHop { details } ;
1916
1929
add_entry ! ( first_hop_candidate, our_node_id,
@@ -6018,12 +6031,9 @@ mod tests {
6018
6031
let route = get_route ( & our_node_id, & payment_params, & network_graph. read_only ( ) ,
6019
6032
Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , amt_msat, Arc :: clone ( & logger) , & scorer, & ( ) ,
6020
6033
& random_seed_bytes) . unwrap ( ) ;
6021
- // TODO: `get_route` returns a suboptimal route here because first hop channels are not
6022
- // resorted on the fly when processing route hints.
6023
- assert_eq ! ( route. paths. len( ) , 3 ) ;
6034
+ assert_eq ! ( route. paths. len( ) , 2 ) ;
6024
6035
assert ! ( route. paths[ 0 ] . hops. last( ) . unwrap( ) . fee_msat <= max_htlc_msat) ;
6025
6036
assert ! ( route. paths[ 1 ] . hops. last( ) . unwrap( ) . fee_msat <= max_htlc_msat) ;
6026
- assert ! ( route. paths[ 2 ] . hops. last( ) . unwrap( ) . fee_msat <= max_htlc_msat) ;
6027
6037
assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
6028
6038
}
6029
6039
0 commit comments