@@ -737,4 +737,197 @@ mod test {
737
737
_ => panic ! ( "Unexpected event" )
738
738
}
739
739
}
740
+
741
+ #[ test]
742
+ #[ cfg( feature = "std" ) ]
743
+ fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes ( ) {
744
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
745
+ let seed_1 = [ 42 as u8 ; 32 ] ;
746
+ let seed_2 = [ 43 as u8 ; 32 ] ;
747
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
748
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
749
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
750
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
751
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
752
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
753
+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
754
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
755
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
756
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
757
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
758
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
759
+
760
+ let payment_amt = 10_000 ;
761
+ let ( _, payment_hash, payment_secret) = {
762
+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
763
+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
764
+ ( payment_preimage, payment_hash, payment_secret)
765
+ } ;
766
+ let route_hints = vec ! [
767
+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
768
+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
769
+ ] ;
770
+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , "test" . to_string ( ) , payment_hash, payment_secret, route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
771
+
772
+ let hints = invoice. private_routes ( ) ;
773
+ assert_eq ! ( hints. len( ) , 2 ) ;
774
+
775
+ let mut short_chan_ids = HashSet :: new ( ) ;
776
+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
777
+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
778
+ for hint in hints {
779
+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
780
+ assert ! ( short_chan_ids. contains( & hint_short_chan_id) ) ;
781
+ short_chan_ids. remove ( & hint_short_chan_id) ;
782
+ }
783
+ }
784
+
785
+ #[ test]
786
+ #[ cfg( feature = "std" ) ]
787
+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
788
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
789
+ let seed_1 = [ 42 as u8 ; 32 ] ;
790
+ let seed_2 = [ 43 as u8 ; 32 ] ;
791
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
792
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
793
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
794
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
795
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
796
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
797
+ let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
798
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 1 ) ;
799
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 0 ) ;
800
+ 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 ( ) ) ;
801
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 1 ) ;
802
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 0 ) ;
803
+ 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 ( ) ) ;
804
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 1 ) ;
805
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 0 ) ;
806
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
807
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
808
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
809
+
810
+ let payment_amt = 10_000 ;
811
+ let ( _, payment_hash, payment_secret) = {
812
+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
813
+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
814
+ ( payment_preimage, payment_hash, payment_secret)
815
+ } ;
816
+ let route_hints = vec ! [
817
+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
818
+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
819
+ ] ;
820
+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , "test" . to_string ( ) , payment_hash, payment_secret, route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
821
+
822
+ let hints = invoice. private_routes ( ) ;
823
+ assert_eq ! ( hints. len( ) , 2 ) ;
824
+
825
+ let mut short_chan_ids = HashSet :: new ( ) ;
826
+ short_chan_ids. insert ( chan_0_1_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
827
+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
828
+ for hint in hints {
829
+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
830
+ assert ! ( short_chan_ids. contains( & hint_short_chan_id) ) ;
831
+ short_chan_ids. remove ( & hint_short_chan_id) ;
832
+ }
833
+ }
834
+
835
+ #[ test]
836
+ #[ cfg( feature = "std" ) ]
837
+ fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
838
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
839
+ let seed_1 = [ 42 as u8 ; 32 ] ;
840
+ let seed_2 = [ 43 as u8 ; 32 ] ;
841
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
842
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
843
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
844
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
845
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
846
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
847
+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
848
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
849
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
850
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
851
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
852
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
853
+
854
+ // 1 msat above chan_0_1's inbound capacity
855
+ let payment_amt_99_000_001_msat = 99_000_001 ;
856
+ let ( _, payment_hash_99_000_001_msat, payment_secret_99_000_001_msat) = {
857
+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt_99_000_001_msat) , 3600 ) . unwrap ( ) ;
858
+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
859
+ ( payment_preimage, payment_hash, payment_secret)
860
+ } ;
861
+
862
+ let route_hints_99_000_001_msat = vec ! [
863
+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
864
+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
865
+ ] ;
866
+
867
+ let invoice_99_000_001_msat = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt_99_000_001_msat) , "test" . to_string ( ) , payment_hash_99_000_001_msat, payment_secret_99_000_001_msat, route_hints_99_000_001_msat, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
868
+
869
+ let hints_99_000_001_msat = invoice_99_000_001_msat. private_routes ( ) ;
870
+ assert_eq ! ( hints_99_000_001_msat. len( ) , 1 ) ;
871
+
872
+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
873
+ short_chan_ids_99_000_001_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
874
+ for hint in hints_99_000_001_msat {
875
+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
876
+ assert ! ( short_chan_ids_99_000_001_msat. contains( & hint_short_chan_id) ) ;
877
+ short_chan_ids_99_000_001_msat. remove ( & hint_short_chan_id) ;
878
+ }
879
+
880
+ // Exactly at chan_0_1's inbound capacity
881
+ let payment_amt_99_000_000_msat = 99_000_000 ;
882
+ let ( _, payment_hash_99_000_000_msat, payment_secret_99_000_000_msat) = {
883
+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt_99_000_000_msat) , 3600 ) . unwrap ( ) ;
884
+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
885
+ ( payment_preimage, payment_hash, payment_secret)
886
+ } ;
887
+
888
+ let route_hints_99_000_000_msat = vec ! [
889
+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
890
+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
891
+ ] ;
892
+
893
+ let invoice_99_000_000_msat = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt_99_000_000_msat) , "test" . to_string ( ) , payment_hash_99_000_000_msat, payment_secret_99_000_000_msat, route_hints_99_000_000_msat, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
894
+
895
+ let hints_99_000_000_msat = invoice_99_000_000_msat. private_routes ( ) ;
896
+ assert_eq ! ( hints_99_000_000_msat. len( ) , 2 ) ;
897
+
898
+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
899
+ short_chan_ids_99_000_000_msat. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
900
+ short_chan_ids_99_000_000_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
901
+ for hint in hints_99_000_000_msat {
902
+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
903
+ assert ! ( short_chan_ids_99_000_000_msat. contains( & hint_short_chan_id) ) ;
904
+ short_chan_ids_99_000_000_msat. remove ( & hint_short_chan_id) ;
905
+ }
906
+
907
+ // An invoice with no specified amount should include all participating nodes in the hints.
908
+ let ( _, payment_hash_no_specified_amount, payment_secret_no_specified_amount) = {
909
+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( None , 3600 ) . unwrap ( ) ;
910
+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
911
+ ( payment_preimage, payment_hash, payment_secret)
912
+ } ;
913
+
914
+ let route_hints_no_specified_amount = vec ! [
915
+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
916
+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
917
+ ] ;
918
+
919
+ let invoice_no_specified_amount = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( None , "test" . to_string ( ) , payment_hash_no_specified_amount, payment_secret_no_specified_amount, route_hints_no_specified_amount, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
920
+
921
+ let hints_no_specified_amount = invoice_no_specified_amount. private_routes ( ) ;
922
+ assert_eq ! ( hints_no_specified_amount. len( ) , 2 ) ;
923
+
924
+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
925
+ short_chan_ids_no_specified_amount. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
926
+ short_chan_ids_no_specified_amount. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
927
+ for hint in hints_no_specified_amount {
928
+ let hint_short_chan_id = ( hint. 0 ) . 0 [ 0 ] . short_channel_id ;
929
+ assert ! ( short_chan_ids_no_specified_amount. contains( & hint_short_chan_id) ) ;
930
+ short_chan_ids_no_specified_amount. remove ( & hint_short_chan_id) ;
931
+ }
932
+ }
740
933
}
0 commit comments