X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=20014f799ee5db53eec61bd1ad4c66cf3096e0ec;hb=fb6e018eb8fc6598da0b9f36ce7aa458f4df6a0c;hp=d802318975e6609adc33f7f50b873afa6108aad5;hpb=8fe7cbe9216975bfdb783af2b11203400e0a2d21;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index d8023189..20014f79 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2233,8 +2233,9 @@ impl ChannelManager { // unknown_next_peer // Note that this is likely a timing oracle for detecting whether an scid is a // phantom or an intercept. - if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) || - fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) + if (self.default_configuration.accept_intercept_htlcs && + fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash)) || + fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) { None } else { @@ -3051,6 +3052,102 @@ impl ChannelManager Result<(), APIError> { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) { + Some(chan) => { + if !chan.is_usable() { + return Err(APIError::APIMisuseError { + err: format!("Channel with id {:?} not fully established", next_hop_channel_id) + }) + } + chan.get_short_channel_id().unwrap_or(chan.outbound_scid_alias()) + }, + None => return Err(APIError::APIMisuseError { + err: format!("Channel with id {:?} not found", next_hop_channel_id) + }) + }; + + let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id) + .ok_or_else(|| APIError::APIMisuseError { + err: format!("Payment with intercept id {:?} not found", intercept_id.0) + })?; + + let routing = match payment.forward_info.routing { + PendingHTLCRouting::Forward { onion_packet, .. } => { + PendingHTLCRouting::Forward { onion_packet, short_channel_id: next_hop_scid } + }, + _ => unreachable!() // Only `PendingHTLCRouting::Forward`s are intercepted + }; + let pending_htlc_info = PendingHTLCInfo { + outgoing_amt_msat: amt_to_forward_msat, routing, ..payment.forward_info + }; + + let mut per_source_pending_forward = [( + payment.prev_short_channel_id, + payment.prev_funding_outpoint, + payment.prev_user_channel_id, + vec![(pending_htlc_info, payment.prev_htlc_id)] + )]; + self.forward_htlcs(&mut per_source_pending_forward); + Ok(()) + } + + /// Fails the intercepted HTLC indicated by intercept_id. Should only be called in response to + /// an [`HTLCIntercepted`] event. See [`ChannelManager::forward_intercepted_htlc`]. + /// + /// Errors if the event was not handled in time, in which case the HTLC was automatically failed + /// backwards. + /// + /// [`HTLCIntercepted`]: events::Event::HTLCIntercepted + pub fn fail_intercepted_htlc(&self, intercept_id: InterceptId) -> Result<(), APIError> { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id) + .ok_or_else(|| APIError::APIMisuseError { + err: format!("Payment with InterceptId {:?} not found", intercept_id) + })?; + + if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing { + let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { + short_channel_id: payment.prev_short_channel_id, + outpoint: payment.prev_funding_outpoint, + htlc_id: payment.prev_htlc_id, + incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret, + phantom_shared_secret: None, + }); + + let failure_reason = HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() }; + let destination = HTLCDestination::UnknownNextHop { requested_forward_scid: short_channel_id }; + self.fail_htlc_backwards_internal(htlc_source, &payment.forward_info.payment_hash, failure_reason, destination); + } else { unreachable!() } // Only `PendingHTLCRouting::Forward`s are intercepted + + Ok(()) + } + /// Processes HTLCs which are pending waiting on random forward delay. /// /// Should only really ever be called in response to a PendingHTLCsForwardable event. @@ -5772,6 +5869,23 @@ impl ChannelManager u64 { + let best_block_height = self.best_block.read().unwrap().height(); + let short_to_chan_info = self.short_to_chan_info.read().unwrap(); + loop { + let scid_candidate = fake_scid::Namespace::Intercept.get_fake_scid(best_block_height, &self.genesis_hash, &self.fake_scid_rand_bytes, &self.keys_manager); + // Ensure the generated scid doesn't conflict with a real channel. + if short_to_chan_info.contains_key(&scid_candidate) { continue } + return scid_candidate + } + } + /// Gets inflight HTLC information by processing pending outbound payments that are in /// our channels. May be used during pathfinding to account for in-use channel liquidity. pub fn compute_inflight_htlcs(&self) -> InFlightHtlcs { @@ -6155,7 +6269,6 @@ where if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER { let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec(); htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height)); - timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: htlc_msat_height_data @@ -6165,6 +6278,29 @@ where }); !htlcs.is_empty() // Only retain this entry if htlcs has at least one entry. }); + + let mut intercepted_htlcs = self.pending_intercepted_htlcs.lock().unwrap(); + intercepted_htlcs.retain(|_, htlc| { + if height >= htlc.forward_info.outgoing_cltv_value - HTLC_FAIL_BACK_BUFFER { + let prev_hop_data = HTLCSource::PreviousHopData(HTLCPreviousHopData { + short_channel_id: htlc.prev_short_channel_id, + htlc_id: htlc.prev_htlc_id, + incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret, + phantom_shared_secret: None, + outpoint: htlc.prev_funding_outpoint, + }); + + let requested_forward_scid /* intercept scid */ = match htlc.forward_info.routing { + PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id, + _ => unreachable!(), + }; + timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash, + HTLCFailReason::Reason { failure_code: 0x2000 | 2, data: Vec::new() }, + HTLCDestination::InvalidForward { requested_forward_scid })); + log_trace!(self.logger, "Timing out intercepted HTLC with requested forward scid {}", requested_forward_scid); + false + } else { true } + }); } self.handle_init_event_channel_failures(failed_channels);