Commit graph

153 commits

Author SHA1 Message Date
Slyghtning
605e72a261
sweepbatcher: reject malformed MuSig2 cosign data
The cooperative batch sweep path receives a server nonce and partial signature before constructing a keyspend witness. Validate both byte slice lengths before registering the nonce or combining signatures, so malformed server responses fail explicitly instead of being zero-padded into fixed-size MuSig2 buffers.

Update batcher test helpers to return size-correct placeholder signing data under the stricter validation.
2026-05-29 11:53:33 +02:00
Boris Nagaev
1b25d8a122
sweepbatcher: assert close-during-add run exit
TestSweepBatcherCloseDuringAdding previously started Batcher.Run in a
detached goroutine and called test assertions from that goroutine. The
test only waited for the add/cancel workers, so a Run-side shutdown
error could be missed or reported unreliably.

Route the Run result through a channel and wait for it in the main test
goroutine. While waiting, keep draining spend registrations so shutdown
cannot deadlock on mock notifier traffic.

This makes the existing shutdown-race test cover both sides of the race:
AddSweep callers may exit with cancellation, and Batcher.Run must also
terminate with an expected shutdown error.
2026-05-18 11:58:54 +02:00
Boris Nagaev
707fef340b
sweepbatcher: mask presign cancellation races
PresignSweepsGroup uses context-sensitive wallet and presigned-helper
calls, but it previously returned their raw wrapped errors even when the
caller context or batcher shutdown state had already become terminal.
That leaves backend/helper errors visible during normal cancellation.

Check for shutdown/cancellation before presigning and after fee lookup
or presigning failures, preferring context.Canceled or
ErrBatcherShuttingDown over lower-level errors.

Log the original presign-path error before returning the shutdown or
cancellation error so normal shutdown remains debuggable without
changing the returned error.

Add a regression test with a presigned helper that cancels the caller
context while returning driver.ErrBadConn from SignTx. The test asserts
PresignSweepsGroup reports context.Canceled and does not wrap the driver
error, and runs against both mock and SQL-backed stores.
2026-05-18 11:58:54 +02:00
Boris Nagaev
8a4e2f1941
sweepbatcher: normalize run-loop shutdown errors
AddSweep now masks cancellation races during its caller-side setup, but
a request can still be accepted by the batcher run loop before the run
context cancellation is selected. If handleSweeps then performs a
context-sensitive store call while shutdown is in progress, a
backend-specific error such as driver.ErrBadConn can still bubble out
through Batcher.Run.

Prefer the run context's terminal error when startup, handleSweeps, or
asynchronous errChan failures happen after the run context has been
canceled. This keeps normal shutdown reporting consistent and avoids
surfacing backend driver errors from the accepted-request and async
error paths.

Log the original run-loop error before returning the context error so
normal shutdown remains debuggable without changing the returned error.

Add regression tests for both covered run-loop races. One lets AddSweep
successfully hand a sweep request to Run, then cancels the run context
from the second GetSweepStatus call while returning driver.ErrBadConn.
The other queues an errChan error from the event loop while canceling
the run context. Both tests assert that Run returns context.Canceled and
does not wrap the driver error.
2026-05-18 11:58:54 +02:00
Slyghtning
b542b50f7f
sweepbatcher: harden AddSweep against ctx closure 2026-05-18 11:58:53 +02:00
Slyghtning
a10c741a26
lint: fix linter issues 2026-03-09 14:39:45 +01:00
Slyghtning
a9977dd5f4
godoc: address copy-paste errors accross the codebase 2026-03-09 14:39:44 +01:00
Boris Nagaev
0b53296aa8
multi: factor out sweep fee clamping function 2026-01-15 03:06:22 -05:00
Slyghtning
417e25463d
sweepbatcher: fix style issues in sweep_batcher_test.go
- Rename testPublishError to errTestPublish (ST1012)
- Add explicit type to all constants in const groups (SA9004)
- Fixes staticcheck style warnings
2025-12-19 10:18:09 +01:00
Boris Nagaev
6d58965930
sweepbatcher: persist confirmed batches atomically
Fixes a crash window where handleConf updated the batch row to confirmed but
failed before marking sweeps complete, so re-added sweeps spawned a duplicate
batch or kept retrying. Batch confirmation and sweep completion are now
persisted inside a single DB transaction ConfirmBatchWithSweeps, and handleConf
uses the helper to atomically store the batch and the set of confirmed sweeps.

Added TestSweepBatcherConfirmedBatchIncompleteSweeps that runs against the real
loopdb backend, injects a failure mid-transaction, and verifies the database
never ends up with confirmed=true batches paired with completed=false sweeps.
2025-12-04 00:37:01 -03:00
Boris Nagaev
37eb3462e5
sweepbatcher: handle batch shutdown during re-add
Started from CI failure of TestSweepBatcherHandleSweepRace/loopdb [1] that
surfaced ErrBatcherShuttingDown when the AddSweep loop caught a batch right as
it finished. Reproduced via:

go test ./sweepbatcher -run TestSweepBatcherHandleSweepRace/loopdb -cpu=12,4,8 -count=1

Discovered that handleSweeps treated ErrBatchShuttingDown from batch.addSweeps
as fatal, so the batcher exited even though the sweep was already confirmed.
Fixed by treating that error as "batch already done" so we fall through to the
persisted status/monitorSpend path, and added a regression test that
deterministically simulates the shutdown window.

New regression test added:
go test ./sweepbatcher -run TestSweepBatcherHandleBatchShutdown

[1] https://github.com/lightninglabs/loop/actions/runs/19282552307/job/55136597881?pr=1041
2025-11-12 01:45:18 -03:00
Boris Nagaev
d82b3624b9
sweepbatcher: fix code format 2025-11-12 01:45:18 -03:00
Boris Nagaev
abf3bb4abf
sweepbatcher: presign transactions in parallel
If a SignTx call is slow, the whole presign() function could timeout if all
the calls are done sequentially. In this commit each call is done in a separate
goroutine to reduce total latency.
2025-10-14 22:37:18 -03:00
Boris Nagaev
1f15c604ac
sweepbatcher: fix fee rate calculation (publish)
We forgot to account for change outputs when checking the feerate of
signed transaction. The bug resulted in fee rate overestimation in the
log message.
2025-10-11 22:15:56 -03:00
Boris Nagaev
a5871d6f3e
sweepbatcher: fix change fee accounting, add test
Presigned sweeps that produce a change output misreported the on-chain fee.
The fee portion was derived from the total swept amount minus only the
first transaction output, so any change output was treated as additional fee.
Update getFeePortionForSweep to subtract the value of every tx output so
the fee portion reflects only the actual miner fee paid. Add regression
coverage that sweeps a presigned input with change and asserts the spend
and confirmation notifications report the corrected fee.
2025-10-11 15:21:30 -03:00
Slyghtning
422bcd7077
sweepbatcher: fast-flag enables zero delay publishing 2025-10-07 08:53:39 +02:00
Boris Nagaev
d90b4c25a7
sweepbatcher: harden AddSweep race handling
Re-ordered the cleanup in handleSweeps so completed batches are deleted only
after any re-add attempt, preventing a finished batch from being dropped before
it can absorb the re-add.

Added a fresh status/parent-batch lookup inside handleSweeps so the logic now
reacts to swaps that complete between AddSweep and the event-loop handler; fully
confirmed sweeps are routed straight to monitorSpendAndNotify instead of
spawning a duplicate batch.

Added regression test testSweepBatcherHandleSweepRace, which replays the
AddSweep/confirmation race and verifies that only the original batch remains and
the sweep keeps its parent assignment.
2025-10-03 02:29:37 -03:00
Boris Nagaev
e3a0587dfe
sweepbatcher: fix TestPresigned/dust_main_output
The Problem:
The test TestPresigned/dust_main_output was causing a deadlock. When the test
called batcher.AddSweep for the second time (with a valid sweep), the batcher
would create a new batch and attempt to register for a spend notification.
However, the test was not waiting for or consuming this notification
registration, leading to a blocked goroutine and a timeout.

The Fix:
I have added a line to the test to consume the spend notification registration
from the mock lnd's channel, similar to how other tests in the same file are
structured. This prevents the deadlock.

The problem was introduced in commit 54652dc641.
2025-09-28 20:57:00 -03:00
Slyghtning
221372b5ef
sweepbatcher: relax output constrained in monitorConfAndNotify 2025-09-25 11:13:35 +02:00
Slyghtning
d00b78ef6b
sweepbatcher: consolidate identical change pkscripts
batch separate change outputs with identical pkscripts
are tallied up and consolidated to a single change output.
2025-07-29 21:22:17 +02:00
Boris Nagaev
54652dc641
sweepbatcher: subtle adjustments for change
- ensurePresigned: use passed minRelayFeeRate instead of chainfee.FeePerKwFloor
 - presign: use minRelayFeeRate for start and minRelayFee
 - presign: make sure minRelayFeeRate is set
 - add tests for presign to test this new behavior; make sure the number of
   transactions is lower if minRelayFeeRate is higher
 - update error message in constructUnsignedTx: use <, not <= (more accurate)
 - use utils.DustLimitForPkScript instead of lnwallet.DustLimitForSize in tests
 - in tests adjust amounts to edge values, add controls
2025-07-29 12:33:56 +02:00
Slyghtning
29348a94df
sweepbatcher: consider min relay fee when constructing batch tx
if constructUnsignedTx constructs a batch transaction that is
below the minimum relay fee, an error is returned.
2025-07-29 12:33:56 +02:00
Slyghtning
bc7d155e69
sweepbatcher: consider change in presigning and batch tx
Presigning sweeps takes change outputs into account.
Each primary deposit id of a sweep group points to
an optional change output.
sweepbatcher.presign scans all passed sweeps for
change outputs and passes them to constructUnsignedTx.
Optional change of a swap is encoded in its sweeps
as a pointer to the same change output. This change
is taken into account when constructing the unsigned
batch transaction when it comes to tx weight and
outputs.
2025-07-29 12:33:55 +02:00
Slyghtning
8399a63091
sweepbatcher: consider optional change in greedy selection 2025-07-29 12:33:55 +02:00
Slyghtning
f30db74756
sweepbatcher: optional change in sweep struct
This commit adds an optional change output to the sweep struct.
2025-07-29 12:33:55 +02:00
Boris Nagaev
534c71b742
sweepbatcher: minimumSweepFeeRate fixes confTarget
This is already done in GetConfTargetAndFeeRate. The fix is just a double check.
2025-07-24 02:30:15 -03:00
Boris Nagaev
8431784338
sweepbatcher: update feerate outside AddSweep
AddSweep may not be called after getting the first confirmation, but feerate
updates are still needed in case of reorg.

Update test TestFeeRateGrows not to call AddSweep again and make sure feerate
is updated itself.
2025-07-24 02:22:06 -03:00
Boris Nagaev
957ca21e61
sweepbatcher: fix reorg detection
The reorg channel is now passed to RegisterSpendNtfn, and waiting for spend
notifications remains active even after the transaction receives its first
confirmation. The dedicated goroutine previously used to wait for the spend
is no longer needed, as we now handle both spend and potential reorg events
in the main event loop while the batch is running.

Following this change, RegisterConfirmationsNtfn runs without a reorg channel,
as it would only detect deep reorgs that undo the final confirmation - something
we can't handle anyway. We can't track fully confirmed swaps indefinitely to
guard against such rare reorgs; instead, we can mitigate the risk by increasing
the required confirmation depth.
2025-07-24 02:21:20 -03:00
Boris Nagaev
22d345a534
sweepbatcher: fix flaky test
Since bb837a4aec AddSweep loads sweeps so
one of possible errors is sql.ErrTxDone. Full error that is fixed:
> fetchSweeps failed: failed to load sweep 0000000000000000000101:1:
> failed to fetch sweep data for 010101000000:
> failed to fetch loop out for 010101000000:
> sql: transaction has already been committed or rolled back
2025-07-24 02:19:25 -03:00
Boris Nagaev
0dc5d9eb69
sweepbatcher: check of conf notification has tx 2025-06-26 14:01:16 -03:00
Boris Nagaev
1794aa21e5
loopdb: remove unused method ConfirmBatch 2025-06-26 14:01:16 -03:00
Boris Nagaev
72caafa14e
sweepbatcher: fix a bug in dest address selection
For presigned possible remaining groups, the destination address of the current
batch was used instead of the destination address of an expected future batch.

TODO: reproduce in unit test "purged". For this, each swap should have a
separate destination address.
2025-06-26 14:01:16 -03:00
Boris Nagaev
64a24177ae
sweepbatcher: more logging in PresignSweepsGroup 2025-06-26 14:01:16 -03:00
Boris Nagaev
59a3af31cc
sweepbatcher: format pkscript as hex 2025-06-26 14:01:16 -03:00
Boris Nagaev
e7d5172a79
sweepbatcher: remove method Presign
Method Presign is not as reliable as SignTx, because it checks transaction by
txid and can miss for example if LockTime is different. SignTx can do everything
Presign was used for.
2025-06-26 14:01:16 -03:00
Boris Nagaev
f19f9f5288
sweepbatcher/presigned: minRelayFee edge cases
Make sure that broadcasted tx has feeRate >= minRelayFee.
Make sure that feeRate of broadcasted tx doesn't decrease.
2025-06-26 14:01:16 -03:00
Boris Nagaev
7735bdfe27
sweepbatcher: make sure HTLC.PkScript is filled 2025-06-26 14:01:16 -03:00
Boris Nagaev
d75f17df47
sweepbatcher: simplify presigned/purging test
It doesn't need loopdb, so remove that code.
2025-06-26 14:01:16 -03:00
Boris Nagaev
8a07107811
sweepbatcher: make sure dest pkscript is filled 2025-06-26 14:01:16 -03:00
Boris Nagaev
8c784ef761
sweepbatcher: pass utxo to fee provider 2025-06-26 14:01:16 -03:00
Boris Nagaev
b961e18fa0
sweepbatcher: fix OnChainFeePortion values
There were two mistakes.

In case of a swap with multiple sweeps only the fee of the first sweep
of a swap was accounted.

Rounding diff (the remainder) was attributed to all the sweeps rather than to
the first (primary) sweep of the batch. The sweep to attribute the remainder
was chosen by comparing SignatureScript which is always empty. New approach is
to find the primary sweep and to compare its outpoint directly.
2025-06-26 14:01:16 -03:00
Boris Nagaev
650cf20fe9
sweepbatcher: re-add sweeps after fully confirmed
In case of a reorg sweeps should not go to another batch but stay in the current
batch until it is reorg-safely confirmed. Only after that the remaining sweeps
are re-added to another batch.

Field sweep.completed is now set to true only for reorg-safely confirmed sweeps.

In handleConf we now use batch.persist() (i.e. store.UpdateSweepBatch) instead
of ConfirmBatch, because we set not only Confirmed flag, but also batchTxid.
2025-06-26 13:36:55 -03:00
Boris Nagaev
1036214160
sweepbatcher: add an option to ignore HTLC txids
Added option WithSkippedTxns, which has one historical problematic tx by default.
Sweeps originating from these transactions are omitted when reading from DB.

loopdb: add column sweep_batches.cancelled and replaced DropBatch with
CancelBatch. It is needed, because sweep.batch_id is a foreign key to batch.

Changed StoreMock.InsertSweepBatch not to reuse batch_id. This is needed by
the test, which checks that new batch has fresh ID.
2025-06-17 14:47:49 -03:00
Boris Nagaev
c70257a4a5
sweepbatcher: notify caller about confirmations
Add fields ConfChan and ConfErrChan to SpendNotifier type which is a part of
SweepRequest passed to AddSweep method.

This is needed to reuse confirmation notifications on the calling side the same
way it is done for spending notifications.
2025-06-12 12:32:09 -03:00
Boris Nagaev
8466e0f8eb
sweepbatcher: test spending notification and error 2025-06-12 12:32:09 -03:00
Boris Nagaev
980c7d4e00
sweepbatcher: align dbBatch type with DB schema
Previously, dbBatch had a State field (enum: Open, Closed, Confirmed), but in
the database it is represented as a boolean Confirmed. The Closed state was
stored the same way as Open. This wasn't an issue in practice, since an Open
batch is quickly transitioned to Closed after startup.

However, the in-memory mock stores plain dbBatch instances, leading to
inconsistent behavior between the mock and the real DB-backed store. This
commit updates dbBatch to match the database representation by replacing
the State field with a Confirmed boolean.
2025-06-12 12:32:09 -03:00
Boris Nagaev
7edbfeadd8
sweepbatcher: store batch status before monitoring
If monitorConfirmations fails, we still want to persist the state to DB.
2025-06-12 12:32:09 -03:00
Boris Nagaev
fa1bc48a68
sweepbatcher: remove unneeded for loops
The loop always had exactly one iteration.
2025-06-12 12:31:58 -03:00
Boris Nagaev
01664ad635
sweepbatcher: cancel spendCtx after processing
Function monitorSpendAndNotify used to cancel the context passed to
RegisterSpendNtfn right after starting the goroutine processing results.
Spend notifications were missed.

Now the context is canceled when the goroutine finishes.
2025-06-11 10:34:22 -03:00
Boris Nagaev
cb7c31c1b9
sweepbatcher: fix mistake in batch reading from DB 2025-06-11 10:34:22 -03:00