@@ -203,7 +203,7 @@ where
203203 for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints {
204204 log_trace ! ( logger, "Generating phantom route hints for node {}" ,
205205 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) ;
207207
208208 // If we have any public channel, the route hints from `filter_channels` will be empty.
209209 // In that case we create a RouteHint on which we will push a single hop with the phantom
@@ -485,7 +485,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
485485 invoice = invoice. amount_milli_satoshis ( amt) ;
486486 }
487487
488- let route_hints = filter_channels ( channels, amt_msat, & logger) ;
488+ let route_hints = sort_and_filter_channels ( channels, amt_msat, & logger) ;
489489 for hint in route_hints {
490490 invoice = invoice. private_route ( hint) ;
491491 }
@@ -504,8 +504,8 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
504504 }
505505}
506506
507- /// Filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include
508- /// in the invoice.
507+ /// Filters the `channels` for an invoice, and returns the three corresponding `RouteHint`s
508+ /// with the most inbound capacity to include in the invoice.
509509///
510510/// The filtering is based on the following criteria:
511511/// * Only one channel per counterparty node
@@ -514,7 +514,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
514514/// `is_usable` (i.e. the peer is connected).
515515/// * If any public channel exists, the returned `RouteHint`s will be empty, and the sender will
516516/// need to find the path by looking at the public channels instead
517- fn filter_channels < L : Deref > (
517+ fn sort_and_filter_channels < L : Deref > (
518518 channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > , logger : & L
519519) -> Vec < RouteHint > where L :: Target : Logger {
520520 let mut filtered_channels: HashMap < PublicKey , ChannelDetails > = HashMap :: new ( ) ;
@@ -597,7 +597,7 @@ fn filter_channels<L: Deref>(
597597 // the payment value and where we're currently connected to the channel counterparty.
598598 // Even if we cannot satisfy both goals, always ensure we include *some* hints, preferring
599599 // those which meet at least one criteria.
600- filtered_channels
600+ let mut eligible_channels = filtered_channels
601601 . into_iter ( )
602602 . map ( |( _, channel) | channel)
603603 . filter ( |channel| {
@@ -610,7 +610,7 @@ fn filter_channels<L: Deref>(
610610 // online-ness.
611611 has_enough_capacity
612612 } else if min_capacity_channel_exists {
613- has_enough_capacity
613+ has_enough_capacity
614614 } else if online_channel_exists {
615615 channel. is_usable
616616 } else { true } ;
@@ -629,8 +629,11 @@ fn filter_channels<L: Deref>(
629629
630630 include_channel
631631 } )
632- . map ( route_hint_from_channel)
633- . collect :: < Vec < RouteHint > > ( )
632+ . collect :: < Vec < ChannelDetails > > ( ) ;
633+
634+ // Sort eligible channels by inbound capacity and return the top 3.
635+ eligible_channels. sort_unstable_by ( |a, b| b. inbound_capacity_msat . cmp ( & a. inbound_capacity_msat ) ) ;
636+ eligible_channels. into_iter ( ) . take ( 3 ) . map ( route_hint_from_channel) . collect :: < Vec < RouteHint > > ( )
634637}
635638
636639#[ cfg( test) ]
@@ -852,6 +855,26 @@ mod test {
852855 match_invoice_routes ( Some ( 1_000_000_000 ) , & nodes[ 0 ] , scid_aliases) ;
853856 }
854857
858+ #[ test]
859+ fn test_hints_limited_to_3 ( ) {
860+ let chanmon_cfgs = create_chanmon_cfgs ( 5 ) ;
861+ let node_cfgs = create_node_cfgs ( 5 , & chanmon_cfgs) ;
862+ let node_chanmgrs = create_node_chanmgrs ( 5 , & node_cfgs, & [ None , None , None , None , None ] ) ;
863+ let nodes = create_network ( 5 , & node_cfgs, & node_chanmgrs) ;
864+
865+ let chan_1_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_004 , 0 ) ;
866+ let chan_2_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100_003 , 0 ) ;
867+ let chan_3_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 3 , 0 , 100_002 , 0 ) ;
868+ let _chan_4_0 = create_unannounced_chan_between_nodes_with_value ( & nodes, 4 , 0 , 100_001 , 0 ) ;
869+
870+ let mut scid_aliases = HashSet :: new ( ) ;
871+ scid_aliases. insert ( chan_1_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
872+ scid_aliases. insert ( chan_2_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
873+ scid_aliases. insert ( chan_3_0. 0 . short_channel_id_alias . unwrap ( ) ) ;
874+
875+ match_invoice_routes ( Some ( 500_000 ) , & nodes[ 0 ] , scid_aliases) ;
876+ }
877+
855878 #[ test]
856879 fn test_forwarding_info_not_assigned_channel_excluded_from_hints ( ) {
857880 let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
0 commit comments