@@ -349,7 +349,7 @@ mod test {
349349 use bitcoin_hashes:: sha256:: Hash as Sha256 ;
350350 use lightning:: chain:: keysinterface:: PhantomKeysManager ;
351351 use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
352- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
352+ use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_FINAL_CLTV_EXPIRY } ;
353353 use lightning:: ln:: functional_test_utils:: * ;
354354 use lightning:: ln:: features:: InitFeatures ;
355355 use lightning:: ln:: msgs:: ChannelMessageHandler ;
@@ -712,4 +712,256 @@ mod test {
712712 _ => panic ! ( "Unexpected event" )
713713 }
714714 }
715+
716+ #[ test]
717+ #[ cfg( feature = "std" ) ]
718+ fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes ( ) {
719+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
720+ let seed_1 = [ 42 as u8 ; 32 ] ;
721+ let seed_2 = [ 43 as u8 ; 32 ] ;
722+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
723+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
724+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
725+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
726+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
727+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
728+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
729+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
730+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
731+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
732+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
733+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
734+
735+ let mut short_chan_ids = HashSet :: new ( ) ;
736+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
737+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
738+
739+ match_multi_node_invoice_routes (
740+ Some ( 10_000 ) ,
741+ & nodes[ 1 ] ,
742+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
743+ short_chan_ids. clone ( ) ,
744+ false
745+ ) ;
746+ }
747+
748+ #[ test]
749+ #[ cfg( feature = "std" ) ]
750+ fn test_multi_node_hints_includes_one_channel_of_each_counterparty_nodes_per_participating_node ( ) {
751+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
752+ let seed_1 = [ 42 as u8 ; 32 ] ;
753+ let seed_2 = [ 43 as u8 ; 32 ] ;
754+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
755+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
756+ chanmon_cfgs[ 3 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
757+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
758+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
759+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
760+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
761+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
762+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
763+ let chan_0_3 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 1000000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
764+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 3 ] . node . get_our_node_id ( ) , & chan_0_3. 1 ) ;
765+ nodes[ 3 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_3. 0 ) ;
766+ let chan_1_3 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 3 , 3_000_000 , 10005 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
767+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 3 ] . node . get_our_node_id ( ) , & chan_1_3. 1 ) ;
768+ nodes[ 3 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_3. 0 ) ;
769+
770+ let mut short_chan_ids = HashSet :: new ( ) ;
771+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
772+ short_chan_ids. insert ( chan_0_3. 0 . contents . short_channel_id . clone ( ) ) ;
773+ short_chan_ids. insert ( chan_1_3. 0 . contents . short_channel_id . clone ( ) ) ;
774+
775+ match_multi_node_invoice_routes (
776+ Some ( 10_000 ) ,
777+ & nodes[ 2 ] ,
778+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
779+ short_chan_ids. clone ( ) ,
780+ false
781+ ) ;
782+ }
783+
784+ #[ test]
785+ #[ cfg( feature = "std" ) ]
786+ fn test_multi_node_with_private_channel_hints_includes_only_phantom_route ( ) {
787+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
788+ let seed_1 = [ 42 as u8 ; 32 ] ;
789+ let seed_2 = [ 43 as u8 ; 32 ] ;
790+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
791+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
792+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
793+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
794+ let mut nodes_2_priv_channels_conf = UserConfig :: default ( ) ;
795+ nodes_2_priv_channels_conf. channel_options . announced_channel = false ;
796+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , Some ( nodes_2_priv_channels_conf) ] ) ;
797+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
798+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
799+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
800+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
801+
802+ let chan_2_0 = create_private_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
803+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
804+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
805+
806+ // Hints should include `chan_0_1` from as `nodes[1]` only have public channels, and no
807+ // channels for `nodes[2]` as it contains private channels.
808+ let mut short_chan_ids = HashSet :: new ( ) ;
809+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
810+
811+ match_multi_node_invoice_routes (
812+ Some ( 10_000 ) ,
813+ & nodes[ 1 ] ,
814+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
815+ short_chan_ids. clone ( ) ,
816+ true
817+ ) ;
818+ }
819+
820+ #[ test]
821+ #[ cfg( feature = "std" ) ]
822+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
823+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
824+ let seed_1 = [ 42 as u8 ; 32 ] ;
825+ let seed_2 = [ 43 as u8 ; 32 ] ;
826+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
827+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
828+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
829+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
830+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
831+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
832+ let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
833+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 1 ) ;
834+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 0 ) ;
835+ 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 ( ) ) ;
836+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 1 ) ;
837+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 0 ) ;
838+ 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 ( ) ) ;
839+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 1 ) ;
840+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 0 ) ;
841+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
842+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
843+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
844+
845+ let mut short_chan_ids = HashSet :: new ( ) ;
846+ short_chan_ids. insert ( chan_0_1_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
847+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
848+
849+ match_multi_node_invoice_routes (
850+ Some ( 10_000 ) ,
851+ & nodes[ 1 ] ,
852+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
853+ short_chan_ids. clone ( ) ,
854+ false
855+ ) ;
856+ }
857+
858+ #[ test]
859+ #[ cfg( feature = "std" ) ]
860+ fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
861+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
862+ let seed_1 = [ 42 as u8 ; 32 ] ;
863+ let seed_2 = [ 43 as u8 ; 32 ] ;
864+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
865+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
866+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
867+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
868+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
869+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
870+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
871+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
872+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
873+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
874+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
875+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
876+
877+ // 1 msat above chan_0_1's inbound capacity
878+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
879+ short_chan_ids_99_000_001_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
880+
881+ match_multi_node_invoice_routes (
882+ Some ( 99_000_001 ) ,
883+ & nodes[ 1 ] ,
884+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
885+ short_chan_ids_99_000_001_msat. clone ( ) ,
886+ false
887+ ) ;
888+
889+ // Exactly at chan_0_1's inbound capacity
890+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
891+ short_chan_ids_99_000_000_msat. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
892+ short_chan_ids_99_000_000_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
893+
894+
895+ match_multi_node_invoice_routes (
896+ Some ( 99_000_000 ) ,
897+ & nodes[ 1 ] ,
898+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
899+ short_chan_ids_99_000_000_msat. clone ( ) ,
900+ false
901+ ) ;
902+
903+ // Invoices with a higher amount than any of our channels' inbound capacity should result
904+ // in no hints.
905+ match_multi_node_invoice_routes (
906+ Some ( 99_000_000_1 ) ,
907+ & nodes[ 1 ] ,
908+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
909+ HashSet :: new ( ) ,
910+ false
911+ ) ;
912+
913+ // An invoice with no specified amount should include all participating nodes in the hints.
914+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
915+ short_chan_ids_no_specified_amount. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
916+ short_chan_ids_no_specified_amount. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
917+
918+ match_multi_node_invoice_routes (
919+ None ,
920+ & nodes[ 1 ] ,
921+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
922+ short_chan_ids_no_specified_amount. clone ( ) ,
923+ false
924+ ) ;
925+ }
926+
927+ #[ cfg( feature = "std" ) ]
928+ fn match_multi_node_invoice_routes < ' a , ' b : ' a , ' c : ' b > (
929+ invoice_amt : Option < u64 > ,
930+ invoice_node : & Node < ' a , ' b , ' c > ,
931+ network_multi_nodes : Vec < & Node < ' a , ' b , ' c > > ,
932+ mut chan_ids_to_match : HashSet < u64 > ,
933+ nodes_contains_private_channels : bool
934+ ) {
935+ let ( payment_hash, payment_secret) = invoice_node. node . create_inbound_payment ( invoice_amt, 3600 ) . unwrap ( ) ;
936+ let phantom_route_hints = network_multi_nodes. iter ( )
937+ . map ( |node| node. node . get_phantom_route_hints ( ) )
938+ . collect :: < Vec < PhantomRouteHints > > ( ) ;
939+ let phantom_scids = phantom_route_hints. iter ( )
940+ . map ( |route_hint| route_hint. phantom_scid )
941+ . collect :: < HashSet < u64 > > ( ) ;
942+
943+ 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 ( ) ;
944+
945+ let invoice_hints = invoice. private_routes ( ) ;
946+
947+ for hint in invoice_hints {
948+ let hints = & ( hint. 0 ) . 0 ;
949+ match hints. len ( ) {
950+ 1 => {
951+ assert ! ( nodes_contains_private_channels) ;
952+ let phantom_scid = hints[ 0 ] . short_channel_id ;
953+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
954+ } ,
955+ 2 => {
956+ let hint_short_chan_id = hints[ 0 ] . short_channel_id ;
957+ assert ! ( chan_ids_to_match. contains( & hint_short_chan_id) ) ;
958+ chan_ids_to_match. remove ( & hint_short_chan_id) ;
959+ let phantom_scid = hints[ 1 ] . short_channel_id ;
960+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
961+ } ,
962+ _ => panic ! ( "Incorrect hint length generated" )
963+ }
964+ }
965+ assert ! ( chan_ids_to_match. is_empty( ) ) ;
966+ }
715967}
0 commit comments