@@ -512,8 +512,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
512512/// * Always select the channel with the highest inbound capacity per counterparty node
513513/// * Prefer channels with capacity at least `min_inbound_capacity_msat` and where the channel
514514/// `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.
517519fn filter_channels < L : Deref > (
518520 channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > , logger : & L
519521) -> Vec < RouteHint > where L :: Target : Logger {
@@ -522,6 +524,7 @@ fn filter_channels<L: Deref>(
522524 let mut min_capacity_channel_exists = false ;
523525 let mut online_channel_exists = false ;
524526 let mut online_min_capacity_channel_exists = false ;
527+ let mut has_pub_unconf_chan = false ;
525528
526529 log_trace ! ( logger, "Considering {} channels for invoice route hints" , channels. len( ) ) ;
527530 for channel in channels. into_iter ( ) . filter ( |chan| chan. is_channel_ready ) {
@@ -531,11 +534,18 @@ fn filter_channels<L: Deref>(
531534 }
532535
533536 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+ }
539549 }
540550
541551 if channel. inbound_capacity_msat >= min_inbound_capacity {
@@ -559,20 +569,32 @@ fn filter_channels<L: Deref>(
559569 match filtered_channels. entry ( channel. counterparty . node_id ) {
560570 hash_map:: Entry :: Occupied ( mut entry) => {
561571 let current_max_capacity = entry. get ( ) . inbound_capacity_msat ;
562- if channel. inbound_capacity_msat < current_max_capacity {
572+ // If this channel is public and the previous channel is not, ensure we replace the
573+ // previous channel to avoid announcing non-public channels.
574+ let new_now_public = channel. is_public && !entry. get ( ) . is_public ;
575+ // If the public-ness of the channel has not changed (in which case simply defer to
576+ // `new_now_public), and this channel has a greater capacity, prefer to announce
577+ // this channel.
578+ let new_higher_capacity = channel. is_public == entry. get ( ) . is_public &&
579+ channel. inbound_capacity_msat > current_max_capacity;
580+ if new_now_public || new_higher_capacity {
581+ log_trace ! ( logger,
582+ "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
583+ log_pubkey!( channel. counterparty. node_id) ,
584+ log_bytes!( channel. channel_id) , channel. short_channel_id,
585+ channel. inbound_capacity_msat,
586+ log_bytes!( entry. get( ) . channel_id) , entry. get( ) . short_channel_id,
587+ current_max_capacity) ;
588+ entry. insert ( channel) ;
589+ } else {
563590 log_trace ! ( logger,
564- "Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints" ,
591+ "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints" ,
565592 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) ;
568- continue ;
593+ log_bytes!( entry. get( ) . channel_id) , entry. get( ) . short_channel_id,
594+ current_max_capacity,
595+ log_bytes!( channel. channel_id) , channel. short_channel_id,
596+ channel. inbound_capacity_msat) ;
569597 }
570- log_trace ! ( logger,
571- "Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints" ,
572- 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) ;
575- entry. insert ( channel) ;
576598 }
577599 hash_map:: Entry :: Vacant ( entry) => {
578600 entry. insert ( channel) ;
@@ -602,7 +624,12 @@ fn filter_channels<L: Deref>(
602624 . map ( |( _, channel) | channel)
603625 . filter ( |channel| {
604626 let has_enough_capacity = channel. inbound_capacity_msat >= min_inbound_capacity;
605- let include_channel = if online_min_capacity_channel_exists {
627+ let include_channel = if has_pub_unconf_chan {
628+ // If we have a public channel, but it doesn't have enough confirmations to (yet)
629+ // be in the public network graph (and have gotten a chance to propagate), include
630+ // route hints but only for public channels to protect private channel privacy.
631+ channel. is_public
632+ } else if online_min_capacity_channel_exists {
606633 has_enough_capacity && channel. is_usable
607634 } else if min_capacity_channel_exists && online_channel_exists {
608635 // If there are some online channels and some min_capacity channels, but no
@@ -622,7 +649,7 @@ fn filter_channels<L: Deref>(
622649 log_trace ! ( logger, "Ignoring channel {} without enough capacity for invoice route hints" ,
623650 log_bytes!( channel. channel_id) ) ;
624651 } else {
625- debug_assert ! ( !channel. is_usable) ;
652+ debug_assert ! ( !channel. is_usable || ( has_pub_unconf_chan && !channel . is_public ) ) ;
626653 log_trace ! ( logger, "Ignoring channel {} with disconnected peer" ,
627654 log_bytes!( channel. channel_id) ) ;
628655 }
@@ -792,6 +819,63 @@ mod test {
792819 assert_eq ! ( invoice. payment_hash( ) , & sha256:: Hash :: from_slice( & payment_hash. 0 [ ..] ) . unwrap( ) ) ;
793820 }
794821
822+ #[ test]
823+ fn test_hints_has_only_public_confd_channels ( ) {
824+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
825+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
826+ let mut config = test_default_channel_config ( ) ;
827+ config. channel_handshake_config . minimum_depth = 1 ;
828+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config) , Some ( config) ] ) ;
829+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
830+
831+ // Create a private channel with lots of capacity and a lower value public channel (without
832+ // confirming the funding tx yet).
833+ let unannounced_scid = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 ) ;
834+ let conf_tx = create_chan_between_nodes_with_value_init ( & nodes[ 0 ] , & nodes[ 1 ] , 10_000 , 0 ) ;
835+
836+ // Before the channel is available, we should include the unannounced_scid.
837+ let mut scid_aliases = HashSet :: new ( ) ;
838+ scid_aliases. insert ( unannounced_scid. 0 . short_channel_id_alias . unwrap ( ) ) ;
839+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
840+
841+ // However after we mine the funding tx and exchange channel_ready messages for the public
842+ // channel we'll immediately switch to including it as a route hint, even though it isn't
843+ // yet announced.
844+ let pub_channel_scid = mine_transaction ( & nodes[ 0 ] , & conf_tx) ;
845+ let node_a_pub_channel_ready = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendChannelReady , nodes[ 1 ] . node. get_our_node_id( ) ) ;
846+ nodes[ 1 ] . node . handle_channel_ready ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_a_pub_channel_ready) ;
847+
848+ assert_eq ! ( mine_transaction( & nodes[ 1 ] , & conf_tx) , pub_channel_scid) ;
849+ let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
850+ assert_eq ! ( events. len( ) , 2 ) ;
851+ if let MessageSendEvent :: SendChannelReady { msg, .. } = & events[ 0 ] {
852+ nodes[ 0 ] . node . handle_channel_ready ( & nodes[ 1 ] . node . get_our_node_id ( ) , msg) ;
853+ } else { panic ! ( ) ; }
854+ if let MessageSendEvent :: SendChannelUpdate { msg, .. } = & events[ 1 ] {
855+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , msg) ;
856+ } else { panic ! ( ) ; }
857+
858+ 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( ) ) ) ;
859+
860+ expect_channel_ready_event ( & nodes[ 0 ] , & nodes[ 1 ] . node . get_our_node_id ( ) ) ;
861+ expect_channel_ready_event ( & nodes[ 1 ] , & nodes[ 0 ] . node . get_our_node_id ( ) ) ;
862+
863+ scid_aliases. clear ( ) ;
864+ scid_aliases. insert ( node_a_pub_channel_ready. short_channel_id_alias . unwrap ( ) ) ;
865+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
866+ // This also applies even if the amount is more than the payment amount, to ensure users
867+ // dont screw up their privacy.
868+ match_invoice_routes ( Some ( 50_000_000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
869+
870+ // The same remains true until the channel has 7 confirmations, at which point we include
871+ // no hints.
872+ connect_blocks ( & nodes[ 1 ] , 5 ) ;
873+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , scid_aliases. clone ( ) ) ;
874+ connect_blocks ( & nodes[ 1 ] , 1 ) ;
875+ get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendAnnouncementSignatures , nodes[ 0 ] . node. get_our_node_id( ) ) ;
876+ match_invoice_routes ( Some ( 5000 ) , & nodes[ 1 ] , HashSet :: new ( ) ) ;
877+ }
878+
795879 #[ test]
796880 fn test_hints_includes_single_channels_to_nodes ( ) {
797881 let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
0 commit comments