@@ -509,7 +509,11 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
509
509
///
510
510
/// The filtering is based on the following criteria:
511
511
/// * Only one channel per counterparty node
512
- /// * Always select the channel with the highest inbound capacity per counterparty node
512
+ /// * If the counterparty has a channel that is above the `min_inbound_capacity_msat` + 10% scaling
513
+ /// factor (to allow some margin for change in inbound), select the channel with the lowest
514
+ /// inbound capacity that is above this threshold.
515
+ /// * If no `min_inbound_capacity_msat` is specified, or the counterparty has no channels above the
516
+ /// minimum + 10% scaling factor, select the channel with the highest inbound capacity per counterparty.
513
517
/// * Prefer channels with capacity at least `min_inbound_capacity_msat` and where the channel
514
518
/// `is_usable` (i.e. the peer is connected).
515
519
/// * If any public channel exists, only public [`RouteHint`]s will be returned.
@@ -570,12 +574,16 @@ fn filter_channels<L: Deref>(
570
574
// If this channel is public and the previous channel is not, ensure we replace the
571
575
// previous channel to avoid announcing non-public channels.
572
576
let new_now_public = channel. is_public && !entry. get ( ) . is_public ;
577
+ // Decide whether we prefer the currently selected channel with the node to the new one,
578
+ // based on their inbound capacity.
579
+ let prefer_current = prefer_current_channel ( min_inbound_capacity_msat, current_max_capacity,
580
+ channel. inbound_capacity_msat ) ;
573
581
// If the public-ness of the channel has not changed (in which case simply defer to
574
- // `new_now_public), and this channel has a greater capacity, prefer to announce
575
- // this channel.
576
- let new_higher_capacity = channel. is_public == entry. get ( ) . is_public &&
577
- channel . inbound_capacity_msat > current_max_capacity ;
578
- if new_now_public || new_higher_capacity {
582
+ // `new_now_public), and this channel has more desirable inbound than the incumbent,
583
+ // prefer to include this channel.
584
+ let new_channel_preferable = channel. is_public == entry. get ( ) . is_public && !prefer_current ;
585
+
586
+ if new_now_public || new_channel_preferable {
579
587
log_trace ! ( logger,
580
588
"Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
581
589
log_pubkey!( channel. counterparty. node_id) ,
@@ -658,6 +666,41 @@ fn filter_channels<L: Deref>(
658
666
. collect :: < Vec < RouteHint > > ( )
659
667
}
660
668
669
+ /// prefer_current_channel chooses a channel to use for route hints between a currently selected and candidate
670
+ /// channel based on the inbound capacity of each channel and the minimum inbound capacity requested for the hints,
671
+ /// returning true if the current channel should be preferred over the candidate channel.
672
+ /// * If no minimum amount is requested, the channel with the most inbound is chosen to maximize the chances that a
673
+ /// payment of any size will succeed.
674
+ /// * If we have channels with inbound above our minimum requested inbound (plus a 10% scaling factor, expressed as a
675
+ /// percentage) then we choose the lowest inbound channel with above this amount. If we have sufficient inbound
676
+ /// channels, we don't want to deplete our larger channels with small payments (the off-chain version of "grinding
677
+ /// our change").
678
+ /// * If no channel above our minimum amount exists, then we just prefer the channel with the most inbound to give
679
+ /// payments the best chance of succeeding in multiple parts.
680
+ fn prefer_current_channel ( min_inbound_capacity_msat : Option < u64 > , current_channel : u64 ,
681
+ candidate_channel : u64 ) -> bool {
682
+
683
+ // If no min amount is given for the hints, err of the side of caution and choose the largest channel inbound to
684
+ // maximize chances of any payment succeeding.
685
+ if min_inbound_capacity_msat. is_none ( ) {
686
+ return current_channel > candidate_channel
687
+ }
688
+
689
+ let scaled_min_inbound = min_inbound_capacity_msat. unwrap ( ) * 110 ;
690
+ let current_sufficient = current_channel * 100 >= scaled_min_inbound;
691
+ let candidate_sufficient = candidate_channel * 100 >= scaled_min_inbound;
692
+
693
+ if current_sufficient && candidate_sufficient {
694
+ return current_channel < candidate_channel
695
+ } else if current_sufficient {
696
+ return true
697
+ } else if candidate_sufficient {
698
+ return false
699
+ }
700
+
701
+ current_channel > candidate_channel
702
+ }
703
+
661
704
#[ cfg( test) ]
662
705
mod test {
663
706
use core:: time:: Duration ;
@@ -676,6 +719,34 @@ mod test {
676
719
use crate :: utils:: create_invoice_from_channelmanager_and_duration_since_epoch;
677
720
use std:: collections:: HashSet ;
678
721
722
+ #[ test]
723
+ fn test_prefer_current_channel ( ) {
724
+ // No minimum, prefer larger candidate channel.
725
+ assert_eq ! ( crate :: utils:: prefer_current_channel( None , 100 , 200 ) , false ) ;
726
+
727
+ // No minimum, prefer larger current channel.
728
+ assert_eq ! ( crate :: utils:: prefer_current_channel( None , 200 , 100 ) , true ) ;
729
+
730
+ // Minimum set, prefer current channel over minimum + buffer.
731
+ assert_eq ! ( crate :: utils:: prefer_current_channel( Some ( 100 ) , 115 , 100 ) , true ) ;
732
+
733
+ // Minimum set, prefer candidate channel over minimum + buffer.
734
+ assert_eq ! ( crate :: utils:: prefer_current_channel( Some ( 100 ) , 105 , 125 ) , false ) ;
735
+
736
+ // Minimum set, both channels sufficient, prefer smaller current channel.
737
+ assert_eq ! ( crate :: utils:: prefer_current_channel( Some ( 100 ) , 115 , 125 ) , true ) ;
738
+
739
+ // Minimum set, both channels sufficient, prefer smaller candidate channel.
740
+ assert_eq ! ( crate :: utils:: prefer_current_channel( Some ( 100 ) , 200 , 160 ) , false ) ;
741
+
742
+ // Minimum set, neither sufficient, prefer larger current channel.
743
+ assert_eq ! ( crate :: utils:: prefer_current_channel( Some ( 200 ) , 100 , 50 ) , true ) ;
744
+
745
+ // Minimum set, neither sufficient, prefer larger candidate channel.
746
+ assert_eq ! ( crate :: utils:: prefer_current_channel( Some ( 200 ) , 100 , 150 ) , false ) ;
747
+ }
748
+
749
+
679
750
#[ test]
680
751
fn test_from_channelmanager ( ) {
681
752
let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
@@ -891,17 +962,19 @@ mod test {
891
962
}
892
963
893
964
#[ test]
894
- fn test_hints_has_only_highest_inbound_capacity_channel ( ) {
965
+ fn test_hints_has_only_lowest_inbound_capacity_channel_above_minimum ( ) {
895
966
let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
896
967
let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
897
968
let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
898
969
let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
899
- let _chan_1_0_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 ) ;
900
- let chan_1_0_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 10_000_000 , 0 ) ;
901
- let _chan_1_0_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 1_000_000 , 0 ) ;
970
+
971
+ let _chan_1_0_inbound_below_amt = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 10_000 , 0 ) ;
972
+ let _chan_1_0_large_inbound_above_amt = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 500_000 , 0 ) ;
973
+ let chan_1_0_low_inbound_above_amt = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 200_000 , 0 ) ;
974
+
902
975
let mut scid_aliases = HashSet :: new ( ) ;
903
- scid_aliases. insert ( chan_1_0_high_inbound_capacity . 0 . short_channel_id_alias . unwrap ( ) ) ;
904
- match_invoice_routes ( Some ( 5000 ) , & nodes[ 0 ] , scid_aliases) ;
976
+ scid_aliases. insert ( chan_1_0_low_inbound_above_amt . 0 . short_channel_id_alias . unwrap ( ) ) ;
977
+ match_invoice_routes ( Some ( 100_000_000 ) , & nodes[ 0 ] , scid_aliases) ;
905
978
}
906
979
907
980
#[ test]
@@ -1474,7 +1547,7 @@ mod test {
1474
1547
1475
1548
#[ test]
1476
1549
#[ cfg( feature = "std" ) ]
1477
- fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
1550
+ fn test_multi_node_hints_has_only_lowest_inbound_channel_above_minimum ( ) {
1478
1551
let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
1479
1552
let seed_1 = [ 42u8 ; 32 ] ;
1480
1553
let seed_2 = [ 43u8 ; 32 ] ;
@@ -1485,17 +1558,17 @@ mod test {
1485
1558
let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
1486
1559
let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
1487
1560
1488
- let _chan_0_1_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 ) ;
1489
- let chan_0_1_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 ) ;
1490
- let _chan_0_1_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
1561
+ let _chan_0_1_below_amt = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 ) ;
1562
+ let _chan_0_1_above_amt_high_inbound = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 500_000 , 0 ) ;
1563
+ let chan_0_1_above_amt_low_inbound = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 180_000 , 0 ) ;
1491
1564
let chan_0_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 ) ;
1492
1565
1493
1566
let mut scid_aliases = HashSet :: new ( ) ;
1494
- scid_aliases. insert ( chan_0_1_high_inbound_capacity . 0 . short_channel_id_alias . unwrap ( ) ) ;
1567
+ scid_aliases. insert ( chan_0_1_above_amt_low_inbound . 0 . short_channel_id_alias . unwrap ( ) ) ;
1495
1568
scid_aliases. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
1496
1569
1497
1570
match_multi_node_invoice_routes (
1498
- Some ( 10_000 ) ,
1571
+ Some ( 100_000_000 ) ,
1499
1572
& nodes[ 1 ] ,
1500
1573
vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
1501
1574
scid_aliases,
0 commit comments