Repository navigation
loopd: check depth, deadline and amount before a recovery sweep - #1290
Draft
claravanstaden wants to merge 4 commits into
Draft
claravanstaden wants to merge 4 commits into
claravanstaden wants to merge 4 commits into
Conversation
claravanstaden
force-pushed
the
loopout-recovery-htlc-confs
branch
2 times, most recently
from
November 13, 2026 13:29
ded0733 to
cf4fe89
Compare
sweepHtlc always waited for one confirmation of the HTLC before it signed and published the success path sweep, which reveals the preimage. The automatic recovery worker reuses that helper, so a loop out that stored a higher htlc_confs value had its preimage revealed after a single confirmation, and a reorg of that block could cost the swap amount. When the sweep uses a stored swap, wait for the swap's stored number of confirmations instead. Stateless recovery has no stored value and keeps waiting for one confirmation.
The recovery worker sweeps a loop out HTLC through the success path, which reveals the preimage. It did so at any height, also when the HTLC was about to expire or had already expired. The server can then take the HTLC back through its timeout path and still settle the swap payment with the preimage. Waiting for the stored htlc_confs moves the sweep closer to the expiry, which makes this easier to reach. Read the block height after the confirmation wait and refuse the sweep once no more than MinLoopOutPreimageRevealDelta blocks are left before the expiry, the bound the swap itself applies right before it reveals the preimage. A swap that already revealed its preimage is still swept. The worker needs the height lookup and doesn't sweep without it. Manual sweeps are unchanged.
The recovery worker swept any output that paid to a swap's HTLC script, whatever its value. The sweep reveals the preimage, so a server could fund the HTLC with a fraction of the swap amount, notify the client, and settle the full swap payment with the revealed preimage. Refuse the sweep when the HTLC holds less than the swap's requested amount, the check the swap itself does before it reveals the preimage. A swap that already revealed its preimage is still swept. Manual sweeps are unchanged.
claravanstaden
force-pushed
the
loopout-recovery-htlc-confs
branch
from
November 13, 2026 17:40
cf4fe89 to
a1f8a63
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The automatic recovery worker sweeps a loop out HTLC through the success path, which reveals the preimage. It skipped three checks the swap itself does before revealing it:
htlc_confs.Before and after
Before
htlc_confsset to 6.sweepHtlc.After
htlc_confsset to 6.sweepHtlc, which waits for the swap's stored 6 confirmations.Fix
Three commits:
HtlcConfirmationsinstead of one. Stateless recovery has no stored value and still waits for one confirmation. This also applies toloop out sweephtlcin database mode, which now waits for the same depth as the normal swap flow.CltvExpiry - MinLoopOutPreimageRevealDelta(20 blocks), the bound the swap applies right before it reveals the preimage. The worker needs the height lookup and doesn't sweep without it.AmountRequested, the check the swap does before it reveals the preimage.A swap that is already in
StatePreimageRevealedis still swept, as in the normal flow. Manual sweeps (loop out sweephtlc) get the confirmation depth but not the deadline or value checks.Tests
TestHtlcConfirmedRecoveryManagerHonorsHtlcConfirmations: recovery sweeps for swaps with a stored depth of 0, 1, 2 and 6 register for 1, 1, 2 and 6 confirmations, then sign and publish. The deeper cases fail on master (registers for one).TestSweepHtlcStateless: a stateless sweep still registers for one confirmation.TestHtlcConfirmedRecoveryManagerRevealDeadline: the worker sweeps one block before the deadline, and doesn't sweep at the deadline, after the expiry, for a timed out swap, when the height lookup fails or when it has no height lookup. A swap that already revealed its preimage is swept at the deadline. The refusing cases fail on master.TestHtlcConfirmedRecoveryManagerChecksHtlcValue: the worker sweeps an HTLC that holds the swap amount or more, and doesn't sweep one that is one sat short or holds half of it. A swap that already revealed its preimage is swept anyway. The refusing cases fail on master.Known limits
loop out sweephtlcin database mode blocks until that depth too. The CLI help says so.loop out sweephtlccan still sweep at any height and any value.