Support manually selecting inputs consuming their entire value#4575
Support manually selecting inputs consuming their entire value#4575wpaulino wants to merge 2 commits intolightningdevkit:mainfrom
Conversation
|
🎉 This PR is now ready for review! |
| ); | ||
|
|
||
| if !self.inputs.is_empty() { | ||
| if !self.inputs.is_empty() && self.input_mode == Some(FundingInputMode::CoinSelected) { |
There was a problem hiding this comment.
Bug: Backwards compatibility issue with persisted FundingContribution objects.
FundingContribution is persisted in PendingFunding.contributions (channel.rs:2917). When deserializing contributions created before this PR, input_mode will be None (it's a new option TLV field). Old coin-selected contributions with inputs will have input_mode == None, causing this condition to be false even though they should take the coin-selected branch.
This causes two problems for old persisted coin-selected contributions:
- Wrong fee buffer calculation: Uses
holder_balance + net_value_without_feeinstead ofestimated_fee + change_value, potentially allowing or rejecting feerate adjustments incorrectly. - Change output silently dropped:
compute_feerate_adjustmentreturnsNonefor change, andat_feeratesetschange_output = None, losing the change value.
This is reachable via for_acceptor_at_feerate / for_initiator_at_feerate called on contributions loaded from pending_splice.contributions (channel.rs lines 12504, 12944, 13127, 13145).
Fix: use self.input_mode != Some(FundingInputMode::Manual) instead of self.input_mode == Some(FundingInputMode::CoinSelected) to preserve old behavior for contributions where input_mode is None:
| if !self.inputs.is_empty() && self.input_mode == Some(FundingInputMode::CoinSelected) { | |
| if !self.inputs.is_empty() && self.input_mode != Some(FundingInputMode::Manual) { |
There was a problem hiding this comment.
There is no backwards compatibility concern because the serialized object has not been included in a release yet.
| if let Some(PriorContribution { contribution: prior_contribution, .. }) = | ||
| self.prior_contribution.as_ref() | ||
| { | ||
| if prior_contribution.input_mode == Some(FundingInputMode::CoinSelected) |
There was a problem hiding this comment.
Minor: Same backwards-compat pattern as line 880. Old persisted coin-selected contributions will have input_mode == None, so this guard won't fire for them. In practice this is mostly mitigated by the check at line 1309 (value_added > 0 && manually_selected_inputs non-empty), but it could miss edge cases where the old prior had value_added() == 0 (inputs exactly covered outputs + fees).
Consider using != Some(FundingInputMode::Manual) combined with a non-empty inputs check:
| if prior_contribution.input_mode == Some(FundingInputMode::CoinSelected) | |
| if prior_contribution.input_mode != Some(FundingInputMode::Manual) | |
| && !prior_contribution.inputs.is_empty() |
|
I've completed a thorough review of the entire PR diff. The two backwards-compatibility issues flagged in the prior review are still present and are the only material bugs. No new issues were found. Review SummaryPreviously Flagged Issues (still open)These are the only issues in this PR and were already flagged in the prior review:
New IssuesNo new issues found. The rest of the implementation is correct:
|
12e5994 to
412ec3d
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4575 +/- ##
==========================================
+ Coverage 87.08% 87.20% +0.11%
==========================================
Files 161 161
Lines 109255 109662 +407
Branches 109255 109662 +407
==========================================
+ Hits 95147 95626 +479
+ Misses 11627 11557 -70
+ Partials 2481 2479 -2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
The root problem seems to be relying on One additional edge case in So overall, it'd be good to make the handling of |
TheBlueMatt
left a comment
There was a problem hiding this comment.
All LGTM. One question.
| self.feerate, | ||
| ); | ||
| if !inputs.is_empty() { | ||
| total_input_value |
There was a problem hiding this comment.
Should this not include the channel's spliceable balance and outputs as well?
There was a problem hiding this comment.
This is for a fresh contribution where the spliceable balance is not available (either because they discarded the previous contribution or there wasn't one at all). The balance will get checked once ChannelManager::funding_contributed is called.
There was a problem hiding this comment.
Its weird that the spliceable-balance is in priorcontribution and not in the FundingTemplate...
|
🔔 1st Reminder Hey @jkczyz! This PR has been waiting for your review. |
This commit introduces an alternative way of splicing in funds without coin selection by requiring the full UTXO to be provided. Each UTXO's entire value (minus fees) is allocated towards the channel, which provides unified balance wallets a more intuitive API when splicing funds into the channel, as they don't particularly care about maintaining a portion of their balance onchain. To simplify the implementation, we require that contributions are not allowed to mix coin-selected inputs with manually-selected ones. Users will need to start a fresh contribution if they want to change the funding input mode.
There's no reason not to do so, and it allows us to fail earlier when the user's net contribution exceeds their spliceable balance.
412ec3d to
228cae8
Compare
|
🔔 2nd Reminder Hey @jkczyz! This PR has been waiting for your review. |
This commit introduces an alternative way of splicing in funds without coin selection by requiring the full UTXO to be provided. Each UTXO's entire value (minus fees) is allocated towards the channel, which provides unified balance wallets a more intuitive API when splicing funds into the channel, as they don't particularly care about maintaining a portion of their balance onchain.
To simplify the implementation, we require that contributions are not allowed to mix coin-selected inputs with manually-selected ones. Users will need to start a fresh contribution if they want to change the funding input mode.