From e0d85958f74e86551155909f87578110019c1d10 Mon Sep 17 00:00:00 2001 From: George Tsagkarelis Date: Thu, 18 Jan 2024 12:26:07 +0100 Subject: [PATCH] multi: move StoreMock to loopdb --- client_test.go | 4 +- loopdb/store_mock.go | 339 +++++++++++++++++++++++++++++++++++++ loopin_test.go | 40 ++--- loopin_testcontext_test.go | 4 +- loopout_test.go | 42 ++--- server_mock_test.go | 10 ++ store_mock_test.go | 322 ----------------------------------- testcontext_test.go | 16 +- 8 files changed, 402 insertions(+), 375 deletions(-) create mode 100644 loopdb/store_mock.go delete mode 100644 store_mock_test.go diff --git a/client_test.go b/client_test.go index 18c24cc..e9b8641 100644 --- a/client_test.go +++ b/client_test.go @@ -340,13 +340,13 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash, // preimage before sweeping in order for the server to trust us with // our MuSig2 signing attempts. if scriptVersion == swap.HtlcV3 { - ctx.assertPreimagePush(ctx.store.loopOutSwaps[hash].Preimage) + ctx.assertPreimagePush(ctx.store.LoopOutSwaps[hash].Preimage) // Try MuSig2 signing first and fail it so that we go for a // normal sweep. for i := 0; i < maxMusigSweepRetries; i++ { ctx.expiryChan <- testTime - ctx.assertPreimagePush(ctx.store.loopOutSwaps[hash].Preimage) + ctx.assertPreimagePush(ctx.store.LoopOutSwaps[hash].Preimage) } <-ctx.Context.Lnd.SignOutputRawChannel } diff --git a/loopdb/store_mock.go b/loopdb/store_mock.go new file mode 100644 index 0000000..6057e2a --- /dev/null +++ b/loopdb/store_mock.go @@ -0,0 +1,339 @@ +package loopdb + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/lightninglabs/loop/test" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/stretchr/testify/require" +) + +// StoreMock implements a mock client swap store. +type StoreMock struct { + LoopOutSwaps map[lntypes.Hash]*LoopOutContract + LoopOutUpdates map[lntypes.Hash][]SwapStateData + loopOutStoreChan chan LoopOutContract + loopOutUpdateChan chan SwapStateData + + LoopInSwaps map[lntypes.Hash]*LoopInContract + LoopInUpdates map[lntypes.Hash][]SwapStateData + loopInStoreChan chan LoopInContract + loopInUpdateChan chan SwapStateData + + t *testing.T +} + +// NewStoreMock instantiates a new mock store. +func NewStoreMock(t *testing.T) *StoreMock { + return &StoreMock{ + loopOutStoreChan: make(chan LoopOutContract, 1), + loopOutUpdateChan: make(chan SwapStateData, 1), + LoopOutSwaps: make(map[lntypes.Hash]*LoopOutContract), + LoopOutUpdates: make(map[lntypes.Hash][]SwapStateData), + + loopInStoreChan: make(chan LoopInContract, 1), + loopInUpdateChan: make(chan SwapStateData, 1), + LoopInSwaps: make(map[lntypes.Hash]*LoopInContract), + LoopInUpdates: make(map[lntypes.Hash][]SwapStateData), + t: t, + } +} + +// FetchLoopOutSwaps returns all swaps currently in the store. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) FetchLoopOutSwaps(ctx context.Context) ([]*LoopOut, error) { + result := []*LoopOut{} + + for hash, contract := range s.LoopOutSwaps { + updates := s.LoopOutUpdates[hash] + events := make([]*LoopEvent, len(updates)) + for i, u := range updates { + events[i] = &LoopEvent{ + SwapStateData: u, + } + } + + swap := &LoopOut{ + Loop: Loop{ + Hash: hash, + Events: events, + }, + Contract: contract, + } + result = append(result, swap) + } + + return result, nil +} + +// FetchLoopOutSwaps returns all swaps currently in the store. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) FetchLoopOutSwap(ctx context.Context, + hash lntypes.Hash) (*LoopOut, error) { + + contract, ok := s.LoopOutSwaps[hash] + if !ok { + return nil, errors.New("swap not found") + } + + updates := s.LoopOutUpdates[hash] + events := make([]*LoopEvent, len(updates)) + for i, u := range updates { + events[i] = &LoopEvent{ + SwapStateData: u, + } + } + + swap := &LoopOut{ + Loop: Loop{ + Hash: hash, + Events: events, + }, + Contract: contract, + } + + return swap, nil +} + +// CreateLoopOut adds an initiated swap to the store. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) CreateLoopOut(ctx context.Context, hash lntypes.Hash, + swap *LoopOutContract) error { + + _, ok := s.LoopOutSwaps[hash] + if ok { + return errors.New("swap already exists") + } + + s.LoopOutSwaps[hash] = swap + s.LoopOutUpdates[hash] = []SwapStateData{} + s.loopOutStoreChan <- *swap + + return nil +} + +// FetchLoopInSwaps returns all in swaps currently in the store. +func (s *StoreMock) FetchLoopInSwaps(ctx context.Context) ([]*LoopIn, + error) { + + result := []*LoopIn{} + + for hash, contract := range s.LoopInSwaps { + updates := s.LoopInUpdates[hash] + events := make([]*LoopEvent, len(updates)) + for i, u := range updates { + events[i] = &LoopEvent{ + SwapStateData: u, + } + } + + swap := &LoopIn{ + Loop: Loop{ + Hash: hash, + Events: events, + }, + Contract: contract, + } + result = append(result, swap) + } + + return result, nil +} + +// CreateLoopIn adds an initiated loop in swap to the store. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) CreateLoopIn(ctx context.Context, hash lntypes.Hash, + swap *LoopInContract) error { + + _, ok := s.LoopInSwaps[hash] + if ok { + return errors.New("swap already exists") + } + + s.LoopInSwaps[hash] = swap + s.LoopInUpdates[hash] = []SwapStateData{} + s.loopInStoreChan <- *swap + + return nil +} + +// UpdateLoopOut stores a new event for a target loop out swap. This appends to +// the event log for a particular swap as it goes through the various stages in +// its lifetime. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) UpdateLoopOut(ctx context.Context, hash lntypes.Hash, + time time.Time, state SwapStateData) error { + + updates, ok := s.LoopOutUpdates[hash] + if !ok { + return errors.New("swap does not exists") + } + + updates = append(updates, state) + s.LoopOutUpdates[hash] = updates + s.loopOutUpdateChan <- state + + return nil +} + +// UpdateLoopIn stores a new event for a target loop in swap. This appends to +// the event log for a particular swap as it goes through the various stages in +// its lifetime. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) UpdateLoopIn(ctx context.Context, hash lntypes.Hash, + time time.Time, state SwapStateData) error { + + updates, ok := s.LoopInUpdates[hash] + if !ok { + return errors.New("swap does not exists") + } + + updates = append(updates, state) + s.LoopInUpdates[hash] = updates + s.loopInUpdateChan <- state + + return nil +} + +// PutLiquidityParams writes the serialized `manager.Parameters` bytes into the +// bucket. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) PutLiquidityParams(ctx context.Context, + params []byte) error { + + return nil +} + +// FetchLiquidityParams reads the serialized `manager.Parameters` bytes from +// the bucket. +// +// NOTE: Part of the SwapStore interface. +func (s *StoreMock) FetchLiquidityParams(ctx context.Context) ([]byte, error) { + return nil, nil +} + +// Close closes the store. +func (s *StoreMock) Close() error { + return nil +} + +// isDone asserts that the store mock has no pending operations. +func (s *StoreMock) IsDone() error { + select { + case <-s.loopOutStoreChan: + return errors.New("storeChan not empty") + default: + } + + select { + case <-s.loopOutUpdateChan: + return errors.New("updateChan not empty") + default: + } + return nil +} + +// AssertLoopOutStored asserts that a swap is stored. +func (s *StoreMock) AssertLoopOutStored() { + s.t.Helper() + + select { + case <-s.loopOutStoreChan: + case <-time.After(test.Timeout): + s.t.Fatalf("expected swap to be stored") + } +} + +// AssertLoopOutState asserts that a specified state transition is persisted to +// disk. +func (s *StoreMock) AssertLoopOutState(expectedState SwapState) { + s.t.Helper() + + select { + case state := <-s.loopOutUpdateChan: + require.Equal(s.t, expectedState, state.State) + case <-time.After(test.Timeout): + s.t.Fatalf("expected swap state to be stored") + } +} + +// AssertLoopInStored asserts that a loop-in swap is stored. +func (s *StoreMock) AssertLoopInStored() { + s.t.Helper() + + select { + case <-s.loopInStoreChan: + case <-time.After(test.Timeout): + s.t.Fatalf("expected swap to be stored") + } +} + +// assertLoopInState asserts that a specified state transition is persisted to +// disk. +func (s *StoreMock) AssertLoopInState( + expectedState SwapState) SwapStateData { + + s.t.Helper() + + state := <-s.loopInUpdateChan + require.Equal(s.t, expectedState, state.State) + + return state +} + +// AssertStorePreimageReveal asserts that a swap is marked as preimage revealed. +func (s *StoreMock) AssertStorePreimageReveal() { + s.t.Helper() + + select { + case state := <-s.loopOutUpdateChan: + require.Equal(s.t, StatePreimageRevealed, state.State) + + case <-time.After(test.Timeout): + s.t.Fatalf("expected swap to be marked as preimage revealed") + } +} + +// AssertStoreFinished asserts that a swap is marked as finished. +func (s *StoreMock) AssertStoreFinished(expectedResult SwapState) { + s.t.Helper() + + select { + case state := <-s.loopOutUpdateChan: + require.Equal(s.t, expectedResult, state.State) + + case <-time.After(test.Timeout): + s.t.Fatalf("expected swap to be finished") + } +} + +// BatchCreateLoopOut creates many loop out swaps in a batch. +func (b *StoreMock) BatchCreateLoopOut(ctx context.Context, + swaps map[lntypes.Hash]*LoopOutContract) error { + + return errors.New("not implemented") +} + +// BatchCreateLoopIn creates many loop in swaps in a batch. +func (b *StoreMock) BatchCreateLoopIn(ctx context.Context, + swaps map[lntypes.Hash]*LoopInContract) error { + + return errors.New("not implemented") +} + +// BatchInsertUpdate inserts many updates for a swap in a batch. +func (b *StoreMock) BatchInsertUpdate(ctx context.Context, + updateData map[lntypes.Hash][]BatchInsertUpdateData) error { + + return errors.New("not implemented") +} diff --git a/loopin_test.go b/loopin_test.go index b648d8c..7c27abe 100644 --- a/loopin_test.go +++ b/loopin_test.go @@ -61,7 +61,7 @@ func testLoopInSuccess(t *testing.T) { inSwap := initResult.swap - ctx.store.assertLoopInStored() + ctx.store.AssertLoopInStored() errChan := make(chan error) go func() { @@ -82,7 +82,7 @@ func testLoopInSuccess(t *testing.T) { require.Nil(t, swapInfo.OutgoingChanSet) ctx.assertState(loopdb.StateHtlcPublished) - ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) // Expect htlc to be published. htlcTx := <-ctx.lnd.SendOutputsChannel @@ -95,7 +95,7 @@ func testLoopInSuccess(t *testing.T) { // Expect the same state to be written again with the htlc tx hash // and on chain fee. - state := ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + state := ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) require.NotNil(t, state.HtlcTxHash) require.Equal(t, cost, state.Cost) @@ -119,7 +119,7 @@ func testLoopInSuccess(t *testing.T) { // Swap is expected to move to the state InvoiceSettled ctx.assertState(loopdb.StateInvoiceSettled) - ctx.store.assertLoopInState(loopdb.StateInvoiceSettled) + ctx.store.AssertLoopInState(loopdb.StateInvoiceSettled) // Server spends htlc. successTx := wire.MsgTx{} @@ -138,7 +138,7 @@ func testLoopInSuccess(t *testing.T) { } ctx.assertState(loopdb.StateSuccess) - ctx.store.assertLoopInState(loopdb.StateSuccess) + ctx.store.AssertLoopInState(loopdb.StateSuccess) require.NoError(t, <-errChan) } @@ -213,7 +213,7 @@ func testLoopInTimeout(t *testing.T, externalValue int64) { require.NoError(t, err) inSwap := initResult.swap - ctx.store.assertLoopInStored() + ctx.store.AssertLoopInStored() errChan := make(chan error) go func() { @@ -227,7 +227,7 @@ func testLoopInTimeout(t *testing.T, externalValue int64) { ctx.assertState(loopdb.StateInitiated) ctx.assertState(loopdb.StateHtlcPublished) - ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) var ( htlcTx wire.MsgTx @@ -246,7 +246,7 @@ func testLoopInTimeout(t *testing.T, externalValue int64) { // Expect the same state to be written again with the htlc tx // hash and cost. - state := ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + state := ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) require.NotNil(t, state.HtlcTxHash) require.Equal(t, cost, state.Cost) } else { @@ -280,7 +280,7 @@ func testLoopInTimeout(t *testing.T, externalValue int64) { invalidAmt := externalValue != 0 && externalValue != int64(req.Amount) if invalidAmt { ctx.assertState(loopdb.StateFailIncorrectHtlcAmt) - ctx.store.assertLoopInState(loopdb.StateFailIncorrectHtlcAmt) + ctx.store.AssertLoopInState(loopdb.StateFailIncorrectHtlcAmt) require.NoError(t, <-errChan) return @@ -329,7 +329,7 @@ func testLoopInTimeout(t *testing.T, externalValue int64) { ctx.updateInvoiceState(0, invpkg.ContractCanceled) ctx.assertState(loopdb.StateFailTimeout) - state := ctx.store.assertLoopInState(loopdb.StateFailTimeout) + state := ctx.store.AssertLoopInState(loopdb.StateFailTimeout) require.Equal(t, cost, state.Cost) require.NoError(t, <-errChan) @@ -503,7 +503,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, } ctx.assertState(loopdb.StateHtlcPublished) - ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) // Expect htlc to be published. htlcTx = <-ctx.lnd.SendOutputsChannel @@ -515,7 +515,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, // Expect the same state to be written again with the htlc tx // hash. - state := ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + state := ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) require.NotNil(t, state.HtlcTxHash) } else { ctx.assertState(loopdb.StateHtlcPublished) @@ -547,7 +547,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, // Swap is expected to move to the state InvoiceSettled ctx.assertState(loopdb.StateInvoiceSettled) - ctx.store.assertLoopInState(loopdb.StateInvoiceSettled) + ctx.store.AssertLoopInState(loopdb.StateInvoiceSettled) // Server spends htlc. successTx := wire.MsgTx{} @@ -566,7 +566,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, } ctx.assertState(loopdb.StateSuccess) - finalState := ctx.store.assertLoopInState(loopdb.StateSuccess) + finalState := ctx.store.AssertLoopInState(loopdb.StateSuccess) // We expect our server fee to reflect as the difference between htlc // value and invoice amount paid. We use our original on-chain cost, set @@ -597,7 +597,7 @@ func TestAbandonPublishedHtlcState(t *testing.T) { // Ensure that the swap is also in the StateFailAbandoned state in the // database. - ctx.store.assertLoopInState(loopdb.StateFailAbandoned) + ctx.store.AssertLoopInState(loopdb.StateFailAbandoned) // Ensure that the swap was abandoned and the execution stopped. err = <-ctx.errChan @@ -668,7 +668,7 @@ func TestAbandonSettledInvoiceState(t *testing.T) { // Swap is expected to move to the state InvoiceSettled ctx.assertState(loopdb.StateInvoiceSettled) - ctx.store.assertLoopInState(loopdb.StateInvoiceSettled) + ctx.store.AssertLoopInState(loopdb.StateInvoiceSettled) // The client requests to abandon the published htlc state. inSwap.abandonChan <- struct{}{} @@ -678,7 +678,7 @@ func TestAbandonSettledInvoiceState(t *testing.T) { // Ensure that the swap is also in the StateFailAbandoned state in the // database. - ctx.store.assertLoopInState(loopdb.StateFailAbandoned) + ctx.store.AssertLoopInState(loopdb.StateFailAbandoned) // Ensure that the swap was abandoned and the execution stopped. err = <-ctx.errChan @@ -728,14 +728,14 @@ func advanceToPublishedHtlc(t *testing.T, ctx *loopInTestContext) SwapInfo { require.Equal(t, loopdb.StateInitiated, swapInfo.State) ctx.assertState(loopdb.StateHtlcPublished) - ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) // Expect htlc to be published. htlcTx := <-ctx.lnd.SendOutputsChannel // Expect the same state to be written again with the htlc tx hash // and on chain fee. - ctx.store.assertLoopInState(loopdb.StateHtlcPublished) + ctx.store.AssertLoopInState(loopdb.StateHtlcPublished) // Expect register for htlc conf (only one, since the htlc is p2tr). <-ctx.lnd.RegisterConfChannel @@ -765,7 +765,7 @@ func startNewLoopIn(t *testing.T, ctx *loopInTestContext, height int32) ( inSwap := initResult.swap - ctx.store.assertLoopInStored() + ctx.store.AssertLoopInStored() go func() { err := inSwap.execute(context.Background(), ctx.cfg, height) diff --git a/loopin_testcontext_test.go b/loopin_testcontext_test.go index 6bf0ad1..cc48990 100644 --- a/loopin_testcontext_test.go +++ b/loopin_testcontext_test.go @@ -18,7 +18,7 @@ type loopInTestContext struct { t *testing.T lnd *test.LndMockServices server *serverMock - store *storeMock + store *loopdb.StoreMock sweeper *sweep.Sweeper cfg *executeConfig statusChan chan SwapInfo @@ -31,7 +31,7 @@ type loopInTestContext struct { func newLoopInTestContext(t *testing.T) *loopInTestContext { lnd := test.NewMockLnd() server := newServerMock(lnd) - store := newStoreMock(t) + store := loopdb.NewStoreMock(t) sweeper := sweep.Sweeper{Lnd: &lnd.LndServices} blockEpochChan := make(chan interface{}) diff --git a/loopout_test.go b/loopout_test.go index 37a7458..e05919e 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -45,7 +45,7 @@ func testLoopOutPaymentParameters(t *testing.T) { lnd := test.NewMockLnd() ctx := test.NewContext(t, lnd) server := newServerMock(lnd) - store := newStoreMock(t) + store := loopdb.NewStoreMock(t) expiryChan := make(chan time.Time) timerFactory := func(_ time.Duration) <-chan time.Time { @@ -99,7 +99,7 @@ func testLoopOutPaymentParameters(t *testing.T) { errChan <- err }() - store.assertLoopOutStored() + store.AssertLoopOutStored() state := <-statusChan require.Equal(t, loopdb.StateInitiated, state.State) @@ -168,7 +168,7 @@ func testLateHtlcPublish(t *testing.T) { server := newServerMock(lnd) - store := newStoreMock(t) + store := loopdb.NewStoreMock(t) expiryChan := make(chan time.Time) timerFactory := func(expiry time.Duration) <-chan time.Time { @@ -208,7 +208,7 @@ func testLateHtlcPublish(t *testing.T) { errChan <- err }() - store.assertLoopOutStored() + store.AssertLoopOutStored() status := <-statusChan require.Equal(t, loopdb.StateInitiated, status.State) @@ -228,7 +228,7 @@ func testLateHtlcPublish(t *testing.T) { errors.New(lndclient.PaymentResultUnknownPaymentHash), ) - store.assertStoreFinished(loopdb.StateFailTimeout) + store.AssertStoreFinished(loopdb.StateFailTimeout) status = <-statusChan require.Equal(t, loopdb.StateFailTimeout, status.State) @@ -273,7 +273,7 @@ func testCustomSweepConfTarget(t *testing.T) { ctx.Lnd.SetFeeEstimate(DefaultSweepConfTarget, 10000) cfg := newSwapConfig( - &lnd.LndServices, newStoreMock(t), server, + &lnd.LndServices, loopdb.NewStoreMock(t), server, ) initResult, err := newLoopOutSwap( @@ -310,7 +310,7 @@ func testCustomSweepConfTarget(t *testing.T) { }() // The swap should be found in its initial state. - cfg.store.(*storeMock).assertLoopOutStored() + cfg.store.(*loopdb.StoreMock).AssertLoopOutStored() state := <-statusChan require.Equal(t, loopdb.StateInitiated, state.State) @@ -350,7 +350,7 @@ func testCustomSweepConfTarget(t *testing.T) { <-ctx.Lnd.SignOutputRawChannel } - cfg.store.(*storeMock).assertLoopOutState(loopdb.StatePreimageRevealed) + cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StatePreimageRevealed) status := <-statusChan require.Equal(t, loopdb.StatePreimageRevealed, status.State) @@ -443,7 +443,7 @@ func testCustomSweepConfTarget(t *testing.T) { // Notify the spend so that the swap reaches its final state. ctx.NotifySpend(sweepTx, 0) - cfg.store.(*storeMock).assertLoopOutState(loopdb.StateSuccess) + cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess) status = <-statusChan require.Equal(t, loopdb.StateSuccess, status.State) require.NoError(t, <-errChan) @@ -493,7 +493,7 @@ func testPreimagePush(t *testing.T) { ) cfg := newSwapConfig( - &lnd.LndServices, newStoreMock(t), server, + &lnd.LndServices, loopdb.NewStoreMock(t), server, ) initResult, err := newLoopOutSwap( @@ -528,7 +528,7 @@ func testPreimagePush(t *testing.T) { }() // The swap should be found in its initial state. - cfg.store.(*storeMock).assertLoopOutStored() + cfg.store.(*loopdb.StoreMock).AssertLoopOutStored() state := <-statusChan require.Equal(t, loopdb.StateInitiated, state.State) @@ -571,7 +571,7 @@ func testPreimagePush(t *testing.T) { // preimage before sweeping in order for the server to trust us with // our MuSig2 signing attempts. if IsTaprootSwap(&swap.SwapContract) { - cfg.store.(*storeMock).assertLoopOutState( + cfg.store.(*loopdb.StoreMock).AssertLoopOutState( loopdb.StatePreimageRevealed, ) status := <-statusChan @@ -624,7 +624,7 @@ func testPreimagePush(t *testing.T) { if !IsTaprootSwap(&swap.SwapContract) { // This is the first time we have swept, so we expect our // preimage revealed state to be set. - cfg.store.(*storeMock).assertLoopOutState( + cfg.store.(*loopdb.StoreMock).AssertLoopOutState( loopdb.StatePreimageRevealed, ) status := <-statusChan @@ -685,7 +685,7 @@ func testPreimagePush(t *testing.T) { // spend our sweepTx and assert that the swap succeeds. ctx.NotifySpend(sweepTx, 0) - cfg.store.(*storeMock).assertLoopOutState(loopdb.StateSuccess) + cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess) status := <-statusChan require.Equal( t, status.State, loopdb.StateSuccess, @@ -720,7 +720,7 @@ func testFailedOffChainCancelation(t *testing.T) { testReq.Expiry = lnd.Height + 20 cfg := newSwapConfig( - &lnd.LndServices, newStoreMock(t), server, + &lnd.LndServices, loopdb.NewStoreMock(t), server, ) initResult, err := newLoopOutSwap( @@ -754,7 +754,7 @@ func testFailedOffChainCancelation(t *testing.T) { }() // The swap should be found in its initial state. - cfg.store.(*storeMock).assertLoopOutStored() + cfg.store.(*loopdb.StoreMock).AssertLoopOutStored() state := <-statusChan require.Equal(t, loopdb.StateInitiated, state.State) @@ -837,7 +837,7 @@ func testFailedOffChainCancelation(t *testing.T) { server.assertSwapCanceled(t, swapCancelation) // Finally, the swap should be recorded with failed off chain timeout. - cfg.store.(*storeMock).assertLoopOutState( + cfg.store.(*loopdb.StoreMock).AssertLoopOutState( loopdb.StateFailOffchainPayments, ) state = <-statusChan @@ -874,7 +874,7 @@ func TestLoopOutMuSig2Sweep(t *testing.T) { ) cfg := newSwapConfig( - &lnd.LndServices, newStoreMock(t), server, + &lnd.LndServices, loopdb.NewStoreMock(t), server, ) initResult, err := newLoopOutSwap( @@ -918,7 +918,7 @@ func TestLoopOutMuSig2Sweep(t *testing.T) { }() // The swap should be found in its initial state. - cfg.store.(*storeMock).assertLoopOutStored() + cfg.store.(*loopdb.StoreMock).AssertLoopOutStored() state := <-statusChan require.Equal(t, loopdb.StateInitiated, state.State) @@ -960,7 +960,7 @@ func TestLoopOutMuSig2Sweep(t *testing.T) { // When using taproot htlcs the flow is different as we do reveal the // preimage before sweeping in order for the server to trust us with // our MuSig2 signing attempts. - cfg.store.(*storeMock).assertLoopOutState( + cfg.store.(*loopdb.StoreMock).AssertLoopOutState( loopdb.StatePreimageRevealed, ) status := <-statusChan @@ -1010,7 +1010,7 @@ func TestLoopOutMuSig2Sweep(t *testing.T) { // spend our sweepTx and assert that the swap succeeds. ctx.NotifySpend(sweepTx, 0) - cfg.store.(*storeMock).assertLoopOutState(loopdb.StateSuccess) + cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess) status = <-statusChan require.Equal(t, status.State, loopdb.StateSuccess) require.NoError(t, <-errChan) diff --git a/server_mock_test.go b/server_mock_test.go index 78a8528..9f52a2c 100644 --- a/server_mock_test.go +++ b/server_mock_test.go @@ -8,6 +8,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/test" @@ -268,6 +269,15 @@ func (s *serverMock) MuSig2SignSweep(_ context.Context, _ loopdb.ProtocolVersion return nil, nil, nil } +func (s *serverMock) MultiMuSig2SignSweep(ctx context.Context, + protocolVersion loopdb.ProtocolVersion, swapHash lntypes.Hash, + paymentAddr [32]byte, nonce []byte, sweepTxPsbt []byte, + prevoutMap map[wire.OutPoint]*wire.TxOut) ( + []byte, []byte, error) { + + return nil, nil, nil +} + func (s *serverMock) PushKey(_ context.Context, _ loopdb.ProtocolVersion, _ lntypes.Hash, _ [32]byte) error { diff --git a/store_mock_test.go b/store_mock_test.go deleted file mode 100644 index 06c134d..0000000 --- a/store_mock_test.go +++ /dev/null @@ -1,322 +0,0 @@ -package loop - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/lightninglabs/loop/loopdb" - "github.com/lightninglabs/loop/test" - "github.com/lightningnetwork/lnd/lntypes" - "github.com/stretchr/testify/require" -) - -// storeMock implements a mock client swap store. -type storeMock struct { - loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract - loopOutUpdates map[lntypes.Hash][]loopdb.SwapStateData - loopOutStoreChan chan loopdb.LoopOutContract - loopOutUpdateChan chan loopdb.SwapStateData - - loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract - loopInUpdates map[lntypes.Hash][]loopdb.SwapStateData - loopInStoreChan chan loopdb.LoopInContract - loopInUpdateChan chan loopdb.SwapStateData - - t *testing.T -} - -// NewStoreMock instantiates a new mock store. -func newStoreMock(t *testing.T) *storeMock { - return &storeMock{ - loopOutStoreChan: make(chan loopdb.LoopOutContract, 1), - loopOutUpdateChan: make(chan loopdb.SwapStateData, 1), - loopOutSwaps: make(map[lntypes.Hash]*loopdb.LoopOutContract), - loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData), - - loopInStoreChan: make(chan loopdb.LoopInContract, 1), - loopInUpdateChan: make(chan loopdb.SwapStateData, 1), - loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract), - loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData), - t: t, - } -} - -// FetchLoopOutSwaps returns all swaps currently in the store. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) FetchLoopOutSwaps(ctx context.Context) ([]*loopdb.LoopOut, error) { - result := []*loopdb.LoopOut{} - - for hash, contract := range s.loopOutSwaps { - updates := s.loopOutUpdates[hash] - events := make([]*loopdb.LoopEvent, len(updates)) - for i, u := range updates { - events[i] = &loopdb.LoopEvent{ - SwapStateData: u, - } - } - - swap := &loopdb.LoopOut{ - Loop: loopdb.Loop{ - Hash: hash, - Events: events, - }, - Contract: contract, - } - result = append(result, swap) - } - - return result, nil -} - -// FetchLoopOutSwaps returns all swaps currently in the store. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) FetchLoopOutSwap(ctx context.Context, - hash lntypes.Hash) (*loopdb.LoopOut, error) { - - contract, ok := s.loopOutSwaps[hash] - if !ok { - return nil, errors.New("swap not found") - } - - updates := s.loopOutUpdates[hash] - events := make([]*loopdb.LoopEvent, len(updates)) - for i, u := range updates { - events[i] = &loopdb.LoopEvent{ - SwapStateData: u, - } - } - - swap := &loopdb.LoopOut{ - Loop: loopdb.Loop{ - Hash: hash, - Events: events, - }, - Contract: contract, - } - - return swap, nil -} - -// CreateLoopOut adds an initiated swap to the store. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) CreateLoopOut(ctx context.Context, hash lntypes.Hash, - swap *loopdb.LoopOutContract) error { - - _, ok := s.loopOutSwaps[hash] - if ok { - return errors.New("swap already exists") - } - - s.loopOutSwaps[hash] = swap - s.loopOutUpdates[hash] = []loopdb.SwapStateData{} - s.loopOutStoreChan <- *swap - - return nil -} - -// FetchLoopInSwaps returns all in swaps currently in the store. -func (s *storeMock) FetchLoopInSwaps(ctx context.Context) ([]*loopdb.LoopIn, - error) { - - result := []*loopdb.LoopIn{} - - for hash, contract := range s.loopInSwaps { - updates := s.loopInUpdates[hash] - events := make([]*loopdb.LoopEvent, len(updates)) - for i, u := range updates { - events[i] = &loopdb.LoopEvent{ - SwapStateData: u, - } - } - - swap := &loopdb.LoopIn{ - Loop: loopdb.Loop{ - Hash: hash, - Events: events, - }, - Contract: contract, - } - result = append(result, swap) - } - - return result, nil -} - -// CreateLoopIn adds an initiated loop in swap to the store. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) CreateLoopIn(ctx context.Context, hash lntypes.Hash, - swap *loopdb.LoopInContract) error { - - _, ok := s.loopInSwaps[hash] - if ok { - return errors.New("swap already exists") - } - - s.loopInSwaps[hash] = swap - s.loopInUpdates[hash] = []loopdb.SwapStateData{} - s.loopInStoreChan <- *swap - - return nil -} - -// UpdateLoopOut stores a new event for a target loop out swap. This appends to -// the event log for a particular swap as it goes through the various stages in -// its lifetime. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) UpdateLoopOut(ctx context.Context, hash lntypes.Hash, - time time.Time, state loopdb.SwapStateData) error { - - updates, ok := s.loopOutUpdates[hash] - if !ok { - return errors.New("swap does not exists") - } - - updates = append(updates, state) - s.loopOutUpdates[hash] = updates - s.loopOutUpdateChan <- state - - return nil -} - -// UpdateLoopIn stores a new event for a target loop in swap. This appends to -// the event log for a particular swap as it goes through the various stages in -// its lifetime. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) UpdateLoopIn(ctx context.Context, hash lntypes.Hash, - time time.Time, state loopdb.SwapStateData) error { - - updates, ok := s.loopInUpdates[hash] - if !ok { - return errors.New("swap does not exists") - } - - updates = append(updates, state) - s.loopInUpdates[hash] = updates - s.loopInUpdateChan <- state - - return nil -} - -// PutLiquidityParams writes the serialized `manager.Parameters` bytes into the -// bucket. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) PutLiquidityParams(ctx context.Context, - params []byte) error { - - return nil -} - -// FetchLiquidityParams reads the serialized `manager.Parameters` bytes from -// the bucket. -// -// NOTE: Part of the loopdb.SwapStore interface. -func (s *storeMock) FetchLiquidityParams(ctx context.Context) ([]byte, error) { - return nil, nil -} - -func (s *storeMock) Close() error { - return nil -} - -func (s *storeMock) isDone() error { - select { - case <-s.loopOutStoreChan: - return errors.New("storeChan not empty") - default: - } - - select { - case <-s.loopOutUpdateChan: - return errors.New("updateChan not empty") - default: - } - return nil -} - -func (s *storeMock) assertLoopOutStored() { - s.t.Helper() - - select { - case <-s.loopOutStoreChan: - case <-time.After(test.Timeout): - s.t.Fatalf("expected swap to be stored") - } -} - -func (s *storeMock) assertLoopOutState(expectedState loopdb.SwapState) { - s.t.Helper() - - state := <-s.loopOutUpdateChan - if state.State != expectedState { - s.t.Fatalf("expected state %v, got %v", expectedState, state) - } -} - -func (s *storeMock) assertLoopInStored() { - s.t.Helper() - - <-s.loopInStoreChan -} - -// assertLoopInState asserts that a specified state transition is persisted to -// disk. -func (s *storeMock) assertLoopInState( - expectedState loopdb.SwapState) loopdb.SwapStateData { - - s.t.Helper() - - state := <-s.loopInUpdateChan - require.Equal(s.t, expectedState, state.State) - - return state -} - -func (s *storeMock) assertStorePreimageReveal() { - s.t.Helper() - - select { - case state := <-s.loopOutUpdateChan: - require.Equal(s.t, loopdb.StatePreimageRevealed, state.State) - - case <-time.After(test.Timeout): - s.t.Fatalf("expected swap to be marked as preimage revealed") - } -} - -func (s *storeMock) assertStoreFinished(expectedResult loopdb.SwapState) { - s.t.Helper() - - select { - case state := <-s.loopOutUpdateChan: - require.Equal(s.t, expectedResult, state.State) - - case <-time.After(test.Timeout): - s.t.Fatalf("expected swap to be finished") - } -} -func (b *storeMock) BatchCreateLoopOut(ctx context.Context, - swaps map[lntypes.Hash]*loopdb.LoopOutContract) error { - - return errors.New("not implemented") -} - -func (b *storeMock) BatchCreateLoopIn(ctx context.Context, - swaps map[lntypes.Hash]*loopdb.LoopInContract) error { - - return errors.New("not implemented") -} - -func (b *storeMock) BatchInsertUpdate(ctx context.Context, - updateData map[lntypes.Hash][]loopdb.BatchInsertUpdateData) error { - - return errors.New("not implemented") -} diff --git a/testcontext_test.go b/testcontext_test.go index e465037..71f0ade 100644 --- a/testcontext_test.go +++ b/testcontext_test.go @@ -36,7 +36,7 @@ type testContext struct { serverMock *serverMock swapClient *Client statusChan chan SwapInfo - store *storeMock + store *loopdb.StoreMock expiryChan chan time.Time runErr chan error stop func() @@ -83,15 +83,15 @@ func createClientTestContext(t *testing.T, clientLnd := test.NewMockLnd() serverMock := newServerMock(clientLnd) - store := newStoreMock(t) + store := loopdb.NewStoreMock(t) for _, s := range pendingSwaps { - store.loopOutSwaps[s.Hash] = s.Contract + store.LoopOutSwaps[s.Hash] = s.Contract updates := []loopdb.SwapStateData{} for _, e := range s.Events { updates = append(updates, e.SwapStateData) } - store.loopOutUpdates[s.Hash] = updates + store.LoopOutUpdates[s.Hash] = updates } expiryChan := make(chan time.Time) @@ -147,7 +147,7 @@ func (ctx *testContext) finish() { } func (ctx *testContext) assertIsDone() { require.NoError(ctx.Context.T, ctx.Context.Lnd.IsDone()) - require.NoError(ctx.Context.T, ctx.store.isDone()) + require.NoError(ctx.Context.T, ctx.store.IsDone()) select { case <-ctx.statusChan: @@ -159,19 +159,19 @@ func (ctx *testContext) assertIsDone() { func (ctx *testContext) assertStored() { ctx.Context.T.Helper() - ctx.store.assertLoopOutStored() + ctx.store.AssertLoopOutStored() } func (ctx *testContext) assertStorePreimageReveal() { ctx.Context.T.Helper() - ctx.store.assertStorePreimageReveal() + ctx.store.AssertStorePreimageReveal() } func (ctx *testContext) assertStoreFinished(expectedResult loopdb.SwapState) { ctx.Context.T.Helper() - ctx.store.assertStoreFinished(expectedResult) + ctx.store.AssertStoreFinished(expectedResult) } func (ctx *testContext) assertStatus(expectedState loopdb.SwapState) {