@@ -1198,6 +1198,41 @@ impl fmt::Display for LoggedPayeePubkey {
1198
1198
}
1199
1199
}
1200
1200
1201
+ #[ inline]
1202
+ fn sort_first_hop_channels (
1203
+ channels : & mut Vec < & ChannelDetails > , used_channel_liquidities : & HashMap < ( u64 , bool ) , u64 > ,
1204
+ recommended_value_msat : u64 , our_node_pubkey : & PublicKey
1205
+ ) {
1206
+ // Sort the first_hops channels to the same node(s) in priority order of which channel we'd
1207
+ // most like to use.
1208
+ //
1209
+ // First, if channels are below `recommended_value_msat`, sort them in descending order,
1210
+ // preferring larger channels to avoid splitting the payment into more MPP parts than is
1211
+ // required.
1212
+ //
1213
+ // Second, because simply always sorting in descending order would always use our largest
1214
+ // available outbound capacity, needlessly fragmenting our available channel capacities,
1215
+ // sort channels above `recommended_value_msat` in ascending order, preferring channels
1216
+ // which have enough, but not too much, capacity for the payment.
1217
+ //
1218
+ // Available outbound balances factor in liquidity already reserved for previously found paths.
1219
+ channels. sort_unstable_by ( |chan_a, chan_b| {
1220
+ let chan_a_outbound_limit_msat = chan_a. next_outbound_htlc_limit_msat
1221
+ . saturating_sub ( * used_channel_liquidities. get ( & ( chan_a. get_outbound_payment_scid ( ) . unwrap ( ) ,
1222
+ our_node_pubkey < & chan_a. counterparty . node_id ) ) . unwrap_or ( & 0 ) ) ;
1223
+ let chan_b_outbound_limit_msat = chan_b. next_outbound_htlc_limit_msat
1224
+ . saturating_sub ( * used_channel_liquidities. get ( & ( chan_b. get_outbound_payment_scid ( ) . unwrap ( ) ,
1225
+ our_node_pubkey < & chan_b. counterparty . node_id ) ) . unwrap_or ( & 0 ) ) ;
1226
+ if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat {
1227
+ // Sort in descending order
1228
+ chan_b_outbound_limit_msat. cmp ( & chan_a_outbound_limit_msat)
1229
+ } else {
1230
+ // Sort in ascending order
1231
+ chan_a_outbound_limit_msat. cmp ( & chan_b_outbound_limit_msat)
1232
+ }
1233
+ } ) ;
1234
+ }
1235
+
1201
1236
/// Finds a route from us (payer) to the given target node (payee).
1202
1237
///
1203
1238
/// If the payee provided features in their invoice, they should be provided via `params.payee`.
@@ -1443,26 +1478,8 @@ where L::Target: Logger {
1443
1478
let mut already_collected_value_msat = 0 ;
1444
1479
1445
1480
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
- } ) ;
1481
+ sort_first_hop_channels ( channels, & used_channel_liquidities, recommended_value_msat,
1482
+ our_node_pubkey) ;
1466
1483
}
1467
1484
1468
1485
log_trace ! ( logger, "Building path from {} to payer {} for value {} msat." ,
@@ -1874,7 +1891,9 @@ where L::Target: Logger {
1874
1891
. saturating_add ( 1 ) ;
1875
1892
1876
1893
// Searching for a direct channel between last checked hop and first_hop_targets
1877
- if let Some ( first_channels) = first_hop_targets. get ( & NodeId :: from_pubkey ( & prev_hop_id) ) {
1894
+ if let Some ( first_channels) = first_hop_targets. get_mut ( & NodeId :: from_pubkey ( & prev_hop_id) ) {
1895
+ sort_first_hop_channels ( first_channels, & used_channel_liquidities,
1896
+ recommended_value_msat, our_node_pubkey) ;
1878
1897
for details in first_channels {
1879
1898
let first_hop_candidate = CandidateRouteHop :: FirstHop { details } ;
1880
1899
add_entry ! ( first_hop_candidate, our_node_id, NodeId :: from_pubkey( & prev_hop_id) ,
@@ -1913,7 +1932,9 @@ where L::Target: Logger {
1913
1932
// Note that we *must* check if the last hop was added as `add_entry`
1914
1933
// always assumes that the third argument is a node to which we have a
1915
1934
// path.
1916
- if let Some ( first_channels) = first_hop_targets. get ( & NodeId :: from_pubkey ( & hop. src_node_id ) ) {
1935
+ if let Some ( first_channels) = first_hop_targets. get_mut ( & NodeId :: from_pubkey ( & hop. src_node_id ) ) {
1936
+ sort_first_hop_channels ( first_channels, & used_channel_liquidities,
1937
+ recommended_value_msat, our_node_pubkey) ;
1917
1938
for details in first_channels {
1918
1939
let first_hop_candidate = CandidateRouteHop :: FirstHop { details } ;
1919
1940
add_entry ! ( first_hop_candidate, our_node_id,
@@ -6032,12 +6053,9 @@ mod tests {
6032
6053
let route = get_route ( & our_node_id, & payment_params, & network_graph. read_only ( ) ,
6033
6054
Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , amt_msat, Arc :: clone ( & logger) , & scorer, & ( ) ,
6034
6055
& random_seed_bytes) . unwrap ( ) ;
6035
- // TODO: `get_route` returns a suboptimal route here because first hop channels are not
6036
- // resorted on the fly when processing route hints.
6037
- assert_eq ! ( route. paths. len( ) , 3 ) ;
6056
+ assert_eq ! ( route. paths. len( ) , 2 ) ;
6038
6057
assert ! ( route. paths[ 0 ] . hops. last( ) . unwrap( ) . fee_msat <= max_htlc_msat) ;
6039
6058
assert ! ( route. paths[ 1 ] . hops. last( ) . unwrap( ) . fee_msat <= max_htlc_msat) ;
6040
- assert ! ( route. paths[ 2 ] . hops. last( ) . unwrap( ) . fee_msat <= max_htlc_msat) ;
6041
6059
assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
6042
6060
}
6043
6061
0 commit comments