From 0c2ba74dba43a5251003b382ab0782a83ca2df83 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 14 May 2024 11:36:47 -0300 Subject: [PATCH] sweepbatcher: factor out loopdb-less version Changed argument of function NewBatcher from LoopOutFetcher to SweepFetcher (returning new public type SweepInfo). This change is backwards-incompatible on the package layer, but nobody seems to use the package outside of Loop. To use NewBatcher inside Loop, turn loopdb into SweepFetcher using function NewSweepFetcherFromSwapStore. --- client.go | 10 +- loopout_test.go | 21 ++- sweepbatcher/sweep_batcher.go | 204 ++++++++++++++++++++--------- sweepbatcher/sweep_batcher_test.go | 151 ++++++++++++++++++--- testcontext_test.go | 11 +- 5 files changed, 309 insertions(+), 88 deletions(-) diff --git a/client.go b/client.go index ae45e9d7..7f350b85 100644 --- a/client.go +++ b/client.go @@ -177,10 +177,18 @@ func NewClient(dbDir string, loopDB loopdb.SwapStore, return nil } + sweepStore, err := sweepbatcher.NewSweepFetcherFromSwapStore( + loopDB, cfg.Lnd.ChainParams, + ) + if err != nil { + return nil, nil, fmt.Errorf("sweepbatcher."+ + "NewSweepFetcherFromSwapStore failed: %w", err) + } + batcher := sweepbatcher.NewBatcher( cfg.Lnd.WalletKit, cfg.Lnd.ChainNotifier, cfg.Lnd.Signer, swapServerClient.MultiMuSig2SignSweep, verifySchnorrSig, - cfg.Lnd.ChainParams, sweeperDb, loopDB, + cfg.Lnd.ChainParams, sweeperDb, sweepStore, ) executor := newExecutor(&executorConfig{ diff --git a/loopout_test.go b/loopout_test.go index 3138b1a3..03cd0e24 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -299,10 +299,15 @@ func testCustomSweepConfTarget(t *testing.T) { batcherStore := sweepbatcher.NewStoreMock() + sweepStore, err := sweepbatcher.NewSweepFetcherFromSwapStore( + cfg.store, lnd.ChainParams, + ) + require.NoError(t, err) + batcher := sweepbatcher.NewBatcher( lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, mockMuSig2SignSweep, mockVerifySchnorrSigSuccess, - lnd.ChainParams, batcherStore, cfg.store, + lnd.ChainParams, batcherStore, sweepStore, ) tctx, cancel := context.WithCancel(context.Background()) @@ -532,10 +537,15 @@ func testPreimagePush(t *testing.T) { batcherStore := sweepbatcher.NewStoreMock() + sweepStore, err := sweepbatcher.NewSweepFetcherFromSwapStore( + cfg.store, lnd.ChainParams, + ) + require.NoError(t, err) + batcher := sweepbatcher.NewBatcher( lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, mockMuSig2SignSweep, mockVerifySchnorrSigSuccess, - lnd.ChainParams, batcherStore, cfg.store, + lnd.ChainParams, batcherStore, sweepStore, ) tctx, cancel := context.WithCancel(context.Background()) @@ -953,10 +963,15 @@ func TestLoopOutMuSig2Sweep(t *testing.T) { batcherStore := sweepbatcher.NewStoreMock() + sweepStore, err := sweepbatcher.NewSweepFetcherFromSwapStore( + cfg.store, lnd.ChainParams, + ) + require.NoError(t, err) + batcher := sweepbatcher.NewBatcher( lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, mockMuSig2SignSweep, mockVerifySchnorrSigSuccess, - lnd.ChainParams, batcherStore, cfg.store, + lnd.ChainParams, batcherStore, sweepStore, ) tctx, cancel := context.WithCancel(context.Background()) diff --git a/sweepbatcher/sweep_batcher.go b/sweepbatcher/sweep_batcher.go index 79481a11..744afd87 100644 --- a/sweepbatcher/sweep_batcher.go +++ b/sweepbatcher/sweep_batcher.go @@ -13,7 +13,9 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop/loopdb" + "github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/utils" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) @@ -82,12 +84,48 @@ type BatcherStore interface { TotalSweptAmount(ctx context.Context, id int32) (btcutil.Amount, error) } -// LoopOutFetcher is used to load LoopOut swaps from the database. -// It is implemented by loopdb.SwapStore. -type LoopOutFetcher interface { - // FetchLoopOutSwap returns the loop out swap with the given hash. - FetchLoopOutSwap(ctx context.Context, - hash lntypes.Hash) (*loopdb.LoopOut, error) +// SweepInfo stores any data related to sweeping a specific outpoint. +type SweepInfo struct { + // ConfTarget is the confirmation target of the sweep. + ConfTarget int32 + + // Timeout is the timeout of the swap that the sweep belongs to. + Timeout int32 + + // InitiationHeight is the height at which the swap was initiated. + InitiationHeight int32 + + // HTLC is the HTLC that is being swept. + HTLC swap.Htlc + + // Preimage is the preimage of the HTLC that is being swept. + Preimage lntypes.Preimage + + // SwapInvoicePaymentAddr is the payment address of the swap invoice. + SwapInvoicePaymentAddr [32]byte + + // HTLCKeys is the set of keys used to sign the HTLC. + HTLCKeys loopdb.HtlcKeys + + // HTLCSuccessEstimator is a function that estimates the weight of the + // HTLC success script. + HTLCSuccessEstimator func(*input.TxWeightEstimator) error + + // ProtocolVersion is the protocol version of the swap that the sweep + // belongs to. + ProtocolVersion loopdb.ProtocolVersion + + // IsExternalAddr is true if the sweep spends to a non-wallet address. + IsExternalAddr bool + + // DestAddr is the destination address of the sweep. + DestAddr btcutil.Address +} + +// SweepFetcher is used to get details of a sweep. +type SweepFetcher interface { + // FetchSweep returns details of the sweep with the given hash. + FetchSweep(ctx context.Context, hash lntypes.Hash) (*SweepInfo, error) } // MuSig2SignSweep is a function that can be used to sign a sweep transaction @@ -191,8 +229,8 @@ type Batcher struct { // batcher and the batches. store BatcherStore - // swapStore is used to load LoopOut swaps from the database. - swapStore LoopOutFetcher + // sweepStore is used to load sweeps from the database. + sweepStore SweepFetcher // wg is a waitgroup that is used to wait for all the goroutines to // exit. @@ -204,7 +242,7 @@ func NewBatcher(wallet lndclient.WalletKitClient, chainNotifier lndclient.ChainNotifierClient, signerClient lndclient.SignerClient, musig2ServerSigner MuSig2SignSweep, verifySchnorrSig VerifySchnorrSig, chainparams *chaincfg.Params, - store BatcherStore, swapStore LoopOutFetcher) *Batcher { + store BatcherStore, sweepStore SweepFetcher) *Batcher { return &Batcher{ batches: make(map[int32]*batch), @@ -219,7 +257,7 @@ func NewBatcher(wallet lndclient.WalletKitClient, VerifySchnorrSig: verifySchnorrSig, chainParams: chainparams, store: store, - swapStore: swapStore, + sweepStore: sweepStore, } } @@ -661,41 +699,96 @@ func (b *Batcher) writeToErrChan(ctx context.Context, err error) error { func (b *Batcher) convertSweep(ctx context.Context, dbSweep *dbSweep) ( *sweep, error) { - swap, err := b.swapStore.FetchLoopOutSwap(ctx, dbSweep.SwapHash) + s, err := b.sweepStore.FetchSweep(ctx, dbSweep.SwapHash) if err != nil { - return nil, fmt.Errorf("failed to fetch loop out for %x: %w", + return nil, fmt.Errorf("failed to fetch sweep data for %x: %v", dbSweep.SwapHash[:6], err) } + return &sweep{ + swapHash: dbSweep.SwapHash, + outpoint: dbSweep.Outpoint, + value: dbSweep.Amount, + confTarget: s.ConfTarget, + timeout: s.Timeout, + initiationHeight: s.InitiationHeight, + htlc: s.HTLC, + preimage: s.Preimage, + swapInvoicePaymentAddr: s.SwapInvoicePaymentAddr, + htlcKeys: s.HTLCKeys, + htlcSuccessEstimator: s.HTLCSuccessEstimator, + protocolVersion: s.ProtocolVersion, + isExternalAddr: s.IsExternalAddr, + destAddr: s.DestAddr, + }, nil +} + +// LoopOutFetcher is used to load LoopOut swaps from the database. +// It is implemented by loopdb.SwapStore. +type LoopOutFetcher interface { + // FetchLoopOutSwap returns the loop out swap with the given hash. + FetchLoopOutSwap(ctx context.Context, + hash lntypes.Hash) (*loopdb.LoopOut, error) +} + +// SwapStoreWrapper is LoopOutFetcher wrapper providing SweepFetcher interface. +type SwapStoreWrapper struct { + // swapStore is used to load LoopOut swaps from the database. + swapStore LoopOutFetcher + + // chainParams are the chain parameters of the chain that is used by + // batches. + chainParams *chaincfg.Params +} + +// FetchSweep returns details of the sweep with the given hash. +// Implements SweepFetcher interface. +func (f *SwapStoreWrapper) FetchSweep(ctx context.Context, + swapHash lntypes.Hash) (*SweepInfo, error) { + + swap, err := f.swapStore.FetchLoopOutSwap(ctx, swapHash) + if err != nil { + return nil, fmt.Errorf("failed to fetch loop out for %x: %v", + swapHash[:6], err) + } + htlc, err := utils.GetHtlc( - dbSweep.SwapHash, &swap.Contract.SwapContract, b.chainParams, + swapHash, &swap.Contract.SwapContract, f.chainParams, ) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get htlc: %v", err) } swapPaymentAddr, err := utils.ObtainSwapPaymentAddr( - swap.Contract.SwapInvoice, b.chainParams, + swap.Contract.SwapInvoice, f.chainParams, ) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get payment addr: %v", err) } - return &sweep{ - swapHash: swap.Hash, - outpoint: dbSweep.Outpoint, - value: dbSweep.Amount, - confTarget: swap.Contract.SweepConfTarget, - timeout: swap.Contract.CltvExpiry, - initiationHeight: swap.Contract.InitiationHeight, - htlc: *htlc, - preimage: swap.Contract.Preimage, - swapInvoicePaymentAddr: *swapPaymentAddr, - htlcKeys: swap.Contract.HtlcKeys, - htlcSuccessEstimator: htlc.AddSuccessToEstimator, - protocolVersion: swap.Contract.ProtocolVersion, - isExternalAddr: swap.Contract.IsExternalAddr, - destAddr: swap.Contract.DestAddr, + return &SweepInfo{ + ConfTarget: swap.Contract.SweepConfTarget, + Timeout: swap.Contract.CltvExpiry, + InitiationHeight: swap.Contract.InitiationHeight, + HTLC: *htlc, + Preimage: swap.Contract.Preimage, + SwapInvoicePaymentAddr: *swapPaymentAddr, + HTLCKeys: swap.Contract.HtlcKeys, + HTLCSuccessEstimator: htlc.AddSuccessToEstimator, + ProtocolVersion: swap.Contract.ProtocolVersion, + IsExternalAddr: swap.Contract.IsExternalAddr, + DestAddr: swap.Contract.DestAddr, + }, nil +} + +// NewSweepFetcherFromSwapStore accepts swapStore (e.g. loopdb) and returns +// a wrapper implementing SweepFetcher interface (suitable for NewBatcher). +func NewSweepFetcherFromSwapStore(swapStore LoopOutFetcher, + chainParams *chaincfg.Params) (*SwapStoreWrapper, error) { + + return &SwapStoreWrapper{ + swapStore: swapStore, + chainParams: chainParams, }, nil } @@ -703,45 +796,26 @@ func (b *Batcher) convertSweep(ctx context.Context, dbSweep *dbSweep) ( func (b *Batcher) fetchSweep(ctx context.Context, sweepReq SweepRequest) (*sweep, error) { - swapHash, err := lntypes.MakeHash(sweepReq.SwapHash[:]) + s, err := b.sweepStore.FetchSweep(ctx, sweepReq.SwapHash) if err != nil { - return nil, fmt.Errorf("failed to parse swapHash: %v", err) - } - - swap, err := b.swapStore.FetchLoopOutSwap(ctx, swapHash) - if err != nil { - return nil, fmt.Errorf("failed to fetch loop out for %x: %v", - swapHash[:6], err) - } - - htlc, err := utils.GetHtlc( - swapHash, &swap.Contract.SwapContract, b.chainParams, - ) - if err != nil { - return nil, fmt.Errorf("failed to get htlc: %v", err) - } - - swapPaymentAddr, err := utils.ObtainSwapPaymentAddr( - swap.Contract.SwapInvoice, b.chainParams, - ) - if err != nil { - return nil, fmt.Errorf("failed to get payment addr: %v", err) + return nil, fmt.Errorf("failed to fetch sweep data for %x: %v", + sweepReq.SwapHash[:6], err) } return &sweep{ - swapHash: swap.Hash, + swapHash: sweepReq.SwapHash, outpoint: sweepReq.Outpoint, value: sweepReq.Value, - confTarget: swap.Contract.SweepConfTarget, - timeout: swap.Contract.CltvExpiry, - initiationHeight: swap.Contract.InitiationHeight, - htlc: *htlc, - preimage: swap.Contract.Preimage, - swapInvoicePaymentAddr: *swapPaymentAddr, - htlcKeys: swap.Contract.HtlcKeys, - htlcSuccessEstimator: htlc.AddSuccessToEstimator, - protocolVersion: swap.Contract.ProtocolVersion, - isExternalAddr: swap.Contract.IsExternalAddr, - destAddr: swap.Contract.DestAddr, + confTarget: s.ConfTarget, + timeout: s.Timeout, + initiationHeight: s.InitiationHeight, + htlc: s.HTLC, + preimage: s.Preimage, + swapInvoicePaymentAddr: s.SwapInvoicePaymentAddr, + htlcKeys: s.HTLCKeys, + htlcSuccessEstimator: s.HTLCSuccessEstimator, + protocolVersion: s.ProtocolVersion, + isExternalAddr: s.IsExternalAddr, + destAddr: s.DestAddr, }, nil } diff --git a/sweepbatcher/sweep_batcher_test.go b/sweepbatcher/sweep_batcher_test.go index 4afb7262..e5dc2f61 100644 --- a/sweepbatcher/sweep_batcher_test.go +++ b/sweepbatcher/sweep_batcher_test.go @@ -12,6 +12,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/test" + "github.com/lightninglabs/loop/utils" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" @@ -63,11 +64,14 @@ func TestSweepBatcherBatchCreation(t *testing.T) { defer cancel() store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) go func() { err := batcher.Run(ctx) checkBatcherError(t, err) @@ -93,7 +97,7 @@ func TestSweepBatcherBatchCreation(t *testing.T) { SwapInvoice: swapInvoice, } - err := store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) + err = store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) require.NoError(t, err) store.AssertLoopOutStored() @@ -217,11 +221,14 @@ func TestSweepBatcherSimpleLifecycle(t *testing.T) { defer cancel() store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) go func() { err := batcher.Run(ctx) checkBatcherError(t, err) @@ -247,7 +254,7 @@ func TestSweepBatcherSimpleLifecycle(t *testing.T) { SweepConfTarget: 111, } - err := store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) + err = store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) require.NoError(t, err) store.AssertLoopOutStored() @@ -354,11 +361,14 @@ func TestSweepBatcherSweepReentry(t *testing.T) { defer cancel() store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) go func() { err := batcher.Run(ctx) checkBatcherError(t, err) @@ -385,7 +395,7 @@ func TestSweepBatcherSweepReentry(t *testing.T) { SweepConfTarget: 111, } - err := store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) + err = store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) require.NoError(t, err) store.AssertLoopOutStored() @@ -561,11 +571,14 @@ func TestSweepBatcherNonWalletAddr(t *testing.T) { defer cancel() store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) go func() { err := batcher.Run(ctx) checkBatcherError(t, err) @@ -591,7 +604,7 @@ func TestSweepBatcherNonWalletAddr(t *testing.T) { SwapInvoice: swapInvoice, } - err := store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) + err = store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) require.NoError(t, err) store.AssertLoopOutStored() @@ -726,11 +739,14 @@ func TestSweepBatcherComposite(t *testing.T) { defer cancel() store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) go func() { err := batcher.Run(ctx) checkBatcherError(t, err) @@ -756,7 +772,7 @@ func TestSweepBatcherComposite(t *testing.T) { SwapInvoice: swapInvoice, } - err := store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) + err = store.CreateLoopOut(ctx, sweepReq1.SwapHash, swap1) require.NoError(t, err) store.AssertLoopOutStored() @@ -1043,13 +1059,16 @@ func TestRestoringEmptyBatch(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() - _, err := batcherStore.InsertSweepBatch(ctx, &dbBatch{}) + _, err = batcherStore.InsertSweepBatch(ctx, &dbBatch{}) require.NoError(t, err) batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) var wg sync.WaitGroup wg.Add(1) @@ -1157,11 +1176,14 @@ func TestHandleSweepTwice(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) store := newLoopStoreMock() + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) var wg sync.WaitGroup wg.Add(1) @@ -1313,11 +1335,14 @@ func TestRestoringPreservesConfTarget(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) store := loopdb.NewStoreMock(t) + sweepStore, err := NewSweepFetcherFromSwapStore(store, lnd.ChainParams) + require.NoError(t, err) batcherStore := NewStoreMock() batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) var wg sync.WaitGroup wg.Add(1) @@ -1352,7 +1377,7 @@ func TestRestoringPreservesConfTarget(t *testing.T) { SweepConfTarget: 123, } - err := store.CreateLoopOut(ctx, sweepReq.SwapHash, swap) + err = store.CreateLoopOut(ctx, sweepReq.SwapHash, swap) require.NoError(t, err) store.AssertLoopOutStored() @@ -1388,7 +1413,8 @@ func TestRestoringPreservesConfTarget(t *testing.T) { // Now launch it again. batcher = NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, - testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, store) + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepStore) ctx, cancel = context.WithCancel(context.Background()) wg.Add(1) go func() { @@ -1419,3 +1445,96 @@ func TestRestoringPreservesConfTarget(t *testing.T) { // Make sure the batcher exited without an error. checkBatcherError(t, runErr) } + +type sweepFetcherMock struct { + store map[lntypes.Hash]*SweepInfo +} + +func (f *sweepFetcherMock) FetchSweep(ctx context.Context, hash lntypes.Hash) ( + *SweepInfo, error) { + + return f.store[hash], nil +} + +// TestSweepFetcher tests providing custom sweep fetcher to Batcher. +func TestSweepFetcher(t *testing.T) { + defer test.Guard(t)() + + lnd := test.NewMockLnd() + ctx, cancel := context.WithCancel(context.Background()) + + // Extract payment address from the invoice. + swapPaymentAddr, err := utils.ObtainSwapPaymentAddr( + swapInvoice, lnd.ChainParams, + ) + require.NoError(t, err) + + sweepFetcher := &sweepFetcherMock{ + store: map[lntypes.Hash]*SweepInfo{ + {1, 1, 1}: { + ConfTarget: 123, + Timeout: 111, + SwapInvoicePaymentAddr: *swapPaymentAddr, + }, + }, + } + + batcherStore := NewStoreMock() + + batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer, + testMuSig2SignSweep, nil, lnd.ChainParams, batcherStore, + sweepFetcher) + + var wg sync.WaitGroup + wg.Add(1) + + var runErr error + go func() { + defer wg.Done() + runErr = batcher.Run(ctx) + }() + + // Wait for the batcher to be initialized. + <-batcher.initDone + + // Create a sweep request. + sweepReq := SweepRequest{ + SwapHash: lntypes.Hash{1, 1, 1}, + Value: 111, + Outpoint: wire.OutPoint{ + Hash: chainhash.Hash{1, 1}, + Index: 1, + }, + Notifier: &dummyNotifier, + } + + // Deliver sweep request to batcher. + require.NoError(t, batcher.AddSweep(&sweepReq)) + + // Since a batch was created we check that it registered for its primary + // sweep's spend. + <-lnd.RegisterSpendChannel + + // Once batcher receives sweep request it will eventually spin up a + // batch. + require.Eventually(t, func() bool { + // Make sure that the sweep was stored and we have exactly one + // active batch, with one sweep and proper batchConfTarget. + return batcherStore.AssertSweepStored(sweepReq.SwapHash) && + len(batcher.batches) == 1 && + len(batcher.batches[0].sweeps) == 1 && + batcher.batches[0].cfg.batchConfTarget == 123 + }, test.Timeout, eventuallyCheckFrequency) + + // Make sure we have stored the batch. + batches, err := batcherStore.FetchUnconfirmedSweepBatches(ctx) + require.NoError(t, err) + require.Len(t, batches, 1) + + // Now make the batcher quit by canceling the context. + cancel() + wg.Wait() + + // Make sure the batcher exited without an error. + checkBatcherError(t, runErr) +} diff --git a/testcontext_test.go b/testcontext_test.go index 423eb31d..617666ce 100644 --- a/testcontext_test.go +++ b/testcontext_test.go @@ -70,7 +70,7 @@ func mockMuSig2SignSweep(ctx context.Context, return nil, nil, nil } -func newSwapClient(config *clientConfig) *Client { +func newSwapClient(t *testing.T, config *clientConfig) *Client { sweeper := &sweep.Sweeper{ Lnd: config.LndServices, } @@ -79,11 +79,16 @@ func newSwapClient(config *clientConfig) *Client { batcherStore := sweepbatcher.NewStoreMock() + sweepStore, err := sweepbatcher.NewSweepFetcherFromSwapStore( + config.Store, config.LndServices.ChainParams, + ) + require.NoError(t, err) + batcher := sweepbatcher.NewBatcher( config.LndServices.WalletKit, config.LndServices.ChainNotifier, config.LndServices.Signer, mockMuSig2SignSweep, mockVerifySchnorrSigSuccess, config.LndServices.ChainParams, - batcherStore, config.Store, + batcherStore, sweepStore, ) executor := newExecutor(&executorConfig{ @@ -128,7 +133,7 @@ func createClientTestContext(t *testing.T, return expiryChan } - swapClient := newSwapClient(&clientConfig{ + swapClient := newSwapClient(t, &clientConfig{ LndServices: &clientLnd.LndServices, Server: serverMock, Store: store,