Skip to content

Conversation

tankyleo
Copy link
Contributor

From BOLT 2:

- If `funding_contribution_satoshis` is negative and its absolute value
  is greater than the sending node's current channel balance:
  - MUST send a `warning` and close the connection or send an `error`
    and fail the channel.

We allow the remote to be below the new reserve as long as their
funding contribution is not negative; we don't care whether they were
above or below the previous funding reserve.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Aug 14, 2025

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

@tankyleo tankyleo changed the title Validate negative funding contributions in splice_ack and splice_init messages Validate negative funding contributions in splice_init and splice_ack messages Aug 14, 2025
@tankyleo tankyleo force-pushed the splice-reserve-check branch from 6d6b07c to 93965c6 Compare August 14, 2025 01:24
@tankyleo tankyleo requested a review from wpaulino August 14, 2025 01:25
Copy link

codecov bot commented Aug 14, 2025

Codecov Report

❌ Patch coverage is 8.33333% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.76%. Comparing base (1c36624) to head (d0023e3).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/sign/tx_builder.rs 8.33% 11 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4011      +/-   ##
==========================================
- Coverage   88.78%   88.76%   -0.03%     
==========================================
  Files         176      176              
  Lines      128139   128533     +394     
  Branches   128139   128533     +394     
==========================================
+ Hits       113768   114087     +319     
- Misses      11803    11859      +56     
- Partials     2568     2587      +19     
Flag Coverage Δ
fuzzing 21.86% <8.33%> (-0.05%) ⬇️
tests 88.59% <8.33%> (-0.03%) ⬇️

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 Aug 14, 2025
@ldk-reviews-bot
Copy link

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

@ldk-reviews-bot
Copy link

🔔 2nd 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 mentioned this pull request Aug 18, 2025
@tankyleo
Copy link
Contributor Author

On hold until splice-out PR gets in.

@ldk-reviews-bot
Copy link

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

@tankyleo tankyleo removed the request for review from wpaulino August 20, 2025 01:37
@tankyleo tankyleo marked this pull request as draft August 20, 2025 01:38
As much as possible, we want to only mutate state once we are done with
input validation.

This also removes complaints when helper functions during validation
take a `&self`.
As in `splice_init`, this helps clearly delineate `splice_ack` message
validation from the subsequent state mutations.

This is a code-move.
We will validate the reserve requirements on the new `FundingScope` in
`validate_splice_contribution`.
`NextCommitmentStats` provides the commitment transaction fee as a
separate value to assist with applying a multiplier on it in
`can_accept_incoming_htlc`.

Nonetheless in most cases, we want the balances to include the
commitment transaction fee, so here we add a helper that gives us these
balances.
This applies to both `splice_init` and `splice_ack` messages.

From BOLT 2:
```
- If `funding_contribution_satoshis` is negative and its absolute value
  is greater than the sending node's current channel balance:
  - MUST send a `warning` and close the connection or send an `error`
    and fail the channel.
```

We allow the remote to be below the new reserve as long as their
funding contribution is not negative; we don't care whether they were
above or below the previous funding reserve.
@tankyleo tankyleo force-pushed the splice-reserve-check branch from 93965c6 to d0023e3 Compare August 26, 2025 22:14
@tankyleo tankyleo marked this pull request as ready for review August 26, 2025 22:14
@tankyleo tankyleo requested review from wpaulino and removed request for valentinewallace August 26, 2025 22:15
@@ -11095,7 +11095,7 @@ where
})
}

/// Handle splice_ack
/// See also [`validate_splice_ack`]
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: just remove the comment

impl NextCommitmentStats {
pub(crate) fn get_balances_including_fee_msat(&self) -> (Option<u64>, Option<u64>) {
let holder_balance_incl_fee_msat = if self.is_outbound_from_holder {
self.holder_balance_before_fee_msat
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this already have the anchor outputs value subtracted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes

Comment on lines +61 to +66
let counterparty_balance_incl_fee_msat = if self.is_outbound_from_holder {
self.counterparty_balance_before_fee_msat
} else {
self.counterparty_balance_before_fee_msat
.and_then(|balance| balance.checked_sub(self.commit_tx_fee_sat * 1000))
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
let counterparty_balance_incl_fee_msat = if self.is_outbound_from_holder {
self.counterparty_balance_before_fee_msat
} else {
self.counterparty_balance_before_fee_msat
.and_then(|balance| balance.checked_sub(self.commit_tx_fee_sat * 1000))
};
let counterparty_balance_incl_fee_msat =
self.counterparty_balance_before_fee_msat.and_then(|balance| {
if self.is_outbound_from_holder {
balance
} else {
balance.checked_sub(self.commit_tx_fee_sat * 1000)
}
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The two branches of the if statement here don't return the same type - will take another look later

// This *should* have no effect because no HTLC updates should be pending, but even if it does,
// the result may be a failed negotiation (and not a force-close), so we choose to include them.
let include_remote_unknown_htlcs = true;
let addl_nondust_htlc_count = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't we want to make sure the new commitment is able to handle a new non-dust HTLC being added?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes thank you ! How about just 1 additional HTLC here ? This parameter increases the commitment transaction fee we get back.


// TODO(splicing): Pre-check for reserve requirement
// (Note: It should also be checked later at tx_complete)
if their_funding_contribution.is_negative() {
Copy link
Contributor

Choose a reason for hiding this comment

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

There's also the case where we make a positive contribution and the counterparty does too, but a much larger one, bringing the reserve high enough that even after our contribution we still are not able to meet it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From my reading of the spec, seems a party should only complain in cases where the counterparty's funding contribution is negative.

Did we want to be stricter than the spec here ?

let validate_stats = |stats: NextCommitmentStats| {
let (_, remote_balance_incl_fee_msat) = stats.get_balances_including_fee_msat();
let splice_remote_balance_msat = remote_balance_incl_fee_msat
.ok_or(ChannelError::Warn(format!("Remote balance does not cover the sum of HTLCs, anchors, and commitment transaction fee")))?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Error needs to be WarnAndDisconnect


// Reserve check on local commitment transaction

let splice_local_commitment_stats = self.context.get_next_local_commitment_stats(
Copy link
Contributor

Choose a reason for hiding this comment

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

The "next" naming is odd here because we're actually building an alternative version of the current commitment transaction

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed :) If a squint a little, the "next" commitment transaction will have different to_local, to_remote balances, that's the one we are validating here. As far as I see at this point, this "alternative" commitment transaction is the one we will sign "next" ?

This is from 3921 feel free to take a look.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants