loopout: re-target sweep's feerate every block
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 withurgentSweepConfTargetand 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.mdif your PR contains major features, breaking changes or bugfixes
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 withurgentSweepConfTargetand 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.
@sputn1ck: review reminder
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.