Skip to content

Conversation

@jkczyz
Copy link
Contributor

@jkczyz jkczyz commented Dec 4, 2025

Some splicing use cases require to simultaneously splice in and out in the same splice transaction. Add support for such splices using the funding inputs to pay the appropriate fees just like the splice-in case, opposed to using the channel value like the splice-out case. This requires using the contributed input value when checking if the inputs are sufficient to cover fees, not the net contributed value. The latter may be negative in the net splice-out case.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Dec 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.

@jkczyz jkczyz self-assigned this Dec 4, 2025
@jkczyz jkczyz force-pushed the 2025-12-splice-in-and-out branch 2 times, most recently from fc608ab to a89b894 Compare December 5, 2025 21:08
@jkczyz jkczyz marked this pull request as ready for review December 5, 2025 21:09
@jkczyz jkczyz force-pushed the 2025-12-splice-in-and-out branch 2 times, most recently from d9f02da to c9cade5 Compare December 5, 2025 22:40
@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

❌ Patch coverage is 98.80240% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.34%. Comparing base (de384ff) to head (c9cade5).
⚠️ Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/channel.rs 95.45% 0 Missing and 4 partials ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #4261    +/-   ##
========================================
  Coverage   89.33%   89.34%            
========================================
  Files         180      180            
  Lines      139042   139228   +186     
  Branches   139042   139228   +186     
========================================
+ Hits       124219   124393   +174     
- Misses      12196    12207    +11     
- Partials     2627     2628     +1     
Flag Coverage Δ
fuzzing 34.99% <57.31%> (-0.98%) ⬇️
tests 88.71% <98.80%> (+<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.

When adding support for mixed splice-in and splice-out, the contribution
amount will need to be computed based on the splice-in and splice-out
values. Rather than add a third variant to SpliceContribution, which
could have an invalid contribution amount, use a more general struct
that can represent splice-in, splice-out, and mixed. Constructors are
provided for the typical splice-in and splice-out case whereas support
for the mixed case will be added in an independent change.
Some splicing use cases require to simultaneously splice in and out in
the same splice transaction. Add support for such splices using the
funding inputs to pay the appropriate fees just like the splice-in case,
opposed to using the channel value like the splice-out case. This
requires using the contributed input value when checking if the inputs
are sufficient to cover fees, not the net contributed value. The latter
may be negative in the net splice-out case.
@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.

@jkczyz jkczyz force-pushed the 2025-12-splice-in-and-out branch from c9cade5 to 175bf79 Compare December 8, 2025 14:32
},
pub struct SpliceContribution {
/// The amount to contribute to the splice.
value: SignedAmount,
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 remind me why we need this? Can we not just have a constructor that calculates the change output and adds it to outputs if needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's a bunch of others things need to calculate change (e.g., signer provider, channel keys id, fee rate, holder dust limit, shared input/output). See:

let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
match calculate_change_output_value(
&self,
self.shared_funding_input.is_some(),
&shared_funding_output.script_pubkey,
context.holder_dust_limit_satoshis,
) {
Ok(change_value_opt) => change_value_opt,
Err(reason) => {
return Err(self.into_negotiation_error(reason));
},
}
} else {
None
};
if let Some(change_value) = change_value_opt {
let change_script = if let Some(script) = self.change_script {
script
} else {
match signer_provider.get_destination_script(context.channel_keys_id) {
Ok(script) => script,
Err(_) => {
let reason = AbortReason::InternalError("Error getting change script");
return Err(self.into_negotiation_error(reason));
},
}
};
let mut change_output =
TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
let change_output_fee =
fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
// Check dust limit again
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
self.our_funding_outputs.push(change_output);
}
}

It also checks if we have enough input to pay for change, so the constructor would be be fallible.

Maybe some of that code can be moved here using some fake values for the shared output, for instance. It's currently used for dual funding, too, though. The user would need to obtain and pass the shared input unless a fake is also fine. Not sure if this would be worth it, though.


/// The inputs included in the splice's funding transaction to meet the contributed amount
/// plus fees. Any excess amount will be sent to a change output.
inputs: Vec<FundingTxInput>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we just leave these fields public as they were (implicitly cause it was an enum)? Could then presumably drop the splice_in_and_out constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm... not sure if we want the user to calculate the net contribution value given it is partly derived from the supplied outputs.

Maybe we could actually keep it as an enum (adding an extra variant) and have a method to derive the net contribution? I'm not 100% certain we need to use a struct, and the enum approach is nice because the fields are named when initializing a SpliceContribution variant.

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