@@ -2083,7 +2083,7 @@ where L::Target: Logger {
20832083 // in the regular network graph.
20842084 first_hop_targets. get ( & intro_node_id) . is_some ( ) ||
20852085 network_nodes. get ( & intro_node_id) . is_some ( ) ;
2086- if !have_intro_node_in_graph { continue }
2086+ if !have_intro_node_in_graph || our_node_id == intro_node_id { continue }
20872087 let candidate = if hint. 1 . blinded_hops . len ( ) == 1 {
20882088 CandidateRouteHop :: OneHopBlinded { hint, hint_idx }
20892089 } else { CandidateRouteHop :: Blinded { hint, hint_idx } } ;
@@ -7170,6 +7170,116 @@ mod tests {
71707170 assert_eq ! ( route. get_total_fees( ) , blinded_payinfo. fee_base_msat as u64 ) ;
71717171 assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
71727172 }
7173+
7174+ #[ test]
7175+ fn we_are_intro_node_candidate_hops ( ) {
7176+ // This previously led to a panic in the router because we'd generate a Path with only a
7177+ // BlindedTail and 0 unblinded hops, due to the only candidate hops being blinded route hints
7178+ // where the origin node is the intro node. We now fully disallow considering candidate hops
7179+ // where the origin node is the intro node.
7180+ let ( secp_ctx, network_graph, _, _, logger) = build_graph ( ) ;
7181+ let ( _, our_id, _, nodes) = get_nodes ( & secp_ctx) ;
7182+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
7183+ let keys_manager = ln_test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
7184+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
7185+ let config = UserConfig :: default ( ) ;
7186+
7187+ // Values are taken from the fuzz input that uncovered this panic.
7188+ let amt_msat = 21_7020_5185_1423_0019 ;
7189+
7190+ let blinded_path = BlindedPath {
7191+ introduction_node_id : our_id,
7192+ blinding_point : ln_test_utils:: pubkey ( 42 ) ,
7193+ blinded_hops : vec ! [
7194+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) } ,
7195+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) }
7196+ ] ,
7197+ } ;
7198+ let blinded_payinfo = BlindedPayInfo {
7199+ fee_base_msat : 5052_9027 ,
7200+ fee_proportional_millionths : 5052_9027 ,
7201+ htlc_minimum_msat : 21_7020_5185_1423_0019 ,
7202+ htlc_maximum_msat : 1844_6744_0737_0955_1615 ,
7203+ cltv_expiry_delta : 0 ,
7204+ features : BlindedHopFeatures :: empty ( ) ,
7205+ } ;
7206+ let mut blinded_hints = vec ! [
7207+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7208+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7209+ ] ;
7210+ blinded_hints[ 1 ] . 1 . introduction_node_id = nodes[ 6 ] ;
7211+
7212+ let bolt12_features: Bolt12InvoiceFeatures = channelmanager:: provided_invoice_features ( & config) . to_context ( ) ;
7213+ let payment_params = PaymentParameters :: blinded ( blinded_hints. clone ( ) )
7214+ . with_bolt12_features ( bolt12_features. clone ( ) ) . unwrap ( ) ;
7215+
7216+ let netgraph = network_graph. read_only ( ) ;
7217+ let route_params = RouteParameters :: from_payment_params_and_value (
7218+ payment_params, amt_msat) ;
7219+ if let Err ( LightningError { err, .. } ) = get_route (
7220+ & our_id, & route_params, & netgraph, None , Arc :: clone ( & logger) , & scorer, & ( ) , & random_seed_bytes
7221+ ) {
7222+ assert_eq ! ( err, "Failed to find a path to the given destination" ) ;
7223+ } else { panic ! ( ) }
7224+ }
7225+
7226+ #[ test]
7227+ fn we_are_intro_node_bp_in_final_path_fee_calc ( ) {
7228+ // This previously led to a debug panic in the router because we'd find an invalid Path with
7229+ // 0 unblinded hops and a blinded tail, leading to the generation of a final
7230+ // PaymentPathHop::fee_msat that included both the blinded path fees and the final value of
7231+ // the payment, when it was intended to only include the final value of the payment.
7232+ let ( secp_ctx, network_graph, _, _, logger) = build_graph ( ) ;
7233+ let ( _, our_id, _, nodes) = get_nodes ( & secp_ctx) ;
7234+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
7235+ let keys_manager = ln_test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
7236+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
7237+ let config = UserConfig :: default ( ) ;
7238+
7239+ // Values are taken from the fuzz input that uncovered this panic.
7240+ let amt_msat = 21_7020_5185_1423_0019 ;
7241+
7242+ let blinded_path = BlindedPath {
7243+ introduction_node_id : our_id,
7244+ blinding_point : ln_test_utils:: pubkey ( 42 ) ,
7245+ blinded_hops : vec ! [
7246+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) } ,
7247+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 42 as u8 ) , encrypted_payload: Vec :: new( ) }
7248+ ] ,
7249+ } ;
7250+ let blinded_payinfo = BlindedPayInfo {
7251+ fee_base_msat : 10_4425_1395 ,
7252+ fee_proportional_millionths : 1_6973_9011 ,
7253+ htlc_minimum_msat : 21_7301_9934_9094_0931 ,
7254+ htlc_maximum_msat : 1844_6744_0737_0955_1615 ,
7255+ cltv_expiry_delta : 0 ,
7256+ features : BlindedHopFeatures :: empty ( ) ,
7257+ } ;
7258+ let mut blinded_hints = vec ! [
7259+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7260+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7261+ ( blinded_payinfo. clone( ) , blinded_path. clone( ) ) ,
7262+ ] ;
7263+ blinded_hints[ 1 ] . 0 . fee_base_msat = 5052_9027 ;
7264+ blinded_hints[ 1 ] . 0 . fee_proportional_millionths = 5052_9027 ;
7265+ blinded_hints[ 1 ] . 0 . htlc_minimum_msat = 21_7020_5185_1423_0019 ;
7266+ blinded_hints[ 1 ] . 0 . htlc_maximum_msat = 1844_6744_0737_0955_1615 ;
7267+
7268+ blinded_hints[ 2 ] . 1 . introduction_node_id = nodes[ 6 ] ;
7269+
7270+ let bolt12_features: Bolt12InvoiceFeatures = channelmanager:: provided_invoice_features ( & config) . to_context ( ) ;
7271+ let payment_params = PaymentParameters :: blinded ( blinded_hints. clone ( ) )
7272+ . with_bolt12_features ( bolt12_features. clone ( ) ) . unwrap ( ) ;
7273+
7274+ let netgraph = network_graph. read_only ( ) ;
7275+ let route_params = RouteParameters :: from_payment_params_and_value (
7276+ payment_params, amt_msat) ;
7277+ if let Err ( LightningError { err, .. } ) = get_route (
7278+ & our_id, & route_params, & netgraph, None , Arc :: clone ( & logger) , & scorer, & ( ) , & random_seed_bytes
7279+ ) {
7280+ assert_eq ! ( err, "Failed to find a path to the given destination" ) ;
7281+ } else { panic ! ( ) }
7282+ }
71737283}
71747284
71757285#[ cfg( all( any( test, ldk_bench) , not( feature = "no-std" ) ) ) ]
0 commit comments