Skip to content

Conversation

tankyleo
Copy link
Contributor

@tankyleo tankyleo commented Sep 4, 2025

Create a single P2A anchor on commitment transactions in 0FC channels

Zero-fee commitment channels replace today's existing `to_local_anchor`
and `to_remote_anchor` outputs with a single `shared_anchor` output.
Use `SINGLE|ACP` sighash on signatures from peer in 0FC channels

Part of #3789

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Sep 4, 2025

👋 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.

@tankyleo
Copy link
Contributor Author

tankyleo commented Sep 4, 2025

Still owe some tests, but here's the API I currently have in mind.

Copy link

codecov bot commented Sep 4, 2025

Codecov Report

❌ Patch coverage is 97.10145% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.76%. Comparing base (9ddd25b) to head (538c4cc).
⚠️ Report is 58 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/chain/channelmonitor.rs 60.00% 2 Missing ⚠️
lightning/src/ln/channel.rs 97.40% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #4053    +/-   ##
========================================
  Coverage   88.76%   88.76%            
========================================
  Files         176      176            
  Lines      129357   129611   +254     
  Branches   129357   129611   +254     
========================================
+ Hits       114823   115051   +228     
- Misses      11929    11953    +24     
- Partials     2605     2607     +2     
Flag Coverage Δ
fuzzing 22.09% <78.83%> (+0.09%) ⬆️
tests 88.60% <97.10%> (+<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.

@tankyleo tankyleo self-assigned this Sep 4, 2025
@tankyleo tankyleo moved this to Goal: Merge in Weekly Goals Sep 4, 2025
// We populate this field for downgrades
self.initial_counterparty_commitment_info = Some((commitment_tx.per_commitment_point(),
commitment_tx.feerate_per_kw(), commitment_tx.to_broadcaster_value_sat(), commitment_tx.to_countersignatory_value_sat()));
// Only populate `initial_counterparty_commitment_info` in non-0FC channels
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you update the comment on initial_counterparty_commitment_info now that its not always set?

@@ -1578,6 +1586,7 @@ impl Writeable for CommitmentTransaction {
(8, self.keys, required),
(10, self.built, required),
(12, self.nondust_htlcs, required_vec),
(13, self.trimmed_sum_sat, option),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm? The commit messages is wrong, this should be even to make sure old clients fail to deserialize.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed offline: old clients will fail to deserialize when they read the unknown 0FC feature bit in the channel_type_features member.

@@ -1538,6 +1544,8 @@ pub struct CommitmentTransaction {
// The set of non-dust HTLCs included in the commitment. They must be sorted in increasing
// output index order.
nondust_htlcs: Vec<HTLCOutputInCommitment>,
// The sum of the values of all outputs that were trimmed to fees
trimmed_sum_sat: Option<Amount>, // Added in 0.2
Copy link
Collaborator

Choose a reason for hiding this comment

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

ISTM this doesn't have to be an Option - just default to 0 if it isn't there on load and skip writing if its zero (which we need to do anyway as the current constructor will always set Some and so we'll currently always write).

@@ -11859,7 +11859,9 @@ where
}
self.context.resend_order = RAACommitmentOrder::RevokeAndACKFirst;

let update = if self.pending_funding.is_empty() {
let update = if self.pending_funding.is_empty()
&& !self.funding.get_channel_type().supports_anchor_zero_fee_commitments()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean, that's fine, but why bother? Is it just to push migration faster by using the new type for cases where we know no downgrade is possible anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mentioned offline: LatestCounterpartyCommitmentTXInfo does not include enough information to build a 0FC commitment transaction from it, as is done in ChannelMonitor.counterparty_commitment_txs_from_update. We have to use the LatestCounterpartyCommitment variant.

@@ -1538,6 +1544,8 @@ pub struct CommitmentTransaction {
// The set of non-dust HTLCs included in the commitment. They must be sorted in increasing
// output index order.
nondust_htlcs: Vec<HTLCOutputInCommitment>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

While we're here can we rename the feerate_per_kw field/accessor method in CommitmentTransaction to negotiated_feerate_per_kw or so? Its confusing that it does not actually refer to the feerate that the commitment transaction has (even if that already was true due to dust rounding).

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

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.

LGTM, feel free to squash.

@tankyleo
Copy link
Contributor Author

tankyleo commented Sep 5, 2025

Squashed, some small edits to the commit messages, no code changes.

tankyleo and others added 4 commits September 6, 2025 00:40
Zero-fee commitment channels replace today's existing `to_local_anchor`
and `to_remote_anchor` outputs with a single `shared_anchor` output.

Co-authored-by: Matt Corallo <[email protected]>
Use `negotiated_feerate_per_kw()` to underscore that this is the feerate
we negotiated with our peer, not the actual feerate of the commitment
transaction. The feerate of the actual commitment transaction may be
higher.
@tankyleo
Copy link
Contributor Author

tankyleo commented Sep 7, 2025

@TheBlueMatt sorry for the rugpull here I looked at the dev branch Carla shared, and turns out ChannelTransactionParameters now has channel_value_satoshis, so we can determine the value of the anchor from the existing data alone :) Should have checked earlier for sure, simplifies things quite a bit.

@ldk-reviews-bot
Copy link

🔔 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

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

Comment on lines +1891 to +1892
// These subtractions panic on underflow, but this should never happen
let trimmed_sum_sat = channel_value_satoshis - nondust_htlcs_value_sum_sat - to_broadcaster_value_sat - to_countersignatory_value_sat;
Copy link
Contributor

Choose a reason for hiding this comment

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

The subtraction operation here could potentially panic if the sum of the values being subtracted exceeds channel_value_satoshis. While the comment acknowledges this shouldn't happen, it would be safer to use checked arithmetic or validate the constraint before performing the subtraction to prevent a potential DoS vulnerability in edge cases.

Consider using checked_sub or similar methods to handle this gracefully:

let trimmed_sum_sat = channel_value_satoshis
    .checked_sub(nondust_htlcs_value_sum_sat)
    .and_then(|result| result.checked_sub(to_broadcaster_value_sat))
    .and_then(|result| result.checked_sub(to_countersignatory_value_sat))
    .unwrap_or(Amount::ZERO); // Or handle the error case appropriately

This would make the code more robust against unexpected inputs while maintaining the same functionality.

Suggested change
// These subtractions panic on underflow, but this should never happen
let trimmed_sum_sat = channel_value_satoshis - nondust_htlcs_value_sum_sat - to_broadcaster_value_sat - to_countersignatory_value_sat;
// Use checked subtraction to avoid potential panics
let trimmed_sum_sat = channel_value_satoshis
.checked_sub(nondust_htlcs_value_sum_sat)
.and_then(|result| result.checked_sub(to_broadcaster_value_sat))
.and_then(|result| result.checked_sub(to_countersignatory_value_sat))
.unwrap_or_else(|| {
// This should never happen, but we handle it gracefully instead of panicking
debug_assert!(false, "Channel value calculation underflowed");
0
});

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

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.

This LGTM. WDYT @wpaulino

@tankyleo tankyleo requested a review from TheBlueMatt September 9, 2025 16:29
@TheBlueMatt TheBlueMatt merged commit 867f084 into lightningdevkit:main Sep 9, 2025
25 checks passed
@github-project-automation github-project-automation bot moved this from Goal: Merge to Done in Weekly Goals Sep 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants