Skip to content
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

Limit FeeRate change for the UpdateFee msg to prevent sharp changes #7805

Merged
merged 3 commits into from Mar 19, 2024

Conversation

ziggie1984
Copy link
Collaborator

@ziggie1984 ziggie1984 commented Jul 4, 2023

Relates to #7666 and #7756

Detailed Problem explanation:

In lnd (lightning) there exist the feeupdate msg which allows channel openers to change the fee of the commitment transaction. For STATIC_REMOTE_KEY channels HTLCs which are part of the Commitment Transaction do have Timeout/Success Transactions which are signed with the same feerate as the Commitment Transaction (see BOLT3 for more details about the HTLC Transaction).
The FeeUpdate is only allowed to be sent by the Channel Opener but it should be in acceptable Limits, because especially for non-achor channels there is no way to accelerate this transaction (only if you pay a miner directly). CLN nodes will check for a specific range and will not allow the feeupdate from happening. If CLN does reject the feeupdate the channel will either be force-closed by the peer (lndk) or the channel becomes unusable and needs to be force-closed eventually by the peer.

This PR fixes 2 Problems:

No valid Fee Estimation by our backend

In case you either wipe your mempool or restart a new bitcoind node you want to connect to your lnd node, there is a short time period where bitcoind is not reporting any fee estimations because it does not have enough data available.

It will report:

bitcoin-cli estimatesmartfee 3
{
  "errors": [
    "Insufficient data or no feerate found"
  ],
  "blocks": 0
}

In such cases lnd would just read this response and the fee estimation would remain zero and then would just enforce the min mempool fee instead. This is a bad choice because when our mempool is big enough this fee rate is always 1 sat/vbyte and does not represent the current fee rate conditions. This PR will return an error in such cases and lnd will use its fallback feerate of 25 sats/vbyte. It is always better to overestimate rather than underestimate in such cases.

Limit Fee Estimation when channel is drained locally

Moreover Lnd reevaluates the MaxFeeRate it is willing to allocate for a Channel every time a feeupdate msg will be sent. When the channel is locally drained this could lead to a situation where we decrease the feerate all the way to the fee floor which does not reflect the current bitcoin network fee rate correctly and could also lead to our peer rejecting these low fee rate updates. With this PR we do not lower the MaxFeeRate we are willing to allocate for this channel if it would fall below the old fee rate. This guarantees that if we had a high fee rate on a channel, that we do not decrease it when the local balance is drained.

Locking for a Concept Ack here before writing tests.

This change will not fix existing channels which ran into this issue, but will most likely prevent future channels form being unusable when proposing very low fee rate updates leading to the channel-peer rejecting those.

Change Description

This PR limits the FeeRate update to a maximum of 30% of the old feerate. It only applies to non-anchor channels because for those the negotiated fee cannot be changed when resolving on-chain.

Open for discussions whether we want to pursue this route if 30% is too conservative and so one.

Needs some style fixing will solve this in the coming days.

Tests

I currently just updated the unit tests in the lnwallet package. I think it is enough and testing this in the htlcswitch where we drain the channel locally and send consecutively fee updates with the default fee-allocation might not be worth it IMO, what are your takes?

Fixes #7756

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where low fee rates could be proposed for channel transactions, ensuring alignment with network standards.
    • Adjusted fee buffer handling in channel openings to comply with BOLT 02 specification.
    • Improved fee estimation when external data is insufficient.
  • New Features
    • Added support for Taproot witness types in RPC calls.
  • Documentation
    • Updated handling instructions for min_final_cltv_expiry_delta for external invoices.
  • Tests
    • Enhanced testing for channel fee rate calculations to cover more scenarios.

@ziggie1984
Copy link
Collaborator Author

ziggie1984 commented Jul 18, 2023

This concept will not fix the problem, stated in #7756 (comment). I need to rework this to make sure we do not scale down the comitment fee all the way to 253 sat/kw.

Hold on for review yet !

@kornpow
Copy link
Contributor

kornpow commented Sep 22, 2023

Will this PR fix stuck channels or will it only prevent channels from entering a stuck state in the future?

@ziggie1984
Copy link
Collaborator Author

Will this PR fix stuck channels or will it only prevent channels from entering a stuck state in the future?

It cannot undo the feeupdate which happend in the past (your case currently) tho it will prevent low feeupdates in the future.

This change will not fix existing channels which ran into this issue, but will most likely prevent future channels form being unusable when proposing very low fee rate updates leading to the channel-peer rejecting those.

maxFee := float64(baseBalance) * maxAllocation
maxFee = math.Max(maxFee, float64(oldFee))
Copy link
Collaborator

Choose a reason for hiding this comment

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

A bit confused here - so this means our fee rate can only go up not down? And if we don't have this local balance, how can we cover the fees here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

exactly we do not want to lower the max_feerate lower than the old_fee, because this could lead to a situation where we go all the way to 253 sats/kw, we want to decrease the feerate here: https://github.com/lightningnetwork/lnd/blob/master/lnwallet/channel.go#L8456-L8458, basically we want to either have a 3 block sample_feerate which is lower than the old_feerate before we allow a lower feeupdate, otherwise it makes not real sense to lower the MaxFeeRate.

Copy link
Collaborator

Choose a reason for hiding this comment

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

In that case I think we should compare it against 3 block sample feerate instead of old feerate, otherwise if the fee spikes for a while then goes down, we'd still use the higher feerate as the max feerate although the current mempool is less congested. Plus this would bypass the value maxAllocation configured by the users?

Copy link
Collaborator 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 I understand the detail of your proposal could you elaborate ?

I think binding the maxAllocation to our current amount we have on our side might cause this strange logic problem.

What about refering the maxAllocation to the ChannelCapacity, I think that makes more sense because as a channelopener you will have most of the balance on your side anyways at the beginning and are willing to pay this max amount anyways. Now when the channel becomes depeleted the maxFeeRate is always (localbalance+oldfee) but if we have a lot of balance on our side it would be capped at the (chancapacity *MaxAllocation) ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We would be protected against big feespikes, not allocating more that our initial willingess to pay, but if the channel is depleted we make sure we do not decrease our MaxFee the more our channel gets depleted hence reducing the local fee of the commitment all the time, that also not fair to the peer imo which now has all the balance but a crappy feerate.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What about refering the maxAllocation to the ChannelCapacity

That's a very interesting proposal, plus it seems like to be the original definition anyway,

The maximum percentage of total funds that can be allocated to a channel's commitment fee. This only applies for the initiator of the channel. Valid values are within [0.1, 1]. (default: 0.5)

However, I think MaxFeeRate really means MaxAffordableFeeRate, which is determined by 1) the capacity, which is routing bandwidth + fee buffer + commit fee and 2) the max fee the user is willing to pay, which is specified by MaxAllocation. If we follow this strictly, we can make sure that, when necessary, there's enough channel balance, so the max fee can be deducted from it to pay the onchain fee.

The current approach doesn't guarantee there's always enough balance to cover the max fee.

After a second thought I think this is the right approach as oldFee(or the commit fee) is always there already, so it makes sense to cap at this value at least.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes I think we can go with the current approach, but I think the FeeRate for the Commitment Tx is really not an easy to solve problem. So I think making sure that the Commitment has always the Relay Fee of its peer is a very important PR which should be prioritized.

@ziggie1984 ziggie1984 force-pushed the updatefee-limiter branch 2 times, most recently from 32a2b26 to 500294f Compare November 6, 2023 11:20
@ziggie1984 ziggie1984 marked this pull request as ready for review November 6, 2023 11:20
@ziggie1984
Copy link
Collaborator Author

ziggie1984 commented Dec 10, 2023

Suffered from this behaviour on my local node as well now, I think this should be addressed asap, Channel is unusable now until we reach lower feelimits.

2023-12-10 13:30:59.882 [WRN] HSWC: ChannelLink(aa4a1c1313bed1063a9529840062c3263aced0b544b28105e79019f91e9c2bba:2): received warning message from peer: chan_id=ba2b9c1ef91990e70581b244b5d0ce3a26c362008429953a06d1be13131c4aa8, err=update_fee 253 outside range 4724-702240 (currently 1795)

Copy link
Collaborator

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

I think if we have #8096 we don't need this anymore since we would then have a fee buffer?

maxFee := float64(baseBalance) * maxAllocation
maxFee = math.Max(maxFee, float64(oldFee))
Copy link
Collaborator

Choose a reason for hiding this comment

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

In that case I think we should compare it against 3 block sample feerate instead of old feerate, otherwise if the fee spikes for a while then goes down, we'd still use the higher feerate as the max feerate although the current mempool is less congested. Plus this would bypass the value maxAllocation configured by the users?

@ziggie1984
Copy link
Collaborator Author

ziggie1984 commented Dec 20, 2023

I think if we have #8096 we don't need this anymore since we would then have a fee buffer?

We would still need this, because the evaluation of the fee (we are willing to pay) would decrease over time and because the buffer is tied to the feerate we would, because of a feerate decrease, decrease the buffer => our channel would get drained more => our local balance shrinks again => the fee for the commitment would shrink as well in the next step => potential worst case fee-floor

@yyforyongyu yyforyongyu added fees Related to the fees paid for transactions (both LN and funding/commitment transactions) P1 MUST be fixed or reviewed labels Dec 26, 2023
Copy link

coderabbitai bot commented Mar 8, 2024

Important

Auto Review Skipped

Auto reviews are limited to the following labels: llm-review. Please add one of these labels to enable auto reviews.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository.

To trigger a single review, invoke the @coderabbitai review command.

Walkthrough

This update addresses several key aspects of fee management and policy updates in the Lightning Network Daemon (LND), including adjustments to fee estimation, channel fee policy handling, and the addition of Taproot witness types to RPC calls. It improves the reliability and specification compliance of fee handling during channel openings and commitment transactions, enhancing overall network stability and user experience.

Changes

Files Change Summary
docs/release-notes/release-notes-0.18.0.md Summarized release notes detailing fee management improvements and Taproot support.
lnwallet/chainfee/estimator.go Adjustments for better fee estimation and logging.
lnwallet/channel.go
.../channel_test.go
Modifications to fee rate calculations in channels and updates to corresponding tests.

Assessment against linked issues

Objective Addressed Explanation
Fee rate and policy handling improvements for channel operations [#7756, #8018, #8396]
Addressing fee estimation discrepancies and backend setup issues [#8018] The changes focus on fee buffer adjustments and do not directly address backend setup discrepancies.
Ensuring UpdateChannelPolicy consistency and addressing failed payments due to fee issues [#8396] The release notes do not mention changes to UpdateChannelPolicy or payment failure issues directly.
Adding Taproot witness types to rpc [#7756]

Related issues

🎉🐇✨
In the fields of code, where logic threads weave,
A rabbit hopped forth, changes to conceive.
With a flick and a hop, fee woes take their leave,
Taproot in sight, as we aim to achieve.
Through tests and through trials, our goals interlace,
In the digital burrow, progress takes its place.
🌟🐾

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@ziggie1984 ziggie1984 force-pushed the updatefee-limiter branch 3 times, most recently from d6232c3 to ee06778 Compare March 8, 2024 18:33
@ziggie1984
Copy link
Collaborator Author

@coderabbitai review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 4f06f58 and ee06778.
Files selected for processing (4)
  • docs/release-notes/release-notes-0.18.0.md (3 hunks)
  • lnwallet/chainfee/estimator.go (2 hunks)
  • lnwallet/channel.go (5 hunks)
  • lnwallet/channel_test.go (3 hunks)
Additional comments: 17
docs/release-notes/release-notes-0.18.0.md (3)
  • 59-62: The addition of a fee buffer for locally opened channels as described in the linked PR is a significant improvement. It aligns with the BOLT 02 specification and addresses the issue of channels becoming stuck due to asynchronous HTLC additions or sharp fee changes. This change enhances the robustness of fee handling in lnd and is a proactive measure against potential channel issues.
  • 81-85: The fix for proposing low fee rates due to insufficient mempool data or local channel drainage is crucial. It addresses a significant issue where channels could default to the fee floor, potentially leading to unusable channels. This change is a direct response to the problems outlined in the PR objectives and is an essential step towards more reliable fee rate handling in lnd.
  • 267-269: Updating the handling of min_final_cltv_expiry_delta for external invoices without the parameter is a thoughtful improvement. By ensuring a minimum value of 18 blocks, lnd enhances the reliability of payment forwarding and settlement, aligning with network standards and expectations. This change contributes to a more predictable and consistent user experience.
lnwallet/chainfee/estimator.go (2)
  • 477-482: The addition of a check to handle cases where Bitcoind has insufficient data for fee estimation is a crucial improvement. It ensures that the system does not proceed with potentially incorrect fee rates, thus enhancing the robustness of fee estimation. This change is particularly important for maintaining the reliability of transaction confirmations.
  • 491-492: The modifications to log messages for fee rate and floor values contribute to better observability and debugging capabilities by providing clearer and more detailed information. This is beneficial for understanding the behavior of fee estimation and ensuring that the system operates as expected.

Also applies to: 498-498

lnwallet/channel.go (5)
  • 7139-7139: This change appears to be a setup or minor adjustment unrelated to the PR's main objectives. It doesn't introduce any issues.
  • 8683-8685: The addition of the maxAllocation parameter to the MaxFeeRate method is a crucial change for implementing dynamic fee rate management based on a maximum allocation percentage. The documentation clearly specifies its intended use case.
  • 8695-8715: The logic implemented here effectively ensures that the fee rate does not fall below the current fee rate, addressing one of the PR's main objectives. The calculations for maxFee, feeAllocation, and maxFeeRate are correctly implemented and align with the intended functionality.
  • 8727-8727: The updated usage of MaxFeeRate with maxFeeAlloc as an argument correctly applies the changes made to the method in the context of calculating the commit fee rate. This aligns with the PR's objectives of managing fee rates more effectively.
  • 8766-8766: The logic for ensuring the commitment fee is above the minimum relay fee rate and providing a warning when the max channel fee allocation is overridden is correctly implemented. This is crucial for the network's operation and aligns with the PR's objectives.
lnwallet/channel_test.go (7)
  • 7518-7520: The introduction of the TestChannelMaxFeeRate function is a positive step towards ensuring that fee rate changes do not lead to unusable channels. It's crucial to have comprehensive tests covering different scenarios, especially given the impact of fee rate changes on channel usability.
  • 7534-7540: Creating both non-anchor and anchor channel setups for testing is a good practice, as it ensures that the changes are validated across different channel types. This thorough testing approach helps in catching potential issues early in the development process.
  • 7555-7617: The addition of comprehensive test cases for different scenarios, including fee rate capping and calculation based on various conditions, is commendable. These tests are crucial for ensuring the robustness of the fee rate logic and preventing future issues related to fee rate changes.
  • 7622-7658: The assertions used in the test cases are well-thought-out, especially the use of require.InEpsilonf to account for rounding inaccuracies. This level of detail in testing demonstrates a commitment to ensuring the accuracy and reliability of the fee rate logic.
  • 7662-7665: The TestIdealCommitFeeRate function is a valuable addition to the test suite, focusing on the computation of the ideal commitment fee rate. Testing this aspect is crucial for ensuring that fee rate adjustments align with network conditions and do not lead to unusable channels.
  • 7688-7715: Creating both non-anchor and anchor test channels for the TestIdealCommitFeeRate function is a good practice. It ensures that the fee rate logic is validated across different channel types, which is essential for catching potential issues early.
  • 7717-7896: The test cases and assertions for the TestIdealCommitFeeRate function are comprehensive and well-designed. The use of helper functions for calculating max fee rate and current fee rate, along with the detailed test cases for both non-anchor and anchor channels, demonstrates a thorough approach to testing the fee rate logic.

Comment on lines +314 to +315
// TODO(ziggie): introduce an interface for the client to enhance
// testability of the estimator.
Copy link

Choose a reason for hiding this comment

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

The addition of a TODO comment to introduce an interface for client testability is a good practice for future enhancements. It's important to ensure that such TODOs are tracked in a project management tool or issue tracker to ensure they are addressed in a timely manner.

Would you like assistance in creating a GitHub issue to track this task?

Copy link
Collaborator

@ProofOfKeags ProofOfKeags left a comment

Choose a reason for hiding this comment

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

I'm happy with this PR with the exception of some nits. I think if we just clean up the rough edges, I think we're ready to ship this. Thank you for the submission! 🧡

lnwallet/channel.go Show resolved Hide resolved
lnwallet/channel.go Outdated Show resolved Hide resolved
lnwallet/channel_test.go Outdated Show resolved Hide resolved
lnwallet/channel_test.go Show resolved Hide resolved
lnwallet/channel_test.go Show resolved Hide resolved
lnwallet/channel_test.go Show resolved Hide resolved
lnwallet/channel_test.go Show resolved Hide resolved
@ziggie1984 ziggie1984 force-pushed the updatefee-limiter branch 2 times, most recently from b30879b to decd98e Compare March 12, 2024 12:06
@Crypt-iQ Crypt-iQ self-requested a review March 12, 2024 18:22
Copy link
Collaborator

@ProofOfKeags ProofOfKeags left a comment

Choose a reason for hiding this comment

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

SNED 🚀

@ziggie1984
Copy link
Collaborator Author

Last Push was just a rebase.

@ProofOfKeags
Copy link
Collaborator

Idk what's going on with CI but there's a lot of complaining checks that I can't figure out why they are failing.

@guggero
Copy link
Collaborator

guggero commented Mar 14, 2024

Related to the build cache. Going to put up a fix to reduce the cache size.
@Crypt-iQ you self-requested review on this PR after 2 approvals. Should we block on your review?

@Crypt-iQ
Copy link
Collaborator

Related to the build cache. Going to put up a fix to reduce the cache size. @Crypt-iQ you self-requested review on this PR after 2 approvals. Should we block on your review?

Yes

@guggero
Copy link
Collaborator

guggero commented Mar 19, 2024

Needs a rebase.

Bitcoind will not report any fee estimation in case it has not
enough data available. We used to just set the min mempool fee
in such cases but this might not represent the current fee situation
of the bitcoin network. We return an error now so that we will use
the fallback fee instead.
When determining the max fee rate of a channel we used to scale
the fee rate depending on our available local balance on this channel.
This lead to a special case that if a channel would be drained we
could especially decrease the fee rate even down to the fee floor.
Now we make sure that our max fee rate will not be lower than the
old fee rate to make sure in case our channel is locally drained
we do not continue to decrease fees too low.
Adding the release-notes for release 0.18 and fixing typos in the
release doc.
@guggero guggero merged commit ad88407 into lightningnetwork:master Mar 19, 2024
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fees Related to the fees paid for transactions (both LN and funding/commitment transactions) interop interop with other implementations P1 MUST be fixed or reviewed
Projects
Status: Done
8 participants