@@ -368,7 +368,9 @@ mod test {
368368 use lightning:: util:: enforcing_trait_impls:: EnforcingSigner ;
369369 use lightning:: util:: events:: { MessageSendEvent , MessageSendEventsProvider , Event } ;
370370 use lightning:: util:: test_utils;
371+ use lightning:: util:: config:: UserConfig ;
371372 use utils:: create_invoice_from_channelmanager_and_duration_since_epoch;
373+ use std:: collections:: HashSet ;
372374
373375 #[ test]
374376 fn test_from_channelmanager ( ) {
@@ -423,6 +425,171 @@ mod test {
423425 assert_eq ! ( events. len( ) , 2 ) ;
424426 }
425427
428+ #[ test]
429+ fn test_hints_includes_single_public_channels_to_nodes ( ) {
430+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
431+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
432+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
433+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
434+ let chan_1_0 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
435+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0. 0 ) ;
436+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0. 1 ) ;
437+ let chan_2_0 = create_announced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
438+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
439+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
440+
441+ let mut short_chan_ids = HashSet :: new ( ) ;
442+ short_chan_ids. insert ( chan_1_0. 0 . contents . short_channel_id . clone ( ) ) ;
443+ short_chan_ids. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
444+
445+ match_invoice_routes (
446+ Some ( 5000 ) ,
447+ & nodes[ 0 ] ,
448+ short_chan_ids. clone ( ) ,
449+ ) ;
450+ }
451+
452+ #[ test]
453+ fn test_hints_has_only_highest_inbound_capacity_channel ( ) {
454+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
455+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
456+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
457+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
458+ let chan_1_0_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
459+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0_low_inbound_capacity. 0 ) ;
460+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0_low_inbound_capacity. 1 ) ;
461+ let chan_1_0_high_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 10_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
462+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0_high_inbound_capacity. 0 ) ;
463+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0_high_inbound_capacity. 1 ) ;
464+ let chan_1_0_medium_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
465+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0_medium_inbound_capacity. 0 ) ;
466+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0_medium_inbound_capacity. 1 ) ;
467+
468+ let mut short_chan_ids = HashSet :: new ( ) ;
469+ short_chan_ids. insert ( chan_1_0_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
470+
471+ match_invoice_routes (
472+ Some ( 5000 ) ,
473+ & nodes[ 0 ] ,
474+ short_chan_ids. clone ( ) ,
475+ ) ;
476+ }
477+
478+ #[ test]
479+ fn test_no_hints_if_any_private_channels_exists ( ) {
480+ let mut nodes_2_priv_channels_conf = UserConfig :: default ( ) ;
481+ nodes_2_priv_channels_conf. channel_options . announced_channel = false ;
482+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
483+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
484+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , Some ( nodes_2_priv_channels_conf) ] ) ;
485+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
486+ let chan_1_0 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
487+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0. 0 ) ;
488+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0. 1 ) ;
489+
490+ // Creates a private channel between `nodes[2]` and `nodes[0]`. Note that create_*_chan
491+ // functions in utils can't be used, as they require announcement_signatures.
492+ nodes[ 2 ] . node . create_channel ( nodes[ 0 ] . node . get_our_node_id ( ) , 100000 , 10001 , 42 , None ) . unwrap ( ) ;
493+ let open_channel = get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendOpenChannel , nodes[ 0 ] . node. get_our_node_id( ) ) ;
494+ nodes[ 0 ] . node . handle_open_channel ( & nodes[ 2 ] . node . get_our_node_id ( ) , InitFeatures :: known ( ) , & open_channel) ;
495+ let accept_channel = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendAcceptChannel , nodes[ 2 ] . node. get_our_node_id( ) ) ;
496+ nodes[ 2 ] . node . handle_accept_channel ( & nodes[ 0 ] . node . get_our_node_id ( ) , InitFeatures :: known ( ) , & accept_channel) ;
497+
498+ let ( temporary_channel_id, tx, _) = create_funding_transaction ( & nodes[ 2 ] , 100000 , 42 ) ;
499+ nodes[ 2 ] . node . funding_transaction_generated ( & temporary_channel_id, tx. clone ( ) ) . unwrap ( ) ;
500+ nodes[ 0 ] . node . handle_funding_created ( & nodes[ 2 ] . node . get_our_node_id ( ) , & get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendFundingCreated , nodes[ 0 ] . node. get_our_node_id( ) ) ) ;
501+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
502+
503+ let cs_funding_signed = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendFundingSigned , nodes[ 2 ] . node. get_our_node_id( ) ) ;
504+ nodes[ 2 ] . node . handle_funding_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & cs_funding_signed) ;
505+ check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
506+
507+ let conf_height = core:: cmp:: max ( nodes[ 2 ] . best_block_info ( ) . 1 + 1 , nodes[ 0 ] . best_block_info ( ) . 1 + 1 ) ;
508+ confirm_transaction_at ( & nodes[ 2 ] , & tx, conf_height) ;
509+ connect_blocks ( & nodes[ 2 ] , CHAN_CONFIRM_DEPTH - 1 ) ;
510+ confirm_transaction_at ( & nodes[ 0 ] , & tx, conf_height) ;
511+ connect_blocks ( & nodes[ 0 ] , CHAN_CONFIRM_DEPTH - 1 ) ;
512+ let as_funding_locked = get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendFundingLocked , nodes[ 0 ] . node. get_our_node_id( ) ) ;
513+ nodes[ 2 ] . node . handle_funding_locked ( & nodes[ 0 ] . node . get_our_node_id ( ) , & get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendFundingLocked , nodes[ 2 ] . node. get_our_node_id( ) ) ) ;
514+ get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 0 ] . node. get_our_node_id( ) ) ;
515+ nodes[ 0 ] . node . handle_funding_locked ( & nodes[ 2 ] . node . get_our_node_id ( ) , & as_funding_locked) ;
516+ get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 2 ] . node. get_our_node_id( ) ) ;
517+
518+ // Ensure that the invoice doesn't include any route hints for any of `nodes[0]` channels,
519+ // even though all channels between `nodes[1]` and `nodes[0]` are public.
520+ let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
521+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 5000 ) , "test" . to_string ( ) ,
522+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
523+ let hints = invoice. private_routes ( ) ;
524+
525+ assert ! ( hints. is_empty( ) ) ;
526+ }
527+
528+ #[ test]
529+ fn test_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
530+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
531+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
532+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
533+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
534+ let chan_1_0 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
535+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0. 0 ) ;
536+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0. 1 ) ;
537+ let chan_2_0 = create_announced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
538+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
539+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
540+
541+ // 1 msat above chan_1_0's inbound capacity
542+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
543+ short_chan_ids_99_000_001_msat. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
544+
545+ match_invoice_routes (
546+ Some ( 99_000_001 ) ,
547+ & nodes[ 0 ] ,
548+ short_chan_ids_99_000_001_msat. clone ( ) ,
549+ ) ;
550+
551+ // Exactly at chan_1_0's inbound capacity
552+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
553+ short_chan_ids_99_000_000_msat. insert ( chan_1_0. 0 . contents . short_channel_id . clone ( ) ) ;
554+ short_chan_ids_99_000_000_msat. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
555+
556+ match_invoice_routes (
557+ Some ( 99_000_000 ) ,
558+ & nodes[ 0 ] ,
559+ short_chan_ids_99_000_000_msat. clone ( ) ,
560+ ) ;
561+
562+ // An invoice with no specified amount should include all route hints.
563+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
564+ short_chan_ids_no_specified_amount. insert ( chan_1_0. 0 . contents . short_channel_id . clone ( ) ) ;
565+ short_chan_ids_no_specified_amount. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
566+
567+ match_invoice_routes (
568+ None ,
569+ & nodes[ 0 ] ,
570+ short_chan_ids_no_specified_amount. clone ( ) ,
571+ ) ;
572+ }
573+
574+ fn match_invoice_routes < ' a , ' b : ' a , ' c : ' b > (
575+ invoice_amt : Option < u64 > ,
576+ invoice_node : & Node < ' a , ' b , ' c > ,
577+ mut chan_ids_to_match : HashSet < u64 >
578+ ) {
579+ let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
580+ & invoice_node. node , invoice_node. keys_manager , Currency :: BitcoinTestnet , invoice_amt, "test" . to_string ( ) ,
581+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
582+ let hints = invoice. private_routes ( ) ;
583+
584+ assert_eq ! ( hints. len( ) , chan_ids_to_match. len( ) ) ;
585+
586+ for hint in hints {
587+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
588+ assert ! ( chan_ids_to_match. contains( & hint_short_chan_id) ) ;
589+ chan_ids_to_match. remove ( & hint_short_chan_id) ;
590+ }
591+ }
592+
426593 #[ test]
427594 #[ cfg( feature = "std" ) ]
428595 fn test_multi_node_receive ( ) {
0 commit comments