@@ -92,8 +92,8 @@ use core::ops::Deref;
92
92
pub ( super ) enum PendingHTLCRouting {
93
93
Forward {
94
94
onion_packet : msgs:: OnionPacket ,
95
- /// The SCID from the onion that we should forward to. This could be a " real" SCID, an
96
- /// outbound SCID alias, or a phantom node SCID .
95
+ /// The SCID from the onion that we should forward to. This could be a real SCID or a fake one
96
+ /// generated using `get_fake_scid` from the scid_utils::fake_scid module .
97
97
short_channel_id : u64 , // This should be NonZero<u64> eventually when we bump MSRV
98
98
} ,
99
99
Receive {
@@ -684,6 +684,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
684
684
// `total_consistency_lock`
685
685
// |
686
686
// |__`forward_htlcs`
687
+ // | |
688
+ // | |__`pending_intercepted_htlcs`
687
689
// |
688
690
// |__`pending_inbound_payments`
689
691
// | |
@@ -2230,8 +2232,10 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
2230
2232
let forwarding_id_opt = match id_option {
2231
2233
None => { // unknown_next_peer
2232
2234
// Note that this is likely a timing oracle for detecting whether an scid is a
2233
- // phantom.
2234
- if fake_scid:: is_valid_phantom ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash ) {
2235
+ // phantom or an intercept.
2236
+ if fake_scid:: is_valid_phantom ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash ) ||
2237
+ fake_scid:: is_valid_intercept ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash )
2238
+ {
2235
2239
None
2236
2240
} else {
2237
2241
break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
@@ -5091,28 +5095,82 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
5091
5095
fn forward_htlcs ( & self , per_source_pending_forwards : & mut [ ( u64 , OutPoint , u128 , Vec < ( PendingHTLCInfo , u64 ) > ) ] ) {
5092
5096
for & mut ( prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, ref mut pending_forwards) in per_source_pending_forwards {
5093
5097
let mut forward_event = None ;
5098
+ let mut new_intercept_events = Vec :: new ( ) ;
5099
+ let mut failed_intercept_forwards = Vec :: new ( ) ;
5094
5100
if !pending_forwards. is_empty ( ) {
5095
- let mut forward_htlcs = self . forward_htlcs . lock ( ) . unwrap ( ) ;
5096
- if forward_htlcs. is_empty ( ) {
5097
- forward_event = Some ( Duration :: from_millis ( MIN_HTLC_RELAY_HOLDING_CELL_MILLIS ) )
5098
- }
5099
5101
for ( forward_info, prev_htlc_id) in pending_forwards. drain ( ..) {
5100
- match forward_htlcs. entry ( match forward_info. routing {
5101
- PendingHTLCRouting :: Forward { short_channel_id, .. } => short_channel_id,
5102
- PendingHTLCRouting :: Receive { .. } => 0 ,
5103
- PendingHTLCRouting :: ReceiveKeysend { .. } => 0 ,
5104
- } ) {
5102
+ let scid = match forward_info. routing {
5103
+ PendingHTLCRouting :: Forward { short_channel_id, .. } => short_channel_id,
5104
+ PendingHTLCRouting :: Receive { .. } => 0 ,
5105
+ PendingHTLCRouting :: ReceiveKeysend { .. } => 0 ,
5106
+ } ;
5107
+ // Pull this now to avoid introducing a lock order with `forward_htlcs`.
5108
+ let is_our_scid = self . short_to_chan_info . read ( ) . unwrap ( ) . contains_key ( & scid) ;
5109
+
5110
+ let mut forward_htlcs = self . forward_htlcs . lock ( ) . unwrap ( ) ;
5111
+ let forward_htlcs_empty = forward_htlcs. is_empty ( ) ;
5112
+ match forward_htlcs. entry ( scid) {
5105
5113
hash_map:: Entry :: Occupied ( mut entry) => {
5106
5114
entry. get_mut ( ) . push ( HTLCForwardInfo :: AddHTLC ( PendingAddHTLCInfo {
5107
5115
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info } ) ) ;
5108
5116
} ,
5109
5117
hash_map:: Entry :: Vacant ( entry) => {
5110
- entry. insert ( vec ! ( HTLCForwardInfo :: AddHTLC ( PendingAddHTLCInfo {
5111
- prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info } ) ) ) ;
5118
+ if !is_our_scid && forward_info. incoming_amt_msat . is_some ( ) &&
5119
+ fake_scid:: is_valid_intercept ( & self . fake_scid_rand_bytes , scid, & self . genesis_hash )
5120
+ {
5121
+ let intercept_id = InterceptId ( Sha256 :: hash ( & forward_info. incoming_shared_secret ) . into_inner ( ) ) ;
5122
+ let mut pending_intercepts = self . pending_intercepted_htlcs . lock ( ) . unwrap ( ) ;
5123
+ match pending_intercepts. entry ( intercept_id) {
5124
+ hash_map:: Entry :: Vacant ( entry) => {
5125
+ new_intercept_events. push ( events:: Event :: HTLCIntercepted {
5126
+ requested_next_hop_scid : scid,
5127
+ payment_hash : forward_info. payment_hash ,
5128
+ inbound_amount_msat : forward_info. incoming_amt_msat . unwrap ( ) ,
5129
+ expected_outbound_amount_msat : forward_info. outgoing_amt_msat ,
5130
+ intercept_id
5131
+ } ) ;
5132
+ entry. insert ( PendingAddHTLCInfo {
5133
+ prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info } ) ;
5134
+ } ,
5135
+ hash_map:: Entry :: Occupied ( _) => {
5136
+ log_info ! ( self . logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}" , scid) ;
5137
+ let htlc_source = HTLCSource :: PreviousHopData ( HTLCPreviousHopData {
5138
+ short_channel_id : prev_short_channel_id,
5139
+ outpoint : prev_funding_outpoint,
5140
+ htlc_id : prev_htlc_id,
5141
+ incoming_packet_shared_secret : forward_info. incoming_shared_secret ,
5142
+ phantom_shared_secret : None ,
5143
+ } ) ;
5144
+
5145
+ failed_intercept_forwards. push ( ( htlc_source, forward_info. payment_hash ,
5146
+ HTLCFailReason :: Reason { failure_code : 0x4000 | 10 , data : Vec :: new ( ) } ,
5147
+ HTLCDestination :: InvalidForward { requested_forward_scid : scid } ,
5148
+ ) ) ;
5149
+ }
5150
+ }
5151
+ } else {
5152
+ // We don't want to generate a PendingHTLCsForwardable event if only intercepted
5153
+ // payments are being processed.
5154
+ if forward_htlcs_empty {
5155
+ forward_event = Some ( Duration :: from_millis ( MIN_HTLC_RELAY_HOLDING_CELL_MILLIS ) ) ;
5156
+ }
5157
+ entry. insert ( vec ! ( HTLCForwardInfo :: AddHTLC ( PendingAddHTLCInfo {
5158
+ prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info } ) ) ) ;
5159
+ }
5112
5160
}
5113
5161
}
5114
5162
}
5115
5163
}
5164
+
5165
+ for ( htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards. drain ( ..) {
5166
+ self . fail_htlc_backwards_internal ( htlc_source, & payment_hash, failure_reason, destination) ;
5167
+ }
5168
+
5169
+ if !new_intercept_events. is_empty ( ) {
5170
+ let mut events = self . pending_events . lock ( ) . unwrap ( ) ;
5171
+ events. append ( & mut new_intercept_events) ;
5172
+ }
5173
+
5116
5174
match forward_event {
5117
5175
Some ( time) => {
5118
5176
let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
0 commit comments