Skip to content

Commit e4f5cc7

Browse files
authored
Merge pull request #906 from starius/sweepbatcher-outpoint
sweepbatcher: allow swap_hash to be non-unique
2 parents c3fa12e + c80ebb9 commit e4f5cc7

14 files changed

+318
-212
lines changed

loopdb/postgres.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ type PostgresStore struct {
6464
*BaseDB
6565
}
6666

67+
// In migration of sweeps table from outpoint_txid and outpoint_index to
68+
// outpoint we need to reverse the order of bytes in outpoint_txid and to
69+
// convert it to hex. This is done differently in sqlite and postgres.
70+
//
71+
// Changes from sqlite to postgres:
72+
// - substr(blob, ...) -> get_byte(blob, index)
73+
// - group_concat -> string_agg
74+
// - 1-based indexing (32+1-i) -> 0-based (32 - i)
75+
// - to_hex() + lpad(..., 2, '0') ensures each byte is two-digit hex
76+
const (
77+
txidSqlite = "group_concat(hex(substr(outpoint_txid,32+1-i,1)),'')"
78+
txidPostgres = "string_agg(lpad(to_hex(get_byte(outpoint_txid, " +
79+
"32 - i)), 2, '0'), '')"
80+
)
81+
6782
// NewPostgresStore creates a new store that is backed by a Postgres database
6883
// backend.
6984
func NewPostgresStore(cfg *PostgresConfig,
@@ -93,6 +108,7 @@ func NewPostgresStore(cfg *PostgresConfig,
93108
postgresFS := newReplacerFS(sqlSchemas, map[string]string{
94109
"BLOB": "BYTEA",
95110
"INTEGER PRIMARY KEY": "SERIAL PRIMARY KEY",
111+
txidSqlite: txidPostgres,
96112
})
97113

98114
err = applyMigrations(

loopdb/sqlc/batch.sql.go

Lines changed: 18 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- We kept old table as sweeps_old. Use it.
2+
ALTER TABLE sweeps RENAME TO sweeps_new;
3+
ALTER TABLE sweeps_old RENAME TO sweeps;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
-- We want to make column swap_hash non-unique and to use the outpoint as a key.
2+
-- We can't make a column non-unique or remove it in sqlite, so work around.
3+
-- See https://stackoverflow.com/a/42013422
4+
5+
-- We also made outpoint a single point replacing columns outpoint_txid and
6+
-- outpoint_index.
7+
8+
-- sweeps stores the individual sweeps that are part of a batch.
9+
CREATE TABLE sweeps2 (
10+
-- id is the autoincrementing primary key.
11+
id INTEGER PRIMARY KEY,
12+
13+
-- swap_hash is the hash of the swap that is being swept.
14+
swap_hash BLOB NOT NULL,
15+
16+
-- batch_id is the id of the batch this swap is part of.
17+
batch_id INTEGER NOT NULL,
18+
19+
-- outpoint is the UTXO id of the output being swept ("txid:index").
20+
outpoint TEXT NOT NULL UNIQUE,
21+
22+
-- amt is the amount of the output being swept.
23+
amt BIGINT NOT NULL,
24+
25+
-- completed indicates whether the sweep has been completed.
26+
completed BOOLEAN NOT NULL DEFAULT FALSE,
27+
28+
-- Foreign key constraint to ensure that we reference an existing batch
29+
-- id.
30+
FOREIGN KEY (batch_id) REFERENCES sweep_batches(id),
31+
32+
-- Foreign key constraint to ensure that swap_hash references an
33+
-- existing swap.
34+
FOREIGN KEY (swap_hash) REFERENCES swaps(swap_hash)
35+
);
36+
37+
-- Copy all the data from sweeps to sweeps2.
38+
-- Explanation:
39+
-- - seq(i) goes from 1 to 32
40+
-- - substr(outpoint_txid, 32+1-i, 1) indexes BLOB bytes in reverse order
41+
-- (SQLite uses 1-based indexing)
42+
-- - hex(...) gives uppercase by default, so wrapped in lower(...)
43+
-- - group_concat(..., '') combines all hex digits
44+
-- - concatenated with ':' || CAST(outpoint_index AS TEXT) for full outpoint.
45+
WITH RECURSIVE seq(i) AS (
46+
SELECT 1
47+
UNION ALL
48+
SELECT i + 1 FROM seq WHERE i < 32
49+
)
50+
INSERT INTO sweeps2 (
51+
id, swap_hash, batch_id, outpoint, amt, completed
52+
)
53+
SELECT
54+
id,
55+
swap_hash,
56+
batch_id,
57+
(
58+
SELECT lower(group_concat(hex(substr(outpoint_txid,32+1-i,1)),''))
59+
FROM seq
60+
) || ':' || CAST(outpoint_index AS TEXT),
61+
amt,
62+
completed
63+
FROM sweeps;
64+
65+
-- Rename tables.
66+
ALTER TABLE sweeps RENAME TO sweeps_old;
67+
ALTER TABLE sweeps2 RENAME TO sweeps;

loopdb/sqlc/models.go

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

loopdb/sqlc/querier.go

Lines changed: 2 additions & 2 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: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,18 @@ WHERE
4747
INSERT INTO sweeps (
4848
swap_hash,
4949
batch_id,
50-
outpoint_txid,
51-
outpoint_index,
50+
outpoint,
5251
amt,
5352
completed
5453
) VALUES (
5554
$1,
5655
$2,
5756
$3,
5857
$4,
59-
$5,
60-
$6
61-
) ON CONFLICT (swap_hash) DO UPDATE SET
58+
$5
59+
) ON CONFLICT (outpoint) DO UPDATE SET
6260
batch_id = $2,
63-
outpoint_txid = $3,
64-
outpoint_index = $4,
65-
amt = $5,
66-
completed = $6;
61+
completed = $5;
6762

6863
-- name: GetParentBatch :one
6964
SELECT
@@ -73,7 +68,7 @@ FROM
7368
JOIN
7469
sweeps ON sweep_batches.id = sweeps.batch_id
7570
WHERE
76-
sweeps.swap_hash = $1;
71+
sweeps.outpoint = $1;
7772

7873
-- name: GetBatchSweptAmount :one
7974
SELECT
@@ -101,4 +96,4 @@ SELECT
10196
FROM
10297
(SELECT false AS false_value) AS f
10398
LEFT JOIN
104-
sweeps s ON s.swap_hash = $1;
99+
sweeps s ON s.outpoint = $1;

sweepbatcher/greedy_batch_selection.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/btcsuite/btcd/btcutil"
1010
"github.com/btcsuite/btcd/txscript"
11+
"github.com/btcsuite/btcd/wire"
1112
sweeppkg "github.com/lightninglabs/loop/sweep"
1213
"github.com/lightningnetwork/lnd/input"
1314
"github.com/lightningnetwork/lnd/lntypes"
@@ -108,8 +109,8 @@ func estimateSweepFeeIncrement(s *sweep) (feeDetails, feeDetails, error) {
108109
rbfCache: rbfCache{
109110
FeeRate: s.minFeeRate,
110111
},
111-
sweeps: map[lntypes.Hash]sweep{
112-
s.swapHash: *s,
112+
sweeps: map[wire.OutPoint]sweep{
113+
s.outpoint: *s,
113114
},
114115
}
115116

@@ -120,9 +121,13 @@ func estimateSweepFeeIncrement(s *sweep) (feeDetails, feeDetails, error) {
120121
}
121122

122123
// Add the same sweep again to measure weight increments.
123-
swapHash2 := s.swapHash
124-
swapHash2[0]++
125-
batch.sweeps[swapHash2] = *s
124+
outpoint2 := s.outpoint
125+
outpoint2.Hash[0]++
126+
if _, has := batch.sweeps[outpoint2]; has {
127+
return feeDetails{}, feeDetails{}, fmt.Errorf("dummy outpoint "+
128+
"%s is present in the batch", outpoint2)
129+
}
130+
batch.sweeps[outpoint2] = *s
126131

127132
// Estimate weight of a batch with two sweeps.
128133
fd2, err := estimateBatchWeight(batch)

0 commit comments

Comments
 (0)