@@ -2042,7 +2042,7 @@ where L::Target: Logger {
2042
2042
// in the regular network graph.
2043
2043
first_hop_targets. get ( & intro_node_id) . is_some ( ) ||
2044
2044
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 }
2046
2046
let candidate = if hint. 1 . blinded_hops . len ( ) == 1 {
2047
2047
CandidateRouteHop :: OneHopBlinded { hint, hint_idx }
2048
2048
} else { CandidateRouteHop :: Blinded { hint, hint_idx } } ;
@@ -7075,6 +7075,116 @@ mod tests {
7075
7075
assert_eq ! ( route. get_total_fees( ) , blinded_payinfo. fee_base_msat as u64 ) ;
7076
7076
assert_eq ! ( route. get_total_amount( ) , amt_msat) ;
7077
7077
}
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
+ }
7078
7188
}
7079
7189
7080
7190
#[ cfg( all( any( test, ldk_bench) , not( feature = "no-std" ) ) ) ]
0 commit comments