Skip to content

Commit 4dc0dd1

Browse files
authored
Merge pull request #579 from ariard/2020-04-sanitize-cltv-delay
Sanititze and document incoming HTLC cltv_expiry handling
2 parents 2cce8d0 + 886223a commit 4dc0dd1

File tree

4 files changed

+29
-22
lines changed

4 files changed

+29
-22
lines changed

fuzz/src/full_stack.rs

Lines changed: 11 additions & 12 deletions
Large diffs are not rendered by default.

lightning/src/ln/channel.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,8 +1727,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17271727
return Err(ChannelError::Close("Remote provided CLTV expiry in seconds instead of block height"));
17281728
}
17291729

1730-
//TODO: Check msg.cltv_expiry further? Do this in channel manager?
1731-
17321730
if self.channel_state & ChannelState::LocalShutdownSent as u32 != 0 {
17331731
if let PendingHTLCStatus::Forward(_) = pending_forward_state {
17341732
panic!("ChannelManager shouldn't be trying to add a forwardable HTLC after we've started closing");
@@ -3559,8 +3557,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
35593557
return Err(ChannelError::Ignore("Cannot send value that would put us over their reserve value"));
35603558
}
35613559

3562-
//TODO: Check cltv_expiry? Do this in channel manager?
3563-
35643560
// Now update local state:
35653561
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
35663562
self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::AddHTLC {

lightning/src/ln/channelmanager.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use secp256k1;
2828
use chain::chaininterface::{BroadcasterInterface,ChainListener,FeeEstimator};
2929
use chain::transaction::OutPoint;
3030
use ln::channel::{Channel, ChannelError};
31-
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, ManyChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, HTLC_FAIL_BACK_BUFFER};
31+
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, ManyChannelMonitor, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
3232
use ln::features::{InitFeatures, NodeFeatures};
3333
use ln::router::{Route, RouteHop};
3434
use ln::msgs;
@@ -1039,7 +1039,11 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
10391039

10401040
// OUR PAYMENT!
10411041
// final_expiry_too_soon
1042-
if (msg.cltv_expiry as u64) < self.latest_block_height.load(Ordering::Acquire) as u64 + (CLTV_CLAIM_BUFFER + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
1042+
// We have to have some headroom to broadcast on chain if we have the preimage, so make sure we have at least
1043+
// HTLC_FAIL_BACK_BUFFER blocks to go.
1044+
// Also, ensure that, in the case of an unknown payment hash, our payment logic has enough time to fail the HTLC backward
1045+
// before our onchain logic triggers a channel closure (see HTLC_FAIL_BACK_BUFFER rational).
1046+
if (msg.cltv_expiry as u64) <= self.latest_block_height.load(Ordering::Acquire) as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
10431047
return_err!("The final CLTV expiry is too soon to handle", 17, &[0;0]);
10441048
}
10451049
// final_incorrect_htlc_amount
@@ -1163,13 +1167,20 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
11631167
break Some(("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, Some(self.get_channel_update(chan).unwrap())));
11641168
}
11651169
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
1166-
// We want to have at least LATENCY_GRACE_PERIOD_BLOCKS to fail prior to going on chain CLAIM_BUFFER blocks before expiration
1167-
if msg.cltv_expiry <= cur_height + CLTV_CLAIM_BUFFER + LATENCY_GRACE_PERIOD_BLOCKS as u32 { // expiry_too_soon
1170+
// Theoretically, channel counterparty shouldn't send us a HTLC expiring now, but we want to be robust wrt to counterparty
1171+
// packet sanitization (see HTLC_FAIL_BACK_BUFFER rational)
1172+
if msg.cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
11681173
break Some(("CLTV expiry is too close", 0x1000 | 14, Some(self.get_channel_update(chan).unwrap())));
11691174
}
11701175
if msg.cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
11711176
break Some(("CLTV expiry is too far in the future", 21, None));
11721177
}
1178+
// In theory, we would be safe against unitentional channel-closure, if we only required a margin of LATENCY_GRACE_PERIOD_BLOCKS.
1179+
// But, to be safe against policy reception, we use a longuer delay.
1180+
if (*outgoing_cltv_value) as u64 <= (cur_height + HTLC_FAIL_BACK_BUFFER) as u64 {
1181+
break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, Some(self.get_channel_update(chan).unwrap())));
1182+
}
1183+
11731184
break None;
11741185
}
11751186
{

lightning/src/util/events.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ pub enum Event {
5151
},
5252
/// Indicates we've received money! Just gotta dig out that payment preimage and feed it to
5353
/// ChannelManager::claim_funds to get it....
54-
/// Note that if the preimage is not known or the amount paid is incorrect, you must call
55-
/// ChannelManager::fail_htlc_backwards to free up resources for this HTLC.
54+
/// Note that if the preimage is not known or the amount paid is incorrect, you should call
55+
/// ChannelManager::fail_htlc_backwards to free up resources for this HTLC and avoid
56+
/// network congestion.
5657
/// The amount paid should be considered 'incorrect' when it is less than or more than twice
5758
/// the amount expected.
5859
/// If you fail to call either ChannelManager::claim_funds or

0 commit comments

Comments
 (0)