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