@@ -104,6 +104,7 @@ pub(super) enum PendingHTLCRouting {
104
104
/// The SCID from the onion that we should forward to. This could be a real SCID or a fake one
105
105
/// generated using `get_fake_scid` from the scid_utils::fake_scid module.
106
106
short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
107
+ incoming_cltv_expiry: Option<u32>,
107
108
},
108
109
Receive {
109
110
payment_data: msgs::FinalOnionHopData,
@@ -124,6 +125,16 @@ pub(super) enum PendingHTLCRouting {
124
125
},
125
126
}
126
127
128
+ impl PendingHTLCRouting {
129
+ fn incoming_cltv_expiry(&self) -> Option<u32> {
130
+ match self {
131
+ Self::Forward { incoming_cltv_expiry, .. } => *incoming_cltv_expiry,
132
+ Self::Receive { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry),
133
+ Self::ReceiveKeysend { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry),
134
+ }
135
+ }
136
+ }
137
+
127
138
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
128
139
pub(super) struct PendingHTLCInfo {
129
140
pub(super) routing: PendingHTLCRouting,
@@ -182,13 +193,16 @@ pub(crate) struct HTLCPreviousHopData {
182
193
// Note that this may be an outbound SCID alias for the associated channel.
183
194
short_channel_id: u64,
184
195
user_channel_id: Option<u128>,
185
- htlc_id: u64,
196
+ pub(crate) htlc_id: u64,
186
197
incoming_packet_shared_secret: [u8; 32],
187
198
phantom_shared_secret: Option<[u8; 32]>,
188
199
189
200
// This field is consumed by `claim_funds_from_hop()` when updating a force-closed backwards
190
201
// channel with a preimage provided by the forward channel.
191
202
outpoint: OutPoint,
203
+ /// Used to preserve our backwards channel by failing back in case an HTLC claim in the forward
204
+ /// channel remains unconfirmed for too long.
205
+ pub(crate) cltv_expiry: Option<u32>,
192
206
}
193
207
194
208
enum OnionPayload {
@@ -2742,6 +2756,7 @@ where
2742
2756
routing: PendingHTLCRouting::Forward {
2743
2757
onion_packet: outgoing_packet,
2744
2758
short_channel_id,
2759
+ incoming_cltv_expiry: Some(msg.cltv_expiry),
2745
2760
},
2746
2761
payment_hash: msg.payment_hash,
2747
2762
incoming_shared_secret: shared_secret,
@@ -3771,8 +3786,9 @@ where
3771
3786
})?;
3772
3787
3773
3788
let routing = match payment.forward_info.routing {
3774
- PendingHTLCRouting::Forward { onion_packet, .. } => {
3775
- PendingHTLCRouting::Forward { onion_packet, short_channel_id: next_hop_scid }
3789
+ PendingHTLCRouting::Forward { onion_packet, incoming_cltv_expiry, .. } => {
3790
+ PendingHTLCRouting::Forward { onion_packet, short_channel_id: next_hop_scid,
3791
+ incoming_cltv_expiry }
3776
3792
},
3777
3793
_ => unreachable!() // Only `PendingHTLCRouting::Forward`s are intercepted
3778
3794
};
@@ -3808,14 +3824,15 @@ where
3808
3824
err: format!("Payment with intercept id {} not found", log_bytes!(intercept_id.0))
3809
3825
})?;
3810
3826
3811
- if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing {
3827
+ if let PendingHTLCRouting::Forward { short_channel_id, incoming_cltv_expiry, .. } = payment.forward_info.routing {
3812
3828
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
3813
3829
short_channel_id: payment.prev_short_channel_id,
3814
3830
user_channel_id: Some(payment.prev_user_channel_id),
3815
3831
outpoint: payment.prev_funding_outpoint,
3816
3832
htlc_id: payment.prev_htlc_id,
3817
3833
incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret,
3818
3834
phantom_shared_secret: None,
3835
+ cltv_expiry: incoming_cltv_expiry,
3819
3836
});
3820
3837
3821
3838
let failure_reason = HTLCFailReason::from_failure_code(0x4000 | 10);
@@ -3853,6 +3870,7 @@ where
3853
3870
outgoing_cltv_value, ..
3854
3871
}
3855
3872
}) => {
3873
+ let cltv_expiry = routing.incoming_cltv_expiry();
3856
3874
macro_rules! failure_handler {
3857
3875
($msg: expr, $err_code: expr, $err_data: expr, $phantom_ss: expr, $next_hop_unknown: expr) => {
3858
3876
log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
@@ -3864,6 +3882,7 @@ where
3864
3882
htlc_id: prev_htlc_id,
3865
3883
incoming_packet_shared_secret: incoming_shared_secret,
3866
3884
phantom_shared_secret: $phantom_ss,
3885
+ cltv_expiry,
3867
3886
});
3868
3887
3869
3888
let reason = if $next_hop_unknown {
@@ -3967,7 +3986,8 @@ where
3967
3986
prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
3968
3987
forward_info: PendingHTLCInfo {
3969
3988
incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
3970
- routing: PendingHTLCRouting::Forward { onion_packet, .. }, skimmed_fee_msat, ..
3989
+ routing: PendingHTLCRouting::Forward { onion_packet, incoming_cltv_expiry, .. },
3990
+ skimmed_fee_msat, ..
3971
3991
},
3972
3992
}) => {
3973
3993
log_trace!(self.logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, &payment_hash, short_chan_id);
@@ -3979,6 +3999,7 @@ where
3979
3999
incoming_packet_shared_secret: incoming_shared_secret,
3980
4000
// Phantom payments are only PendingHTLCRouting::Receive.
3981
4001
phantom_shared_secret: None,
4002
+ cltv_expiry: incoming_cltv_expiry,
3982
4003
});
3983
4004
if let Err(e) = chan.get_mut().queue_add_htlc(outgoing_amt_msat,
3984
4005
payment_hash, outgoing_cltv_value, htlc_source.clone(),
@@ -4060,6 +4081,7 @@ where
4060
4081
htlc_id: prev_htlc_id,
4061
4082
incoming_packet_shared_secret: incoming_shared_secret,
4062
4083
phantom_shared_secret,
4084
+ cltv_expiry: Some(cltv_expiry),
4063
4085
},
4064
4086
// We differentiate the received value from the sender intended value
4065
4087
// if possible so that we don't prematurely mark MPP payments complete
@@ -4090,6 +4112,7 @@ where
4090
4112
htlc_id: $htlc.prev_hop.htlc_id,
4091
4113
incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
4092
4114
phantom_shared_secret,
4115
+ cltv_expiry: Some(cltv_expiry),
4093
4116
}), payment_hash,
4094
4117
HTLCFailReason::reason(0x4000 | 15, htlc_msat_height_data),
4095
4118
HTLCDestination::FailedPayment { payment_hash: $payment_hash },
@@ -6099,6 +6122,7 @@ where
6099
6122
htlc_id: prev_htlc_id,
6100
6123
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
6101
6124
phantom_shared_secret: None,
6125
+ cltv_expiry: forward_info.routing.incoming_cltv_expiry(),
6102
6126
});
6103
6127
6104
6128
failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
@@ -7228,6 +7252,7 @@ where
7228
7252
incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret,
7229
7253
phantom_shared_secret: None,
7230
7254
outpoint: htlc.prev_funding_outpoint,
7255
+ cltv_expiry: htlc.forward_info.routing.incoming_cltv_expiry(),
7231
7256
});
7232
7257
7233
7258
let requested_forward_scid /* intercept scid */ = match htlc.forward_info.routing {
@@ -7933,6 +7958,7 @@ impl_writeable_tlv_based!(PhantomRouteHints, {
7933
7958
impl_writeable_tlv_based_enum!(PendingHTLCRouting,
7934
7959
(0, Forward) => {
7935
7960
(0, onion_packet, required),
7961
+ (1, incoming_cltv_expiry, option),
7936
7962
(2, short_channel_id, required),
7937
7963
},
7938
7964
(1, Receive) => {
@@ -8038,6 +8064,7 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
8038
8064
(0, short_channel_id, required),
8039
8065
(1, phantom_shared_secret, option),
8040
8066
(2, outpoint, required),
8067
+ (3, cltv_expiry, option),
8041
8068
(4, htlc_id, required),
8042
8069
(6, incoming_packet_shared_secret, required),
8043
8070
(7, user_channel_id, option),
0 commit comments