Skip to content

Commit 42a20c9

Browse files
committed
staticaddr: selected swap amount migration
The selected_amount column of all previous swaps is filled with the total value of deposits that partook in these swaps.
1 parent e3f3842 commit 42a20c9

File tree

8 files changed

+265
-7
lines changed

8 files changed

+265
-7
lines changed

loopd/daemon.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,16 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
636636
return err
637637
}
638638

639+
// Run the selected amount migration.
640+
err = loopin.MigrateSelectedSwapAmount(
641+
d.mainCtx, swapDb, depositStore, staticAddressLoopInStore,
642+
)
643+
if err != nil {
644+
errorf("Selected amount migration failed: %v", err)
645+
646+
return err
647+
}
648+
639649
staticLoopInManager = loopin.NewManager(&loopin.Config{
640650
Server: staticAddressClient,
641651
QuoteGetter: swapClient.Server,

loopdb/sqlc/querier.go

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

loopdb/sqlc/queries/static_address_loopin.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ SELECT EXISTS (
9696
WHERE swap_hash = $1
9797
);
9898

99+
-- name: OverrideSelectedSwapAmount :exec
100+
UPDATE static_address_swaps
101+
SET
102+
selected_amount = $2
103+
WHERE swap_hash = $1;
104+
99105
-- name: MapDepositToSwap :exec
100106
UPDATE
101107
deposits

loopdb/sqlc/static_address_loopin.sql.go

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

staticaddr/loopin/deposit_swaphash_migration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,13 @@ func TestDepositSwapHashMigration(t *testing.T) {
119119
// If so, we reject the loop-in to prevent potential issues with
120120
// parsing.
121121
for _, outpoint := range loopIn.DepositOutpoints {
122-
if strings.Contains(outpoint, outpointSeparator) {
122+
if strings.Contains(outpoint, OutpointSeparator) {
123123
return ErrInvalidOutpoint
124124
}
125125
}
126126

127127
joinedOutpoints := strings.Join(
128-
loopIn.DepositOutpoints, outpointSeparator,
128+
loopIn.DepositOutpoints, OutpointSeparator,
129129
)
130130
staticAddressLoopInParams := sqlc.InsertStaticAddressLoopInParams{
131131
SwapHash: loopIn.SwapHash[:],
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package loopin
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/btcsuite/btcd/btcutil"
9+
"github.com/lightninglabs/loop/loopdb"
10+
"github.com/lightninglabs/loop/staticaddr/deposit"
11+
"github.com/lightningnetwork/lnd/lntypes"
12+
)
13+
14+
const (
15+
// selectedAmountMigrationID is the identifier for the selected swap
16+
// amount migration.
17+
selectedAmountMigrationID = "selected_amount"
18+
)
19+
20+
// MigrateSelectedSwapAmount will update the selected swap amount of past swaps
21+
// with the sum of the values of the deposits they swapped.
22+
func MigrateSelectedSwapAmount(ctx context.Context, db loopdb.SwapStore,
23+
depositStore *deposit.SqlStore, swapStore *SqlStore) error {
24+
25+
migrationDone, err := db.HasMigration(ctx, selectedAmountMigrationID)
26+
if err != nil {
27+
return fmt.Errorf("unable to check migration status: %w", err)
28+
}
29+
if migrationDone {
30+
log.Infof("Selected swap amount migration already done, " +
31+
"skipping")
32+
33+
return nil
34+
}
35+
36+
log.Infof("Starting swap amount migration")
37+
startTs := time.Now()
38+
defer func() {
39+
log.Infof("Finished swap amount migration in %v",
40+
time.Since(startTs))
41+
}()
42+
43+
// First we'll fetch all loop out swaps from the database.
44+
swaps, err := swapStore.GetStaticAddressLoopInSwapsByStates(
45+
ctx, FinalStates,
46+
)
47+
if err != nil {
48+
return err
49+
}
50+
51+
// Now we'll calculate the cost for each swap and finally update the
52+
// costs in the database.
53+
// TODO(hieblmi): normalize swap hash and deposit ids.
54+
updateAmounts := make(map[lntypes.Hash]btcutil.Amount)
55+
for _, swap := range swaps {
56+
for _, outpoint := range swap.DepositOutpoints {
57+
deposit, err := depositStore.DepositForOutpoint(
58+
ctx, outpoint,
59+
)
60+
if err != nil {
61+
return fmt.Errorf("unable to fetch deposit "+
62+
"for outpoint %s: %w", outpoint, err)
63+
}
64+
if deposit == nil {
65+
return fmt.Errorf("deposit for outpoint %s "+
66+
"not found", outpoint)
67+
}
68+
69+
// Set the selected amount to the value of the deposit.
70+
updateAmounts[swap.SwapHash] += deposit.Value
71+
}
72+
}
73+
74+
log.Infof("Updating selected swap amounts for %d loop out swaps",
75+
len(updateAmounts))
76+
77+
err = swapStore.BatchUpdateSelectedSwapAmounts(ctx, updateAmounts)
78+
if err != nil {
79+
return err
80+
}
81+
82+
// Finally mark the migration as done.
83+
return db.SetMigration(ctx, selectedAmountMigrationID)
84+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package loopin
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
"github.com/btcsuite/btcd/btcutil"
9+
"github.com/btcsuite/btcd/chaincfg"
10+
"github.com/btcsuite/btcd/chaincfg/chainhash"
11+
"github.com/btcsuite/btcd/wire"
12+
"github.com/lightninglabs/loop/loopdb"
13+
"github.com/lightninglabs/loop/staticaddr/deposit"
14+
"github.com/lightninglabs/loop/test"
15+
"github.com/lightningnetwork/lnd/clock"
16+
"github.com/lightningnetwork/lnd/lntypes"
17+
"github.com/stretchr/testify/require"
18+
)
19+
20+
// TestMigrateSelectedSwapAmount tests the selected amount migration.
21+
func TestMigrateSelectedSwapAmount(t *testing.T) {
22+
// Set up test context objects.
23+
ctxb := context.Background()
24+
testDb := loopdb.NewTestDB(t)
25+
testClock := clock.NewTestClock(time.Now())
26+
defer testDb.Close()
27+
28+
db := loopdb.NewStoreMock(t)
29+
depositStore := deposit.NewSqlStore(testDb.BaseDB)
30+
swapStore := NewSqlStore(
31+
loopdb.NewTypedStore[Querier](testDb), testClock,
32+
&chaincfg.MainNetParams,
33+
)
34+
35+
newID := func() deposit.ID {
36+
did, err := deposit.GetRandomDepositID()
37+
require.NoError(t, err)
38+
39+
return did
40+
}
41+
42+
d1, d2 := &deposit.Deposit{
43+
ID: newID(),
44+
OutPoint: wire.OutPoint{
45+
Hash: chainhash.Hash{0x1a, 0x2b, 0x3c, 0x4d},
46+
Index: 0,
47+
},
48+
Value: btcutil.Amount(100_000),
49+
TimeOutSweepPkScript: []byte{
50+
0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x41,
51+
},
52+
},
53+
&deposit.Deposit{
54+
ID: newID(),
55+
OutPoint: wire.OutPoint{
56+
Hash: chainhash.Hash{0x2a, 0x2b, 0x3c, 0x4e},
57+
Index: 1,
58+
},
59+
Value: btcutil.Amount(200_000),
60+
TimeOutSweepPkScript: []byte{
61+
0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x4d,
62+
},
63+
}
64+
65+
err := depositStore.CreateDeposit(ctxb, d1)
66+
require.NoError(t, err)
67+
err = depositStore.CreateDeposit(ctxb, d2)
68+
require.NoError(t, err)
69+
70+
outpoints := []string{
71+
d1.OutPoint.String(),
72+
d2.OutPoint.String(),
73+
}
74+
_, clientPubKey := test.CreateKey(1)
75+
_, serverPubKey := test.CreateKey(2)
76+
p2wkhAddr := "bcrt1qq68r6ff4k4pjx39efs44gcyccf7unqnu5qtjjz"
77+
addr, err := btcutil.DecodeAddress(p2wkhAddr, nil)
78+
require.NoError(t, err)
79+
80+
swap := StaticAddressLoopIn{
81+
SwapHash: lntypes.Hash{0x1, 0x2, 0x3, 0x4},
82+
DepositOutpoints: outpoints,
83+
ClientPubkey: clientPubKey,
84+
ServerPubkey: serverPubKey,
85+
HtlcTimeoutSweepAddress: addr,
86+
Deposits: []*deposit.Deposit{d1, d2},
87+
}
88+
swap.SetState(Succeeded)
89+
90+
err = swapStore.CreateLoopIn(ctxb, &swap)
91+
require.NoError(t, err)
92+
93+
storedSwaps, err := swapStore.GetStaticAddressLoopInSwapsByStates(
94+
ctxb, FinalStates,
95+
)
96+
require.NoError(t, err)
97+
require.EqualValues(t, 0, storedSwaps[0].SelectedAmount)
98+
99+
err = MigrateSelectedSwapAmount(ctxb, db, depositStore, swapStore)
100+
require.NoError(t, err)
101+
102+
storedSwaps, err = swapStore.GetStaticAddressLoopInSwapsByStates(
103+
ctxb, FinalStates,
104+
)
105+
require.NoError(t, err)
106+
require.EqualValues(t, d1.Value+d2.Value, storedSwaps[0].SelectedAmount)
107+
}

staticaddr/loopin/sql_store.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
2323
)
2424

25-
const outpointSeparator = ";"
25+
const OutpointSeparator = ";"
2626

2727
var (
2828
// ErrInvalidOutpoint is returned when an outpoint contains the outpoint
@@ -88,6 +88,11 @@ type Querier interface {
8888
// DepositsForSwapHash retrieves all deposits for a given swap hash.
8989
DepositsForSwapHash(ctx context.Context,
9090
swapHash []byte) ([]sqlc.DepositsForSwapHashRow, error)
91+
92+
// OverrideSelectedSwapAmount updates the selected swap amount for
93+
// a given swap hash.
94+
OverrideSelectedSwapAmount(ctx context.Context,
95+
params sqlc.OverrideSelectedSwapAmountParams) error
9196
}
9297

9398
// BaseDB is the interface that contains all the queries generated by sqlc for
@@ -226,11 +231,16 @@ func (s *SqlStore) CreateLoopIn(ctx context.Context,
226231
return errors.New("loop-in must have at least one deposit")
227232
}
228233

234+
amountRequested := int64(loopIn.TotalDepositAmount())
235+
if loopIn.SelectedAmount > 0 {
236+
amountRequested = int64(loopIn.SelectedAmount)
237+
}
238+
229239
swapArgs := sqlc.InsertSwapParams{
230240
SwapHash: loopIn.SwapHash[:],
231241
Preimage: loopIn.SwapPreimage[:],
232242
InitiationTime: loopIn.InitiationTime,
233-
AmountRequested: int64(loopIn.TotalDepositAmount()),
243+
AmountRequested: amountRequested,
234244
CltvExpiry: loopIn.HtlcCltvExpiry,
235245
MaxSwapFee: int64(loopIn.MaxSwapFee),
236246
InitiationHeight: int32(loopIn.InitiationHeight),
@@ -250,13 +260,13 @@ func (s *SqlStore) CreateLoopIn(ctx context.Context,
250260
// If so, we reject the loop-in to prevent potential issues with
251261
// parsing.
252262
for _, outpoint := range loopIn.DepositOutpoints {
253-
if strings.Contains(outpoint, outpointSeparator) {
263+
if strings.Contains(outpoint, OutpointSeparator) {
254264
return ErrInvalidOutpoint
255265
}
256266
}
257267

258268
joinedOutpoints := strings.Join(
259-
loopIn.DepositOutpoints, outpointSeparator,
269+
loopIn.DepositOutpoints, OutpointSeparator,
260270
)
261271
staticAddressLoopInParams := sqlc.InsertStaticAddressLoopInParams{
262272
SwapHash: loopIn.SwapHash[:],
@@ -266,6 +276,7 @@ func (s *SqlStore) CreateLoopIn(ctx context.Context,
266276
HtlcTimeoutSweepAddress: loopIn.HtlcTimeoutSweepAddress.String(),
267277
HtlcTxFeeRateSatKw: int64(loopIn.HtlcTxFeeRate),
268278
DepositOutpoints: joinedOutpoints,
279+
SelectedAmount: int64(loopIn.SelectedAmount),
269280
PaymentTimeoutSeconds: int32(loopIn.PaymentTimeoutSeconds),
270281
}
271282

@@ -350,6 +361,27 @@ func (s *SqlStore) UpdateLoopIn(ctx context.Context,
350361
)
351362
}
352363

364+
func (s *SqlStore) BatchUpdateSelectedSwapAmounts(ctx context.Context,
365+
updateAmounts map[lntypes.Hash]btcutil.Amount) error {
366+
367+
return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
368+
func(q Querier) error {
369+
for swapHash, amount := range updateAmounts {
370+
err := q.OverrideSelectedSwapAmount(
371+
ctx, sqlc.OverrideSelectedSwapAmountParams{
372+
SwapHash: swapHash[:],
373+
SelectedAmount: int64(amount),
374+
},
375+
)
376+
if err != nil {
377+
return err
378+
}
379+
}
380+
381+
return nil
382+
})
383+
}
384+
353385
// IsStored returns true if a swap with the given hash is stored in the
354386
// database, false otherwise.
355387
func (s *SqlStore) IsStored(ctx context.Context, swapHash lntypes.Hash) (bool,
@@ -478,7 +510,7 @@ func toStaticAddressLoopIn(_ context.Context, network *chaincfg.Params,
478510
}
479511

480512
depositOutpoints := strings.Split(
481-
swap.DepositOutpoints, outpointSeparator,
513+
swap.DepositOutpoints, OutpointSeparator,
482514
)
483515

484516
timeoutAddressString := swap.HtlcTimeoutSweepAddress
@@ -548,6 +580,7 @@ func toStaticAddressLoopIn(_ context.Context, network *chaincfg.Params,
548580
LastHop: swap.LastHop,
549581
QuotedSwapFee: btcutil.Amount(swap.QuotedSwapFeeSatoshis),
550582
DepositOutpoints: depositOutpoints,
583+
SelectedAmount: btcutil.Amount(swap.SelectedAmount),
551584
HtlcTxFeeRate: chainfee.SatPerKWeight(
552585
swap.HtlcTxFeeRateSatKw,
553586
),

0 commit comments

Comments
 (0)