Skip to content

[Splicing] Tx negotiation during splicing #3736

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

optout21
Copy link
Contributor

@optout21 optout21 commented Apr 15, 2025

Implementation of transaction negotiation during splicing.
Builds on 3407 and 3443.

  • No new phase, Funded(FundedChannel) is used throughout splicing
  • Both FundedChannel and PendingV2Channel can act as a transaction constructor
  • PendingV2Channel logic is put behind a trait -- FundingTxConstructorV2
  • A RenegotiatingScope is used to store extra state during splicing
  • FundingChannel can act as a FundingTxConstructorV2, using the state from RenegotiatingScope (if present)
  • Since both FundedChannel and FundingTxConstructor has context(), context accessors are extracted into a common base trait, ChannelContextProvider (it is also shared by InitialRemoteCommitmentReceiver).

(Also relevant: #3444)

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Apr 15, 2025

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

@ldk-reviews-bot
Copy link

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

1 similar comment
@ldk-reviews-bot
Copy link

🔔 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

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

1 similar comment
@ldk-reviews-bot
Copy link

🔔 2nd 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

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

1 similar comment
@ldk-reviews-bot
Copy link

🔔 3rd 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

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

1 similar comment
@ldk-reviews-bot
Copy link

🔔 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

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

1 similar comment
@ldk-reviews-bot
Copy link

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

@ldk-reviews-bot
Copy link

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

1 similar comment
@ldk-reviews-bot
Copy link

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

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Sorry about the late review. We were traveling to an off site last week. Just a high-level pass on the first four commits. Will need to take a closer look at the last one.

Copy link

codecov bot commented Apr 30, 2025

Codecov Report

❌ Patch coverage is 74.33962% with 68 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.95%. Comparing base (7ec13dc) to head (36ad1c0).
⚠️ Report is 34 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/channel.rs 70.27% 33 Missing ⚠️
lightning/src/ln/channelmanager.rs 37.77% 21 Missing and 7 partials ⚠️
lightning/src/ln/interactivetxs.rs 93.57% 6 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3736      +/-   ##
==========================================
+ Coverage   88.92%   88.95%   +0.03%     
==========================================
  Files         174      174              
  Lines      123869   124165     +296     
  Branches   123869   124165     +296     
==========================================
+ Hits       110152   110456     +304     
+ Misses      11256    11228      -28     
- Partials     2461     2481      +20     
Flag Coverage Δ
fuzzing 22.65% <0.00%> (+0.46%) ⬆️
tests 88.78% <74.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.

@optout21 optout21 force-pushed the splice-dual-tx4 branch 3 times, most recently from 88d2e83 to 866368d Compare May 5, 2025 11:59
@optout21
Copy link
Contributor Author

optout21 commented May 6, 2025

Ready for a new round of review. I have addressed the comments, applied most of them. There is still one to-do (update channel reserve values), that I will do, but the rest is ready for review.
I did the changes in separate 'fix' commits.

@optout21
Copy link
Contributor Author

Ready for a new round of review. All pending and newly raised comments addressed.

@wpaulino wpaulino removed their request for review July 21, 2025 23:04
@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from 3b31240 to d400a8b Compare July 22, 2025 04:42
Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Squashed all the fixups and created some standalone commits where possible. Will need to update some of the commit authorship. Hopefully, this will be a little easier to review now.

@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from d400a8b to 07190d1 Compare July 22, 2025 17:16
@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from f3a3877 to 575990a Compare July 22, 2025 23:42
@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from 575990a to 1cbfc55 Compare July 23, 2025 22:57
Comment on lines +2256 to +2270
let post_value_to_self_msat = AddSigned::checked_add_signed(
prev_funding.value_to_self_msat,
our_funding_contribution_sats * 1000,
);
debug_assert!(post_value_to_self_msat.is_some());
let post_value_to_self_msat = post_value_to_self_msat.unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

The debug_assert!(post_value_to_self_msat.is_some()) assumes that adding our_funding_contribution_sats * 1000 to prev_funding.value_to_self_msat will never overflow. However, this isn't guaranteed, especially with large values.

If the addition overflows, post_value_to_self_msat will be None, and the subsequent unwrap() will panic. Consider handling the overflow case explicitly, perhaps by capping the value at u64::MAX or returning an error if the addition would overflow. This would make the code more robust against edge cases.

Spotted by Diamond

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

Copy link
Contributor

Choose a reason for hiding this comment

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

This shouldn't be possible so long as our_funding_contribution_sats doesn't exceed the total bitcoin supply. I will add more checks in the splice-out follow-up PR.

@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from 1cbfc55 to 2eeb134 Compare July 24, 2025 19:31
This is a simple rename, DualFundingContext to FundingNegotiationContext,
to suggest that this is use not only in dual-funded channel open.
Also rename the field dual_funding_context to funding_negotiation_context.
@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from 2eeb134 to 4eb980e Compare July 28, 2025 17:32
@jkczyz jkczyz force-pushed the splice-dual-tx4 branch from 4eb980e to 0a52fd6 Compare July 29, 2025 00:19
Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Couple comments still left to address

@jkczyz jkczyz force-pushed the splice-dual-tx4 branch 3 times, most recently from 9766f21 to cdc393c Compare July 29, 2025 22:15
@@ -1270,6 +1270,10 @@ impl SharedOwnedInput {
Self { input, prev_output, local_owned }
}

pub fn local_owned(&self) -> u64 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: doesn't look like this belongs in commit 526bf62

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, doesn't look like it is used at all actually.

chan.holder_commitment_point.transaction_number(),
&&logger,
)
// Don't close a funded channel if splicing fails
Copy link
Contributor

Choose a reason for hiding this comment

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

I think if we always return a tx_abort from funding_tx_constructed then it should handle both dual funded and splicing cases appropriately.

Copy link
Contributor

Choose a reason for hiding this comment

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

As in for the Err type instead of ChannelError? Don't we want to close the channel for the dual funding case?

@@ -10515,50 +10691,191 @@ where
// MUST send a warning and close the connection or send an error
// and fail the channel.
if !self.context.is_live() {
return Err(ChannelError::Warn(format!("Splicing requested on a channel that is not live")));
return Err(ChannelError::Warn(format!(
Copy link
Contributor

Choose a reason for hiding this comment

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

We should WarnAndDisconnect instead whenever we come across an error on a counterparty message, otherwise we'll be stuck in quiescence until the timeout. Though it's short, might as well do it immediately.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done. Though used Ignore in a couple places that seemed more appropriate.

jkczyz and others added 8 commits July 31, 2025 10:24
PendingSplice holds a FundingScope being negotiated. However, when
implementing funding negotiation, other states are possible depending on
which party initiated the splice. Using an enum prevents needing various
Option fields which may result in invalid states.

When the user initiates the splice, the FundingNegotiationContext must
be held until the counterparty responds with splice_ack. At that point
enough information becomes available to create a new FundingScope and an
InteractiveTxConstructor.

When the counterparty initiates the splice, both a new FundingScope and
an InteractiveTxConstructor can be created immediately when responding
with splice_ack.

After the transaction is constructed, those are no longer needed. At
that point an InteractiveTxSigningSession is tracked until signatures
are exchanged.
FundingNegotiationContext and PendingSplice both hold the user's
contribution to a splice, which doesn't need to be duplicated. Instead,
only store this in FundingNegotiationContext, which then can be used to
create an InteractiveTxConstructor when transitioning to
FundingNegotiation:::ConstructingTransaction.

This commit updates that code to properly compute change outputs using
the FundingNegotiationContext by not considering the shared input since
it is accounted for in the shared output.

Co-authored-by: Wilmer Paulino <[email protected]>
Co-authored-by: Jeffrey Czyz <[email protected]>
Instead of passing the shared funding input as another parameter to
FundingNegotiationContext::into_interactive_tx_constructor, make it a
member of FundingNegotiationContext.
InteractiveTxConstructor was only used in PendingV2Channel methods, but
for splicing those methods are needed for FundedChannel, too. Refactor
the code such that each type has a method for accessing its
InteractiveTxConstructor such that it can be called in either use,
refactoring code out of PendingV2Channel as needed.

Co-authored-by: Wilmer Paulino <[email protected]>
Co-authored-by: Jeffrey Czyz <[email protected]>
Update splice_channel, split_init, and splice_ack to implement
transitioning from splice initialization to funding transaction
negotiation.

Co-authored-by: optout <[email protected]>
Co-authored-by: Jeffrey Czyz <[email protected]>
Instead of passing the optional change script as another parameter to
FundingNegotiationContext::into_interactive_tx_constructor, make it a
member of FundingNegotiationContext. Also, allow it to be passed to
ChannelManager::splice_channel.
If splicing fails, the previous funding is still usable. Convert any
ChannelError::Close to ChannelClose::Warn when this is the case to avoid
closing a usable channel.
Once splice has been promoted, the interactive_tx_signing_session is no
longer needed. Clear it at this time to prevent being in an inconsistent
state.
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.

4 participants