Skip to content

Disallow holders from selecting 0-reserve in legacy channels#4613

Open
tankyleo wants to merge 5 commits into
lightningdevkit:mainfrom
tankyleo:2026-05-ban-0reserve-legacy-chans
Open

Disallow holders from selecting 0-reserve in legacy channels#4613
tankyleo wants to merge 5 commits into
lightningdevkit:mainfrom
tankyleo:2026-05-ban-0reserve-legacy-chans

Conversation

@tankyleo
Copy link
Copy Markdown
Contributor

@tankyleo tankyleo commented May 13, 2026

We still allow counterparties to set 0-reserve legacy channels, as in prior releases.

@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented May 13, 2026

👋 Thanks for assigning @wpaulino 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.

@tankyleo tankyleo added this to the 0.3 milestone May 13, 2026
@tankyleo tankyleo moved this to Goal: Merge in Weekly Goals May 13, 2026
@tankyleo tankyleo self-assigned this May 13, 2026
@tankyleo tankyleo force-pushed the 2026-05-ban-0reserve-legacy-chans branch 4 times, most recently from e90865f to 603754d Compare May 15, 2026 07:37
@tankyleo tankyleo changed the title Disallow opening and accepting 0-reserve legacy channels Disallow holders from selecting 0-reserve in legacy channels May 15, 2026
@tankyleo tankyleo marked this pull request as ready for review May 15, 2026 08:00
@tankyleo tankyleo requested review from TheBlueMatt and removed request for joostjager May 15, 2026 08:02
use crate::sign::ChannelSigner;
use crate::types::features::ChannelTypeFeatures;
use crate::types::payment::{PaymentHash, PaymentPreimage};
use crate::types::payment::PaymentPreimage;
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: PaymentHash is imported from bolt11_invoice which re-exports it from lightning_types::payment. Every other file in this crate imports it from crate::types::payment::PaymentHash. Consider keeping it consistent:

Suggested change
use crate::types::payment::PaymentPreimage;
use crate::types::payment::{PaymentHash, PaymentPreimage};

(and removing the bolt11_invoice::PaymentHash import on line 30)

Comment thread fuzz/src/chanmon_consistency.rs Outdated
connect_peers(&nodes[0], &nodes[1]);
connect_peers(&nodes[1], &nodes[2]);

let set_0reserve = if chan_type == ChanType::Legacy { false } else { true };
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 can be simplified to chan_type != ChanType::Legacy (which also explains why PartialEq was derived above).

Comment thread fuzz/src/chanmon_consistency.rs Outdated
Comment on lines 2090 to 2091
// A-B: channel 2 A and B have 0-reserve (trusted open + trusted accept),
// channel 3 A has 0-reserve (trusted accept).
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.

The comments on lines 2090-2091 and 2095-2096 still describe channel 2/3/4/5 as having 0-reserve unconditionally, but that's no longer the case for ChanType::Legacy. Consider qualifying these with "if non-legacy" or restructuring the comments to be accurate for both code paths.

@ldk-claude-review-bot
Copy link
Copy Markdown
Collaborator

ldk-claude-review-bot commented May 15, 2026

I've re-reviewed the entire PR diff against the current codebase, verified my prior findings, and confirmed my analysis of the key changes. My prior review covered all the issues.

No new issues found. The three nits from my prior review remain the only findings:

  1. lightning/src/ln/htlc_reserve_unit_tests.rs:26PaymentHash imported inconsistently from bolt11_invoice instead of crate::types::payment
  2. fuzz/src/chanmon_consistency.rs:2085chan_type != ChanType::Legacy is simpler than the current expression
  3. fuzz/src/chanmon_consistency.rs:2090-2091 — Channel comments still describe 0-reserve unconditionally but behavior now differs for Legacy

All enforcement points are correctly implemented. The relaxation of get_available_balances from spiked to current feerate for boundary checks is safe — get_next_commitment_stats still hard-checks at spiked feerate, and the design comment at tx_builder.rs:294-296 explicitly acknowledges this tradeoff.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

❌ Patch coverage is 94.54545% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.40%. Comparing base (b8118e3) to head (96a9e7b).

Files with missing lines Patch % Lines
lightning/src/ln/channel.rs 90.32% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4613      +/-   ##
==========================================
- Coverage   86.40%   86.40%   -0.01%     
==========================================
  Files         158      158              
  Lines      109293   109294       +1     
  Branches   109293   109294       +1     
==========================================
- Hits        94439    94432       -7     
- Misses      12309    12313       +4     
- Partials     2545     2549       +4     
Flag Coverage Δ
fuzzing-fake-hashes 5.08% <0.00%> (-0.01%) ⬇️
fuzzing-real-hashes 22.77% <60.00%> (-0.02%) ⬇️
tests 86.13% <94.54%> (-0.01%) ⬇️

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
Copy Markdown
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.

LGTM, but please reorder the commits so that the "remove tests of legacy + 0-reserve" change happens before we remove the legacy reserve change, that way at each commit tests pass.

@tankyleo tankyleo force-pushed the 2026-05-ban-0reserve-legacy-chans branch from 603754d to 96a9e7b Compare May 15, 2026 14:48
@tankyleo
Copy link
Copy Markdown
Contributor Author

Thank you done, no other changes

@tankyleo tankyleo requested a review from TheBlueMatt May 15, 2026 14:51
let spiked_feerate = feerate_per_kw.saturating_mul(
if is_outbound_from_holder && !channel_type.supports_anchors_zero_fee_htlc_tx() {
let spiked_feerate =
feerate_per_kw.saturating_mul(if !channel_type.supports_anchors_zero_fee_htlc_tx() {
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.

Why are we dropping is_outbound_from_holder?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Would rather have the variable spiked_feerate be solely based on whether we are in a legacy channel or not.

No functional change, all the dependents on this variable are only used if is_outbound_from_holder is true.

@TheBlueMatt TheBlueMatt requested a review from wpaulino May 15, 2026 18:53
@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st 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.

wpaulino
wpaulino previously approved these changes May 19, 2026
Copy link
Copy Markdown
Contributor

@wpaulino wpaulino left a comment

Choose a reason for hiding this comment

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

Would be nice to fix the review bot nits

@wpaulino wpaulino requested a review from TheBlueMatt May 19, 2026 18:21
tankyleo added 3 commits May 19, 2026 18:46
We still allow counterparties to set 0-reserve legacy channels, as in
prior releases.
We only assume fee spikes in legacy channels, and we do not allow
`holder_selected_channel_reserve_satoshis` to be set to zero in such
channels. It is nonetheless still possible to reach the no-outputs case
in a fee spike with solely the counterparty selected reserve set to
zero, so we still guard against this case in
`get_next_commitment_stats`.

We don't guard against no-outputs under fee spikes
`get_available_balances`; in the worst case, the receiver of the HTLC we
just sent fails it back.
@tankyleo tankyleo force-pushed the 2026-05-ban-0reserve-legacy-chans branch from 96a9e7b to 257033f Compare May 19, 2026 18:51
@tankyleo
Copy link
Copy Markdown
Contributor Author

Would be nice to fix the review bot nits

Thanks diff from last review:

diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs
index 1f9e42ce8..4ff0e4a4a 100644
--- a/fuzz/src/chanmon_consistency.rs
+++ b/fuzz/src/chanmon_consistency.rs
@@ -2082,18 +2082,18 @@
                connect_peers(&nodes[0], &nodes[1]);
                connect_peers(&nodes[1], &nodes[2]);

-               let set_0reserve = if chan_type == ChanType::Legacy { false } else { true };
+               let set_0reserve = chan_type != ChanType::Legacy;
                // Create 3 channels between A-B and 3 channels between B-C (6 total).
                //
                // Use distinct version numbers for each funding transaction so each test
                // channel gets its own txid and funding outpoint.
                // A-B: channel 2 A and B have 0-reserve (trusted open + trusted accept),
-               //      channel 3 A has 0-reserve (trusted accept).
+               //      channel 3 A has 0-reserve (trusted accept), if channels are non-legacy.
                make_channel(&nodes[0], &nodes[1], 1, false, false, &mut chain_state);
                make_channel(&nodes[0], &nodes[1], 2, set_0reserve, set_0reserve, &mut chain_state);
                make_channel(&nodes[0], &nodes[1], 3, false, set_0reserve, &mut chain_state);
                // B-C: channel 4 B has 0-reserve (via trusted accept),
-               //      channel 5 C has 0-reserve (via trusted open).
+               //      channel 5 C has 0-reserve (via trusted open), if channels are non-legacy.
                make_channel(&nodes[1], &nodes[2], 4, false, set_0reserve, &mut chain_state);
                make_channel(&nodes[1], &nodes[2], 5, set_0reserve, false, &mut chain_state);
                make_channel(&nodes[1], &nodes[2], 6, false, false, &mut chain_state);
diff --git a/lightning/src/ln/htlc_reserve_unit_tests.rs b/lightning/src/ln/htlc_reserve_unit_tests.rs
index 17b0ffee4..86d98b788 100644
--- a/lightning/src/ln/htlc_reserve_unit_tests.rs
+++ b/lightning/src/ln/htlc_reserve_unit_tests.rs
@@ -23,11 +23,10 @@
 use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder};
 use crate::sign::ChannelSigner;
 use crate::types::features::ChannelTypeFeatures;
-use crate::types::payment::PaymentPreimage;
+use crate::types::payment::{PaymentHash, PaymentPreimage};
 use crate::util::config::UserConfig;
 use crate::util::errors::APIError;

-use bolt11_invoice::PaymentHash;
 use lightning_macros::xtest;

 use bitcoin::secp256k1::{Secp256k1, SecretKey};

@tankyleo tankyleo requested a review from wpaulino May 19, 2026 18:52
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