Skip to content

Add AvailableBalances::next_splice_out_maximum_sat#4550

Open
tankyleo wants to merge 5 commits intolightningdevkit:mainfrom
tankyleo:2026-04-next-splice-out-maximum
Open

Add AvailableBalances::next_splice_out_maximum_sat#4550
tankyleo wants to merge 5 commits intolightningdevkit:mainfrom
tankyleo:2026-04-next-splice-out-maximum

Conversation

@tankyleo
Copy link
Copy Markdown
Contributor

@tankyleo tankyleo commented Apr 9, 2026

This is the maximum value the holder can splice out of their channel balance, accounting for the updated v2 reserves after the splice, and the "must have at least one output" constraint on zero-reserve channels.

@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented Apr 9, 2026

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@ldk-reviews-bot ldk-reviews-bot requested a review from jkczyz April 9, 2026 08:13
Comment thread lightning/src/ln/channel_state.rs Outdated
Comment thread lightning/src/sign/tx_builder.rs
Comment thread lightning/src/sign/tx_builder.rs Outdated
Comment thread lightning/src/ln/channel.rs
Comment thread lightning/src/routing/router.rs Outdated
Comment thread lightning/src/routing/router.rs Outdated
@tankyleo tankyleo force-pushed the 2026-04-next-splice-out-maximum branch from 724acf9 to 3bd7a76 Compare April 9, 2026 08:29
@ldk-claude-review-bot
Copy link
Copy Markdown
Collaborator

ldk-claude-review-bot commented Apr 9, 2026

After a thorough review of every file and hunk in the diff, including examination of the surrounding codebase for context, I have no new issues to flag beyond what was already covered in my prior review comments.

Review Summary

No new issues found beyond what was previously flagged.

Corrections to Prior Comments

My prior comments about unit mismatches were incorrect — I'm noting this so reviewers don't waste time on them:

  • lightning/src/ln/channel_state.rs:628 — The TLV default correctly divides by 1000: u64::from(outbound_capacity_msat.0.unwrap()) / 1000. No bug.
  • lightning/src/routing/router.rs:4153 — The test helper correctly divides: outbound_capacity_msat / 1000. No bug.
  • lightning/src/routing/router.rs:9653 — The hardcoded value 10_000_000 is correct (10B msat / 1000 = 10M sat). No bug.

Previously Flagged Issues (Still Valid)

  • lightning/src/sign/tx_builder.rs:355 / lightning/src/ln/channel.rs:13438 — Dust limit inconsistency: get_next_splice_out_maximum_sat uses holder_dust_limit_satoshis as the floor in the v2 reserve calculation, while FundingScope::for_splice uses MIN_CHAN_DUST_LIMIT_SATOSHIS (354) for the counterparty-selected reserve. For channels where holder_dust_limit > MIN_CHAN_DUST_LIMIT_SATOSHIS and the channel is small enough, the debug assertion unwrap_err() at channel.rs:13437 could panic.

  • lightning/src/sign/tx_builder.rs:398-416 / lightning/src/ln/channel.rs:13429has_output only checks the local commitment (holder_dust_limit), while validate_splice_contributions via get_holder_counterparty_balances_floor_incl_fee checks both commitments (including the remote with counterparty_dust_limit). If counterparty_dust_limit > holder_dust_limit in a zero-reserve unbalanced channel, the debug assertion unwrap() at channel.rs:13429 could panic.

  • lightning/src/sign/tx_builder.rs:386 — Comment nit: says "free to withdraw up to its post_splice_delta_above_reserve_sat" but the code computes balance - delta.

  • lightning/src/sign/tx_builder.rs:391 — Comment nit: says "bump this maximum" when the code reduces it.

Notes on Positive Changes

  • The old debug assertions in FundingScope::for_splice had a unit mismatch bug (comparing msat with sat). The new assertions in validate_splice_contributions correctly multiply by 1000. This is a good fix.
  • The consolidation of FundingScope::for_splice + validate_splice_contributions into a single call is a clean refactor that eliminates the possibility of creating an unvalidated FundingScope.
  • The replacement of saturating_add with checked_add_signed in for_splice correctly rejects impossible contributions rather than silently clamping.

@tankyleo tankyleo requested review from TheBlueMatt and wpaulino and removed request for jkczyz April 9, 2026 08:32
@tankyleo tankyleo self-assigned this Apr 9, 2026
@tankyleo tankyleo moved this to Goal: Merge in Weekly Goals Apr 9, 2026
@tankyleo
Copy link
Copy Markdown
Contributor Author

tankyleo commented Apr 9, 2026

Seems the fuzz failure produces this error on my machine

Hex:

ff1cb4a6a6ffffff02000000ffffb4a669696969696969691b00000000000000ffffffffffa2ad06301100ffffffffffffcf111f7d29000000000000001f0007

Target: chanmon_consistency

Error:

2      ERROR [lightning::ln::channelmanager:4635]      ch:8c0000 p:020000          Closed channel due to close-required error: Channel closed because of an exception: splice tx of another pending funding already confirmed
2      ERROR [lightning::ln::channelmanager:4557]      ch:8c0000 p:020000          Closing channel: Channel closed because of an exception: splice tx of another pending funding already confirmed

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

1 similar comment
@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@Alkamal01
Copy link
Copy Markdown

Curious about estimated_fees = 183 in do_test_splice_max_value — is that commit_tx_fee_sat(253, 0, legacy_channel) (the unspiked fee)? The test already subtracts commit_tx_fee_sat at the spiked feerate separately, so I wasn't sure what the 183 is covering.

@tankyleo
Copy link
Copy Markdown
Contributor Author

Curious about estimated_fees = 183 in do_test_splice_max_value — is that commit_tx_fee_sat(253, 0, legacy_channel) (the unspiked fee)? The test already subtracts commit_tx_fee_sat at the spiked feerate separately, so I wasn't sure what the 183 is covering.

Thanks for taking a look ! 183sats is the amount allocated to the fee of the splice out transaction at the default feerate of 253sat/kw, and will be added on top of the splice amount. Will clarify this in the test.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 2nd Reminder

Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

1 similar comment
@ldk-reviews-bot
Copy link
Copy Markdown

🔔 2nd Reminder

Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment thread lightning/src/ln/channel.rs Outdated
their_contribution_candidate: SignedAmount, addl_nondust_htlc_count: usize,
feerate_per_kw: u32,
) -> Result<(Amount, Amount), String> {
let htlc_candidate = None;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This really feels like it could/should be substantially DRYd with get_next_local/remote_commitment_stats - what we're really asking at the callsites is "is this splice even valid" which istm should really be done by just saying "did get_next_local_commitment_stats return an Error or not" (with appropriate balance modification flags, maybe a wrapper method calling an internal impl method rather than modifying the existing methods).

Comment thread lightning/src/sign/tx_builder.rs Outdated
/// retains at least one output after the splice, which is particularly relevant for
/// zero-reserve channels.
//
// The equation to determine `percent_max_splice_out_sat` is:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

discussed offline but this feels super unclear to me because "percent_" as a prefix implies to me, that the value is a percent, but its not.

@TheBlueMatt
Copy link
Copy Markdown
Collaborator

Needs rebase, sorry about that. Do think its worth doing this for 0.3, yes, given it fixed splice <-> 0 reserve compat. Its also not a big deal to add a field rn.

@TheBlueMatt TheBlueMatt added this to the 0.3 milestone Apr 13, 2026
@Alkamal01
Copy link
Copy Markdown

Curious about estimated_fees = 183 in do_test_splice_max_value — is that commit_tx_fee_sat(253, 0, legacy_channel) (the unspiked fee)? The test already subtracts commit_tx_fee_sat at the spiked feerate separately, so I wasn't sure what the 183 is covering.

Thanks for taking a look ! 183sats is the amount allocated to the fee of the splice out transaction at the default feerate of 253sat/kw, and will be added on top of the splice amount. Will clarify this in the test.

Makes sense, thanks for clarifying!

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 3rd Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@jkczyz jkczyz self-requested a review April 16, 2026 17:20
@ldk-reviews-bot
Copy link
Copy Markdown

🔔 4th Reminder

Hey @jkczyz @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @jkczyz @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 5th Reminder

Hey @jkczyz @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@tankyleo tankyleo force-pushed the 2026-04-next-splice-out-maximum branch from 3bd7a76 to 245edbe Compare April 20, 2026 02:54
}
max_splice_out_sat
} else {
// In a zero-reserve channel, the holder is free to withdraw up to its `post_splice_delta_above_reserve_sat`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: This comment is backwards — it reads as if post_splice_delta_above_reserve_sat is the maximum the holder can withdraw, but the code computes local_balance - delta, meaning the holder can withdraw everything except the delta. Consider:

Suggested change
// In a zero-reserve channel, the holder is free to withdraw up to its `post_splice_delta_above_reserve_sat`
// In a zero-reserve channel, the holder is free to withdraw up to its balance minus `post_splice_delta_above_reserve_sat`

@tankyleo tankyleo force-pushed the 2026-04-next-splice-out-maximum branch from 245edbe to bb91e11 Compare April 20, 2026 03:02
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 90.74890% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.02%. Comparing base (6573d42) to head (ccde0da).

Files with missing lines Patch % Lines
lightning/src/ln/channel.rs 88.38% 11 Missing and 7 partials ⚠️
lightning/src/ln/channel_state.rs 66.66% 1 Missing ⚠️
lightning/src/ln/channelmanager.rs 0.00% 1 Missing ⚠️
lightning/src/routing/router.rs 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4550      +/-   ##
==========================================
+ Coverage   86.99%   87.02%   +0.02%     
==========================================
  Files         163      161       -2     
  Lines      109008   109019      +11     
  Branches   109008   109019      +11     
==========================================
+ Hits        94828    94870      +42     
+ Misses      11696    11662      -34     
- Partials     2484     2487       +3     
Flag Coverage Δ
fuzzing 39.64% <77.67%> (+1.42%) ⬆️
tests 86.12% <90.74%> (+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.

As a result, we now validate that both commitments retain at least one
output under the new funding scope, which is crucial for zero-reserve
channels.
We previously determined this value by subtracting the htlcs, the
anchors, and the commitment transaction fee. This ignored the reserve,
as well as the at-least-one-output requirement in zero-reserve channels.

This new field now accounts for both of these constraints.
This is equivalent to the previous commit, see the debug assertions
added in the previous commit. We now also get to communicate the
exact maximum back to the user, instead of some "balance is lower
than our reserve" message, which is hard to react to.
@tankyleo tankyleo force-pushed the 2026-04-next-splice-out-maximum branch from bb91e11 to ccde0da Compare April 20, 2026 04:09
@tankyleo tankyleo requested a review from TheBlueMatt April 20, 2026 05:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Goal: Merge

Development

Successfully merging this pull request may close these issues.

5 participants