@@ -7691,6 +7691,203 @@ mod tests {
7691
7691
assert_eq ! ( route. paths. len( ) , 1 ) ;
7692
7692
assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
7693
7693
}
7694
+
7695
+ #[ test]
7696
+ fn first_hop_preferred_over_hint ( ) {
7697
+ // Check that if we have a first hop to a peer we'd always prefer that over a route hint
7698
+ // they gave us, but we'd still consider all subsequent hints if they are more attractive.
7699
+ let secp_ctx = Secp256k1 :: new ( ) ;
7700
+ let logger = Arc :: new ( ln_test_utils:: TestLogger :: new ( ) ) ;
7701
+ let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , Arc :: clone ( & logger) ) ) ;
7702
+ let gossip_sync = P2PGossipSync :: new ( Arc :: clone ( & network_graph) , None , Arc :: clone ( & logger) ) ;
7703
+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
7704
+ let keys_manager = ln_test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
7705
+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
7706
+ let config = UserConfig :: default ( ) ;
7707
+
7708
+ let amt_msat = 1_000_000 ;
7709
+ let ( our_privkey, our_node_id, privkeys, nodes) = get_nodes ( & secp_ctx) ;
7710
+
7711
+ add_channel ( & gossip_sync, & secp_ctx, & our_privkey, & privkeys[ 0 ] ,
7712
+ ChannelFeatures :: from_le_bytes ( id_to_feature_flags ( 1 ) ) , 1 ) ;
7713
+ update_channel ( & gossip_sync, & secp_ctx, & our_privkey, UnsignedChannelUpdate {
7714
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
7715
+ short_channel_id : 1 ,
7716
+ timestamp : 1 ,
7717
+ flags : 0 ,
7718
+ cltv_expiry_delta : 42 ,
7719
+ htlc_minimum_msat : 1_000 ,
7720
+ htlc_maximum_msat : 10_000_000 ,
7721
+ fee_base_msat : 800 ,
7722
+ fee_proportional_millionths : 0 ,
7723
+ excess_data : Vec :: new ( )
7724
+ } ) ;
7725
+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 0 ] , UnsignedChannelUpdate {
7726
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
7727
+ short_channel_id : 1 ,
7728
+ timestamp : 1 ,
7729
+ flags : 1 ,
7730
+ cltv_expiry_delta : 42 ,
7731
+ htlc_minimum_msat : 1_000 ,
7732
+ htlc_maximum_msat : 10_000_000 ,
7733
+ fee_base_msat : 800 ,
7734
+ fee_proportional_millionths : 0 ,
7735
+ excess_data : Vec :: new ( )
7736
+ } ) ;
7737
+
7738
+ add_channel ( & gossip_sync, & secp_ctx, & privkeys[ 0 ] , & privkeys[ 1 ] ,
7739
+ ChannelFeatures :: from_le_bytes ( id_to_feature_flags ( 1 ) ) , 2 ) ;
7740
+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 0 ] , UnsignedChannelUpdate {
7741
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
7742
+ short_channel_id : 2 ,
7743
+ timestamp : 2 ,
7744
+ flags : 0 ,
7745
+ cltv_expiry_delta : 42 ,
7746
+ htlc_minimum_msat : 1_000 ,
7747
+ htlc_maximum_msat : 10_000_000 ,
7748
+ fee_base_msat : 800 ,
7749
+ fee_proportional_millionths : 0 ,
7750
+ excess_data : Vec :: new ( )
7751
+ } ) ;
7752
+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 1 ] , UnsignedChannelUpdate {
7753
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
7754
+ short_channel_id : 2 ,
7755
+ timestamp : 2 ,
7756
+ flags : 1 ,
7757
+ cltv_expiry_delta : 42 ,
7758
+ htlc_minimum_msat : 1_000 ,
7759
+ htlc_maximum_msat : 10_000_000 ,
7760
+ fee_base_msat : 800 ,
7761
+ fee_proportional_millionths : 0 ,
7762
+ excess_data : Vec :: new ( )
7763
+ } ) ;
7764
+
7765
+ let dest_node_id = nodes[ 2 ] ;
7766
+
7767
+ let route_hint = RouteHint ( vec ! [ RouteHintHop {
7768
+ src_node_id: our_node_id,
7769
+ short_channel_id: 44 ,
7770
+ fees: RoutingFees {
7771
+ base_msat: 234 ,
7772
+ proportional_millionths: 0 ,
7773
+ } ,
7774
+ cltv_expiry_delta: 10 ,
7775
+ htlc_minimum_msat: None ,
7776
+ htlc_maximum_msat: Some ( 5_000_000 ) ,
7777
+ } ,
7778
+ RouteHintHop {
7779
+ src_node_id: nodes[ 0 ] ,
7780
+ short_channel_id: 45 ,
7781
+ fees: RoutingFees {
7782
+ base_msat: 123 ,
7783
+ proportional_millionths: 0 ,
7784
+ } ,
7785
+ cltv_expiry_delta: 10 ,
7786
+ htlc_minimum_msat: None ,
7787
+ htlc_maximum_msat: None ,
7788
+ } ] ) ;
7789
+
7790
+ let payment_params = PaymentParameters :: from_node_id ( dest_node_id, 42 )
7791
+ . with_route_hints ( vec ! [ route_hint] ) . unwrap ( )
7792
+ . with_bolt11_features ( channelmanager:: provided_invoice_features ( & config) ) . unwrap ( ) ;
7793
+ let route_params = RouteParameters :: from_payment_params_and_value (
7794
+ payment_params, amt_msat) ;
7795
+
7796
+ // First create an insufficient first hop for channel with SCID 1 and check we'd use the
7797
+ // route hint.
7798
+ let first_hop = get_channel_details ( Some ( 1 ) , nodes[ 0 ] ,
7799
+ channelmanager:: provided_init_features ( & config) , 999_999 ) ;
7800
+ let first_hops = vec ! [ first_hop] ;
7801
+
7802
+ let route = get_route ( & our_node_id, & route_params. clone ( ) , & network_graph. read_only ( ) ,
7803
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , Arc :: clone ( & logger) , & scorer,
7804
+ & Default :: default ( ) , & random_seed_bytes) . unwrap ( ) ;
7805
+ assert_eq ! ( route. paths. len( ) , 1 ) ;
7806
+ assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
7807
+ assert_eq ! ( route. paths[ 0 ] . hops. len( ) , 2 ) ;
7808
+ assert_eq ! ( route. paths[ 0 ] . hops[ 0 ] . short_channel_id, 44 ) ;
7809
+ assert_eq ! ( route. paths[ 0 ] . hops[ 1 ] . short_channel_id, 45 ) ;
7810
+ assert_eq ! ( route. get_total_fees( ) , 123 ) ;
7811
+
7812
+ // Now check we would trust our first hop info, i.e., fail if we detect the route hint is
7813
+ // for a first hop channel.
7814
+ let mut first_hop = get_channel_details ( Some ( 1 ) , nodes[ 0 ] , channelmanager:: provided_init_features ( & config) , 999_999 ) ;
7815
+ first_hop. outbound_scid_alias = Some ( 44 ) ;
7816
+ let first_hops = vec ! [ first_hop] ;
7817
+
7818
+ let route_res = get_route ( & our_node_id, & route_params. clone ( ) , & network_graph. read_only ( ) ,
7819
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , Arc :: clone ( & logger) , & scorer,
7820
+ & Default :: default ( ) , & random_seed_bytes) ;
7821
+ assert ! ( route_res. is_err( ) ) ;
7822
+
7823
+ // Finally check we'd use the first hop if has sufficient outbound capacity. But we'd stil
7824
+ // use the cheaper second hop of the route hint.
7825
+ let mut first_hop = get_channel_details ( Some ( 1 ) , nodes[ 0 ] ,
7826
+ channelmanager:: provided_init_features ( & config) , 10_000_000 ) ;
7827
+ first_hop. outbound_scid_alias = Some ( 44 ) ;
7828
+ let first_hops = vec ! [ first_hop] ;
7829
+
7830
+ let route = get_route ( & our_node_id, & route_params. clone ( ) , & network_graph. read_only ( ) ,
7831
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , Arc :: clone ( & logger) , & scorer,
7832
+ & Default :: default ( ) , & random_seed_bytes) . unwrap ( ) ;
7833
+ assert_eq ! ( route. paths. len( ) , 1 ) ;
7834
+ assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
7835
+ assert_eq ! ( route. paths[ 0 ] . hops. len( ) , 2 ) ;
7836
+ assert_eq ! ( route. paths[ 0 ] . hops[ 0 ] . short_channel_id, 1 ) ;
7837
+ assert_eq ! ( route. paths[ 0 ] . hops[ 1 ] . short_channel_id, 45 ) ;
7838
+ assert_eq ! ( route. get_total_fees( ) , 123 ) ;
7839
+ }
7840
+
7841
+ #[ test]
7842
+ fn allow_us_being_first_hint ( ) {
7843
+ // Check that we consider a route hint even if we are the src of the first hop.
7844
+ let secp_ctx = Secp256k1 :: new ( ) ;
7845
+ let logger = Arc :: new ( ln_test_utils:: TestLogger :: new ( ) ) ;
7846
+ let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , Arc :: clone ( & logger) ) ) ;
7847
+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
7848
+ let keys_manager = ln_test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
7849
+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
7850
+ let config = UserConfig :: default ( ) ;
7851
+
7852
+ let ( _, our_node_id, _, nodes) = get_nodes ( & secp_ctx) ;
7853
+
7854
+ let amt_msat = 1_000_000 ;
7855
+ let dest_node_id = nodes[ 1 ] ;
7856
+
7857
+ let first_hop = get_channel_details ( Some ( 1 ) , nodes[ 0 ] , channelmanager:: provided_init_features ( & config) , 10_000_000 ) ;
7858
+ let first_hops = vec ! [ first_hop] ;
7859
+
7860
+ let route_hint = RouteHint ( vec ! [ RouteHintHop {
7861
+ src_node_id: our_node_id,
7862
+ short_channel_id: 44 ,
7863
+ fees: RoutingFees {
7864
+ base_msat: 123 ,
7865
+ proportional_millionths: 0 ,
7866
+ } ,
7867
+ cltv_expiry_delta: 10 ,
7868
+ htlc_minimum_msat: None ,
7869
+ htlc_maximum_msat: None ,
7870
+ } ] ) ;
7871
+
7872
+ let payment_params = PaymentParameters :: from_node_id ( dest_node_id, 42 )
7873
+ . with_route_hints ( vec ! [ route_hint] ) . unwrap ( )
7874
+ . with_bolt11_features ( channelmanager:: provided_invoice_features ( & config) ) . unwrap ( ) ;
7875
+
7876
+ let route_params = RouteParameters :: from_payment_params_and_value (
7877
+ payment_params, amt_msat) ;
7878
+
7879
+
7880
+ let route = get_route ( & our_node_id, & route_params, & network_graph. read_only ( ) ,
7881
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , Arc :: clone ( & logger) , & scorer,
7882
+ & Default :: default ( ) , & random_seed_bytes) . unwrap ( ) ;
7883
+
7884
+ assert_eq ! ( route. paths. len( ) , 1 ) ;
7885
+ assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
7886
+ assert_eq ! ( route. get_total_fees( ) , 0 ) ;
7887
+ assert_eq ! ( route. paths[ 0 ] . hops. len( ) , 1 ) ;
7888
+
7889
+ assert_eq ! ( route. paths[ 0 ] . hops[ 0 ] . short_channel_id, 44 ) ;
7890
+ }
7694
7891
}
7695
7892
7696
7893
#[ cfg( all( any( test, ldk_bench) , not( feature = "no-std" ) ) ) ]
0 commit comments