@@ -2083,7 +2083,7 @@ where L::Target: Logger {
2083
2083
// in the regular network graph.
2084
2084
first_hop_targets. get ( & intro_node_id) . is_some ( ) ||
2085
2085
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 }
2087
2087
let candidate = if hint. 1 . blinded_hops . len ( ) == 1 {
2088
2088
CandidateRouteHop :: OneHopBlinded { hint, hint_idx }
2089
2089
} else { CandidateRouteHop :: Blinded { hint, hint_idx } } ;
@@ -7170,6 +7170,115 @@ mod tests {
7170
7170
assert_eq ! ( route. get_total_fees( ) , blinded_payinfo. fee_base_msat as u64 ) ;
7171
7171
assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
7172
7172
}
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 : 0 ,
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 : 0 ,
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 . htlc_minimum_msat = 21_7020_5185_1423_0019 ;
7265
+ blinded_hints[ 1 ] . 0 . htlc_maximum_msat = 1844_6744_0737_0955_1615 ;
7266
+
7267
+ blinded_hints[ 2 ] . 1 . introduction_node_id = nodes[ 6 ] ;
7268
+
7269
+ let bolt12_features: Bolt12InvoiceFeatures = channelmanager:: provided_invoice_features ( & config) . to_context ( ) ;
7270
+ let payment_params = PaymentParameters :: blinded ( blinded_hints. clone ( ) )
7271
+ . with_bolt12_features ( bolt12_features. clone ( ) ) . unwrap ( ) ;
7272
+
7273
+ let netgraph = network_graph. read_only ( ) ;
7274
+ let route_params = RouteParameters :: from_payment_params_and_value (
7275
+ payment_params, amt_msat) ;
7276
+ if let Err ( LightningError { err, .. } ) = get_route (
7277
+ & our_id, & route_params, & netgraph, None , Arc :: clone ( & logger) , & scorer, & ( ) , & random_seed_bytes
7278
+ ) {
7279
+ assert_eq ! ( err, "Failed to find a path to the given destination" ) ;
7280
+ } else { panic ! ( ) }
7281
+ }
7173
7282
}
7174
7283
7175
7284
#[ cfg( all( any( test, ldk_bench) , not( feature = "no-std" ) ) ) ]
0 commit comments