@@ -522,6 +522,7 @@ fn filter_channels<L: Deref>(
522
522
let mut min_capacity_channel_exists = false ;
523
523
let mut online_channel_exists = false ;
524
524
let mut online_min_capacity_channel_exists = false ;
525
+ let mut has_pub_unconf_chan = false ;
525
526
526
527
log_trace ! ( logger, "Considering {} channels for invoice route hints" , channels. len( ) ) ;
527
528
for channel in channels. into_iter ( ) . filter ( |chan| chan. is_channel_ready ) {
@@ -531,11 +532,18 @@ fn filter_channels<L: Deref>(
531
532
}
532
533
533
534
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 ! [ ]
535
+ if channel. confirmations . is_some ( ) && channel. confirmations < Some ( 7 ) {
536
+ // If we have a public channel, but it doesn't have enough confirmations to (yet)
537
+ // be in the public network graph (and have gotten a chance to propagate), include
538
+ // route hints but only for public channels to protect private channel privacy.
539
+ has_pub_unconf_chan = true ;
540
+ } else {
541
+ // If any public channel exists, return no hints and let the sender
542
+ // look at the public channels instead.
543
+ log_trace ! ( logger, "Not including channels in invoice route hints on account of public channel {}" ,
544
+ log_bytes!( channel. channel_id) ) ;
545
+ return vec ! [ ]
546
+ }
539
547
}
540
548
541
549
if channel. inbound_capacity_msat >= min_inbound_capacity {
@@ -559,19 +567,26 @@ fn filter_channels<L: Deref>(
559
567
match filtered_channels. entry ( channel. counterparty . node_id ) {
560
568
hash_map:: Entry :: Occupied ( mut entry) => {
561
569
let current_max_capacity = entry. get ( ) . inbound_capacity_msat ;
562
- if channel. inbound_capacity_msat < current_max_capacity {
570
+ let new_now_public = channel. is_public && !entry. get ( ) . is_public ;
571
+ let new_higher_capacity = channel. is_public == entry. get ( ) . is_public &&
572
+ channel. inbound_capacity_msat > current_max_capacity;
573
+ if !new_now_public && !new_higher_capacity {
563
574
log_trace ! ( logger,
564
- "Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints" ,
575
+ "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
565
576
log_pubkey!( channel. counterparty. node_id) ,
566
- log_bytes!( entry. get( ) . channel_id) , current_max_capacity,
567
- log_bytes!( channel. channel_id) , channel. inbound_capacity_msat) ;
577
+ log_bytes!( entry. get( ) . channel_id) , entry. get( ) . short_channel_id,
578
+ current_max_capacity,
579
+ log_bytes!( channel. channel_id) , channel. short_channel_id,
580
+ channel. inbound_capacity_msat) ;
568
581
continue ;
569
582
}
570
583
log_trace ! ( logger,
571
- "Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints" ,
584
+ "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
572
585
log_pubkey!( channel. counterparty. node_id) ,
573
- log_bytes!( channel. channel_id) , channel. inbound_capacity_msat,
574
- log_bytes!( entry. get( ) . channel_id) , current_max_capacity) ;
586
+ log_bytes!( channel. channel_id) , channel. short_channel_id,
587
+ channel. inbound_capacity_msat,
588
+ log_bytes!( entry. get( ) . channel_id) , entry. get( ) . short_channel_id,
589
+ current_max_capacity) ;
575
590
entry. insert ( channel) ;
576
591
}
577
592
hash_map:: Entry :: Vacant ( entry) => {
@@ -602,7 +617,12 @@ fn filter_channels<L: Deref>(
602
617
. map ( |( _, channel) | channel)
603
618
. filter ( |channel| {
604
619
let has_enough_capacity = channel. inbound_capacity_msat >= min_inbound_capacity;
605
- let include_channel = if online_min_capacity_channel_exists {
620
+ let include_channel = if has_pub_unconf_chan {
621
+ // If we have a public channel, but it doesn't have enough confirmations to (yet)
622
+ // be in the public network graph (and have gotten a chance to propagate), include
623
+ // route hints but only for public channels to protect private channel privacy.
624
+ channel. is_public
625
+ } else if online_min_capacity_channel_exists {
606
626
has_enough_capacity && channel. is_usable
607
627
} else if min_capacity_channel_exists && online_channel_exists {
608
628
// If there are some online channels and some min_capacity channels, but no
@@ -622,7 +642,7 @@ fn filter_channels<L: Deref>(
622
642
log_trace ! ( logger, "Ignoring channel {} without enough capacity for invoice route hints" ,
623
643
log_bytes!( channel. channel_id) ) ;
624
644
} else {
625
- debug_assert ! ( !channel. is_usable) ;
645
+ debug_assert ! ( !channel. is_usable || ( has_pub_unconf_chan && !channel . is_public ) ) ;
626
646
log_trace ! ( logger, "Ignoring channel {} with disconnected peer" ,
627
647
log_bytes!( channel. channel_id) ) ;
628
648
}
@@ -792,6 +812,55 @@ mod test {
792
812
assert_eq ! ( invoice. payment_hash( ) , & sha256:: Hash :: from_slice( & payment_hash. 0 [ ..] ) . unwrap( ) ) ;
793
813
}
794
814
815
+ #[ test]
816
+ fn test_hints_has_only_public_confd_channels ( ) {
817
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
818
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
819
+ let mut config = test_default_channel_config ( ) ;
820
+ config. channel_handshake_config . minimum_depth = 1 ;
821
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config) , Some ( config) ] ) ;
822
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
823
+
824
+ // Create a private channel with lots of capacity and a lower value public channel (without
825
+ // confirming the funding tx yet).
826
+ let unannounced_scid = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 ) ;
827
+ let conf_tx = create_chan_between_nodes_with_value_init ( & nodes[ 0 ] , & nodes[ 1 ] , 10_000 , 0 ) ;
828
+
829
+ // Before the channel is available, we should include the unannounced_scid.
830
+ let mut scid_aliases = HashSet :: new ( ) ;
831
+ scid_aliases. insert ( unannounced_scid. 0 . short_channel_id_alias . unwrap ( ) ) ;
832
+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
833
+
834
+ // However after we mine the funding tx and exchange channel_ready messages for the public
835
+ // channel we'll immediately switch to including it as a route hint, even though isn't yet
836
+ // announced.
837
+ let pub_channel_scid = mine_transaction ( & nodes[ 0 ] , & conf_tx) ;
838
+ let node_a_pub_channel_ready = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendChannelReady , nodes[ 1 ] . node. get_our_node_id( ) ) ;
839
+ nodes[ 1 ] . node . handle_channel_ready ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_a_pub_channel_ready) ;
840
+
841
+ assert_eq ! ( mine_transaction( & nodes[ 1 ] , & conf_tx) , pub_channel_scid) ;
842
+ let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
843
+ assert_eq ! ( events. len( ) , 2 ) ;
844
+ if let MessageSendEvent :: SendChannelReady { msg, .. } = & events[ 0 ] {
845
+ nodes[ 0 ] . node . handle_channel_ready ( & nodes[ 1 ] . node . get_our_node_id ( ) , msg) ;
846
+ } else { panic ! ( ) ; }
847
+ if let MessageSendEvent :: SendChannelUpdate { msg, .. } = & events[ 1 ] {
848
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , msg) ;
849
+ } else { panic ! ( ) ; }
850
+
851
+ 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( ) ) ) ;
852
+
853
+ expect_channel_ready_event ( & nodes[ 0 ] , & nodes[ 1 ] . node . get_our_node_id ( ) ) ;
854
+ expect_channel_ready_event ( & nodes[ 1 ] , & nodes[ 0 ] . node . get_our_node_id ( ) ) ;
855
+
856
+ scid_aliases. clear ( ) ;
857
+ scid_aliases. insert ( node_a_pub_channel_ready. short_channel_id_alias . unwrap ( ) ) ;
858
+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
859
+ // This also applies even if the amount is more than the payment amount, to ensure users
860
+ // dont screw up their privacy.
861
+ match_invoice_routes ( Some ( 50_000_000 ) , & nodes[ 1 ] , scid_aliases) ;
862
+ }
863
+
795
864
#[ test]
796
865
fn test_hints_includes_single_channels_to_nodes ( ) {
797
866
let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
0 commit comments