Skip to content

Commit d18fc72

Browse files
committed
Correct sanity checking of MIN_CLTV_EXPIRY_DELTA constants
The `CHECK_CLTV_EXPIRY_SANITY_2` check actually made no sense - its use of `2*CLTV_CLAIM_BUFFER` implicitly assumed that we were failing HTLCs `CLTV_CLAIM_BUFFER` after they expired, which is nonsense. Instead, we improve the readability of the docs on `_CHECK_CLTV_EXPIRY_SANITY` and add a new `_CHECK_CLTV_EXPIRY_OFFCHAIN` that correctly tests for what the `CHECK_CLTV_EXPIRY_SANITY_2` check was supposed to look at.
1 parent 5bc9ffa commit d18fc72

File tree

2 files changed

+28
-25
lines changed

2 files changed

+28
-25
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,18 +4511,6 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
45114511
// chain when our counterparty is waiting for expiration to off-chain fail an HTLC
45124512
// we give ourselves a few blocks of headroom after expiration before going
45134513
// on-chain for an expired HTLC.
4514-
// Note that, to avoid a potential attack whereby a node delays claiming an HTLC
4515-
// from us until we've reached the point where we go on-chain with the
4516-
// corresponding inbound HTLC, we must ensure that outbound HTLCs go on chain at
4517-
// least CLTV_CLAIM_BUFFER blocks prior to the inbound HTLC.
4518-
// aka outbound_cltv + LATENCY_GRACE_PERIOD_BLOCKS == height - CLTV_CLAIM_BUFFER
4519-
// inbound_cltv == height + CLTV_CLAIM_BUFFER
4520-
// outbound_cltv + LATENCY_GRACE_PERIOD_BLOCKS + CLTV_CLAIM_BUFFER <= inbound_cltv - CLTV_CLAIM_BUFFER
4521-
// LATENCY_GRACE_PERIOD_BLOCKS + 2*CLTV_CLAIM_BUFFER <= inbound_cltv - outbound_cltv
4522-
// CLTV_EXPIRY_DELTA <= inbound_cltv - outbound_cltv (by check in ChannelManager::decode_update_add_htlc_onion)
4523-
// LATENCY_GRACE_PERIOD_BLOCKS + 2*CLTV_CLAIM_BUFFER <= CLTV_EXPIRY_DELTA
4524-
// The final, above, condition is checked for statically in channelmanager
4525-
// with CHECK_CLTV_EXPIRY_SANITY_2.
45264514
let htlc_outbound = $holder_tx == htlc.offered;
45274515
if ( htlc_outbound && htlc.cltv_expiry + LATENCY_GRACE_PERIOD_BLOCKS <= height) ||
45284516
(!htlc_outbound && htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER && self.payment_preimages.contains_key(&htlc.payment_hash)) {

lightning/src/ln/channelmanager.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,19 +2850,34 @@ pub(super) const CLTV_FAR_FAR_AWAY: u32 = 14 * 24 * 6;
28502850
// a payment was being routed, so we add an extra block to be safe.
28512851
pub const MIN_FINAL_CLTV_EXPIRY_DELTA: u16 = HTLC_FAIL_BACK_BUFFER as u16 + 3;
28522852

2853-
// Check that our CLTV_EXPIRY is at least CLTV_CLAIM_BUFFER + ANTI_REORG_DELAY + LATENCY_GRACE_PERIOD_BLOCKS,
2854-
// ie that if the next-hop peer fails the HTLC within
2855-
// LATENCY_GRACE_PERIOD_BLOCKS then we'll still have CLTV_CLAIM_BUFFER left to timeout it onchain,
2856-
// then waiting ANTI_REORG_DELAY to be reorg-safe on the outbound HLTC and
2857-
// failing the corresponding htlc backward, and us now seeing the last block of ANTI_REORG_DELAY before
2858-
// LATENCY_GRACE_PERIOD_BLOCKS.
2859-
#[allow(dead_code)]
2860-
const CHECK_CLTV_EXPIRY_SANITY: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - CLTV_CLAIM_BUFFER - ANTI_REORG_DELAY - LATENCY_GRACE_PERIOD_BLOCKS;
2861-
2862-
// Check for ability of an attacker to make us fail on-chain by delaying an HTLC claim. See
2863-
// ChannelMonitor::should_broadcast_holder_commitment_txn for a description of why this is needed.
2864-
#[allow(dead_code)]
2865-
const CHECK_CLTV_EXPIRY_SANITY_2: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER;
2853+
// Check that our MIN_CLTV_EXPIRY_DELTA gives us enough time to get everything on chain and locked
2854+
// in with enough time left to fail the corresponding HTLC back to our inbound edge before they
2855+
// force-close on us.
2856+
// In other words, if the next-hop peer fails HTLC LATENCY_GRACE_PERIOD_BLOCKS after our
2857+
// CLTV_CLAIM_BUFFER (because that's how many blocks we allow them after expiry), we'll still have
2858+
// CLTV_CLAIM_BUFFER + ANTI_REORG_DELAY left to get two transactions on chain and the second
2859+
// fully locked in before the peer force-closes on us (LATENCY_GRACE_PERIOD_BLOCKS before the
2860+
// expiry, i.e. assuming the peer force-closes right at the expiry and we're behind by
2861+
// LATENCY_GRACE_PERIOD_BLOCKS).
2862+
const _CHECK_CLTV_EXPIRY_SANITY: () = assert!(
2863+
MIN_CLTV_EXPIRY_DELTA as u32 >= 2*LATENCY_GRACE_PERIOD_BLOCKS + CLTV_CLAIM_BUFFER + ANTI_REORG_DELAY
2864+
);
2865+
2866+
// Check that our MIN_CLTV_EXPIRY_DELTA gives us enough time to get the HTLC preimage back to our
2867+
// counterparty if the outbound edge gives us the preimage only one block before we'd force-close
2868+
// the channel.
2869+
// ie they provide the preimage LATENCY_GRACE_PERIOD_BLOCKS - 1 after the HTLC expires, then we
2870+
// pass the preimage back, which takes LATENCY_GRACE_PERIOD_BLOCKS to complete, and we want to make
2871+
// sure this all happens at least N blocks before the inbound HTLC expires (where N is the
2872+
// counterparty's CLTV_CLAIM_BUFFER or equivalent).
2873+
const _ASSUMED_COUNTERPARTY_CLTV_CLAIM_BUFFER: u32 = 6 * 6;
2874+
2875+
const _CHECK_COUNTERPARTY_REALISTIC: () =
2876+
assert!(_ASSUMED_COUNTERPARTY_CLTV_CLAIM_BUFFER >= CLTV_CLAIM_BUFFER);
2877+
2878+
const _CHECK_CLTV_EXPIRY_OFFCHAIN: () = assert!(
2879+
MIN_CLTV_EXPIRY_DELTA as u32 >= 2*LATENCY_GRACE_PERIOD_BLOCKS - 1 + _ASSUMED_COUNTERPARTY_CLTV_CLAIM_BUFFER
2880+
);
28662881

28672882
/// The number of ticks of [`ChannelManager::timer_tick_occurred`] until expiry of incomplete MPPs
28682883
pub(crate) const MPP_TIMEOUT_TICKS: u8 = 3;

0 commit comments

Comments
 (0)