loop icon indicating copy to clipboard operation
loop copied to clipboard

loopout: re-target sweep's feerate every block

Open starius opened this issue 1 year ago • 1 comments

Add type loopOutSweepFeerateProvider which determines confTarget based on distance to swap expiration, then determines feerate and fee using. Fee rate is plugged into sweepbatcher using WithCustomFeeRate.

When determining confTarget, there are few adjustments over raw distance to cltv_expiry:

  • make sure confTarget is positive (if the swap has expired, raw distance is negative)
  • If confTarget is less than or equal to DefaultSweepConfTargetDelta (10), cap it with urgentSweepConfTarget and apply fee factor (1.1x).

Also, if feerate is less than floor (1 sat/vbyte), then the floor is used.

DefaultSweepConfTargetDelta was decreased from 18 to 10.

Every block 100 sats/kw fee bump is disabled. Sweepbatcher re-targets feerate every block according to current mempool conditions and the number of blocks until expiry.

Added tests for loopOutSweepFeerateProvider simulating various conditions.

Pull Request Checklist

  • [ ] Update release_notes.md if your PR contains major features, breaking changes or bugfixes

starius avatar Oct 19 '24 04:10 starius

I removed SweepFeeProvider and moved parts of the logic to loopOutSweepFeerateProvider (method GetConfTargetAndFeeRate).

Decided to keep urgent logic and floor logic. High prio logic is removed.


New description of the change looks like this:

Add type loopOutSweepFeerateProvider which determines confTarget based on distance to swap expiration, then determines feerate and fee using. Fee rate is plugged into sweepbatcher using WithCustomFeeRate.

When determining confTarget, there are few adjustments over raw distance to cltv_expiry:

  • make sure confTarget is positive (if the swap has expired, raw distance is negative)
  • If confTarget is less than or equal to DefaultSweepConfTargetDelta (10), cap it with urgentSweepConfTarget and apply fee factor (1.1x).

Also, if feerate is less than floor (1 sat/vbyte), then the floor is used.

DefaultSweepConfTargetDelta was decreased from 18 to 10.

Every block 100 sats/kw fee bump is disabled. Sweepbatcher re-targets feerate every block according to current mempool conditions and the number of blocks until expiry.

Added tests for loopOutSweepFeerateProvider simulating various conditions.

starius avatar Oct 22 '24 21:10 starius

@sputn1ck: review reminder

lightninglabs-deploy avatar Nov 07 '24 21:11 lightninglabs-deploy

I tested the PR in regtest simulating changing of feerate environment.

It works!

But I found a bug in the approved version of the PR: loopout.go calls AddSweep after sweepbatcher tries to sweep. The fee rate is updated by sweepbatcher reacting on AddSweep call, so this results in the fee rate being outdated by one block:

2024-11-11 00:32:29.156 [DBG] SWEEP: [Batch 1] received block 163                                                                                                                                                  
2024-11-11 00:32:29.157 [DBG] RSRV: Received block 163                                                                                                                                                             
2024-11-11 00:32:29.687 [INF] SWEEP: [Batch 1] attempting to publish coop tx=4ea6cde3857e0bedee5098995903d26c578398d1777d99332bdda0d449053343 with feerate=500 sat/kw, weight=444 wu, feeForWeight=0.00000222 BTC, 
fee=0.00000222 BTC, sweeps=1, destAddr=bcrt1phptyurxht2p8masl8vqflgv4xfzg0n72cdax62yl8r7c95q7ngtsgkxgpj
2024-11-11 00:32:29.687 [DBG] SWEEP: [Batch 1] serialized coop sweep: 0200000000010113ddb9206aadd5be8c08da7edf6e3767dd2977f2ffda39c9551ecce3198ceaa000000000000000000001b2cf030000000000225120b8564e0cd75a827df61f3
b009fa195324487cfcac37a6d289f38fd82d01e9a170140803e6a6c415dcc89964580c2188288954ba9daaa9d49d713c8b32b84e7c35604baa621812ef504b83b82c7dc3ea3cc46b3e072be5d1becb04853186393e29443a3000000
2024-11-11 00:32:30.064 [INF] SWEEP: [Batch 1] co-op publish error: rpc error: code = Unknown desc = insufficient fee
2024-11-11 00:32:30.212 [DBG] SWP: Estimations for a tx (label=loopout-sweep-eb60dd506db6): weight=444 wu, fee=0.00002220 BTC, feerate=5000 sat/kw, sweepConfTarget=22.
2024-11-11 00:32:30.212 [DBG] LOOP: Estimated for swap eb60dd506db6: feeRate=5000 sat/kw, confTarget=22.
2024-11-11 00:32:30.212 [INF] SWEEP: Batcher handling sweep eb60dd506db6, completed=false

In this example, the fee rate spiked from 500 sat/kw to 5000 sat/kw, but the old value (500 sat/kw) was used when making the sweep transaction.

I fixed this by adding sweepbatcher.WithPublishDelay option to sweepbatcher. It sets the delay to 2 seconds. The delay in loopout.go before calling AddSweep is 1 second. Now the order is correct:

2024-11-11 01:10:40.613 [DBG] RSRV: Received block 176
2024-11-11 01:10:41.618 [DBG] SWP: Estimations for a tx (label=loopout-sweep-f0b718b1bb25): weight=444 wu, fee=0.00002220 BTC, feerate=5000 sat/kw, sweepConfTarget=48.
2024-11-11 01:10:41.618 [DBG] LOOP: Estimated for swap f0b718b1bb25: feeRate=5000 sat/kw, confTarget=48.
2024-11-11 01:10:41.619 [INF] SWEEP: Batcher handling sweep f0b718b1bb25, completed=false
2024-11-11 01:10:42.644 [INF] SWEEP: [Batch 2] attempting to publish coop tx=8870799108c578670426cb2dcd21e4ae2eda6d01642f1f37c85bcb95bc7a5c97 with feerate=5000 sat/kw, weight=444 wu, feeForWeight=0.00002220 BTC, fee=0.00002220 BTC, sweeps=1, destAddr=bcrt1p22v8sjqkvkn9wl94p32cfxemsu4cnj2kntxzcjpa5jwxnw5ay5lsq4twtf
2024-11-11 01:10:42.644 [DBG] SWEEP: [Batch 2] serialized coop sweep: 020000000001016e42dde2cfe3dbb077d887a58682df43776d65af1db9316164f06e3fabc3160a00000000000000000001e4c7030000000000225120529878481665a6577cb50c55849b3b872b89c9569acc2c483da49c69ba9d253f01401fd68c3d194d3770d4da71cf4ff266a12adeaa228cf2373e731a7b55f07d1c2294a5fcb2de81e2c67b58408bf8bb6d1c8453734c471d918bfeb5c70cfa4c17fcb0000000
2024-11-11 01:10:42.940 [INF] SWEEP: [Batch 2] co-op publish error: rpc error: code = Unknown desc = insufficient fee

Fee estimation (and possible update) now happens before the sweep transaction creation.

I pushed the fix in a separate commit. I'll squash it with the previous commit before merging.

starius avatar Nov 11 '24 04:11 starius