@@ -402,6 +402,9 @@ pub(crate) struct HTLCPreviousHopData {
402
402
// channel with a preimage provided by the forward channel.
403
403
outpoint: OutPoint,
404
404
counterparty_node_id: Option<PublicKey>,
405
+ /// Used to preserve our backwards channel by failing back in case an HTLC claim in the forward
406
+ /// channel remains unconfirmed for too long.
407
+ cltv_expiry: Option<u32>,
405
408
}
406
409
407
410
#[derive(PartialEq, Eq)]
@@ -704,6 +707,15 @@ impl HTLCSource {
704
707
true
705
708
}
706
709
}
710
+
711
+ /// Returns the CLTV expiry of the inbound HTLC (i.e. the source referred to by this object),
712
+ /// if the source was a forwarded HTLC and the HTLC was first forwarded on LDK 0.1.1 or later.
713
+ pub(crate) fn inbound_htlc_expiry(&self) -> Option<u32> {
714
+ match self {
715
+ Self::PreviousHopData(HTLCPreviousHopData { cltv_expiry, .. }) => *cltv_expiry,
716
+ _ => None,
717
+ }
718
+ }
707
719
}
708
720
709
721
/// This enum is used to specify which error data to send to peers when failing back an HTLC
@@ -5559,7 +5571,7 @@ where
5559
5571
err: format!("Payment with intercept id {} not found", log_bytes!(intercept_id.0))
5560
5572
})?;
5561
5573
5562
- if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing {
5574
+ if let PendingHTLCRouting::Forward { short_channel_id, incoming_cltv_expiry, .. } = payment.forward_info.routing {
5563
5575
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
5564
5576
short_channel_id: payment.prev_short_channel_id,
5565
5577
user_channel_id: Some(payment.prev_user_channel_id),
@@ -5570,6 +5582,7 @@ where
5570
5582
incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret,
5571
5583
phantom_shared_secret: None,
5572
5584
blinded_failure: payment.forward_info.routing.blinded_failure(),
5585
+ cltv_expiry: incoming_cltv_expiry,
5573
5586
});
5574
5587
5575
5588
let failure_reason = HTLCFailReason::from_failure_code(0x4000 | 10);
@@ -5744,6 +5757,7 @@ where
5744
5757
outgoing_cltv_value, ..
5745
5758
}
5746
5759
}) => {
5760
+ let cltv_expiry = routing.incoming_cltv_expiry();
5747
5761
macro_rules! failure_handler {
5748
5762
($msg: expr, $err_code: expr, $err_data: expr, $phantom_ss: expr, $next_hop_unknown: expr) => {
5749
5763
let logger = WithContext::from(&self.logger, forwarding_counterparty, Some(prev_channel_id), Some(payment_hash));
@@ -5759,6 +5773,7 @@ where
5759
5773
incoming_packet_shared_secret: incoming_shared_secret,
5760
5774
phantom_shared_secret: $phantom_ss,
5761
5775
blinded_failure: routing.blinded_failure(),
5776
+ cltv_expiry,
5762
5777
});
5763
5778
5764
5779
let reason = if $next_hop_unknown {
@@ -5868,7 +5883,7 @@ where
5868
5883
prev_user_channel_id, prev_counterparty_node_id, forward_info: PendingHTLCInfo {
5869
5884
incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
5870
5885
routing: PendingHTLCRouting::Forward {
5871
- ref onion_packet, blinded, ..
5886
+ ref onion_packet, blinded, incoming_cltv_expiry, ..
5872
5887
}, skimmed_fee_msat, ..
5873
5888
},
5874
5889
}) => {
@@ -5883,6 +5898,7 @@ where
5883
5898
// Phantom payments are only PendingHTLCRouting::Receive.
5884
5899
phantom_shared_secret: None,
5885
5900
blinded_failure: blinded.map(|b| b.failure),
5901
+ cltv_expiry: incoming_cltv_expiry,
5886
5902
});
5887
5903
let next_blinding_point = blinded.and_then(|b| {
5888
5904
b.next_blinding_override.or_else(|| {
@@ -6073,6 +6089,7 @@ where
6073
6089
incoming_packet_shared_secret: incoming_shared_secret,
6074
6090
phantom_shared_secret,
6075
6091
blinded_failure,
6092
+ cltv_expiry: Some(cltv_expiry),
6076
6093
},
6077
6094
// We differentiate the received value from the sender intended value
6078
6095
// if possible so that we don't prematurely mark MPP payments complete
@@ -6106,6 +6123,7 @@ where
6106
6123
incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
6107
6124
phantom_shared_secret,
6108
6125
blinded_failure,
6126
+ cltv_expiry: Some(cltv_expiry),
6109
6127
}), payment_hash,
6110
6128
HTLCFailReason::reason(0x4000 | 15, htlc_msat_height_data),
6111
6129
HTLCDestination::FailedPayment { payment_hash: $payment_hash },
@@ -8889,6 +8907,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
8889
8907
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
8890
8908
phantom_shared_secret: None,
8891
8909
blinded_failure: forward_info.routing.blinded_failure(),
8910
+ cltv_expiry: forward_info.routing.incoming_cltv_expiry(),
8892
8911
});
8893
8912
8894
8913
failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
@@ -11154,6 +11173,7 @@ where
11154
11173
outpoint: htlc.prev_funding_outpoint,
11155
11174
channel_id: htlc.prev_channel_id,
11156
11175
blinded_failure: htlc.forward_info.routing.blinded_failure(),
11176
+ cltv_expiry: htlc.forward_info.routing.incoming_cltv_expiry(),
11157
11177
});
11158
11178
11159
11179
let requested_forward_scid /* intercept scid */ = match htlc.forward_info.routing {
@@ -12494,6 +12514,7 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
12494
12514
(2, outpoint, required),
12495
12515
(3, blinded_failure, option),
12496
12516
(4, htlc_id, required),
12517
+ (5, cltv_expiry, option),
12497
12518
(6, incoming_packet_shared_secret, required),
12498
12519
(7, user_channel_id, option),
12499
12520
// Note that by the time we get past the required read for type 2 above, outpoint will be
0 commit comments