@@ -512,8 +512,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
512
512
/// * Always select the channel with the highest inbound capacity per counterparty node
513
513
/// * Prefer channels with capacity at least `min_inbound_capacity_msat` and where the channel
514
514
/// `is_usable` (i.e. the peer is connected).
515
- /// * If any public channel exists, the returned `RouteHint`s will be empty, and the sender will
516
- /// need to find the path by looking at the public channels instead
515
+ /// * If any public channel exists, only public [`RouteHint`]s will be returned.
516
+ /// * If any public, announced, channel exists (i.e. a channel with 7+ confs, to ensure the
517
+ /// announcement has had a chance to propagate), no [`RouteHint`]s will be returned, as the
518
+ /// sender is expected to find the path by looking at the public channels instead.
517
519
fn filter_channels < L : Deref > (
518
520
channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > , logger : & L
519
521
) -> Vec < RouteHint > where L :: Target : Logger {
@@ -522,6 +524,7 @@ fn filter_channels<L: Deref>(
522
524
let mut min_capacity_channel_exists = false ;
523
525
let mut online_channel_exists = false ;
524
526
let mut online_min_capacity_channel_exists = false ;
527
+ let mut has_pub_unconf_chan = false ;
525
528
526
529
log_trace ! ( logger, "Considering {} channels for invoice route hints" , channels. len( ) ) ;
527
530
for channel in channels. into_iter ( ) . filter ( |chan| chan. is_channel_ready ) {
@@ -531,11 +534,18 @@ fn filter_channels<L: Deref>(
531
534
}
532
535
533
536
if channel. is_public {
534
- // If any public channel exists, return no hints and let the sender
535
- // look at the public channels instead.
536
- log_trace ! ( logger, "Not including channels in invoice route hints on account of public channel {}" ,
537
- log_bytes!( channel. channel_id) ) ;
538
- return vec ! [ ]
537
+ if channel. confirmations . is_some ( ) && channel. confirmations < Some ( 7 ) {
538
+ // If we have a public channel, but it doesn't have enough confirmations to (yet)
539
+ // be in the public network graph (and have gotten a chance to propagate), include
540
+ // route hints but only for public channels to protect private channel privacy.
541
+ has_pub_unconf_chan = true ;
542
+ } else {
543
+ // If any public channel exists, return no hints and let the sender
544
+ // look at the public channels instead.
545
+ log_trace ! ( logger, "Not including channels in invoice route hints on account of public channel {}" ,
546
+ log_bytes!( channel. channel_id) ) ;
547
+ return vec ! [ ]
548
+ }
539
549
}
540
550
541
551
if channel. inbound_capacity_msat >= min_inbound_capacity {
@@ -557,20 +567,32 @@ fn filter_channels<L: Deref>(
557
567
match filtered_channels. entry ( channel. counterparty . node_id ) {
558
568
hash_map:: Entry :: Occupied ( mut entry) => {
559
569
let current_max_capacity = entry. get ( ) . inbound_capacity_msat ;
560
- if channel. inbound_capacity_msat < current_max_capacity {
570
+ // If this channel is public and the previous channel is not, ensure we replace the
571
+ // previous channel to avoid announcing non-public channels.
572
+ let new_now_public = channel. is_public && !entry. get ( ) . is_public ;
573
+ // 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 {
579
+ log_trace ! ( logger,
580
+ "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
581
+ log_pubkey!( channel. counterparty. node_id) ,
582
+ log_bytes!( channel. channel_id) , channel. short_channel_id,
583
+ channel. inbound_capacity_msat,
584
+ log_bytes!( entry. get( ) . channel_id) , entry. get( ) . short_channel_id,
585
+ current_max_capacity) ;
586
+ entry. insert ( channel) ;
587
+ } else {
561
588
log_trace ! ( logger,
562
- "Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints" ,
589
+ "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
563
590
log_pubkey!( channel. counterparty. node_id) ,
564
- log_bytes!( entry. get( ) . channel_id) , current_max_capacity,
565
- log_bytes!( channel. channel_id) , channel. inbound_capacity_msat) ;
566
- continue ;
591
+ log_bytes!( entry. get( ) . channel_id) , entry. get( ) . short_channel_id,
592
+ current_max_capacity,
593
+ log_bytes!( channel. channel_id) , channel. short_channel_id,
594
+ channel. inbound_capacity_msat) ;
567
595
}
568
- log_trace ! ( logger,
569
- "Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints" ,
570
- log_pubkey!( channel. counterparty. node_id) ,
571
- log_bytes!( channel. channel_id) , channel. inbound_capacity_msat,
572
- log_bytes!( entry. get( ) . channel_id) , current_max_capacity) ;
573
- entry. insert ( channel) ;
574
596
}
575
597
hash_map:: Entry :: Vacant ( entry) => {
576
598
entry. insert ( channel) ;
@@ -600,7 +622,12 @@ fn filter_channels<L: Deref>(
600
622
. map ( |( _, channel) | channel)
601
623
. filter ( |channel| {
602
624
let has_enough_capacity = channel. inbound_capacity_msat >= min_inbound_capacity;
603
- let include_channel = if online_min_capacity_channel_exists {
625
+ let include_channel = if has_pub_unconf_chan {
626
+ // If we have a public channel, but it doesn't have enough confirmations to (yet)
627
+ // be in the public network graph (and have gotten a chance to propagate), include
628
+ // route hints but only for public channels to protect private channel privacy.
629
+ channel. is_public
630
+ } else if online_min_capacity_channel_exists {
604
631
has_enough_capacity && channel. is_usable
605
632
} else if min_capacity_channel_exists && online_channel_exists {
606
633
// If there are some online channels and some min_capacity channels, but no
@@ -620,7 +647,7 @@ fn filter_channels<L: Deref>(
620
647
log_trace ! ( logger, "Ignoring channel {} without enough capacity for invoice route hints" ,
621
648
log_bytes!( channel. channel_id) ) ;
622
649
} else {
623
- debug_assert ! ( !channel. is_usable) ;
650
+ debug_assert ! ( !channel. is_usable || ( has_pub_unconf_chan && !channel . is_public ) ) ;
624
651
log_trace ! ( logger, "Ignoring channel {} with disconnected peer" ,
625
652
log_bytes!( channel. channel_id) ) ;
626
653
}
@@ -789,6 +816,63 @@ mod test {
789
816
assert_eq ! ( invoice. payment_hash( ) , & sha256:: Hash :: from_slice( & payment_hash. 0 [ ..] ) . unwrap( ) ) ;
790
817
}
791
818
819
+ #[ test]
820
+ fn test_hints_has_only_public_confd_channels ( ) {
821
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
822
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
823
+ let mut config = test_default_channel_config ( ) ;
824
+ config. channel_handshake_config . minimum_depth = 1 ;
825
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config) , Some ( config) ] ) ;
826
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
827
+
828
+ // Create a private channel with lots of capacity and a lower value public channel (without
829
+ // confirming the funding tx yet).
830
+ let unannounced_scid = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 ) ;
831
+ let conf_tx = create_chan_between_nodes_with_value_init ( & nodes[ 0 ] , & nodes[ 1 ] , 10_000 , 0 ) ;
832
+
833
+ // Before the channel is available, we should include the unannounced_scid.
834
+ let mut scid_aliases = HashSet :: new ( ) ;
835
+ scid_aliases. insert ( unannounced_scid. 0 . short_channel_id_alias . unwrap ( ) ) ;
836
+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
837
+
838
+ // However after we mine the funding tx and exchange channel_ready messages for the public
839
+ // channel we'll immediately switch to including it as a route hint, even though it isn't
840
+ // yet announced.
841
+ let pub_channel_scid = mine_transaction ( & nodes[ 0 ] , & conf_tx) ;
842
+ let node_a_pub_channel_ready = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendChannelReady , nodes[ 1 ] . node. get_our_node_id( ) ) ;
843
+ nodes[ 1 ] . node . handle_channel_ready ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_a_pub_channel_ready) ;
844
+
845
+ assert_eq ! ( mine_transaction( & nodes[ 1 ] , & conf_tx) , pub_channel_scid) ;
846
+ let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
847
+ assert_eq ! ( events. len( ) , 2 ) ;
848
+ if let MessageSendEvent :: SendChannelReady { msg, .. } = & events[ 0 ] {
849
+ nodes[ 0 ] . node . handle_channel_ready ( & nodes[ 1 ] . node . get_our_node_id ( ) , msg) ;
850
+ } else { panic ! ( ) ; }
851
+ if let MessageSendEvent :: SendChannelUpdate { msg, .. } = & events[ 1 ] {
852
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , msg) ;
853
+ } else { panic ! ( ) ; }
854
+
855
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 1 ] . node. get_our_node_id( ) ) ) ;
856
+
857
+ expect_channel_ready_event ( & nodes[ 0 ] , & nodes[ 1 ] . node . get_our_node_id ( ) ) ;
858
+ expect_channel_ready_event ( & nodes[ 1 ] , & nodes[ 0 ] . node . get_our_node_id ( ) ) ;
859
+
860
+ scid_aliases. clear ( ) ;
861
+ scid_aliases. insert ( node_a_pub_channel_ready. short_channel_id_alias . unwrap ( ) ) ;
862
+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
863
+ // This also applies even if the amount is more than the payment amount, to ensure users
864
+ // dont screw up their privacy.
865
+ match_invoice_routes ( Some ( 50_000_000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
866
+
867
+ // The same remains true until the channel has 7 confirmations, at which point we include
868
+ // no hints.
869
+ connect_blocks ( & nodes[ 1 ] , 5 ) ;
870
+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
871
+ connect_blocks ( & nodes[ 1 ] , 1 ) ;
872
+ get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendAnnouncementSignatures , nodes[ 0 ] . node. get_our_node_id( ) ) ;
873
+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , HashSet :: new ( ) ) ;
874
+ }
875
+
792
876
#[ test]
793
877
fn test_hints_includes_single_channels_to_nodes ( ) {
794
878
let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
0 commit comments