@@ -326,7 +326,7 @@ where
326
326
F :: Target : FeeEstimator ,
327
327
L :: Target : Logger ,
328
328
{
329
- let route_hints = filter_channels ( channelmanager. list_usable_channels ( ) , amt_msat) ;
329
+ let route_hints = filter_channels ( channelmanager. list_channels ( ) , amt_msat) ;
330
330
331
331
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
332
332
// supply.
@@ -377,16 +377,18 @@ where
377
377
/// The filtering is based on the following criteria:
378
378
/// * Only one channel per counterparty node
379
379
/// * Always select the channel with the highest inbound capacity per counterparty node
380
- /// * Filter out channels with a lower inbound capacity than `min_inbound_capacity_msat`, if any
381
- /// channel with a higher or equal inbound capacity than `min_inbound_capacity_msat` exists
380
+ /// * Prefer channels with capacity at least `min_inbound_capacity_msat` and where the channel
381
+ /// `is_usable` (i.e. the peer is connected).
382
382
/// * If any public channel exists, the returned `RouteHint`s will be empty, and the sender will
383
- /// need to find the path by looking at the public channels instead
383
+ /// need to find the path by looking at the public channels instead
384
384
fn filter_channels ( channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > ) -> Vec < RouteHint > {
385
- let mut filtered_channels: HashMap < PublicKey , & ChannelDetails > = HashMap :: new ( ) ;
385
+ let mut filtered_channels: HashMap < PublicKey , ChannelDetails > = HashMap :: new ( ) ;
386
386
let min_inbound_capacity = min_inbound_capacity_msat. unwrap_or ( 0 ) ;
387
387
let mut min_capacity_channel_exists = false ;
388
+ let mut online_channel_exists = false ;
389
+ let mut online_min_capacity_channel_exists = false ;
388
390
389
- for channel in channels. iter ( ) {
391
+ for channel in channels. into_iter ( ) . filter ( |chan| chan . is_channel_ready ) {
390
392
if channel. get_inbound_payment_scid ( ) . is_none ( ) || channel. counterparty . forwarding_info . is_none ( ) {
391
393
continue ;
392
394
}
@@ -399,7 +401,13 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
399
401
400
402
if channel. inbound_capacity_msat >= min_inbound_capacity {
401
403
min_capacity_channel_exists = true ;
402
- } ;
404
+ if channel. is_usable {
405
+ online_min_capacity_channel_exists = true ;
406
+ }
407
+ }
408
+ if channel. is_usable {
409
+ online_channel_exists = true ;
410
+ }
403
411
match filtered_channels. entry ( channel. counterparty . node_id ) {
404
412
hash_map:: Entry :: Occupied ( mut entry) => {
405
413
let current_max_capacity = entry. get ( ) . inbound_capacity_msat ;
@@ -414,7 +422,7 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
414
422
}
415
423
}
416
424
417
- let route_hint_from_channel = |channel : & ChannelDetails | {
425
+ let route_hint_from_channel = |channel : ChannelDetails | {
418
426
let forwarding_info = channel. counterparty . forwarding_info . as_ref ( ) . unwrap ( ) ;
419
427
RouteHint ( vec ! [ RouteHintHop {
420
428
src_node_id: channel. counterparty. node_id,
@@ -427,15 +435,26 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
427
435
htlc_minimum_msat: channel. inbound_htlc_minimum_msat,
428
436
htlc_maximum_msat: channel. inbound_htlc_maximum_msat, } ] )
429
437
} ;
430
- // If all channels are private, return the route hint for the highest inbound capacity channel
431
- // per counterparty node. If channels with an higher inbound capacity than the
432
- // min_inbound_capacity exists, filter out the channels with a lower capacity than that.
438
+ // If all channels are private, prefer to return route hints which have a higher capacity than
439
+ // the payment value and where we're currently connected to the channel counterparty.
440
+ // Even if we cannot satisfy both goals, always ensure we include *some* hints, preferring
441
+ // those which meet at least one criteria.
433
442
filtered_channels. into_iter ( )
434
443
. filter ( |( _counterparty_id, channel) | {
435
- min_capacity_channel_exists && channel. inbound_capacity_msat >= min_inbound_capacity ||
436
- !min_capacity_channel_exists
444
+ if online_min_capacity_channel_exists {
445
+ channel. inbound_capacity_msat >= min_inbound_capacity && channel. is_usable
446
+ } else if min_capacity_channel_exists && online_channel_exists {
447
+ // If there are some online channels and some min_capacity channels, but no
448
+ // online-and-min_capacity channels, just include the min capacity ones and ignore
449
+ // online-ness.
450
+ channel. inbound_capacity_msat >= min_inbound_capacity
451
+ } else if min_capacity_channel_exists {
452
+ channel. inbound_capacity_msat >= min_inbound_capacity
453
+ } else if online_channel_exists {
454
+ channel. is_usable
455
+ } else { true }
437
456
} )
438
- . map ( |( _counterparty_id, channel) | route_hint_from_channel ( & channel) )
457
+ . map ( |( _counterparty_id, channel) | route_hint_from_channel ( channel) )
439
458
. collect :: < Vec < RouteHint > > ( )
440
459
}
441
460
@@ -723,6 +742,35 @@ mod test {
723
742
match_invoice_routes ( Some ( 5000 ) , & nodes[ 0 ] , scid_aliases) ;
724
743
}
725
744
745
+ #[ test]
746
+ fn test_hints_has_only_online_channels ( ) {
747
+ let chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
748
+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
749
+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
750
+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
751
+ let chan_a = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 10_000_000 , 0 , channelmanager:: provided_init_features ( ) , channelmanager:: provided_init_features ( ) ) ;
752
+ let chan_b = create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 10_000_000 , 0 , channelmanager:: provided_init_features ( ) , channelmanager:: provided_init_features ( ) ) ;
753
+ let _chan_c = create_unannounced_chan_between_nodes_with_value ( & nodes, 3 , 0 , 1_000_000 , 0 , channelmanager:: provided_init_features ( ) , channelmanager:: provided_init_features ( ) ) ;
754
+
755
+ // With all peers connected we should get all hints that have sufficient value
756
+ let mut scid_aliases = HashSet :: new ( ) ;
757
+ scid_aliases. insert ( chan_a. 0 . short_channel_id_alias . unwrap ( ) ) ;
758
+ scid_aliases. insert ( chan_b. 0 . short_channel_id_alias . unwrap ( ) ) ;
759
+
760
+ match_invoice_routes ( Some ( 1_000_000_000 ) , & nodes[ 0 ] , scid_aliases. clone ( ) ) ;
761
+
762
+ // With only one sufficient-value peer connected we should only get its hint
763
+ scid_aliases. remove ( & chan_b. 0 . short_channel_id_alias . unwrap ( ) ) ;
764
+ nodes[ 0 ] . node . peer_disconnected ( & nodes[ 2 ] . node . get_our_node_id ( ) , false ) ;
765
+ match_invoice_routes ( Some ( 1_000_000_000 ) , & nodes[ 0 ] , scid_aliases. clone ( ) ) ;
766
+
767
+ // If we don't have any sufficient-value peers connected we should get all hints with
768
+ // sufficient value, even though there is a connected insufficient-value peer.
769
+ scid_aliases. insert ( chan_b. 0 . short_channel_id_alias . unwrap ( ) ) ;
770
+ nodes[ 0 ] . node . peer_disconnected ( & nodes[ 1 ] . node . get_our_node_id ( ) , false ) ;
771
+ match_invoice_routes ( Some ( 1_000_000_000 ) , & nodes[ 0 ] , scid_aliases) ;
772
+ }
773
+
726
774
#[ test]
727
775
fn test_forwarding_info_not_assigned_channel_excluded_from_hints ( ) {
728
776
let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
0 commit comments