@@ -349,7 +349,7 @@ mod test {
349
349
use bitcoin_hashes:: sha256:: Hash as Sha256 ;
350
350
use lightning:: chain:: keysinterface:: PhantomKeysManager ;
351
351
use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
352
- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
352
+ use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_FINAL_CLTV_EXPIRY } ;
353
353
use lightning:: ln:: functional_test_utils:: * ;
354
354
use lightning:: ln:: features:: InitFeatures ;
355
355
use lightning:: ln:: msgs:: ChannelMessageHandler ;
@@ -712,4 +712,256 @@ mod test {
712
712
_ => panic ! ( "Unexpected event" )
713
713
}
714
714
}
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
+ }
715
967
}
0 commit comments