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

Force-close channels if their feerate gets stale without any update #3037

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

Conversation

TheBlueMatt
Copy link
Collaborator

For quite some time, LDK has force-closed channels if the peer
sends us a feerate update which is below our FeeEstimator's
concept of a channel lower-bound. This is intended to ensure that
channel feerates are always sufficient to get our commitment
transaction confirmed on-chain if we do need to force-close.

However, we've never checked our channel feerate regularly - if a
peer is offline (or just uninterested in updating the channel
feerate) and the prevailing feerates on-chain go up, we'll simply
ignore it and allow our commitment transaction to sit around with a
feerate too low to get confirmed.

Here we rectify this oversight by force-closing channels with stale
feerates, checking after each block. However, because fee
estimators are often buggy and force-closures piss off users, we
only do so rather conservatively. Specifically, we only force-close
if a channel's feerate is below the minimum FeeEstimator-provided
minimum across the last day.

Further, because fee estimators are often especially buggy on
startup (and because peers haven't had a chance to update the
channel feerates yet), we don't force-close channels until we have
a full day of feerate lower-bound history.

This should reduce the incidence of force-closures substantially,
but it is expected this will still increase force-closures somewhat
substantially depending on the users' FeeEstimator.

Fixes #993
Previous attempt was #1056

I thought about just closing #993 entirely without addressing it as we really don't want to do this, we really want Bitcoin Core 28 to ship with package relay, users to use anchor channels, and never force-close a channel for too-low-feerate issues again.

However, if we don't do this there's kinda no point in force-closing for too-low-feerate at all - it means an honest node that just has a bad fee estimator will get force-closed on but a malicious node will just be mum as feerates go up and leave us high and dry.

@TheBlueMatt TheBlueMatt added this to the 0.1 milestone May 6, 2024
@codecov-commenter
Copy link

codecov-commenter commented May 6, 2024

Codecov Report

Attention: Patch coverage is 55.80524% with 118 lines in your changes are missing coverage. Please review.

Project coverage is 89.88%. Comparing base (7d2d047) to head (8b320be).

Files Patch % Lines
lightning/src/ln/channel.rs 35.22% 97 Missing and 6 partials ⚠️
lightning/src/ln/channelmanager.rs 70.58% 14 Missing and 1 partial ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #3037    +/-   ##
========================================
  Coverage   89.88%   89.88%            
========================================
  Files         117      117            
  Lines       97203    97306   +103     
  Branches    97203    97306   +103     
========================================
+ Hits        87369    87465    +96     
- Misses       7269     7273     +4     
- Partials     2565     2568     +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@benthecarman benthecarman left a comment

Choose a reason for hiding this comment

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

Would be good if there was a way to disable this functionality, I assume a lot of people will not want their channels randomly force closing

@TheBlueMatt
Copy link
Collaborator Author

Because this uses the existing FeeEstimator MinAllowedAnchorChannelRemoteFee and MinAllowedNonAnchorChannelRemoteFee values, setting them to 0/253 will disable this entirely including the existing force-closes from peers sending us low values. Are you anticipating a desire to disable this without disabling the checking when peers do send update_fee?

@valentinewallace
Copy link
Contributor

Because this uses the existing FeeEstimator MinAllowedAnchorChannelRemoteFee and MinAllowedNonAnchorChannelRemoteFee values, setting them to 0/253 will disable this entirely including the existing force-closes from peers sending us low values. Are you anticipating a desire to disable this without disabling the checking when peers do send update_fee?

Thoughts on this @benthecarman?

@benthecarman
Copy link
Contributor

yeah i guess that is fine

Comment on lines +2107 to +2111
/// We only keep this in memory as we assume any feerates we receive immediately after startup
/// may be bunk (as they often are if Bitcoin Core crashes) and want to delay taking any
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we likely to receive a very low feerate right after startup if bitcoin core crashed, setting the bar too low for FC? Might we want to wait 1-3 blocks after startup before starting to store any feerates?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's okay, after a few extra hours the min will fall off our horizon and we'll FC.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, rereading some chat logs it looks like Cash App LDK node pods automatically restart every ~24 hours, other users may have a similar setup. Not sure if 144 blocks might be a bit on the conservative side.

@valentinewallace
Copy link
Contributor

Basically LGTM pending 2nd reviewer. Needs rebase as well.

In the next commit we'll add a second field to
`ChannelError::Close` so here we prep by converting existing calls
to the constructor function, which is almost a full-file sed.
This will allow us to add more granular failure reasons when
returning the general `ChannelError::Close`.
Closure due to feerate disagreements are a specific closure reason
which admins can understand and tune their config (in the form of
their `FeeEstimator`) to avoid, so having a separate
`ClosureReason` for it is useful.
For quite some time, LDK has force-closed channels if the peer
sends us a feerate update which is below our `FeeEstimator`'s
concept of a channel lower-bound. This is intended to ensure that
channel feerates are always sufficient to get our commitment
transaction confirmed on-chain if we do need to force-close.

However, we've never checked our channel feerate regularly - if a
peer is offline (or just uninterested in updating the channel
feerate) and the prevailing feerates on-chain go up, we'll simply
ignore it and allow our commitment transaction to sit around with a
feerate too low to get confirmed.

Here we rectify this oversight by force-closing channels with stale
feerates, checking after each block. However, because fee
estimators are often buggy and force-closures piss off users, we
only do so rather conservatively. Specifically, we only force-close
if a channel's feerate is below the minimum `FeeEstimator`-provided
minimum across the last day.

Further, because fee estimators are often especially buggy on
startup (and because peers haven't had a chance to update the
channel feerates yet), we don't force-close channels until we have
a full day of feerate lower-bound history.

This should reduce the incidence of force-closures substantially,
but it is expected this will still increase force-closures somewhat
substantially depending on the users' `FeeEstimator`.

Fixes lightningdevkit#993
@TheBlueMatt
Copy link
Collaborator Author

Rebased and added a test.

Copy link
Contributor

@vincenzopalazzo vincenzopalazzo left a comment

Choose a reason for hiding this comment

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

LGTM and thanks to try address this issue before core v28

CI looks like it is failing, but It looks like unrelated?

thread 'full_stack::tests::test_no_existing_test_breakage' panicked at 'assertion failed: `(left == right)`
  left: `None`,
 right: `Some(1)`', src/full_stack.rs:1320:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    full_stack::tests::test_no_existing_test_breakage

test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

Maybe I am wrong, the fuzz testing of ldk is still a black-box to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Auto-Close on update_fee delay
5 participants