@@ -338,7 +338,9 @@ mod test {
338338 use lightning:: util:: enforcing_trait_impls:: EnforcingSigner ;
339339 use lightning:: util:: events:: { MessageSendEvent , MessageSendEventsProvider , Event } ;
340340 use lightning:: util:: test_utils;
341+ use lightning:: util:: config:: UserConfig ;
341342 use utils:: create_invoice_from_channelmanager_and_duration_since_epoch;
343+ use std:: collections:: HashSet ;
342344
343345 #[ test]
344346 fn test_from_channelmanager ( ) {
@@ -393,6 +395,182 @@ mod test {
393395 assert_eq ! ( events. len( ) , 2 ) ;
394396 }
395397
398+ #[ test]
399+ fn test_hints_includes_single_public_channels_to_nodes ( ) {
400+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
401+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
402+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
403+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
404+ let chan_1_0 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
405+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0. 0 ) ;
406+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0. 1 ) ;
407+ let chan_2_0 = create_announced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
408+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
409+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
410+
411+ let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
412+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 5000 ) , "test" . to_string ( ) ,
413+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
414+ let hints = invoice. private_routes ( ) ;
415+
416+ assert_eq ! ( hints. len( ) , 2 ) ;
417+
418+ let mut short_chan_ids = HashSet :: new ( ) ;
419+ short_chan_ids. insert ( chan_1_0. 0 . contents . short_channel_id . clone ( ) ) ;
420+ short_chan_ids. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
421+ for hint in hints {
422+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
423+ assert ! ( short_chan_ids. contains( & hint_short_chan_id) ) ;
424+ short_chan_ids. remove ( & hint_short_chan_id) ;
425+ }
426+ }
427+
428+ #[ test]
429+ fn test_hints_has_only_highest_inbound_capacity_channel ( ) {
430+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
431+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
432+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
433+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
434+ let chan_1_0_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
435+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0_low_inbound_capacity. 0 ) ;
436+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0_low_inbound_capacity. 1 ) ;
437+ 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 ( ) ) ;
438+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0_high_inbound_capacity. 0 ) ;
439+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0_high_inbound_capacity. 1 ) ;
440+ 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 ( ) ) ;
441+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0_medium_inbound_capacity. 0 ) ;
442+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0_medium_inbound_capacity. 1 ) ;
443+
444+ let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
445+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 5000 ) , "test" . to_string ( ) ,
446+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
447+ let hints = invoice. private_routes ( ) ;
448+
449+ assert_eq ! ( hints. len( ) , 1 ) ;
450+
451+ let mut short_chan_ids = HashSet :: new ( ) ;
452+ short_chan_ids. insert ( chan_1_0_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
453+ for hint in hints {
454+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
455+ assert ! ( short_chan_ids. contains( & hint_short_chan_id) ) ;
456+ short_chan_ids. remove ( & hint_short_chan_id) ;
457+ }
458+ }
459+
460+ #[ test]
461+ fn test_no_hints_if_any_private_channels_exists ( ) {
462+ let mut nodes_2_priv_channels_conf = UserConfig :: default ( ) ;
463+ nodes_2_priv_channels_conf. channel_options . announced_channel = false ;
464+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
465+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
466+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , Some ( nodes_2_priv_channels_conf) ] ) ;
467+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
468+ let chan_1_0 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
469+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0. 0 ) ;
470+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0. 1 ) ;
471+
472+ // Creates a private channel between `nodes[2]` and `nodes[0]`. Note that create_*_chan
473+ // functions in utils can't be used, as they require announcement_signatures.
474+ nodes[ 2 ] . node . create_channel ( nodes[ 0 ] . node . get_our_node_id ( ) , 100000 , 10001 , 42 , None ) . unwrap ( ) ;
475+ let open_channel = get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendOpenChannel , nodes[ 0 ] . node. get_our_node_id( ) ) ;
476+ nodes[ 0 ] . node . handle_open_channel ( & nodes[ 2 ] . node . get_our_node_id ( ) , InitFeatures :: known ( ) , & open_channel) ;
477+ let accept_channel = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendAcceptChannel , nodes[ 2 ] . node. get_our_node_id( ) ) ;
478+ nodes[ 2 ] . node . handle_accept_channel ( & nodes[ 0 ] . node . get_our_node_id ( ) , InitFeatures :: known ( ) , & accept_channel) ;
479+
480+ let ( temporary_channel_id, tx, _) = create_funding_transaction ( & nodes[ 2 ] , 100000 , 42 ) ;
481+ nodes[ 2 ] . node . funding_transaction_generated ( & temporary_channel_id, tx. clone ( ) ) . unwrap ( ) ;
482+ 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( ) ) ) ;
483+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
484+
485+ let cs_funding_signed = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendFundingSigned , nodes[ 2 ] . node. get_our_node_id( ) ) ;
486+ nodes[ 2 ] . node . handle_funding_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & cs_funding_signed) ;
487+ check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
488+
489+ let conf_height = core:: cmp:: max ( nodes[ 2 ] . best_block_info ( ) . 1 + 1 , nodes[ 0 ] . best_block_info ( ) . 1 + 1 ) ;
490+ confirm_transaction_at ( & nodes[ 2 ] , & tx, conf_height) ;
491+ connect_blocks ( & nodes[ 2 ] , CHAN_CONFIRM_DEPTH - 1 ) ;
492+ confirm_transaction_at ( & nodes[ 0 ] , & tx, conf_height) ;
493+ connect_blocks ( & nodes[ 0 ] , CHAN_CONFIRM_DEPTH - 1 ) ;
494+ let as_funding_locked = get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendFundingLocked , nodes[ 0 ] . node. get_our_node_id( ) ) ;
495+ 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( ) ) ) ;
496+ get_event_msg ! ( nodes[ 2 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 0 ] . node. get_our_node_id( ) ) ;
497+ nodes[ 0 ] . node . handle_funding_locked ( & nodes[ 2 ] . node . get_our_node_id ( ) , & as_funding_locked) ;
498+ get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 2 ] . node. get_our_node_id( ) ) ;
499+
500+ // Ensure that the invoice doesn't include any route hints for any of `nodes[0]` channels,
501+ // even though all channels between `nodes[1]` and `nodes[0]` are public.
502+ let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
503+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 5000 ) , "test" . to_string ( ) ,
504+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
505+ let hints = invoice. private_routes ( ) ;
506+
507+ assert ! ( hints. is_empty( ) ) ;
508+ }
509+
510+ #[ test]
511+ fn test_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
512+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
513+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
514+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
515+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
516+ let chan_1_0 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 0 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
517+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_0. 0 ) ;
518+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_1_0. 1 ) ;
519+ let chan_2_0 = create_announced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
520+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
521+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
522+
523+ // 1 msat above chan_1_0's inbound capacity
524+ let invoice_99_000_001_msat = create_invoice_from_channelmanager_and_duration_since_epoch (
525+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 99_000_001 ) , "test" . to_string ( ) ,
526+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
527+ let hints_99_000_001_msat = invoice_99_000_001_msat. private_routes ( ) ;
528+
529+ assert_eq ! ( hints_99_000_001_msat. len( ) , 1 ) ;
530+
531+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
532+ short_chan_ids_99_000_001_msat. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
533+ for hint in hints_99_000_001_msat {
534+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
535+ assert ! ( short_chan_ids_99_000_001_msat. contains( & hint_short_chan_id) ) ;
536+ short_chan_ids_99_000_001_msat. remove ( & hint_short_chan_id) ;
537+ }
538+
539+ // Exactly at chan_1_0's inbound capacity
540+ let invoice_99_000_000_msat = create_invoice_from_channelmanager_and_duration_since_epoch (
541+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 99_000_000 ) , "test" . to_string ( ) ,
542+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
543+ let hints_99_000_000_msat = invoice_99_000_000_msat. private_routes ( ) ;
544+
545+ assert_eq ! ( hints_99_000_000_msat. len( ) , 2 ) ;
546+
547+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
548+ short_chan_ids_99_000_000_msat. insert ( chan_1_0. 0 . contents . short_channel_id . clone ( ) ) ;
549+ short_chan_ids_99_000_000_msat. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
550+ for hint in hints_99_000_000_msat {
551+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
552+ assert ! ( short_chan_ids_99_000_000_msat. contains( & hint_short_chan_id) ) ;
553+ short_chan_ids_99_000_000_msat. remove ( & hint_short_chan_id) ;
554+ }
555+
556+ // An invoice with no specified amount should include all route hints.
557+ let invoice_no_specified_amount = create_invoice_from_channelmanager_and_duration_since_epoch (
558+ & nodes[ 0 ] . node , nodes[ 0 ] . keys_manager , Currency :: BitcoinTestnet , None , "test" . to_string ( ) ,
559+ Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
560+ let hints_no_specified_amount = invoice_no_specified_amount. private_routes ( ) ;
561+
562+ assert_eq ! ( hints_no_specified_amount. len( ) , 2 ) ;
563+
564+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
565+ short_chan_ids_no_specified_amount. insert ( chan_1_0. 0 . contents . short_channel_id . clone ( ) ) ;
566+ short_chan_ids_no_specified_amount. insert ( chan_2_0. 0 . contents . short_channel_id . clone ( ) ) ;
567+ for hint in hints_no_specified_amount {
568+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
569+ assert ! ( short_chan_ids_no_specified_amount. contains( & hint_short_chan_id) ) ;
570+ short_chan_ids_no_specified_amount. remove ( & hint_short_chan_id) ;
571+ }
572+ }
573+
396574 #[ test]
397575 #[ cfg( feature = "std" ) ]
398576 fn test_multi_node_receive ( ) {
0 commit comments