@@ -338,7 +338,7 @@ mod test {
338338 use bitcoin_hashes:: sha256:: Hash as Sha256 ;
339339 use lightning:: chain:: keysinterface:: PhantomKeysManager ;
340340 use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
341- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
341+ use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_FINAL_CLTV_EXPIRY } ;
342342 use lightning:: ln:: functional_test_utils:: * ;
343343 use lightning:: ln:: features:: InitFeatures ;
344344 use lightning:: ln:: msgs:: ChannelMessageHandler ;
@@ -661,4 +661,256 @@ mod test {
661661 _ => panic ! ( "Unexpected event" )
662662 }
663663 }
664+
665+ #[ test]
666+ #[ cfg( feature = "std" ) ]
667+ fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes ( ) {
668+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
669+ let seed_1 = [ 42 as u8 ; 32 ] ;
670+ let seed_2 = [ 43 as u8 ; 32 ] ;
671+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
672+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
673+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
674+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
675+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
676+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
677+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
678+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
679+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
680+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
681+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
682+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
683+
684+ let mut short_chan_ids = HashSet :: new ( ) ;
685+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
686+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
687+
688+ match_multi_node_invoice_routes (
689+ Some ( 10_000 ) ,
690+ & nodes[ 1 ] ,
691+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
692+ short_chan_ids. clone ( ) ,
693+ false
694+ ) ;
695+ }
696+
697+ #[ test]
698+ #[ cfg( feature = "std" ) ]
699+ fn test_multi_node_hints_includes_one_channel_of_each_counterparty_nodes_per_participating_node ( ) {
700+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
701+ let seed_1 = [ 42 as u8 ; 32 ] ;
702+ let seed_2 = [ 43 as u8 ; 32 ] ;
703+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
704+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
705+ chanmon_cfgs[ 3 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
706+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
707+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
708+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
709+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
710+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
711+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
712+ let chan_0_3 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 1000000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
713+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 3 ] . node . get_our_node_id ( ) , & chan_0_3. 1 ) ;
714+ nodes[ 3 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_3. 0 ) ;
715+ let chan_1_3 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 3 , 3_000_000 , 10005 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
716+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 3 ] . node . get_our_node_id ( ) , & chan_1_3. 1 ) ;
717+ nodes[ 3 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_3. 0 ) ;
718+
719+ let mut short_chan_ids = HashSet :: new ( ) ;
720+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
721+ short_chan_ids. insert ( chan_0_3. 0 . contents . short_channel_id . clone ( ) ) ;
722+ short_chan_ids. insert ( chan_1_3. 0 . contents . short_channel_id . clone ( ) ) ;
723+
724+ match_multi_node_invoice_routes (
725+ Some ( 10_000 ) ,
726+ & nodes[ 2 ] ,
727+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
728+ short_chan_ids. clone ( ) ,
729+ false
730+ ) ;
731+ }
732+
733+ #[ test]
734+ #[ cfg( feature = "std" ) ]
735+ fn test_multi_node_with_private_channel_hints_includes_only_phantom_route ( ) {
736+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
737+ let seed_1 = [ 42 as u8 ; 32 ] ;
738+ let seed_2 = [ 43 as u8 ; 32 ] ;
739+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
740+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
741+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
742+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
743+ let mut nodes_2_priv_channels_conf = UserConfig :: default ( ) ;
744+ nodes_2_priv_channels_conf. channel_options . announced_channel = false ;
745+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , Some ( nodes_2_priv_channels_conf) ] ) ;
746+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
747+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
748+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
749+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
750+
751+ let chan_2_0 = create_private_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
752+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
753+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
754+
755+ // Hints should include `chan_0_1` from as `nodes[1]` only have public channels, and no
756+ // channels for `nodes[2]` as it contains private channels.
757+ let mut short_chan_ids = HashSet :: new ( ) ;
758+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
759+
760+ match_multi_node_invoice_routes (
761+ Some ( 10_000 ) ,
762+ & nodes[ 1 ] ,
763+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
764+ short_chan_ids. clone ( ) ,
765+ true
766+ ) ;
767+ }
768+
769+ #[ test]
770+ #[ cfg( feature = "std" ) ]
771+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
772+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
773+ let seed_1 = [ 42 as u8 ; 32 ] ;
774+ let seed_2 = [ 43 as u8 ; 32 ] ;
775+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
776+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
777+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
778+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
779+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
780+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
781+ let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
782+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 1 ) ;
783+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 0 ) ;
784+ 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 ( ) ) ;
785+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 1 ) ;
786+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 0 ) ;
787+ 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 ( ) ) ;
788+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 1 ) ;
789+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 0 ) ;
790+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
791+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
792+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
793+
794+ let mut short_chan_ids = HashSet :: new ( ) ;
795+ short_chan_ids. insert ( chan_0_1_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
796+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
797+
798+ match_multi_node_invoice_routes (
799+ Some ( 10_000 ) ,
800+ & nodes[ 1 ] ,
801+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
802+ short_chan_ids. clone ( ) ,
803+ false
804+ ) ;
805+ }
806+
807+ #[ test]
808+ #[ cfg( feature = "std" ) ]
809+ fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
810+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
811+ let seed_1 = [ 42 as u8 ; 32 ] ;
812+ let seed_2 = [ 43 as u8 ; 32 ] ;
813+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
814+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
815+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
816+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
817+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
818+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
819+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
820+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
821+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
822+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
823+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
824+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
825+
826+ // 1 msat above chan_0_1's inbound capacity
827+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
828+ short_chan_ids_99_000_001_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
829+
830+ match_multi_node_invoice_routes (
831+ Some ( 99_000_001 ) ,
832+ & nodes[ 1 ] ,
833+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
834+ short_chan_ids_99_000_001_msat. clone ( ) ,
835+ false
836+ ) ;
837+
838+ // Exactly at chan_0_1's inbound capacity
839+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
840+ short_chan_ids_99_000_000_msat. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
841+ short_chan_ids_99_000_000_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
842+
843+
844+ match_multi_node_invoice_routes (
845+ Some ( 99_000_000 ) ,
846+ & nodes[ 1 ] ,
847+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
848+ short_chan_ids_99_000_000_msat. clone ( ) ,
849+ false
850+ ) ;
851+
852+ // Invoices with a higher amount than any of our channels' inbound capacity should result
853+ // in no hints.
854+ match_multi_node_invoice_routes (
855+ Some ( 99_000_000_1 ) ,
856+ & nodes[ 1 ] ,
857+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
858+ HashSet :: new ( ) ,
859+ false
860+ ) ;
861+
862+ // An invoice with no specified amount should include all participating nodes in the hints.
863+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
864+ short_chan_ids_no_specified_amount. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
865+ short_chan_ids_no_specified_amount. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
866+
867+ match_multi_node_invoice_routes (
868+ None ,
869+ & nodes[ 1 ] ,
870+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
871+ short_chan_ids_no_specified_amount. clone ( ) ,
872+ false
873+ ) ;
874+ }
875+
876+ #[ cfg( feature = "std" ) ]
877+ fn match_multi_node_invoice_routes < ' a , ' b : ' a , ' c : ' b > (
878+ invoice_amt : Option < u64 > ,
879+ invoice_node : & Node < ' a , ' b , ' c > ,
880+ network_multi_nodes : Vec < & Node < ' a , ' b , ' c > > ,
881+ mut chan_ids_to_match : HashSet < u64 > ,
882+ nodes_contains_private_channels : bool
883+ ) {
884+ let ( payment_hash, payment_secret) = invoice_node. node . create_inbound_payment ( invoice_amt, 3600 ) . unwrap ( ) ;
885+ let phantom_route_hints = network_multi_nodes. iter ( )
886+ . map ( |node| node. node . get_phantom_route_hints ( ) )
887+ . collect :: < Vec < PhantomRouteHints > > ( ) ;
888+ let phantom_scids = phantom_route_hints. iter ( )
889+ . map ( |route_hint| route_hint. phantom_scid )
890+ . collect :: < HashSet < u64 > > ( ) ;
891+
892+ 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 ( ) ;
893+
894+ let invoice_hints = invoice. private_routes ( ) ;
895+
896+ for hint in invoice_hints {
897+ let hints = & ( hint. 0 ) . 0 ;
898+ match hints. len ( ) {
899+ 1 => {
900+ assert ! ( nodes_contains_private_channels) ;
901+ let phantom_scid = hints[ 0 ] . short_channel_id ;
902+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
903+ } ,
904+ 2 => {
905+ let hint_short_chan_id = hints[ 0 ] . short_channel_id ;
906+ assert ! ( chan_ids_to_match. contains( & hint_short_chan_id) ) ;
907+ chan_ids_to_match. remove ( & hint_short_chan_id) ;
908+ let phantom_scid = hints[ 1 ] . short_channel_id ;
909+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
910+ } ,
911+ _ => panic ! ( "Incorrect hint length generated" )
912+ }
913+ }
914+ assert ! ( chan_ids_to_match. is_empty( ) ) ;
915+ }
664916}
0 commit comments