Skip to content

Commit 92cfc52

Browse files
committed
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.
1 parent 2fdf4c1 commit 92cfc52

File tree

4 files changed

+28
-61
lines changed

4 files changed

+28
-61
lines changed

sweepbatcher/store.go

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,8 @@ type dbBatch struct {
213213
// ID is the unique identifier of the batch.
214214
ID int32
215215

216-
// State is the current state of the batch.
217-
State string
216+
// Confirmed is set when the batch is fully confirmed.
217+
Confirmed bool
218218

219219
// BatchTxid is the txid of the batch transaction.
220220
BatchTxid chainhash.Hash
@@ -255,11 +255,8 @@ type dbSweep struct {
255255
// convertBatchRow converts a batch row from db to a sweepbatcher.Batch struct.
256256
func convertBatchRow(row sqlc.SweepBatch) *dbBatch {
257257
batch := dbBatch{
258-
ID: row.ID,
259-
}
260-
261-
if row.Confirmed {
262-
batch.State = batchConfirmed
258+
ID: row.ID,
259+
Confirmed: row.Confirmed,
263260
}
264261

265262
if row.BatchTxID.Valid {
@@ -288,7 +285,7 @@ func convertBatchRow(row sqlc.SweepBatch) *dbBatch {
288285
// it into the database.
289286
func batchToInsertArgs(batch dbBatch) sqlc.InsertBatchParams {
290287
args := sqlc.InsertBatchParams{
291-
Confirmed: false,
288+
Confirmed: batch.Confirmed,
292289
BatchTxID: sql.NullString{
293290
Valid: true,
294291
String: batch.BatchTxid.String(),
@@ -305,10 +302,6 @@ func batchToInsertArgs(batch dbBatch) sqlc.InsertBatchParams {
305302
MaxTimeoutDistance: batch.MaxTimeoutDistance,
306303
}
307304

308-
if batch.State == batchConfirmed {
309-
args.Confirmed = true
310-
}
311-
312305
return args
313306
}
314307

@@ -317,7 +310,7 @@ func batchToInsertArgs(batch dbBatch) sqlc.InsertBatchParams {
317310
func batchToUpdateArgs(batch dbBatch) sqlc.UpdateBatchParams {
318311
args := sqlc.UpdateBatchParams{
319312
ID: batch.ID,
320-
Confirmed: false,
313+
Confirmed: batch.Confirmed,
321314
BatchTxID: sql.NullString{
322315
Valid: true,
323316
String: batch.BatchTxid.String(),
@@ -333,10 +326,6 @@ func batchToUpdateArgs(batch dbBatch) sqlc.UpdateBatchParams {
333326
},
334327
}
335328

336-
if batch.State == batchConfirmed {
337-
args.Confirmed = true
338-
}
339-
340329
return args
341330
}
342331

sweepbatcher/store_mock.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func (s *StoreMock) FetchUnconfirmedSweepBatches(ctx context.Context) (
3535

3636
result := []*dbBatch{}
3737
for _, batch := range s.batches {
38-
if batch.State != "confirmed" {
38+
if !batch.Confirmed {
3939
result = append(result, &batch)
4040
}
4141
}
@@ -90,7 +90,7 @@ func (s *StoreMock) ConfirmBatch(ctx context.Context, id int32) error {
9090
return errors.New("batch not found")
9191
}
9292

93-
batch.State = "confirmed"
93+
batch.Confirmed = true
9494
s.batches[batch.ID] = batch
9595

9696
return nil
@@ -189,7 +189,7 @@ func (s *StoreMock) TotalSweptAmount(ctx context.Context, batchID int32) (
189189
return 0, errors.New("batch not found")
190190
}
191191

192-
if batch.State != batchConfirmed && batch.State != batchClosed {
192+
if !batch.Confirmed {
193193
return 0, nil
194194
}
195195

sweepbatcher/sweep_batch.go

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ const (
131131
Open batchState = 0
132132

133133
// Closed is the state in which the batch is no longer able to accept
134-
// new sweeps.
134+
// new sweeps. NOTE: this state exists only in-memory. In the database
135+
// it is stored as Open and converted to Closed after a spend
136+
// notification arrives (quickly after start of Batch.Run).
135137
Closed batchState = 1
136138

137139
// Confirmed is the state in which the batch transaction has reached the
@@ -778,8 +780,8 @@ func (b *batch) Run(ctx context.Context) error {
778780
// completes.
779781
timerChan := clock.TickAfter(b.cfg.batchPublishDelay)
780782

781-
b.Infof("started, primary %s, total sweeps %d",
782-
b.primarySweepID, len(b.sweeps))
783+
b.Infof("started, primary %s, total sweeps %d, state: %d",
784+
b.primarySweepID, len(b.sweeps), b.state)
783785

784786
for {
785787
// If the batch is not empty, find earliest initialDelay.
@@ -1935,7 +1937,7 @@ func (b *batch) persist(ctx context.Context) error {
19351937
bch := &dbBatch{}
19361938

19371939
bch.ID = b.id
1938-
bch.State = stateEnumToString(b.state)
1940+
bch.Confirmed = b.state == Confirmed
19391941

19401942
if b.batchTxid != nil {
19411943
bch.BatchTxid = *b.batchTxid
@@ -1979,7 +1981,7 @@ func (b *batch) getBatchDestAddr(ctx context.Context) (btcutil.Address, error) {
19791981

19801982
func (b *batch) insertAndAcquireID(ctx context.Context) (int32, error) {
19811983
bch := &dbBatch{}
1982-
bch.State = stateEnumToString(b.state)
1984+
bch.Confirmed = b.state == Confirmed
19831985
bch.MaxTimeoutDistance = b.cfg.maxTimeoutDistance
19841986

19851987
id, err := b.store.InsertSweepBatch(ctx, bch)
@@ -2080,18 +2082,3 @@ func clampBatchFee(fee btcutil.Amount,
20802082

20812083
return fee
20822084
}
2083-
2084-
func stateEnumToString(state batchState) string {
2085-
switch state {
2086-
case Open:
2087-
return batchOpen
2088-
2089-
case Closed:
2090-
return batchClosed
2091-
2092-
case Confirmed:
2093-
return batchConfirmed
2094-
}
2095-
2096-
return ""
2097-
}

sweepbatcher/sweep_batcher.go

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,6 @@ const (
3131
// of sweeps that can appear in the same batch.
3232
defaultMaxTimeoutDistance = 288
3333

34-
// batchOpen is the string representation of the state of a batch that
35-
// is open.
36-
batchOpen = "open"
37-
38-
// batchClosed is the string representation of the state of a batch
39-
// that is closed.
40-
batchClosed = "closed"
41-
42-
// batchConfirmed is the string representation of the state of a batch
43-
// that is confirmed.
44-
batchConfirmed = "confirmed"
45-
4634
// defaultMainnetPublishDelay is the default publish delay that is used
4735
// for mainnet.
4836
defaultMainnetPublishDelay = 5 * time.Second
@@ -669,7 +657,7 @@ func (b *Batcher) handleSweeps(ctx context.Context, sweeps []*sweep,
669657

670658
// The parent batch is indeed confirmed, meaning it is complete
671659
// and we won't be able to attach this sweep to it.
672-
if parentBatch.State == batchConfirmed {
660+
if parentBatch.Confirmed {
673661
return b.monitorSpendAndNotify(
674662
ctx, sweep, parentBatch.ID, notifier,
675663
)
@@ -916,15 +904,18 @@ func (b *Batcher) FetchUnconfirmedBatches(ctx context.Context) ([]*batch,
916904
batch := batch{}
917905
batch.id = bch.ID
918906

919-
switch bch.State {
920-
case batchOpen:
921-
batch.state = Open
922-
923-
case batchClosed:
924-
batch.state = Closed
925-
926-
case batchConfirmed:
907+
if bch.Confirmed {
927908
batch.state = Confirmed
909+
} else {
910+
// We don't store Closed state separately in DB.
911+
// If the batch is closed (included into a block, but
912+
// not fully confirmed), it is now considered Open
913+
// again. It will receive a spending notification as
914+
// soon as it starts, so it is not an issue. If a sweep
915+
// manages to be added during this time, it will be
916+
// detected as missing when analyzing the spend
917+
// notification and will be added to new batch.
918+
batch.state = Open
928919
}
929920

930921
batch.batchTxid = &bch.BatchTxid

0 commit comments

Comments
 (0)