@@ -338,7 +338,7 @@ mod test {
338
338
use bitcoin_hashes:: sha256:: Hash as Sha256 ;
339
339
use lightning:: chain:: keysinterface:: PhantomKeysManager ;
340
340
use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
341
- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
341
+ use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_FINAL_CLTV_EXPIRY } ;
342
342
use lightning:: ln:: functional_test_utils:: * ;
343
343
use lightning:: ln:: features:: InitFeatures ;
344
344
use lightning:: ln:: msgs:: ChannelMessageHandler ;
@@ -661,4 +661,256 @@ mod test {
661
661
_ => panic ! ( "Unexpected event" )
662
662
}
663
663
}
664
+
665
+ #[ test]
666
+ #[ cfg( feature = "std" ) ]
667
+ fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes ( ) {
668
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
669
+ let seed_1 = [ 42 as u8 ; 32 ] ;
670
+ let seed_2 = [ 43 as u8 ; 32 ] ;
671
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
672
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
673
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
674
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
675
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
676
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
677
+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
678
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
679
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
680
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
681
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
682
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
683
+
684
+ let mut short_chan_ids = HashSet :: new ( ) ;
685
+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
686
+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
687
+
688
+ match_multi_node_invoice_routes (
689
+ Some ( 10_000 ) ,
690
+ & nodes[ 1 ] ,
691
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
692
+ short_chan_ids. clone ( ) ,
693
+ false
694
+ ) ;
695
+ }
696
+
697
+ #[ test]
698
+ #[ cfg( feature = "std" ) ]
699
+ fn test_multi_node_hints_includes_one_channel_of_each_counterparty_nodes_per_participating_node ( ) {
700
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
701
+ let seed_1 = [ 42 as u8 ; 32 ] ;
702
+ let seed_2 = [ 43 as u8 ; 32 ] ;
703
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
704
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
705
+ chanmon_cfgs[ 3 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
706
+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
707
+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
708
+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
709
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
710
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
711
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
712
+ let chan_0_3 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 3 , 1000000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
713
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 3 ] . node . get_our_node_id ( ) , & chan_0_3. 1 ) ;
714
+ nodes[ 3 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_3. 0 ) ;
715
+ let chan_1_3 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 3 , 3_000_000 , 10005 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
716
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 3 ] . node . get_our_node_id ( ) , & chan_1_3. 1 ) ;
717
+ nodes[ 3 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_1_3. 0 ) ;
718
+
719
+ let mut short_chan_ids = HashSet :: new ( ) ;
720
+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
721
+ short_chan_ids. insert ( chan_0_3. 0 . contents . short_channel_id . clone ( ) ) ;
722
+ short_chan_ids. insert ( chan_1_3. 0 . contents . short_channel_id . clone ( ) ) ;
723
+
724
+ match_multi_node_invoice_routes (
725
+ Some ( 10_000 ) ,
726
+ & nodes[ 2 ] ,
727
+ vec ! [ & nodes[ 2 ] , & nodes[ 3 ] , ] ,
728
+ short_chan_ids. clone ( ) ,
729
+ false
730
+ ) ;
731
+ }
732
+
733
+ #[ test]
734
+ #[ cfg( feature = "std" ) ]
735
+ fn test_multi_node_with_private_channel_hints_includes_only_phantom_route ( ) {
736
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
737
+ let seed_1 = [ 42 as u8 ; 32 ] ;
738
+ let seed_2 = [ 43 as u8 ; 32 ] ;
739
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
740
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
741
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
742
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
743
+ let mut nodes_2_priv_channels_conf = UserConfig :: default ( ) ;
744
+ nodes_2_priv_channels_conf. channel_options . announced_channel = false ;
745
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , Some ( nodes_2_priv_channels_conf) ] ) ;
746
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
747
+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
748
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
749
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
750
+
751
+ let chan_2_0 = create_private_chan_between_nodes_with_value ( & nodes, 2 , 0 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
752
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_2_0. 1 ) ;
753
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_2_0. 0 ) ;
754
+
755
+ // Hints should include `chan_0_1` from as `nodes[1]` only have public channels, and no
756
+ // channels for `nodes[2]` as it contains private channels.
757
+ let mut short_chan_ids = HashSet :: new ( ) ;
758
+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
759
+
760
+ match_multi_node_invoice_routes (
761
+ Some ( 10_000 ) ,
762
+ & nodes[ 1 ] ,
763
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
764
+ short_chan_ids. clone ( ) ,
765
+ true
766
+ ) ;
767
+ }
768
+
769
+ #[ test]
770
+ #[ cfg( feature = "std" ) ]
771
+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
772
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
773
+ let seed_1 = [ 42 as u8 ; 32 ] ;
774
+ let seed_2 = [ 43 as u8 ; 32 ] ;
775
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
776
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
777
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
778
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
779
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
780
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
781
+ let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
782
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 1 ) ;
783
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 0 ) ;
784
+ 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 ( ) ) ;
785
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 1 ) ;
786
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 0 ) ;
787
+ 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 ( ) ) ;
788
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 1 ) ;
789
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 0 ) ;
790
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
791
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
792
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
793
+
794
+ let mut short_chan_ids = HashSet :: new ( ) ;
795
+ short_chan_ids. insert ( chan_0_1_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
796
+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
797
+
798
+ match_multi_node_invoice_routes (
799
+ Some ( 10_000 ) ,
800
+ & nodes[ 1 ] ,
801
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
802
+ short_chan_ids. clone ( ) ,
803
+ false
804
+ ) ;
805
+ }
806
+
807
+ #[ test]
808
+ #[ cfg( feature = "std" ) ]
809
+ fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
810
+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
811
+ let seed_1 = [ 42 as u8 ; 32 ] ;
812
+ let seed_2 = [ 43 as u8 ; 32 ] ;
813
+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
814
+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
815
+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
816
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
817
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
818
+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
819
+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
820
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
821
+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
822
+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
823
+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
824
+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
825
+
826
+ // 1 msat above chan_0_1's inbound capacity
827
+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
828
+ short_chan_ids_99_000_001_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
829
+
830
+ match_multi_node_invoice_routes (
831
+ Some ( 99_000_001 ) ,
832
+ & nodes[ 1 ] ,
833
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
834
+ short_chan_ids_99_000_001_msat. clone ( ) ,
835
+ false
836
+ ) ;
837
+
838
+ // Exactly at chan_0_1's inbound capacity
839
+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
840
+ short_chan_ids_99_000_000_msat. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
841
+ short_chan_ids_99_000_000_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
842
+
843
+
844
+ match_multi_node_invoice_routes (
845
+ Some ( 99_000_000 ) ,
846
+ & nodes[ 1 ] ,
847
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
848
+ short_chan_ids_99_000_000_msat. clone ( ) ,
849
+ false
850
+ ) ;
851
+
852
+ // Invoices with a higher amount than any of our channels' inbound capacity should result
853
+ // in no hints.
854
+ match_multi_node_invoice_routes (
855
+ Some ( 99_000_000_1 ) ,
856
+ & nodes[ 1 ] ,
857
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
858
+ HashSet :: new ( ) ,
859
+ false
860
+ ) ;
861
+
862
+ // An invoice with no specified amount should include all participating nodes in the hints.
863
+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
864
+ short_chan_ids_no_specified_amount. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
865
+ short_chan_ids_no_specified_amount. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
866
+
867
+ match_multi_node_invoice_routes (
868
+ None ,
869
+ & nodes[ 1 ] ,
870
+ vec ! [ & nodes[ 1 ] , & nodes[ 2 ] , ] ,
871
+ short_chan_ids_no_specified_amount. clone ( ) ,
872
+ false
873
+ ) ;
874
+ }
875
+
876
+ #[ cfg( feature = "std" ) ]
877
+ fn match_multi_node_invoice_routes < ' a , ' b : ' a , ' c : ' b > (
878
+ invoice_amt : Option < u64 > ,
879
+ invoice_node : & Node < ' a , ' b , ' c > ,
880
+ network_multi_nodes : Vec < & Node < ' a , ' b , ' c > > ,
881
+ mut chan_ids_to_match : HashSet < u64 > ,
882
+ nodes_contains_private_channels : bool
883
+ ) {
884
+ let ( payment_hash, payment_secret) = invoice_node. node . create_inbound_payment ( invoice_amt, 3600 ) . unwrap ( ) ;
885
+ let phantom_route_hints = network_multi_nodes. iter ( )
886
+ . map ( |node| node. node . get_phantom_route_hints ( ) )
887
+ . collect :: < Vec < PhantomRouteHints > > ( ) ;
888
+ let phantom_scids = phantom_route_hints. iter ( )
889
+ . map ( |route_hint| route_hint. phantom_scid )
890
+ . collect :: < HashSet < u64 > > ( ) ;
891
+
892
+ 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 ( ) ;
893
+
894
+ let invoice_hints = invoice. private_routes ( ) ;
895
+
896
+ for hint in invoice_hints {
897
+ let hints = & ( hint. 0 ) . 0 ;
898
+ match hints. len ( ) {
899
+ 1 => {
900
+ assert ! ( nodes_contains_private_channels) ;
901
+ let phantom_scid = hints[ 0 ] . short_channel_id ;
902
+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
903
+ } ,
904
+ 2 => {
905
+ let hint_short_chan_id = hints[ 0 ] . short_channel_id ;
906
+ assert ! ( chan_ids_to_match. contains( & hint_short_chan_id) ) ;
907
+ chan_ids_to_match. remove ( & hint_short_chan_id) ;
908
+ let phantom_scid = hints[ 1 ] . short_channel_id ;
909
+ assert ! ( phantom_scids. contains( & phantom_scid) ) ;
910
+ } ,
911
+ _ => panic ! ( "Incorrect hint length generated" )
912
+ }
913
+ }
914
+ assert ! ( chan_ids_to_match. is_empty( ) ) ;
915
+ }
664
916
}
0 commit comments