@@ -235,6 +235,7 @@ pub enum PendingHTLCRouting {
235
235
blinded: Option<BlindedForward>,
236
236
/// The absolute CLTV of the inbound HTLC
237
237
incoming_cltv_expiry: Option<u32>,
238
+ /// Signals that the HTLC should be held for release by an offline recipient.
238
239
hold_htlc: bool,
239
240
},
240
241
/// An HTLC which should be forwarded on to another Trampoline node.
@@ -2558,6 +2559,7 @@ pub struct ChannelManager<
2558
2559
/// See `ChannelManager` struct-level documentation for lock order requirements.
2559
2560
pending_intercepted_htlcs: Mutex<HashMap<InterceptId, PendingAddHTLCInfo>>,
2560
2561
2562
+ #[cfg(async_payments)]
2561
2563
pending_held_htlcs: Mutex<HashMap<(u64, u64), PendingAddHTLCInfo>>,
2562
2564
2563
2565
/// SCID/SCID Alias -> pending `update_add_htlc`s to decode.
@@ -3757,6 +3759,8 @@ where
3757
3759
decode_update_add_htlcs: Mutex::new(new_hash_map()),
3758
3760
claimable_payments: Mutex::new(ClaimablePayments { claimable_payments: new_hash_map(), pending_claiming_payments: new_hash_map() }),
3759
3761
pending_intercepted_htlcs: Mutex::new(new_hash_map()),
3762
+ #[cfg(async_payments)]
3763
+ pending_held_htlcs: Mutex::new(new_hash_map()),
3760
3764
short_to_chan_info: FairRwLock::new(new_hash_map()),
3761
3765
3762
3766
our_network_pubkey,
@@ -6052,6 +6056,7 @@ where
6052
6056
Ok(())
6053
6057
}
6054
6058
6059
+ #[cfg(async_payments)]
6055
6060
fn forward_held_htlc(&self, short_channel_id: u64, htlc_id: u64) -> Result<(), APIError> {
6056
6061
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
6057
6062
@@ -10314,11 +10319,44 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
10314
10319
let mut failed_intercept_forwards = Vec::new();
10315
10320
if !pending_forwards.is_empty() {
10316
10321
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
10322
+ // If this HTLC needs to be held for release by an offline recipient, we'll move it to a dedicated
10323
+ // hash map for held HTLCs.
10324
+ #[cfg(async_payments)]
10317
10325
if let PendingHTLCRouting::Forward { hold_htlc: true, .. } =
10318
10326
forward_info.routing
10319
10327
{
10320
10328
let mut held_htlcs = self.pending_held_htlcs.lock().unwrap();
10321
- held_htlcs.entry((prev_short_channel_id, prev_htlc_id));
10329
+ held_htlcs.insert(
10330
+ (prev_short_channel_id, prev_htlc_id),
10331
+ PendingAddHTLCInfo {
10332
+ prev_short_channel_id,
10333
+ prev_counterparty_node_id,
10334
+ prev_funding_outpoint,
10335
+ prev_channel_id,
10336
+ prev_htlc_id,
10337
+ prev_user_channel_id,
10338
+ forward_info,
10339
+ },
10340
+ );
10341
+
10342
+ // TODO: Where to get message paths from?!?
10343
+ let message_paths = [];
10344
+
10345
+ self.flow.enqueue_held_forward_htlc_available(
10346
+ prev_short_channel_id,
10347
+ prev_htlc_id,
10348
+ self.get_peers_for_blinded_path(),
10349
+ &message_paths,
10350
+ );
10351
+
10352
+ log_debug!(
10353
+ self.logger,
10354
+ "Holding HTLC {}:{} for release by an offline recipient",
10355
+ prev_short_channel_id,
10356
+ prev_htlc_id
10357
+ );
10358
+
10359
+ continue;
10322
10360
}
10323
10361
10324
10362
let scid = match forward_info.routing {
@@ -14387,19 +14425,30 @@ where
14387
14425
fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {
14388
14426
#[cfg(async_payments)]
14389
14427
{
14390
- let payment_id = match _context {
14391
- AsyncPaymentsContext::OutboundPayment { payment_id } => payment_id,
14428
+ match _context {
14429
+ AsyncPaymentsContext::OutboundPayment { payment_id } => {
14430
+ if let Err(e) = self.send_payment_for_static_invoice(payment_id) {
14431
+ log_trace!(
14432
+ self.logger,
14433
+ "Failed to release held HTLC with payment id {}: {:?}",
14434
+ payment_id,
14435
+ e
14436
+ );
14437
+ }
14438
+ },
14439
+ AsyncPaymentsContext::OutboundHTLC { chan_id, htlc_id } => {
14440
+ if let Err(e) = self.forward_held_htlc(chan_id, htlc_id) {
14441
+ log_trace!(
14442
+ self.logger,
14443
+ "Failed to release held forward HTLC {}:{} {:?}",
14444
+ chan_id,
14445
+ htlc_id,
14446
+ e
14447
+ );
14448
+ }
14449
+ },
14392
14450
_ => return,
14393
14451
};
14394
-
14395
- if let Err(e) = self.send_payment_for_static_invoice(payment_id) {
14396
- log_trace!(
14397
- self.logger,
14398
- "Failed to release held HTLC with payment id {}: {:?}",
14399
- payment_id,
14400
- e
14401
- );
14402
- }
14403
14452
}
14404
14453
}
14405
14454
@@ -16772,6 +16821,8 @@ where
16772
16821
inbound_payment_key: expanded_inbound_key,
16773
16822
pending_outbound_payments: pending_outbounds,
16774
16823
pending_intercepted_htlcs: Mutex::new(pending_intercepted_htlcs.unwrap()),
16824
+ #[cfg(async_payments)]
16825
+ pending_held_htlcs: Mutex::new(new_hash_map()), // TODO: Persistence.
16775
16826
16776
16827
forward_htlcs: Mutex::new(forward_htlcs),
16777
16828
decode_update_add_htlcs: Mutex::new(decode_update_add_htlcs),
0 commit comments