@@ -203,11 +203,11 @@ where
203
203
for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints {
204
204
log_trace ! ( logger, "Generating phantom route hints for node {}" ,
205
205
log_pubkey!( real_node_pubkey) ) ;
206
- let mut route_hints = filter_channels ( channels, amt_msat, & logger) ;
206
+ let mut route_hints = sort_and_filter_channels ( channels, amt_msat, & logger) ;
207
207
208
- // If we have any public channel, the route hints from `filter_channels ` will be empty.
209
- // In that case we create a RouteHint on which we will push a single hop with the phantom
210
- // route into the invoice, and let the sender find the path to the `real_node_pubkey`
208
+ // If we have any public channel, the route hints from `sort_and_filter_channels ` will be
209
+ // empty. In that case we create a RouteHint on which we will push a single hop with the
210
+ // phantom route into the invoice, and let the sender find the path to the `real_node_pubkey`
211
211
// node by looking at our public channels.
212
212
if route_hints. is_empty ( ) {
213
213
route_hints. push ( RouteHint ( vec ! [ ] ) )
@@ -485,7 +485,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
485
485
invoice = invoice. amount_milli_satoshis ( amt) ;
486
486
}
487
487
488
- let route_hints = filter_channels ( channels, amt_msat, & logger) ;
488
+ let route_hints = sort_and_filter_channels ( channels, amt_msat, & logger) ;
489
489
for hint in route_hints {
490
490
invoice = invoice. private_route ( hint) ;
491
491
}
@@ -504,7 +504,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
504
504
}
505
505
}
506
506
507
- /// Filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include
507
+ /// Sorts and filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include
508
508
/// in the invoice.
509
509
///
510
510
/// The filtering is based on the following criteria:
@@ -520,7 +520,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
520
520
/// * If any public, announced, channel exists (i.e. a channel with 7+ confs, to ensure the
521
521
/// announcement has had a chance to propagate), no [`RouteHint`]s will be returned, as the
522
522
/// sender is expected to find the path by looking at the public channels instead.
523
- fn filter_channels < L : Deref > (
523
+ /// * Limited to a total of 3 channels.
524
+ /// * Sorted by lowest inbound capacity if an online channel with the minimum amount requested exists,
525
+ /// otherwise sort by highest inbound capacity to give the payment the best chance of succeeding.
526
+ fn sort_and_filter_channels < L : Deref > (
524
527
channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > , logger : & L
525
528
) -> Vec < RouteHint > where L :: Target : Logger {
526
529
let mut filtered_channels: HashMap < PublicKey , ChannelDetails > = HashMap :: new ( ) ;
@@ -626,7 +629,7 @@ fn filter_channels<L: Deref>(
626
629
// the payment value and where we're currently connected to the channel counterparty.
627
630
// Even if we cannot satisfy both goals, always ensure we include *some* hints, preferring
628
631
// those which meet at least one criteria.
629
- filtered_channels
632
+ let mut eligible_channels = filtered_channels
630
633
. into_iter ( )
631
634
. map ( |( _, channel) | channel)
632
635
. filter ( |channel| {
@@ -663,8 +666,15 @@ fn filter_channels<L: Deref>(
663
666
664
667
include_channel
665
668
} )
666
- . map ( route_hint_from_channel)
667
- . collect :: < Vec < RouteHint > > ( )
669
+ . collect :: < Vec < ChannelDetails > > ( ) ;
670
+
671
+ eligible_channels. sort_unstable_by ( |a, b| {
672
+ if online_min_capacity_channel_exists {
673
+ a. inbound_capacity_msat . cmp ( & b. inbound_capacity_msat )
674
+ } else {
675
+ b. inbound_capacity_msat . cmp ( & a. inbound_capacity_msat )
676
+ } } ) ;
677
+ eligible_channels. into_iter ( ) . take ( 3 ) . map ( route_hint_from_channel) . collect :: < Vec < RouteHint > > ( )
668
678
}
669
679
670
680
/// prefer_current_channel chooses a channel to use for route hints between a currently selected and candidate
@@ -1006,6 +1016,48 @@ mod test {
1006
1016
match_invoice_routes ( Some ( 1_000_000_000 ) , & nodes[ 0 ] , scid_aliases) ;
1007
1017
}
1008
1018
1019
+ #[ test]
1020
+ fn test_insufficient_inbound_sort_by_highest_capacity ( ) {
1021
+ let chanmon_cfgs = create_chanmon_cfgs ( 5 ) ;
1022
+ let node_cfgs = create_node_cfgs ( 5 , & chanmon_cfgs) ;
1023
+ let node_chanmgrs = create_node_chanmgrs ( 5 , & node_cfgs, & [ None , None , None , None , None ] ) ;
1024
+ let nodes = create_network ( 5 , & node_cfgs, & node_chanmgrs) ;
1025
+ let _chan_1_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 ) ;
1026
+ let chan_2_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 200_000 , 0 ) ;
1027
+ let chan_3_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 3 , 0 , 300_000 , 0 ) ;
1028
+ let chan_4_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 4 , 0 , 400_000 , 0 ) ;
1029
+
1030
+ // When no single channel has enough inbound capacity for the payment, we expect the three
1031
+ // highest inbound channels to be chosen.
1032
+ let mut scid_aliases = HashSet :: new ( ) ;
1033
+ scid_aliases. insert ( chan_2_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
1034
+ scid_aliases. insert ( chan_3_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
1035
+ scid_aliases. insert ( chan_4_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
1036
+
1037
+ match_invoice_routes ( Some ( 1_000_000_000 ) , & nodes[ 0 ] , scid_aliases. clone ( ) ) ;
1038
+ }
1039
+
1040
+ #[ test]
1041
+ fn test_sufficient_inbound_sort_by_lowest_capacity ( ) {
1042
+ let chanmon_cfgs = create_chanmon_cfgs ( 5 ) ;
1043
+ let node_cfgs = create_node_cfgs ( 5 , & chanmon_cfgs) ;
1044
+ let node_chanmgrs = create_node_chanmgrs ( 5 , & node_cfgs, & [ None , None , None , None , None ] ) ;
1045
+ let nodes = create_network ( 5 , & node_cfgs, & node_chanmgrs) ;
1046
+ let chan_1_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 ) ;
1047
+ let chan_2_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 200_000 , 0 ) ;
1048
+ let chan_3_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 3 , 0 , 300_000 , 0 ) ;
1049
+ let _chan_4_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 4 , 0 , 400_000 , 0 ) ;
1050
+
1051
+ // When we have channels that have sufficient inbound for the payment, test that we sort
1052
+ // by lowest inbound capacity.
1053
+ let mut scid_aliases = HashSet :: new ( ) ;
1054
+ scid_aliases. insert ( chan_1_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
1055
+ scid_aliases. insert ( chan_2_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
1056
+ scid_aliases. insert ( chan_3_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
1057
+
1058
+ match_invoice_routes ( Some ( 50_000_000 ) , & nodes[ 0 ] , scid_aliases. clone ( ) ) ;
1059
+ }
1060
+
1009
1061
#[ test]
1010
1062
fn test_forwarding_info_not_assigned_channel_excluded_from_hints ( ) {
1011
1063
let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
0 commit comments