Skip to content

feat: allow configurable force-close buffer for claimable HTLCs#4401

Open
okekefrancis112 wants to merge 1 commit intolightningdevkit:mainfrom
okekefrancis112:claimable_htcl
Open

feat: allow configurable force-close buffer for claimable HTLCs#4401
okekefrancis112 wants to merge 1 commit intolightningdevkit:mainfrom
okekefrancis112:claimable_htcl

Conversation

@okekefrancis112
Copy link
Contributor

This PR adds a configurable force_close_claimable_htlc_cltv_buffer to ChannelConfig, allowing users to control how far in advance an inbound channel is force-closed when an HTLC becomes claimable. Previously, this buffer was hardcoded to CLTV_CLAIM_BUFFER (36 blocks), limiting users’ ability to tolerate their own downtime. The new field defaults to the existing constant, enforces the same minimum, and is validated against cltv_expiry_delta to preserve safety guarantees. The value is propagated to ChannelMonitor, persisted via monitor updates and serialization, and used in place of the hardcoded constant when deciding whether to broadcast a holder commitment transaction. This change improves configurability without altering default behavior.

Closes: #3837

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Feb 8, 2026

👋 I see @valentinewallace was un-assigned.
If you'd like another reviewer assignment, please click here.

@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 67.28972% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.04%. Comparing base (2e4a2ac) to head (711eadc).
⚠️ Report is 32 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/chain/channelmonitor.rs 53.65% 18 Missing and 1 partial ⚠️
lightning/src/chain/chainmonitor.rs 66.66% 10 Missing ⚠️
lightning/src/ln/channelmanager.rs 53.84% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4401      +/-   ##
==========================================
+ Coverage   86.02%   86.04%   +0.02%     
==========================================
  Files         156      156              
  Lines      103100   103477     +377     
  Branches   103100   103477     +377     
==========================================
+ Hits        88693    89040     +347     
- Misses      11896    11925      +29     
- Partials     2511     2512       +1     
Flag Coverage Δ
tests 86.04% <67.28%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bunch of checks in channelmanager.rs that need to be equivalently enforce on settings. In any case, please carefully go through every use of CLTV_CLAIM_BUFFER and maybe all the block-count-constants read the associated comments, and consider if we should update anything or if it might imply changes somewhere.

htlc: SentHTLCId,
},
/// Used to update the configurable force-close CLTV buffer for claimable HTLCs.
ChannelConfigUpdated {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, pushing through a monitor update is a heavy persistence operation. Instead, let's just make this configurable on the ChainMonitor and keep the settings memory-only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing this out. Your review is greatly appreciated, I will work on this and push it.

@TheBlueMatt TheBlueMatt removed the request for review from valentinewallace February 9, 2026 02:08
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry I let this one drop. Feel free to ping a PR if no one has looked at it in a week or two and you're expecting review.

You still need to calculate exact min/max bounds for this based on the various assertions at the top of channelmanager.rs.

/// Memory-only per-channel configuration for the CLTV buffer used when deciding
/// to force-close channels with claimable inbound HTLCs. This is not persisted
/// and is rebuilt from channel state on restart.
channel_force_close_buffers: RwLock<HashMap<ChannelId, u32>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, is there a reason to want this per-channel vs just setting a global value and calling it done?

/// Returns an error if the buffer value is below [`CLTV_CLAIM_BUFFER`].
///
/// [`CLTV_CLAIM_BUFFER`]: channelmonitor::CLTV_CLAIM_BUFFER
pub fn update_channel_force_close_buffer(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than a setter, can we just have this be a parameter on the constructor?

///
/// [`cltv_expiry_delta`]: ChannelConfig::cltv_expiry_delta
/// [`CLTV_CLAIM_BUFFER`]: crate::chain::channelmonitor::CLTV_CLAIM_BUFFER
pub force_close_claimable_htlc_cltv_buffer: u32,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't have two separate values as we can't allow these to conflict.

@okekefrancis112
Copy link
Contributor Author

Oops, sorry I let this one drop. Feel free to ping a PR if no one has looked at it in a week or two and you're expecting review.

You still need to calculate exact min/max bounds for this based on the various assertions at the top of channelmanager.rs.

On the min/max bounds: tracing through the assertions at the top of channelmanager.rs, I arrive at:

Min = CLTV_CLAIM_BUFFER (36) — need at least 2 * MAX_BLOCKS_FOR_CONF blocks to get both transactions confirmed on-chain.
Max = HTLC_FAIL_BACK_BUFFER (39) — going above this would mean the monitor force-closes before ChannelManager fails back other pending HTLCs on the same channel.
That gives a configurable range of 36–39 blocks. Does that match what you had in mind, or am I missing something in the bounds calculation?

…o global ChainMonitor param

Remove `force_close_claimable_htlc_cltv_buffer` from `ChannelConfig`,
`ChannelConfigUpdate`, `ChannelMonitor`, and the `Watch` trait. Instead,
accept it as a constructor parameter on `ChainMonitor`, making it a
single global, memory-only setting.

The valid range is [CLTV_CLAIM_BUFFER, HTLC_FAIL_BACK_BUFFER] (36-39
blocks), enforced via assert at construction time. The lower bound
ensures enough time to confirm both commitment and HTLC-Success
transactions. The upper bound ensures the monitor doesn't force-close
before ChannelManager has a chance to fail back other pending HTLCs.

This addresses review feedback to:
- Avoid two conflicting values (ChannelConfig vs ChainMonitor)
- Use a global value rather than per-channel configuration
- Pass via constructor rather than a setter method
- Keep the setting memory-only (no persistence overhead)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow for earlier FC of channels with unresponsive counterparies with claimable HTLCs

3 participants