mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
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.
This commit is contained in:
parent
23f6c24c0c
commit
2ee772b251
8 changed files with 265 additions and 7 deletions
|
|
@ -635,6 +635,16 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Run the selected amount migration.
|
||||
err = loopin.MigrateSelectedSwapAmount(
|
||||
d.mainCtx, swapDb, depositStore, staticAddressLoopInStore,
|
||||
)
|
||||
if err != nil {
|
||||
errorf("Selected amount migration failed: %v", err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
staticLoopInManager = loopin.NewManager(&loopin.Config{
|
||||
Server: staticAddressClient,
|
||||
QuoteGetter: swapClient.Server,
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ type Querier interface {
|
|||
InsertSwapUpdate(ctx context.Context, arg InsertSwapUpdateParams) error
|
||||
IsStored(ctx context.Context, swapHash []byte) (bool, error)
|
||||
MapDepositToSwap(ctx context.Context, arg MapDepositToSwapParams) error
|
||||
OverrideSelectedSwapAmount(ctx context.Context, arg OverrideSelectedSwapAmountParams) error
|
||||
OverrideSwapCosts(ctx context.Context, arg OverrideSwapCostsParams) error
|
||||
SwapHashForDepositID(ctx context.Context, depositID []byte) ([]byte, error)
|
||||
UpdateBatch(ctx context.Context, arg UpdateBatchParams) error
|
||||
|
|
|
|||
|
|
@ -96,6 +96,12 @@ SELECT EXISTS (
|
|||
WHERE swap_hash = $1
|
||||
);
|
||||
|
||||
-- name: OverrideSelectedSwapAmount :exec
|
||||
UPDATE static_address_swaps
|
||||
SET
|
||||
selected_amount = $2
|
||||
WHERE swap_hash = $1;
|
||||
|
||||
-- name: MapDepositToSwap :exec
|
||||
UPDATE
|
||||
deposits
|
||||
|
|
|
|||
|
|
@ -457,6 +457,23 @@ func (q *Queries) MapDepositToSwap(ctx context.Context, arg MapDepositToSwapPara
|
|||
return err
|
||||
}
|
||||
|
||||
const overrideSelectedSwapAmount = `-- name: OverrideSelectedSwapAmount :exec
|
||||
UPDATE static_address_swaps
|
||||
SET
|
||||
selected_amount = $2
|
||||
WHERE swap_hash = $1
|
||||
`
|
||||
|
||||
type OverrideSelectedSwapAmountParams struct {
|
||||
SwapHash []byte
|
||||
SelectedAmount int64
|
||||
}
|
||||
|
||||
func (q *Queries) OverrideSelectedSwapAmount(ctx context.Context, arg OverrideSelectedSwapAmountParams) error {
|
||||
_, err := q.db.ExecContext(ctx, overrideSelectedSwapAmount, arg.SwapHash, arg.SelectedAmount)
|
||||
return err
|
||||
}
|
||||
|
||||
const swapHashForDepositID = `-- name: SwapHashForDepositID :one
|
||||
SELECT
|
||||
swap_hash
|
||||
|
|
|
|||
|
|
@ -119,13 +119,13 @@ func TestDepositSwapHashMigration(t *testing.T) {
|
|||
// If so, we reject the loop-in to prevent potential issues with
|
||||
// parsing.
|
||||
for _, outpoint := range loopIn.DepositOutpoints {
|
||||
if strings.Contains(outpoint, outpointSeparator) {
|
||||
if strings.Contains(outpoint, OutpointSeparator) {
|
||||
return ErrInvalidOutpoint
|
||||
}
|
||||
}
|
||||
|
||||
joinedOutpoints := strings.Join(
|
||||
loopIn.DepositOutpoints, outpointSeparator,
|
||||
loopIn.DepositOutpoints, OutpointSeparator,
|
||||
)
|
||||
staticAddressLoopInParams := sqlc.InsertStaticAddressLoopInParams{
|
||||
SwapHash: loopIn.SwapHash[:],
|
||||
|
|
|
|||
84
staticaddr/loopin/selected_amount_migration.go
Normal file
84
staticaddr/loopin/selected_amount_migration.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package loopin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/staticaddr/deposit"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
)
|
||||
|
||||
const (
|
||||
// selectedAmountMigrationID is the identifier for the selected swap
|
||||
// amount migration.
|
||||
selectedAmountMigrationID = "selected_amount"
|
||||
)
|
||||
|
||||
// MigrateSelectedSwapAmount will update the selected swap amount of past swaps
|
||||
// with the sum of the values of the deposits they swapped.
|
||||
func MigrateSelectedSwapAmount(ctx context.Context, db loopdb.SwapStore,
|
||||
depositStore *deposit.SqlStore, swapStore *SqlStore) error {
|
||||
|
||||
migrationDone, err := db.HasMigration(ctx, selectedAmountMigrationID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to check migration status: %w", err)
|
||||
}
|
||||
if migrationDone {
|
||||
log.Infof("Selected swap amount migration already done, " +
|
||||
"skipping")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("Starting swap amount migration")
|
||||
startTs := time.Now()
|
||||
defer func() {
|
||||
log.Infof("Finished swap amount migration in %v",
|
||||
time.Since(startTs))
|
||||
}()
|
||||
|
||||
// First we'll fetch all loop out swaps from the database.
|
||||
swaps, err := swapStore.GetStaticAddressLoopInSwapsByStates(
|
||||
ctx, FinalStates,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now we'll calculate the cost for each swap and finally update the
|
||||
// costs in the database.
|
||||
// TODO(hieblmi): normalize swap hash and deposit ids.
|
||||
updateAmounts := make(map[lntypes.Hash]btcutil.Amount)
|
||||
for _, swap := range swaps {
|
||||
for _, outpoint := range swap.DepositOutpoints {
|
||||
deposit, err := depositStore.DepositForOutpoint(
|
||||
ctx, outpoint,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch deposit "+
|
||||
"for outpoint %s: %w", outpoint, err)
|
||||
}
|
||||
if deposit == nil {
|
||||
return fmt.Errorf("deposit for outpoint %s "+
|
||||
"not found", outpoint)
|
||||
}
|
||||
|
||||
// Set the selected amount to the value of the deposit.
|
||||
updateAmounts[swap.SwapHash] += deposit.Value
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Updating selected swap amounts for %d loop in swaps",
|
||||
len(updateAmounts))
|
||||
|
||||
err = swapStore.BatchUpdateSelectedSwapAmounts(ctx, updateAmounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Finally mark the migration as done.
|
||||
return db.SetMigration(ctx, selectedAmountMigrationID)
|
||||
}
|
||||
107
staticaddr/loopin/selected_amount_migration_test.go
Normal file
107
staticaddr/loopin/selected_amount_migration_test.go
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package loopin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/staticaddr/deposit"
|
||||
"github.com/lightninglabs/loop/test"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestMigrateSelectedSwapAmount tests the selected amount migration.
|
||||
func TestMigrateSelectedSwapAmount(t *testing.T) {
|
||||
// Set up test context objects.
|
||||
ctxb := context.Background()
|
||||
testDb := loopdb.NewTestDB(t)
|
||||
testClock := clock.NewTestClock(time.Now())
|
||||
defer testDb.Close()
|
||||
|
||||
db := loopdb.NewStoreMock(t)
|
||||
depositStore := deposit.NewSqlStore(testDb.BaseDB)
|
||||
swapStore := NewSqlStore(
|
||||
loopdb.NewTypedStore[Querier](testDb), testClock,
|
||||
&chaincfg.MainNetParams,
|
||||
)
|
||||
|
||||
newID := func() deposit.ID {
|
||||
did, err := deposit.GetRandomDepositID()
|
||||
require.NoError(t, err)
|
||||
|
||||
return did
|
||||
}
|
||||
|
||||
d1, d2 := &deposit.Deposit{
|
||||
ID: newID(),
|
||||
OutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash{0x1a, 0x2b, 0x3c, 0x4d},
|
||||
Index: 0,
|
||||
},
|
||||
Value: btcutil.Amount(100_000),
|
||||
TimeOutSweepPkScript: []byte{
|
||||
0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x41,
|
||||
},
|
||||
},
|
||||
&deposit.Deposit{
|
||||
ID: newID(),
|
||||
OutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash{0x2a, 0x2b, 0x3c, 0x4e},
|
||||
Index: 1,
|
||||
},
|
||||
Value: btcutil.Amount(200_000),
|
||||
TimeOutSweepPkScript: []byte{
|
||||
0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x4d,
|
||||
},
|
||||
}
|
||||
|
||||
err := depositStore.CreateDeposit(ctxb, d1)
|
||||
require.NoError(t, err)
|
||||
err = depositStore.CreateDeposit(ctxb, d2)
|
||||
require.NoError(t, err)
|
||||
|
||||
outpoints := []string{
|
||||
d1.OutPoint.String(),
|
||||
d2.OutPoint.String(),
|
||||
}
|
||||
_, clientPubKey := test.CreateKey(1)
|
||||
_, serverPubKey := test.CreateKey(2)
|
||||
p2wkhAddr := "bcrt1qq68r6ff4k4pjx39efs44gcyccf7unqnu5qtjjz"
|
||||
addr, err := btcutil.DecodeAddress(p2wkhAddr, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
swap := StaticAddressLoopIn{
|
||||
SwapHash: lntypes.Hash{0x1, 0x2, 0x3, 0x4},
|
||||
DepositOutpoints: outpoints,
|
||||
ClientPubkey: clientPubKey,
|
||||
ServerPubkey: serverPubKey,
|
||||
HtlcTimeoutSweepAddress: addr,
|
||||
Deposits: []*deposit.Deposit{d1, d2},
|
||||
}
|
||||
swap.SetState(Succeeded)
|
||||
|
||||
err = swapStore.CreateLoopIn(ctxb, &swap)
|
||||
require.NoError(t, err)
|
||||
|
||||
storedSwaps, err := swapStore.GetStaticAddressLoopInSwapsByStates(
|
||||
ctxb, FinalStates,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 0, storedSwaps[0].SelectedAmount)
|
||||
|
||||
err = MigrateSelectedSwapAmount(ctxb, db, depositStore, swapStore)
|
||||
require.NoError(t, err)
|
||||
|
||||
storedSwaps, err = swapStore.GetStaticAddressLoopInSwapsByStates(
|
||||
ctxb, FinalStates,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, d1.Value+d2.Value, storedSwaps[0].SelectedAmount)
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
)
|
||||
|
||||
const outpointSeparator = ";"
|
||||
const OutpointSeparator = ";"
|
||||
|
||||
var (
|
||||
// ErrInvalidOutpoint is returned when an outpoint contains the outpoint
|
||||
|
|
@ -88,6 +88,11 @@ type Querier interface {
|
|||
// DepositsForSwapHash retrieves all deposits for a given swap hash.
|
||||
DepositsForSwapHash(ctx context.Context,
|
||||
swapHash []byte) ([]sqlc.DepositsForSwapHashRow, error)
|
||||
|
||||
// OverrideSelectedSwapAmount updates the selected swap amount for
|
||||
// a given swap hash.
|
||||
OverrideSelectedSwapAmount(ctx context.Context,
|
||||
params sqlc.OverrideSelectedSwapAmountParams) error
|
||||
}
|
||||
|
||||
// BaseDB is the interface that contains all the queries generated by sqlc for
|
||||
|
|
@ -226,11 +231,16 @@ func (s *SqlStore) CreateLoopIn(ctx context.Context,
|
|||
return errors.New("loop-in must have at least one deposit")
|
||||
}
|
||||
|
||||
amountRequested := int64(loopIn.TotalDepositAmount())
|
||||
if loopIn.SelectedAmount > 0 {
|
||||
amountRequested = int64(loopIn.SelectedAmount)
|
||||
}
|
||||
|
||||
swapArgs := sqlc.InsertSwapParams{
|
||||
SwapHash: loopIn.SwapHash[:],
|
||||
Preimage: loopIn.SwapPreimage[:],
|
||||
InitiationTime: loopIn.InitiationTime,
|
||||
AmountRequested: int64(loopIn.TotalDepositAmount()),
|
||||
AmountRequested: amountRequested,
|
||||
CltvExpiry: loopIn.HtlcCltvExpiry,
|
||||
MaxSwapFee: int64(loopIn.MaxSwapFee),
|
||||
InitiationHeight: int32(loopIn.InitiationHeight),
|
||||
|
|
@ -250,13 +260,13 @@ func (s *SqlStore) CreateLoopIn(ctx context.Context,
|
|||
// If so, we reject the loop-in to prevent potential issues with
|
||||
// parsing.
|
||||
for _, outpoint := range loopIn.DepositOutpoints {
|
||||
if strings.Contains(outpoint, outpointSeparator) {
|
||||
if strings.Contains(outpoint, OutpointSeparator) {
|
||||
return ErrInvalidOutpoint
|
||||
}
|
||||
}
|
||||
|
||||
joinedOutpoints := strings.Join(
|
||||
loopIn.DepositOutpoints, outpointSeparator,
|
||||
loopIn.DepositOutpoints, OutpointSeparator,
|
||||
)
|
||||
staticAddressLoopInParams := sqlc.InsertStaticAddressLoopInParams{
|
||||
SwapHash: loopIn.SwapHash[:],
|
||||
|
|
@ -266,6 +276,7 @@ func (s *SqlStore) CreateLoopIn(ctx context.Context,
|
|||
HtlcTimeoutSweepAddress: loopIn.HtlcTimeoutSweepAddress.String(),
|
||||
HtlcTxFeeRateSatKw: int64(loopIn.HtlcTxFeeRate),
|
||||
DepositOutpoints: joinedOutpoints,
|
||||
SelectedAmount: int64(loopIn.SelectedAmount),
|
||||
PaymentTimeoutSeconds: int32(loopIn.PaymentTimeoutSeconds),
|
||||
}
|
||||
|
||||
|
|
@ -350,6 +361,27 @@ func (s *SqlStore) UpdateLoopIn(ctx context.Context,
|
|||
)
|
||||
}
|
||||
|
||||
func (s *SqlStore) BatchUpdateSelectedSwapAmounts(ctx context.Context,
|
||||
updateAmounts map[lntypes.Hash]btcutil.Amount) error {
|
||||
|
||||
return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
|
||||
func(q Querier) error {
|
||||
for swapHash, amount := range updateAmounts {
|
||||
err := q.OverrideSelectedSwapAmount(
|
||||
ctx, sqlc.OverrideSelectedSwapAmountParams{
|
||||
SwapHash: swapHash[:],
|
||||
SelectedAmount: int64(amount),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// IsStored returns true if a swap with the given hash is stored in the
|
||||
// database, false otherwise.
|
||||
func (s *SqlStore) IsStored(ctx context.Context, swapHash lntypes.Hash) (bool,
|
||||
|
|
@ -478,7 +510,7 @@ func toStaticAddressLoopIn(_ context.Context, network *chaincfg.Params,
|
|||
}
|
||||
|
||||
depositOutpoints := strings.Split(
|
||||
swap.DepositOutpoints, outpointSeparator,
|
||||
swap.DepositOutpoints, OutpointSeparator,
|
||||
)
|
||||
|
||||
timeoutAddressString := swap.HtlcTimeoutSweepAddress
|
||||
|
|
@ -548,6 +580,7 @@ func toStaticAddressLoopIn(_ context.Context, network *chaincfg.Params,
|
|||
LastHop: swap.LastHop,
|
||||
QuotedSwapFee: btcutil.Amount(swap.QuotedSwapFeeSatoshis),
|
||||
DepositOutpoints: depositOutpoints,
|
||||
SelectedAmount: btcutil.Amount(swap.SelectedAmount),
|
||||
HtlcTxFeeRate: chainfee.SatPerKWeight(
|
||||
swap.HtlcTxFeeRateSatKw,
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue