@@ -361,7 +361,7 @@ mod test {
361361 use bitcoin_hashes:: sha256:: Hash as Sha256 ;
362362 use lightning:: chain:: keysinterface:: PhantomKeysManager ;
363363 use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
364- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
364+ use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_FINAL_CLTV_EXPIRY } ;
365365 use lightning:: ln:: functional_test_utils:: * ;
366366 use lightning:: ln:: features:: InitFeatures ;
367367 use lightning:: ln:: msgs:: ChannelMessageHandler ;
@@ -707,4 +707,156 @@ mod test {
707707 _ => panic ! ( "Unexpected event" )
708708 }
709709 }
710+
711+ #[ test]
712+ #[ cfg( feature = "std" ) ]
713+ fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes ( ) {
714+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
715+ let seed_1 = [ 42 as u8 ; 32 ] ;
716+ let seed_2 = [ 43 as u8 ; 32 ] ;
717+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
718+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
719+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
720+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
721+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
722+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
723+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
724+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
725+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
726+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
727+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
728+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
729+
730+ let mut short_chan_ids = HashSet :: new ( ) ;
731+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
732+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
733+
734+ match_multi_node_invoice_routes (
735+ Some ( 10_000 ) ,
736+ & nodes[ 1 ] ,
737+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
738+ short_chan_ids. clone ( ) ,
739+ ) ;
740+ }
741+
742+ #[ test]
743+ #[ cfg( feature = "std" ) ]
744+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
745+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
746+ let seed_1 = [ 42 as u8 ; 32 ] ;
747+ let seed_2 = [ 43 as u8 ; 32 ] ;
748+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
749+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
750+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
751+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
752+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
753+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
754+ let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
755+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 1 ) ;
756+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 0 ) ;
757+ let chan_0_1_high_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
758+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 1 ) ;
759+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 0 ) ;
760+ let chan_0_1_medium_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
761+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 1 ) ;
762+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 0 ) ;
763+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
764+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
765+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
766+
767+ let mut short_chan_ids = HashSet :: new ( ) ;
768+ short_chan_ids. insert ( chan_0_1_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
769+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
770+
771+ match_multi_node_invoice_routes (
772+ Some ( 10_000 ) ,
773+ & nodes[ 1 ] ,
774+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
775+ short_chan_ids. clone ( ) ,
776+ ) ;
777+ }
778+
779+ #[ test]
780+ #[ cfg( feature = "std" ) ]
781+ fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
782+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
783+ let seed_1 = [ 42 as u8 ; 32 ] ;
784+ let seed_2 = [ 43 as u8 ; 32 ] ;
785+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
786+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
787+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
788+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
789+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
790+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
791+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
792+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
793+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
794+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
795+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
796+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
797+
798+ // 1 msat above chan_0_1's inbound capacity
799+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
800+ short_chan_ids_99_000_001_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
801+
802+ match_multi_node_invoice_routes (
803+ Some ( 99_000_001 ) ,
804+ & nodes[ 1 ] ,
805+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
806+ short_chan_ids_99_000_001_msat. clone ( ) ,
807+ ) ;
808+
809+ // Exactly at chan_0_1's inbound capacity
810+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
811+ short_chan_ids_99_000_000_msat. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
812+ short_chan_ids_99_000_000_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
813+
814+
815+ match_multi_node_invoice_routes (
816+ Some ( 99_000_000 ) ,
817+ & nodes[ 1 ] ,
818+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
819+ short_chan_ids_99_000_000_msat. clone ( ) ,
820+ ) ;
821+
822+ // An invoice with no specified amount should include all participating nodes in the hints.
823+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
824+ short_chan_ids_no_specified_amount. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
825+ short_chan_ids_no_specified_amount. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
826+
827+ match_multi_node_invoice_routes (
828+ None ,
829+ & nodes[ 1 ] ,
830+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
831+ short_chan_ids_no_specified_amount. clone ( ) ,
832+ ) ;
833+ }
834+
835+ #[ cfg( feature = "std" ) ]
836+ fn match_multi_node_invoice_routes < ' a , ' b : ' a , ' c : ' b > (
837+ invoice_amt : Option < u64 > ,
838+ invoice_node : & Node < ' a , ' b , ' c > ,
839+ network_multi_nodes : Vec < & Node < ' a , ' b , ' c > > ,
840+ mut chan_ids_to_match : HashSet < u64 >
841+ ) {
842+ let ( _, payment_hash, payment_secret) = {
843+ let ( payment_hash, payment_secret) = invoice_node. node . create_inbound_payment ( invoice_amt, 3600 ) . unwrap ( ) ;
844+ let payment_preimage = invoice_node. node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
845+ ( payment_preimage, payment_hash, payment_secret)
846+ } ;
847+ let phantom_route_hints = network_multi_nodes. iter ( )
848+ . map ( |node| node. node . get_phantom_route_hints ( ) )
849+ . collect :: < Vec < PhantomRouteHints > > ( ) ;
850+
851+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( invoice_amt, "test" . to_string ( ) , payment_hash, payment_secret, phantom_route_hints, & invoice_node. keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
852+
853+ let invoice_hints = invoice. private_routes ( ) ;
854+ assert_eq ! ( invoice_hints. len( ) , chan_ids_to_match. len( ) ) ;
855+
856+ for hint in invoice_hints {
857+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
858+ assert ! ( chan_ids_to_match. contains( & hint_short_chan_id) ) ;
859+ chan_ids_to_match. remove ( & hint_short_chan_id) ;
860+ }
861+ }
710862}
0 commit comments