@@ -356,7 +356,7 @@ mod test {
356356 use bitcoin_hashes:: sha256:: Hash as Sha256 ;
357357 use lightning:: chain:: keysinterface:: PhantomKeysManager ;
358358 use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
359- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
359+ use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_FINAL_CLTV_EXPIRY } ;
360360 use lightning:: ln:: functional_test_utils:: * ;
361361 use lightning:: ln:: features:: InitFeatures ;
362362 use lightning:: ln:: msgs:: ChannelMessageHandler ;
@@ -748,4 +748,333 @@ mod test {
748748 _ => panic ! ( "Unexpected event" )
749749 }
750750 }
751+
752+ #[ test]
753+ #[ cfg( feature = "std" ) ]
754+ fn test_multi_node_hints_includes_single_channels_to_participating_nodes ( ) {
755+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
756+ let seed_1 = [ 42 as u8 ; 32 ] ;
757+ let seed_2 = [ 43 as u8 ; 32 ] ;
758+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
759+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
760+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
761+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
762+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
763+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
764+
765+ let chan_0_1 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
766+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
767+
768+ let mut scid_aliases = HashSet :: new ( ) ;
769+ scid_aliases. insert ( chan_0_1. 0 . short_channel_id_alias . unwrap ( ) ) ;
770+ scid_aliases. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
771+
772+ match_multi_node_invoice_routes (
773+ Some ( 10_000 ) ,
774+ & nodes[ 1 ] ,
775+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
776+ scid_aliases,
777+ false
778+ ) ;
779+ }
780+
781+ #[ test]
782+ #[ cfg( feature = "std" ) ]
783+ fn test_multi_node_hints_includes_one_channel_of_each_counterparty_nodes_per_participating_node ( ) {
784+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
785+ let seed_1 = [ 42 as u8 ; 32 ] ;
786+ let seed_2 = [ 43 as u8 ; 32 ] ;
787+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
788+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
789+ chanmon_cfgs[ 3 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
790+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
791+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
792+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
793+
794+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
795+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 1000000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
796+ let chan_1_3 = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 3 , 3_000_000 , 10005 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
797+
798+ let mut scid_aliases = HashSet :: new ( ) ;
799+ scid_aliases. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
800+ scid_aliases. insert ( chan_0_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
801+ scid_aliases. insert ( chan_1_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
802+
803+ match_multi_node_invoice_routes (
804+ Some ( 10_000 ) ,
805+ & nodes[ 2 ] ,
806+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
807+ scid_aliases,
808+ false
809+ ) ;
810+ }
811+
812+ #[ test]
813+ #[ cfg( feature = "std" ) ]
814+ fn test_multi_node_forwarding_info_not_assigned_channel_excluded_from_hints ( ) {
815+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
816+ let seed_1 = [ 42 as u8 ; 32 ] ;
817+ let seed_2 = [ 43 as u8 ; 32 ] ;
818+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
819+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
820+ chanmon_cfgs[ 3 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
821+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
822+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
823+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
824+
825+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
826+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 1000000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
827+
828+ // Create an unannonced channel between `nodes[1]` and `nodes[3]`, for which the
829+ // `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
830+ // is never handled, the `channel.counterparty.forwarding_info` is never assigned.
831+ let mut private_chan_cfg = UserConfig :: default ( ) ;
832+ private_chan_cfg. channel_options . announced_channel = false ;
833+ let temporary_channel_id = nodes[ 1 ] . node . create_channel ( nodes[ 3 ] . node . get_our_node_id ( ) , 1_000_000 , 500_000_000 , 42 , Some ( private_chan_cfg) ) . unwrap ( ) ;
834+ let open_channel = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendOpenChannel , nodes[ 3 ] . node. get_our_node_id( ) ) ;
835+ nodes[ 3 ] . node . handle_open_channel ( & nodes[ 1 ] . node . get_our_node_id ( ) , InitFeatures :: known ( ) , & open_channel) ;
836+ let accept_channel = get_event_msg ! ( nodes[ 3 ] , MessageSendEvent :: SendAcceptChannel , nodes[ 1 ] . node. get_our_node_id( ) ) ;
837+ nodes[ 1 ] . node . handle_accept_channel ( & nodes[ 3 ] . node . get_our_node_id ( ) , InitFeatures :: known ( ) , & accept_channel) ;
838+
839+ let tx = sign_funding_transaction ( & nodes[ 1 ] , & nodes[ 3 ] , 1_000_000 , temporary_channel_id) ;
840+
841+ let conf_height = core:: cmp:: max ( nodes[ 1 ] . best_block_info ( ) . 1 + 1 , nodes[ 3 ] . best_block_info ( ) . 1 + 1 ) ;
842+ confirm_transaction_at ( & nodes[ 1 ] , & tx, conf_height) ;
843+ connect_blocks ( & nodes[ 1 ] , CHAN_CONFIRM_DEPTH - 1 ) ;
844+ confirm_transaction_at ( & nodes[ 3 ] , & tx, conf_height) ;
845+ connect_blocks ( & nodes[ 3 ] , CHAN_CONFIRM_DEPTH - 1 ) ;
846+ let as_funding_locked = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendFundingLocked , nodes[ 3 ] . node. get_our_node_id( ) ) ;
847+ nodes[ 1 ] . node . handle_funding_locked ( & nodes[ 3 ] . node . get_our_node_id ( ) , & get_event_msg ! ( nodes[ 3 ] , MessageSendEvent :: SendFundingLocked , nodes[ 1 ] . node. get_our_node_id( ) ) ) ;
848+ get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 3 ] . node. get_our_node_id( ) ) ;
849+ nodes[ 3 ] . node . handle_funding_locked ( & nodes[ 1 ] . node . get_our_node_id ( ) , & as_funding_locked) ;
850+ get_event_msg ! ( nodes[ 3 ] , MessageSendEvent :: SendChannelUpdate , nodes[ 1 ] . node. get_our_node_id( ) ) ;
851+
852+ // As `msgs::ChannelUpdate` was never handled for the participating node(s) of the third
853+ // channel, the channel will never be assigned any `counterparty.forwarding_info`.
854+ // Therefore only `chan_0_3` should be included in the hints for `nodes[3]`.
855+ let mut scid_aliases = HashSet :: new ( ) ;
856+ scid_aliases. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
857+ scid_aliases. insert ( chan_0_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
858+
859+ match_multi_node_invoice_routes (
860+ Some ( 10_000 ) ,
861+ & nodes[ 2 ] ,
862+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
863+ scid_aliases,
864+ false
865+ ) ;
866+ }
867+
868+ #[ test]
869+ #[ cfg( feature = "std" ) ]
870+ fn test_multi_node_with_only_public_channels_hints_includes_only_phantom_route ( ) {
871+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
872+ let seed_1 = [ 42 as u8 ; 32 ] ;
873+ let seed_2 = [ 43 as u8 ; 32 ] ;
874+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
875+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
876+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
877+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
878+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
879+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
880+
881+ let chan_0_1 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
882+
883+ let chan_2_0 = create_announced_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
884+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
885+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
886+
887+ // Hints should include `chan_0_1` from as `nodes[1]` only have private channels, but not
888+ // `chan_0_2` as `nodes[2]` only has public channels.
889+ let mut scid_aliases = HashSet :: new ( ) ;
890+ scid_aliases. insert ( chan_0_1. 0 . short_channel_id_alias . unwrap ( ) ) ;
891+
892+ match_multi_node_invoice_routes (
893+ Some ( 10_000 ) ,
894+ & nodes[ 1 ] ,
895+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
896+ scid_aliases,
897+ true
898+ ) ;
899+ }
900+
901+ #[ test]
902+ #[ cfg( feature = "std" ) ]
903+ fn test_multi_node_with_mixed_public_and_private_channel_hints_includes_only_phantom_route ( ) {
904+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
905+ let seed_1 = [ 42 as u8 ; 32 ] ;
906+ let seed_2 = [ 43 as u8 ; 32 ] ;
907+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
908+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
909+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
910+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
911+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
912+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
913+
914+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
915+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
916+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
917+ let _chan_1_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
918+
919+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
920+
921+ // Hints should include `chan_0_3` from as `nodes[3]` only have private channels, and no
922+ // channels for `nodes[2]` as it contains a mix of public and private channels.
923+ let mut scid_aliases = HashSet :: new ( ) ;
924+ scid_aliases. insert ( chan_0_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
925+
926+ match_multi_node_invoice_routes (
927+ Some ( 10_000 ) ,
928+ & nodes[ 2 ] ,
929+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
930+ scid_aliases,
931+ true
932+ ) ;
933+ }
934+
935+ #[ test]
936+ #[ cfg( feature = "std" ) ]
937+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
938+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
939+ let seed_1 = [ 42 as u8 ; 32 ] ;
940+ let seed_2 = [ 43 as u8 ; 32 ] ;
941+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
942+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
943+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
944+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
945+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
946+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
947+
948+ let _chan_0_1_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
949+ let chan_0_1_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
950+ let _chan_0_1_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
951+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
952+
953+ let mut scid_aliases = HashSet :: new ( ) ;
954+ scid_aliases. insert ( chan_0_1_high_inbound_capacity. 0 . short_channel_id_alias . unwrap ( ) ) ;
955+ scid_aliases. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
956+
957+ match_multi_node_invoice_routes (
958+ Some ( 10_000 ) ,
959+ & nodes[ 1 ] ,
960+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
961+ scid_aliases,
962+ false
963+ ) ;
964+ }
965+
966+ #[ test]
967+ #[ cfg( feature = "std" ) ]
968+ fn test_multi_node_channels_inbound_capacity_lower_than_invoice_amt_filtering ( ) {
969+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
970+ let seed_1 = [ 42 as u8 ; 32 ] ;
971+ let seed_2 = [ 43 as u8 ; 32 ] ;
972+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
973+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
974+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
975+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
976+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
977+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
978+
979+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
980+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
981+ let chan_1_3 = create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 3 , 200_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
982+
983+ // Since the invoice 1 msat above chan_0_3's inbound capacity, it should be filtered out.
984+ let mut scid_aliases_99_000_001_msat = HashSet :: new ( ) ;
985+ scid_aliases_99_000_001_msat. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
986+ scid_aliases_99_000_001_msat. insert ( chan_1_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
987+
988+ match_multi_node_invoice_routes (
989+ Some ( 99_000_001 ) ,
990+ & nodes[ 2 ] ,
991+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
992+ scid_aliases_99_000_001_msat,
993+ false
994+ ) ;
995+
996+ // Since the invoice is exactly at chan_0_3's inbound capacity, it should be included.
997+ let mut scid_aliases_99_000_000_msat = HashSet :: new ( ) ;
998+ scid_aliases_99_000_000_msat. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
999+ scid_aliases_99_000_000_msat. insert ( chan_0_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
1000+ scid_aliases_99_000_000_msat. insert ( chan_1_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
1001+
1002+ match_multi_node_invoice_routes (
1003+ Some ( 99_000_000 ) ,
1004+ & nodes[ 2 ] ,
1005+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
1006+ scid_aliases_99_000_000_msat,
1007+ false
1008+ ) ;
1009+
1010+ // Since the invoice is above all of `nodes[2]` channels' inbound capacity, all of
1011+ // `nodes[2]` them should be included.
1012+ let mut scid_aliases_300_000_000_msat = HashSet :: new ( ) ;
1013+ scid_aliases_300_000_000_msat. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
1014+ scid_aliases_300_000_000_msat. insert ( chan_0_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
1015+ scid_aliases_300_000_000_msat. insert ( chan_1_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
1016+
1017+ match_multi_node_invoice_routes (
1018+ Some ( 300_000_000 ) ,
1019+ & nodes[ 2 ] ,
1020+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
1021+ scid_aliases_300_000_000_msat,
1022+ false
1023+ ) ;
1024+
1025+ // Since the no specified amount, all channels should included.
1026+ let mut scid_aliases_no_specified_amount = HashSet :: new ( ) ;
1027+ scid_aliases_no_specified_amount. insert ( chan_0_2. 0 . short_channel_id_alias . unwrap ( ) ) ;
1028+ scid_aliases_no_specified_amount. insert ( chan_0_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
1029+ scid_aliases_no_specified_amount. insert ( chan_1_3. 0 . short_channel_id_alias . unwrap ( ) ) ;
1030+
1031+ match_multi_node_invoice_routes (
1032+ None ,
1033+ & nodes[ 2 ] ,
1034+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
1035+ scid_aliases_no_specified_amount,
1036+ false
1037+ ) ;
1038+ }
1039+
1040+ #[ cfg( feature = "std" ) ]
1041+ fn match_multi_node_invoice_routes < ' a , ' b : ' a , ' c : ' b > (
1042+ invoice_amt : Option < u64 > ,
1043+ invoice_node : & Node < ' a , ' b , ' c > ,
1044+ network_multi_nodes : Vec < & Node < ' a , ' b , ' c > > ,
1045+ mut chan_ids_to_match : HashSet < u64 > ,
1046+ nodes_contains_public_channels : bool
1047+ ) {
1048+ let ( payment_hash, payment_secret) = invoice_node. node . create_inbound_payment ( invoice_amt, 3600 ) . unwrap ( ) ;
1049+ let phantom_route_hints = network_multi_nodes. iter ( )
1050+ . map ( |node| node. node . get_phantom_route_hints ( ) )
1051+ . collect :: < Vec < PhantomRouteHints > > ( ) ;
1052+ let phantom_scids = phantom_route_hints. iter ( )
1053+ . map ( |route_hint| route_hint. phantom_scid )
1054+ . collect :: < HashSet < u64 > > ( ) ;
1055+
1056+ 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 ( ) ;
1057+
1058+ let invoice_hints = invoice. private_routes ( ) ;
1059+
1060+ for hint in invoice_hints {
1061+ let hints = & ( hint. 0 ) . 0 ;
1062+ match hints. len ( ) {
1063+ 1 => {
1064+ assert ! ( nodes_contains_public_channels) ;
1065+ let phantom_scid = hints[ 0 ] . short_channel_id ;
1066+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
1067+ } ,
1068+ 2 => {
1069+ let hint_short_chan_id = hints[ 0 ] . short_channel_id ;
1070+ assert ! ( chan_ids_to_match. contains( & hint_short_chan_id) ) ;
1071+ chan_ids_to_match. remove ( & hint_short_chan_id) ;
1072+ let phantom_scid = hints[ 1 ] . short_channel_id ;
1073+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
1074+ } ,
1075+ _ => panic ! ( "Incorrect hint length generated" )
1076+ }
1077+ }
1078+ assert ! ( chan_ids_to_match. is_empty( ) ) ;
1079+ }
7511080}
0 commit comments