@@ -690,6 +690,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
690690// `total_consistency_lock`
691691// |
692692// |__`forward_htlcs`
693+ // | |
694+ // | |__`pending_intercepted_htlcs`
693695// |
694696// |__`channel_state`
695697// | |
@@ -2334,8 +2336,10 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
23342336 let forwarding_id_opt = match id_option {
23352337 None => { // unknown_next_peer
23362338 // Note that this is likely a timing oracle for detecting whether an scid is a
2337- // phantom.
2338- if fake_scid:: is_valid_phantom ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash ) {
2339+ // phantom or an intercept.
2340+ if fake_scid:: is_valid_phantom ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash ) ||
2341+ fake_scid:: is_valid_intercept ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash )
2342+ {
23392343 None
23402344 } else {
23412345 break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
@@ -5113,28 +5117,82 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
51135117 fn forward_htlcs ( & self , per_source_pending_forwards : & mut [ ( u64 , OutPoint , Vec < ( PendingHTLCInfo , u64 ) > ) ] ) {
51145118 for & mut ( prev_short_channel_id, prev_funding_outpoint, ref mut pending_forwards) in per_source_pending_forwards {
51155119 let mut forward_event = None ;
5120+ let mut new_intercept_events = Vec :: new ( ) ;
5121+ let mut failed_intercept_forwards = Vec :: new ( ) ;
51165122 if !pending_forwards. is_empty ( ) {
5117- let mut forward_htlcs = self . forward_htlcs . lock ( ) . unwrap ( ) ;
5118- if forward_htlcs. is_empty ( ) {
5119- forward_event = Some ( Duration :: from_millis ( MIN_HTLC_RELAY_HOLDING_CELL_MILLIS ) )
5120- }
51215123 for ( forward_info, prev_htlc_id) in pending_forwards. drain ( ..) {
5122- match forward_htlcs. entry ( match forward_info. routing {
5123- PendingHTLCRouting :: Forward { short_channel_id, .. } => short_channel_id,
5124- PendingHTLCRouting :: Receive { .. } => 0 ,
5125- PendingHTLCRouting :: ReceiveKeysend { .. } => 0 ,
5126- } ) {
5124+ let scid = match forward_info. routing {
5125+ PendingHTLCRouting :: Forward { short_channel_id, .. } => short_channel_id,
5126+ PendingHTLCRouting :: Receive { .. } => 0 ,
5127+ PendingHTLCRouting :: ReceiveKeysend { .. } => 0 ,
5128+ } ;
5129+ // Pull this now to avoid introducing a lock order with `forward_htlcs`.
5130+ let our_scid = self . short_to_chan_info . read ( ) . unwrap ( ) . contains_key ( & scid) ;
5131+
5132+ let mut forward_htlcs = self . forward_htlcs . lock ( ) . unwrap ( ) ;
5133+ let forward_htlcs_empty = forward_htlcs. is_empty ( ) ;
5134+ match forward_htlcs. entry ( scid) {
51275135 hash_map:: Entry :: Occupied ( mut entry) => {
51285136 entry. get_mut ( ) . push ( HTLCForwardInfo :: AddHTLC ( PendingAddHTLCInfo {
51295137 prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info } ) ) ;
51305138 } ,
51315139 hash_map:: Entry :: Vacant ( entry) => {
5132- entry. insert ( vec ! ( HTLCForwardInfo :: AddHTLC ( PendingAddHTLCInfo {
5133- prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info } ) ) ) ;
5140+ if !our_scid && forward_info. incoming_amt_msat . is_some ( ) &&
5141+ fake_scid:: is_valid_intercept ( & self . fake_scid_rand_bytes , scid, & self . genesis_hash )
5142+ {
5143+ let intercept_id = InterceptId ( Sha256 :: hash ( & forward_info. incoming_shared_secret ) . into_inner ( ) ) ;
5144+ let mut pending_intercepts = self . pending_intercepted_htlcs . lock ( ) . unwrap ( ) ;
5145+ match pending_intercepts. entry ( intercept_id) {
5146+ hash_map:: Entry :: Vacant ( entry) => {
5147+ new_intercept_events. push ( events:: Event :: HTLCIntercepted {
5148+ requested_next_hop_scid : scid,
5149+ payment_hash : forward_info. payment_hash ,
5150+ inbound_amount_msat : forward_info. incoming_amt_msat . unwrap ( ) ,
5151+ expected_outbound_amount_msat : forward_info. outgoing_amt_msat ,
5152+ intercept_id
5153+ } ) ;
5154+ entry. insert ( PendingAddHTLCInfo {
5155+ prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info } ) ;
5156+ } ,
5157+ hash_map:: Entry :: Occupied ( _) => {
5158+ log_info ! ( self . logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}" , scid) ;
5159+ let htlc_source = HTLCSource :: PreviousHopData ( HTLCPreviousHopData {
5160+ short_channel_id : prev_short_channel_id,
5161+ outpoint : prev_funding_outpoint,
5162+ htlc_id : prev_htlc_id,
5163+ incoming_packet_shared_secret : forward_info. incoming_shared_secret ,
5164+ phantom_shared_secret : None ,
5165+ } ) ;
5166+
5167+ failed_intercept_forwards. push ( ( htlc_source, forward_info. payment_hash ,
5168+ HTLCFailReason :: Reason { failure_code : 0x4000 | 10 , data : Vec :: new ( ) } ,
5169+ HTLCDestination :: InvalidForward { requested_forward_scid : scid } ,
5170+ ) ) ;
5171+ }
5172+ }
5173+ } else {
5174+ // We don't want to generate a PendingHTLCsForwardable event if only intercepted
5175+ // payments are being forwarded.
5176+ if forward_htlcs_empty {
5177+ forward_event = Some ( Duration :: from_millis ( MIN_HTLC_RELAY_HOLDING_CELL_MILLIS ) ) ;
5178+ }
5179+ entry. insert ( vec ! ( HTLCForwardInfo :: AddHTLC ( PendingAddHTLCInfo {
5180+ prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info } ) ) ) ;
5181+ }
51345182 }
51355183 }
51365184 }
51375185 }
5186+
5187+ for ( htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards. drain ( ..) {
5188+ self . fail_htlc_backwards_internal ( htlc_source, & payment_hash, failure_reason, destination) ;
5189+ }
5190+
5191+ if !new_intercept_events. is_empty ( ) {
5192+ let mut events = self . pending_events . lock ( ) . unwrap ( ) ;
5193+ events. append ( & mut new_intercept_events) ;
5194+ }
5195+
51385196 match forward_event {
51395197 Some ( time) => {
51405198 let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
0 commit comments