Don't trim HTLCs when calculating the commit tx fee including the fee spike multiple#4574
Don't trim HTLCs when calculating the commit tx fee including the fee spike multiple#4574tankyleo wants to merge 3 commits into
Conversation
|
👋 Thanks for assigning @TheBlueMatt as a reviewer! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4574 +/- ##
==========================================
+ Coverage 86.18% 86.40% +0.22%
==========================================
Files 156 158 +2
Lines 108528 109079 +551
Branches 108528 109079 +551
==========================================
+ Hits 93532 94252 +720
+ Misses 12386 12282 -104
+ Partials 2610 2545 -65
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:
|
89ef026 to
059fb46
Compare
305a12d to
6d8b153
Compare
| let spiked_feerate = | ||
| feerate_per_kw.saturating_mul(if !channel_type.supports_anchors_zero_fee_htlc_tx() { | ||
| crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32 | ||
| } else { | ||
| 1 | ||
| }, | ||
| ); | ||
| }); |
There was a problem hiding this comment.
The is_outbound_from_holder guard has been removed from the spiked feerate calculation. Previously, only the channel funder (outbound) applied the 2x fee spike buffer here; now it applies to both funder and fundee channels.
This is a behavioral change beyond the stated fix: for non-anchor inbound (fundee) channels, spiked_feerate was previously just feerate_per_kw, and now it's feerate_per_kw * 2. This affects downstream calculations including:
local_max_commit_tx_fee_sat/local_min_commit_tx_fee_sat(though only used in the outbound branch)get_next_splice_out_maximum_sat(usesspiked_feeratefor thehas_outputcheck)- Both
adjust_boundaries_if_max_dust_htlc_produces_no_outputcalls (now use 2x feerate for inbound channels)
This makes capacity reporting more conservative for fundee channels, which may be intentional (aligning reported capacity with what can_accept_incoming_htlc actually accepts). If so, it would be good to mention this in the PR description / commit message as a deliberate secondary change.
| let htlcs_in_tx = vec![ | ||
| HTLCOutputInCommitment { | ||
| offered: false, | ||
| cltv_expiry: 81, | ||
| payment_hash: payment_hashes.iter().find(|hash| hash.0[0] == 0x75).unwrap().clone(), | ||
| amount_msat: 688_000, | ||
| transaction_output_index: Some(0), | ||
| }, | ||
| HTLCOutputInCommitment { | ||
| offered: false, | ||
| cltv_expiry: 81, | ||
| payment_hash: payment_hashes.iter().find(|hash| hash.0[0] == 0x64).unwrap().clone(), | ||
| amount_msat: 688_000, | ||
| transaction_output_index: Some(1), | ||
| }, | ||
| HTLCOutputInCommitment { | ||
| offered: false, | ||
| cltv_expiry: 81, | ||
| payment_hash, | ||
| amount_msat: 688_000, | ||
| transaction_output_index: Some(2), | ||
| }, | ||
| HTLCOutputInCommitment { | ||
| offered: false, | ||
| cltv_expiry: 81, | ||
| payment_hash: payment_hashes.iter().find(|hash| hash.0[0] == 0x72).unwrap().clone(), | ||
| amount_msat: 688_000, | ||
| transaction_output_index: Some(3), | ||
| }, | ||
| HTLCOutputInCommitment { | ||
| offered: false, | ||
| cltv_expiry: 81, | ||
| payment_hash: payment_hashes.iter().find(|hash| hash.0[0] == 0x66).unwrap().clone(), | ||
| amount_msat: 688_000, | ||
| transaction_output_index: Some(4), | ||
| }, | ||
| ]; |
There was a problem hiding this comment.
Identifying HTLCs by hardcoded first-byte values of payment hashes (0x75, 0x64, 0x72, 0x66) is fragile. This depends on the internal deterministic hash generation of the test framework, and will panic at the unwrap() if the test infrastructure changes how payment hashes are derived.
Consider tracking payment hashes directly from the route_payment return values instead. For example, store them in a Vec as they are created, and reference them by index to build htlcs_in_tx.
|
Good — the I've now completed a thorough review of the entire diff. The core logic changes are correct. My prior review comments cover all the issues I've found. No new bugs or security issues have been identified in this re-review. Review SummaryRe-reviewed the entire PR diff thoroughly. The core logic change — using base-feerate nondust HTLC count with spiked feerate for fee reservation — is mathematically sound and correctly ensures the funder can afford any feerate between 1x and 2x (not just exactly 2x). Prior inline comments (already posted, not repeated)
No new bugs or security issues found.The |
|
Just noting that this is the last bigger PR that will make our fuzz tests green again |
|
🔔 1st Reminder Hey @TheBlueMatt @carlaKC! This PR has been waiting for your review. |
1 similar comment
|
🔔 1st Reminder Hey @TheBlueMatt @carlaKC! This PR has been waiting for your review. |
|
🔔 2nd Reminder Hey @TheBlueMatt @carlaKC! This PR has been waiting for your review. |
1 similar comment
|
🔔 2nd Reminder Hey @TheBlueMatt @carlaKC! This PR has been waiting for your review. |
TheBlueMatt
left a comment
There was a problem hiding this comment.
didn't get through this yesterday but here's one comment.
| let spiked_feerate = feerate_per_kw.saturating_mul( | ||
| if is_outbound_from_holder && !channel_type.supports_anchors_zero_fee_htlc_tx() { | ||
| let spiked_feerate = | ||
| feerate_per_kw.saturating_mul(if !channel_type.supports_anchors_zero_fee_htlc_tx() { |
There was a problem hiding this comment.
If the issue is just with legacy 0-reserve channels, should we not be restricting this more and maybe just banning 0-reserve non-anchor channels (seems kinda weird to do such a channel?).
There was a problem hiding this comment.
I'd prefer to remove the if is_outbound_from_holder condition here rather than adding more checks to ban 0-reserve legacy channels.
There was a problem hiding this comment.
I understand legacy 0-reserve channels are weird, but they still allow the fundee to spend all its balance so they do have their place I'm thinking.
There was a problem hiding this comment.
I mean other nodes are gonna start requiring anchors for all new channels (or already have?) and I kinda feel like we should be moving towards the same. I see the reason for them (I guess someone who doesn't want to deal with anchors but wants to have an LSP open to a client?) but non-anchors are just so borderline insecure...
There was a problem hiding this comment.
See below I delete the first commit, and will add it to a standalone PR to ban legacy 0-reserve channels.
6d8b153 to
cc6965f
Compare
0d8def8 to
6211878
Compare
We previously accounted for HTLC trims at the spiked feerate when calculating the reserved commitment transaction fees. This could cause an underestimate of the real current commitment fee at the current channel feerate. This is because a 2x increase in the feerate could trim enough HTLCs to result in a smaller commitment transaction fee. Also, the previous code only reserved the fee for an exact 2x increase in the feerate, instead of reserving the fee for any increase in the feerate between 1x to 2x. Fixes lightningdevkit#4563.
In the next commit, we will make changes to how the fee spike buffer is calculated which require the real feerate to always be passed to `tx_builder::get_next_commitment_stats`, even in the case where we include a fee spike multiple.
We previously accounted for HTLC trims at the spiked feerate when calculating the commitment transaction fee including the fee spike multiple. This only ensured that the funder of the channel could afford the commitment transaction fee for an exact 2x increase in the feerate. Now, we check that the funder can cover any increase in the feerate between 1x to 2x.
6211878 to
0a194ba
Compare
TheBlueMatt
left a comment
There was a problem hiding this comment.
Okay, yea, I think I'm good with this now. Needs a second reviewer tho.
| &self, local: bool, is_outbound_from_holder: bool, channel_value_satoshis: u64, | ||
| value_to_holder_msat: u64, pending_htlcs: &[HTLCAmountDirection], | ||
| addl_nondust_htlc_count: usize, feerate_per_kw: u32, | ||
| addl_nondust_htlc_count: usize, feerate_per_kw: u32, include_fee_spike_multiple: bool, |
There was a problem hiding this comment.
nit: can we call this something more descriptive? Like assuming_future_increased_feerate? I think the "fee spike multiple" is a bit of an inside-LDK thing and we eventually want this API to be public.
We previously accounted for HTLC trims at the spiked feerate when calculating the reserved commitment transaction fees.
This could cause an underestimate of the real current commitment fee at the current channel feerate. This is because a 2x increase in the feerate could trim enough HTLCs to result in a smaller commitment transaction fee.
Also, the previous code only reserved the fee for an exact 2x increase in the feerate, instead of reserving the fee for any increase in the feerate between 1x to 2x.
Fixes #4563.