Skip to content

Commit 6a4ef36

Browse files
committed
sweepbatcher: fix spawning condition "unattached" spend notifiers
Previously, when handling a sweep we assumed that if a sweep status was completed, the parent batch was also finished. However, since the batch confirmation status depends on three on-chain confirmations, it is possible that a spend notifier was started for a sweep of an active batch. The notifier would fetch the parent batch from the database, but because we incorrectly assumed that the parent was confirmed (when it was not), the DB call would fail with a 'no rows returned' error. This failure would cause the sweep to fail and the sweep batcher to stop, resulting in a permanent failure state.
1 parent 2024791 commit 6a4ef36

File tree

4 files changed

+21
-22
lines changed

4 files changed

+21
-22
lines changed

loopdb/sqlc/batch.sql.go

Lines changed: 0 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

loopdb/sqlc/queries/batch.sql

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,7 @@ FROM
7373
JOIN
7474
sweeps ON sweep_batches.id = sweeps.batch_id
7575
WHERE
76-
sweeps.swap_hash = $1
77-
AND
78-
sweeps.completed = TRUE
79-
AND
80-
sweep_batches.confirmed = TRUE;
76+
sweeps.swap_hash = $1;
8177

8278
-- name: GetBatchSweptAmount :one
8379
SELECT

sweepbatcher/store.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,6 @@ func (s *SQLStore) GetParentBatch(ctx context.Context, swapHash lntypes.Hash) (
196196
return nil, err
197197
}
198198

199-
if err != nil {
200-
return nil, err
201-
}
202-
203199
return convertBatchRow(batch), nil
204200
}
205201

sweepbatcher/sweep_batcher.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,24 @@ func (b *Batcher) handleSweep(ctx context.Context, sweep *sweep,
418418
// can't attach its notifier to the batch as that is no longer running.
419419
// Instead we directly detect and return the spend here.
420420
if completed && *notifier != (SpendNotifier{}) {
421-
return b.monitorSpendAndNotify(ctx, sweep, notifier)
421+
// Verify that the parent batch is confirmed. Note that a batch
422+
// is only considered confirmed after it has received three
423+
// on-chain confirmations to prevent issues caused by reorgs.
424+
parentBatch, err := b.store.GetParentBatch(ctx, sweep.swapHash)
425+
if err != nil {
426+
log.Errorf("unable to get parent batch for sweep %x: "+
427+
"%v", sweep.swapHash[:6], err)
428+
429+
return err
430+
}
431+
432+
// The parent batch is indeed confirmed, meaning it is complete
433+
// and we won't be able to attach this sweep to it.
434+
if parentBatch.State == batchConfirmed {
435+
return b.monitorSpendAndNotify(
436+
ctx, sweep, parentBatch.ID, notifier,
437+
)
438+
}
422439
}
423440

424441
sweep.notifier = notifier
@@ -688,19 +705,13 @@ func (b *Batcher) FetchUnconfirmedBatches(ctx context.Context) ([]*batch,
688705
// monitorSpendAndNotify monitors the spend of a specific outpoint and writes
689706
// the response back to the response channel.
690707
func (b *Batcher) monitorSpendAndNotify(ctx context.Context, sweep *sweep,
691-
notifier *SpendNotifier) error {
708+
parentBatchID int32, notifier *SpendNotifier) error {
692709

693710
spendCtx, cancel := context.WithCancel(ctx)
694711
defer cancel()
695712

696-
// First get the batch that completed the sweep.
697-
parentBatch, err := b.store.GetParentBatch(ctx, sweep.swapHash)
698-
if err != nil {
699-
return err
700-
}
701-
702713
// Then we get the total amount that was swept by the batch.
703-
totalSwept, err := b.store.TotalSweptAmount(ctx, parentBatch.ID)
714+
totalSwept, err := b.store.TotalSweptAmount(ctx, parentBatchID)
704715
if err != nil {
705716
return err
706717
}

0 commit comments

Comments
 (0)