@@ -2042,7 +2042,7 @@ where L::Target: Logger {
20422042 // in the regular network graph.
20432043 first_hop_targets. get ( & intro_node_id) . is_some ( ) ||
20442044 network_nodes. get ( & intro_node_id) . is_some ( ) ;
2045- if !have_intro_node_in_graph { continue }
2045+ if !have_intro_node_in_graph || our_node_id == intro_node_id { continue }
20462046 let candidate = if hint. 1 . blinded_hops . len ( ) == 1 {
20472047 CandidateRouteHop :: OneHopBlinded { hint, hint_idx }
20482048 } else { CandidateRouteHop :: Blinded { hint, hint_idx } } ;
@@ -7075,6 +7075,116 @@ mod tests {
70757075 assert_eq ! ( route. get_total_fees( ) , blinded_payinfo. fee_base_msat as u64 ) ;
70767076 assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
70777077 }
7078+
7079+ #[ test]
7080+ fn we_are_intro_node_candidate_hops ( ) {
7081+ // This previously led to a panic in the router because we'd generate a Path with only a
7082+ // BlindedTail and 0 unblinded hops, due to the only candidate hops being blinded route hints
7083+ // where the origin node is the intro node. We now fully disallow considering candidate hops
7084+ // where the origin node is the intro node.
7085+ let ( secp_ctx, network_graph, _, _, logger) = build_graph ( ) ;
7086+ let ( _, our_id, _, nodes) = get_nodes ( & secp_ctx) ;
7087+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
7088+ let keys_manager = ln_test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
7089+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
7090+ let config = UserConfig :: default ( ) ;
7091+
7092+ // Values are taken from the fuzz input that uncovered this panic.
7093+ let amt_msat = 21_7020_5185_1423_0019 ;
7094+
7095+ let blinded_path = BlindedPath {
7096+ introduction_node_id : our_id,
7097+ blinding_point : ln_test_utils:: pubkey ( 42 ) ,
7098+ blinded_hops : vec ! [
7099+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) } ,
7100+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) }
7101+ ] ,
7102+ } ;
7103+ let blinded_payinfo = BlindedPayInfo {
7104+ fee_base_msat : 5052_9027 ,
7105+ fee_proportional_millionths : 5052_9027 ,
7106+ htlc_minimum_msat : 21_7020_5185_1423_0019 ,
7107+ htlc_maximum_msat : 1844_6744_0737_0955_1615 ,
7108+ cltv_expiry_delta : 0 ,
7109+ features : BlindedHopFeatures :: empty ( ) ,
7110+ } ;
7111+ let mut blinded_hints = vec ! [
7112+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7113+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7114+ ] ;
7115+ blinded_hints[ 1 ] . 1 . introduction_node_id = nodes[ 6 ] ;
7116+
7117+ let bolt12_features: Bolt12InvoiceFeatures = channelmanager:: provided_invoice_features ( & config) . to_context ( ) ;
7118+ let payment_params = PaymentParameters :: blinded ( blinded_hints. clone ( ) )
7119+ . with_bolt12_features ( bolt12_features. clone ( ) ) . unwrap ( ) ;
7120+
7121+ let netgraph = network_graph. read_only ( ) ;
7122+ let route_params = RouteParameters :: from_payment_params_and_value (
7123+ payment_params, amt_msat) ;
7124+ if let Err ( LightningError { err, .. } ) = get_route (
7125+ & our_id, & route_params, & netgraph, None , Arc :: clone ( & logger) , & scorer, & ( ) , & random_seed_bytes
7126+ ) {
7127+ assert_eq ! ( err, "Failed to find a path to the given destination" ) ;
7128+ } else { panic ! ( ) }
7129+ }
7130+
7131+ #[ test]
7132+ fn we_are_intro_node_bp_in_final_path_fee_calc ( ) {
7133+ // This previously led to a debug panic in the router because we'd find an invalid Path with
7134+ // 0 unblinded hops and a blinded tail, leading to the generation of a final
7135+ // PaymentPathHop::fee_msat that included both the blinded path fees and the final value of
7136+ // the payment, when it was intended to only include the final value of the payment.
7137+ let ( secp_ctx, network_graph, _, _, logger) = build_graph ( ) ;
7138+ let ( _, our_id, _, nodes) = get_nodes ( & secp_ctx) ;
7139+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
7140+ let keys_manager = ln_test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
7141+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
7142+ let config = UserConfig :: default ( ) ;
7143+
7144+ // Values are taken from the fuzz input that uncovered this panic.
7145+ let amt_msat = 21_7020_5185_1423_0019 ;
7146+
7147+ let blinded_path = BlindedPath {
7148+ introduction_node_id : our_id,
7149+ blinding_point : ln_test_utils:: pubkey ( 42 ) ,
7150+ blinded_hops : vec ! [
7151+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) } ,
7152+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) }
7153+ ] ,
7154+ } ;
7155+ let blinded_payinfo = BlindedPayInfo {
7156+ fee_base_msat : 10_4425_1395 ,
7157+ fee_proportional_millionths : 1_6973_9011 ,
7158+ htlc_minimum_msat : 21_7301_9934_9094_0931 ,
7159+ htlc_maximum_msat : 1844_6744_0737_0955_1615 ,
7160+ cltv_expiry_delta : 0 ,
7161+ features : BlindedHopFeatures :: empty ( ) ,
7162+ } ;
7163+ let mut blinded_hints = vec ! [
7164+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7165+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7166+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7167+ ] ;
7168+ blinded_hints[ 1 ] . 0 . fee_base_msat = 5052_9027 ;
7169+ blinded_hints[ 1 ] . 0 . fee_proportional_millionths = 5052_9027 ;
7170+ blinded_hints[ 1 ] . 0 . htlc_minimum_msat = 21_7020_5185_1423_0019 ;
7171+ blinded_hints[ 1 ] . 0 . htlc_maximum_msat = 1844_6744_0737_0955_1615 ;
7172+
7173+ blinded_hints[ 2 ] . 1 . introduction_node_id = nodes[ 6 ] ;
7174+
7175+ let bolt12_features: Bolt12InvoiceFeatures = channelmanager:: provided_invoice_features ( & config) . to_context ( ) ;
7176+ let payment_params = PaymentParameters :: blinded ( blinded_hints. clone ( ) )
7177+ . with_bolt12_features ( bolt12_features. clone ( ) ) . unwrap ( ) ;
7178+
7179+ let netgraph = network_graph. read_only ( ) ;
7180+ let route_params = RouteParameters :: from_payment_params_and_value (
7181+ payment_params, amt_msat) ;
7182+ if let Err ( LightningError { err, .. } ) = get_route (
7183+ & our_id, & route_params, & netgraph, None , Arc :: clone ( & logger) , & scorer, & ( ) , & random_seed_bytes
7184+ ) {
7185+ assert_eq ! ( err, "Failed to find a path to the given destination" ) ;
7186+ } else { panic ! ( ) }
7187+ }
70787188}
70797189
70807190#[ cfg( all( any( test, ldk_bench) , not( feature = "no-std" ) ) ) ]
0 commit comments