@@ -229,6 +229,9 @@ pub enum PendingHTLCRouting {
229229 blinded: Option<BlindedForward>,
230230 /// The absolute CLTV of the inbound HTLC
231231 incoming_cltv_expiry: Option<u32>,
232+ /// Whether this HTLC should be held by our node until we receive a corresponding
233+ /// [`ReleaseHeldHtlc`] onion message.
234+ hold_htlc: Option<()>,
232235 },
233236 /// An HTLC which should be forwarded on to another Trampoline node.
234237 TrampolineForward {
@@ -371,6 +374,15 @@ impl PendingHTLCRouting {
371374 Self::ReceiveKeysend { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry),
372375 }
373376 }
377+
378+ /// Whether this HTLC should be held by our node until we receive a corresponding
379+ /// [`ReleaseHeldHtlc`] onion message.
380+ fn should_hold_htlc(&self) -> bool {
381+ match self {
382+ Self::Forward { hold_htlc: Some(()), .. } => true,
383+ _ => false,
384+ }
385+ }
374386}
375387
376388/// Information about an incoming HTLC, including the [`PendingHTLCRouting`] describing where it
@@ -638,9 +650,40 @@ impl Readable for PaymentId {
638650/// An identifier used to uniquely identify an intercepted HTLC to LDK.
639651///
640652/// This is not exported to bindings users as we just use [u8; 32] directly
641- #[derive(Hash, Copy, Clone, PartialEq, Eq, Debug )]
653+ #[derive(Hash, Copy, Clone, PartialEq, Eq)]
642654pub struct InterceptId(pub [u8; 32]);
643655
656+ impl InterceptId {
657+ /// This intercept id corresponds to an HTLC that will be forwarded on
658+ /// [`ChannelManager::forward_intercepted_htlc`].
659+ fn from_incoming_shared_secret(ss: &[u8; 32]) -> Self {
660+ Self(Sha256::hash(ss).to_byte_array())
661+ }
662+
663+ /// This intercept id corresponds to an HTLC that will be forwarded on receipt of a
664+ /// [`ReleaseHeldHtlc`] onion message.
665+ fn from_htlc_id_and_chan_id(
666+ htlc_id: u64, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
667+ ) -> Self {
668+ let mut sha = Sha256::engine();
669+ sha.input(&htlc_id.to_be_bytes());
670+ sha.input(&channel_id.0);
671+ sha.input(&counterparty_node_id.serialize());
672+ Self(Sha256::from_engine(sha).to_byte_array())
673+ }
674+ }
675+
676+ impl Borrow<[u8]> for InterceptId {
677+ fn borrow(&self) -> &[u8] {
678+ &self.0[..]
679+ }
680+ }
681+ impl_fmt_traits! {
682+ impl fmt_traits for InterceptId {
683+ const LENGTH: usize = 32;
684+ }
685+ }
686+
644687impl Writeable for InterceptId {
645688 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
646689 self.0.write(w)
@@ -2598,8 +2641,14 @@ pub struct ChannelManager<
25982641 pub(super) forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>,
25992642 #[cfg(not(test))]
26002643 forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>,
2601- /// Storage for HTLCs that have been intercepted and bubbled up to the user. We hold them here
2602- /// until the user tells us what we should do with them.
2644+ /// Storage for HTLCs that have been intercepted.
2645+ ///
2646+ /// These HTLCs fall into two categories:
2647+ /// 1. HTLCs that are bubbled up to the user and held until the invocation of
2648+ /// [`ChannelManager::forward_intercepted_htlc`] or [`ChannelManager::fail_intercepted_htlc`]
2649+ /// (or timeout)
2650+ /// 2. HTLCs that are being held on behalf of an often-offline sender until receipt of a
2651+ /// [`ReleaseHeldHtlc`] onion message from an often-offline recipient
26032652 ///
26042653 /// See `ChannelManager` struct-level documentation for lock order requirements.
26052654 pending_intercepted_htlcs: Mutex<HashMap<InterceptId, PendingAddHTLCInfo>>,
@@ -6282,11 +6331,19 @@ where
62826331 })?;
62836332
62846333 let routing = match payment.forward_info.routing {
6285- PendingHTLCRouting::Forward { onion_packet, blinded, incoming_cltv_expiry, .. } => {
6334+ PendingHTLCRouting::Forward {
6335+ onion_packet,
6336+ blinded,
6337+ incoming_cltv_expiry,
6338+ hold_htlc,
6339+ ..
6340+ } => {
6341+ debug_assert!(hold_htlc.is_none(), "Held intercept HTLCs should not be surfaced in an event until the recipient comes online");
62866342 PendingHTLCRouting::Forward {
62876343 onion_packet,
62886344 blinded,
62896345 incoming_cltv_expiry,
6346+ hold_htlc,
62906347 short_channel_id: next_hop_scid,
62916348 }
62926349 },
@@ -10719,16 +10776,43 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1071910776 ));
1072010777 };
1072110778
10722- if !is_our_scid
10779+ // In the case that we have an HTLC that we're supposed to hold onto until the
10780+ // recipient comes online *and* the outbound scid is encoded as
10781+ // `fake_scid::is_valid_intercept`, we should first wait for the recipient to come
10782+ // online before generating an `HTLCIntercepted` event, since the event cannot be
10783+ // acted on until the recipient is online to cooperatively open the JIT channel. Once
10784+ // we receive the `ReleaseHeldHtlc` message from the recipient, we will circle back
10785+ // here and resume generating the event below.
10786+ if pending_add.forward_info.routing.should_hold_htlc() {
10787+ let intercept_id = InterceptId::from_htlc_id_and_chan_id(
10788+ prev_htlc_id,
10789+ &prev_channel_id,
10790+ &prev_counterparty_node_id,
10791+ );
10792+ let mut held_htlcs = self.pending_intercepted_htlcs.lock().unwrap();
10793+ match held_htlcs.entry(intercept_id) {
10794+ hash_map::Entry::Vacant(entry) => {
10795+ log_trace!(
10796+ logger,
10797+ "Intercepted held HTLC with id {}, holding until the recipient is online",
10798+ intercept_id
10799+ );
10800+ entry.insert(pending_add);
10801+ },
10802+ hash_map::Entry::Occupied(_) => {
10803+ debug_assert!(false, "Should never have two HTLCs with the same channel id and htlc id");
10804+ fail_intercepted_htlc(pending_add);
10805+ },
10806+ }
10807+ } else if !is_our_scid
1072310808 && pending_add.forward_info.incoming_amt_msat.is_some()
1072410809 && fake_scid::is_valid_intercept(
1072510810 &self.fake_scid_rand_bytes,
1072610811 scid,
1072710812 &self.chain_hash,
1072810813 ) {
10729- let intercept_id = InterceptId(
10730- Sha256::hash(&pending_add.forward_info.incoming_shared_secret)
10731- .to_byte_array(),
10814+ let intercept_id = InterceptId::from_incoming_shared_secret(
10815+ &pending_add.forward_info.incoming_shared_secret,
1073210816 );
1073310817 let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap();
1073410818 match pending_intercepts.entry(intercept_id) {
@@ -14905,6 +14989,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
1490514989 (1, blinded, option),
1490614990 (2, short_channel_id, required),
1490714991 (3, incoming_cltv_expiry, option),
14992+ (4, hold_htlc, option),
1490814993 },
1490914994 (1, Receive) => {
1491014995 (0, payment_data, required),
0 commit comments