Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightninglabs/aperture/l402"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/assets"
Expand Down Expand Up @@ -146,6 +147,10 @@ type ClientConfig struct {
// be attempted.
LoopOutMaxParts uint32

// SkippedTxns is the list of existing HTLC txids to skip when starting
// Loop. This should only be used if affected by the historical bug.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe mention reorg here, so the historical reorg bug. Should we also include reorg here to make it easier to understand, like SkippedReorgdTxns?

SkippedTxns []string

// TotalPaymentTimeout is the total amount of time until we time out
// off-chain payments (used in loop out).
TotalPaymentTimeout time.Duration
Expand Down Expand Up @@ -246,11 +251,7 @@ func NewClient(dbDir string, loopDB loopdb.SwapStore,
sweeper, loopDB, cfg.Lnd.ChainParams, getHeight,
)

batcher := sweepbatcher.NewBatcher(
cfg.Lnd.WalletKit, cfg.Lnd.ChainNotifier, cfg.Lnd.Signer,
swapServerClient.MultiMuSig2SignSweep, verifySchnorrSig,
cfg.Lnd.ChainParams, sweeperDb, sweepStore,

batcherOpts := []sweepbatcher.BatcherOption{
// Disable 100 sats/kw fee bump every block and retarget feerate
// every block according to the current mempool condition.
sweepbatcher.WithCustomFeeRate(
Expand All @@ -265,8 +266,29 @@ func NewClient(dbDir string, loopDB loopdb.SwapStore,
// delay time to sweepbatcher's handling. The delay used in
// loopout.go is repushDelay.
sweepbatcher.WithPublishDelay(
repushDelay+additionalDelay,
repushDelay + additionalDelay,
),
}

if len(cfg.SkippedTxns) != 0 {
skippedTxns := make(map[chainhash.Hash]struct{})
for _, txid := range cfg.SkippedTxns {
txid, err := chainhash.NewHashFromStr(txid)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse "+
"txid to skip %v: %w", txid, err)
}
skippedTxns[*txid] = struct{}{}
}
batcherOpts = append(batcherOpts, sweepbatcher.WithSkippedTxns(
skippedTxns,
))
}

batcher := sweepbatcher.NewBatcher(
cfg.Lnd.WalletKit, cfg.Lnd.ChainNotifier, cfg.Lnd.Signer,
swapServerClient.MultiMuSig2SignSweep, verifySchnorrSig,
cfg.Lnd.ChainParams, sweeperDb, sweepStore, batcherOpts...,
)

executor = newExecutor(&executorConfig{
Expand Down
2 changes: 1 addition & 1 deletion client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed,

// Expect client to register for our expected number of confirmations.
confIntent := ctx.Context.AssertRegisterConf(
preimageRevealed, int32(confs),
false, int32(confs),
)

htlc, err := utils.GetHtlc(
Expand Down
2 changes: 2 additions & 0 deletions loopd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ type Config struct {

LoopOutMaxParts uint32 `long:"loopoutmaxparts" description:"The maximum number of payment parts that may be used for a loop out swap."`

SkippedTxns []string `long:"skippedtxns" description:"The list of existing HTLC txids to skip when starting Loop. This should only be used if affected by the historical bug." hidden:"true"`

TotalPaymentTimeout time.Duration `long:"totalpaymenttimeout" description:"The timeout to use for off-chain payments."`
MaxPaymentRetries int `long:"maxpaymentretries" description:"The maximum number of times an off-chain payment may be retried."`

Expand Down
1 change: 1 addition & 0 deletions loopd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func getClient(cfg *Config, swapDb loopdb.SwapStore,
MaxL402Cost: btcutil.Amount(cfg.MaxL402Cost),
MaxL402Fee: btcutil.Amount(cfg.MaxL402Fee),
LoopOutMaxParts: cfg.LoopOutMaxParts,
SkippedTxns: cfg.SkippedTxns,
TotalPaymentTimeout: cfg.TotalPaymentTimeout,
MaxPaymentRetries: cfg.MaxPaymentRetries,
MaxStaticAddrHtlcFeePercentage: cfg.MaxStaticAddrHtlcFeePercentage,
Expand Down
28 changes: 16 additions & 12 deletions loopdb/sqlc/batch.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions loopdb/sqlc/migrations/000016_batch_cancelled.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE sweep_batches DROP COLUMN cancelled;
1 change: 1 addition & 0 deletions loopdb/sqlc/migrations/000016_batch_cancelled.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE sweep_batches ADD COLUMN cancelled BOOLEAN NOT NULL DEFAULT FALSE;
1 change: 1 addition & 0 deletions loopdb/sqlc/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion loopdb/sqlc/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions loopdb/sqlc/queries/batch.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ SELECT
FROM
sweep_batches
WHERE
confirmed = FALSE;
confirmed = FALSE AND cancelled = FALSE;

-- name: InsertBatch :one
INSERT INTO sweep_batches (
Expand All @@ -23,8 +23,10 @@ INSERT INTO sweep_batches (
$6
) RETURNING id;

-- name: DropBatch :exec
DELETE FROM sweep_batches WHERE id = $1;
-- name: CancelBatch :exec
UPDATE sweep_batches SET
cancelled = TRUE
WHERE id = $1;

-- name: UpdateBatch :exec
UPDATE sweep_batches SET
Expand Down
1 change: 0 additions & 1 deletion loopout.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ func resumeLoopOutSwap(cfg *swapConfig, pend *loopdb.LoopOut,
} else {
swap.state = lastUpdate.State
swap.lastUpdateTime = lastUpdate.Time
swap.htlcTxHash = lastUpdate.HtlcTxHash
}

return swap, nil
Expand Down
2 changes: 2 additions & 0 deletions sweepbatcher/presigned.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ func (b *batch) getOrderedSweeps(ctx context.Context) ([]sweep, error) {
return nil, fmt.Errorf("FetchBatchSweeps(%d) failed: %w", b.id,
err)
}
dbSweeps = filterDbSweeps(b.cfg.skippedTxns, dbSweeps)

if len(dbSweeps) != len(utxo2sweep) {
return nil, fmt.Errorf("FetchBatchSweeps(%d) returned %d "+
"sweeps, len(b.sweeps) is %d", b.id, len(dbSweeps),
Expand Down
65 changes: 62 additions & 3 deletions sweepbatcher/presigned_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ func TestOrderedSweeps(t *testing.T) {
ctx := context.Background()

cases := []struct {
name string
sweeps []sweep
name string
sweeps []sweep
skippedTxns map[chainhash.Hash]struct{}

// Testing errors.
skipStore bool
Expand Down Expand Up @@ -69,6 +70,20 @@ func TestOrderedSweeps(t *testing.T) {
},
},

{
name: "one sweep, skipped",
sweeps: []sweep{
{
outpoint: op1,
swapHash: swapHash1,
},
},
skippedTxns: map[chainhash.Hash]struct{}{
op1.Hash: {},
},
wantGroups: [][]sweep{},
},

{
name: "two sweeps, one swap",
sweeps: []sweep{
Expand All @@ -95,6 +110,31 @@ func TestOrderedSweeps(t *testing.T) {
},
},

{
name: "two sweeps, one swap, one skipped",
sweeps: []sweep{
{
outpoint: op2,
swapHash: swapHash1,
},
{
outpoint: op1,
swapHash: swapHash1,
},
},
skippedTxns: map[chainhash.Hash]struct{}{
op1.Hash: {},
},
wantGroups: [][]sweep{
{
{
outpoint: op2,
swapHash: swapHash1,
},
},
},
},

{
name: "two sweeps, two swap",
sweeps: []sweep{
Expand Down Expand Up @@ -266,6 +306,9 @@ func TestOrderedSweeps(t *testing.T) {
b := &batch{
sweeps: m,
store: NewStoreMock(),
cfg: &batchConfig{
skippedTxns: tc.skippedTxns,
},
}

// Store the sweeps in mock store.
Expand Down Expand Up @@ -299,6 +342,14 @@ func TestOrderedSweeps(t *testing.T) {
m[added.outpoint] = added
}

// Remove skipped sweeps from the batch to make it
// match with what is read from DB after filtering.
for op := range m {
if _, has := tc.skippedTxns[op.Hash]; has {
delete(m, op)
}
}

// Now run the tested functions.
orderedSweeps, err := b.getOrderedSweeps(ctx)
if tc.wantErr1 != "" {
Expand All @@ -313,7 +364,15 @@ func TestOrderedSweeps(t *testing.T) {
}

// The wanted list of sweeps matches the input order.
require.Equal(t, tc.sweeps, orderedSweeps)
notSkipped := make([]sweep, 0, len(tc.sweeps))
for _, s := range tc.sweeps {
_, has := tc.skippedTxns[s.outpoint.Hash]
if has {
continue
}
notSkipped = append(notSkipped, s)
}
require.Equal(t, notSkipped, orderedSweeps)

groups, err := b.getSweepsGroups(ctx)
if tc.wantErr2 != "" {
Expand Down
26 changes: 7 additions & 19 deletions sweepbatcher/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package sweepbatcher
import (
"context"
"database/sql"
"fmt"

"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
Expand Down Expand Up @@ -44,8 +43,8 @@ type Querier interface {
InsertBatch(ctx context.Context, arg sqlc.InsertBatchParams) (
int32, error)

// DropBatch drops a batch from the database.
DropBatch(ctx context.Context, id int32) error
// CancelBatch marks the batch as cancelled.
CancelBatch(ctx context.Context, id int32) error

// UpdateBatch updates a batch in the database.
UpdateBatch(ctx context.Context, arg sqlc.UpdateBatchParams) error
Expand Down Expand Up @@ -113,22 +112,11 @@ func (s *SQLStore) InsertSweepBatch(ctx context.Context, batch *dbBatch) (int32,
return s.baseDb.InsertBatch(ctx, batchToInsertArgs(*batch))
}

// DropBatch drops a batch from the database. Note that we only use this call
// for batches that have no sweeps and so we'd not be able to resume.
func (s *SQLStore) DropBatch(ctx context.Context, id int32) error {
readOpts := loopdb.NewSqlWriteOpts()
return s.baseDb.ExecTx(ctx, readOpts, func(tx Querier) error {
dbSweeps, err := tx.GetBatchSweeps(ctx, id)
if err != nil {
return err
}

if len(dbSweeps) != 0 {
return fmt.Errorf("cannot drop a non-empty batch")
}

return tx.DropBatch(ctx, id)
})
// CancelBatch marks a batch as cancelled in the database. Note that we only use
// this call for batches that have no sweeps or all the sweeps are in skipped
// transaction and so we'd not be able to resume.
func (s *SQLStore) CancelBatch(ctx context.Context, id int32) error {
return s.baseDb.CancelBatch(ctx, id)
}

// UpdateSweepBatch updates a batch in the database.
Expand Down
Loading