2
0
mirror of https://github.com/lightninglabs/loop synced 2024-11-04 06:00:21 +00:00

multi: move StoreMock to loopdb

This commit is contained in:
George Tsagkarelis 2024-01-18 12:26:07 +01:00
parent 99608ad515
commit e0d85958f7
No known key found for this signature in database
GPG Key ID: E08DEA9B12B66AF6
8 changed files with 402 additions and 375 deletions

View File

@ -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
}

339
loopdb/store_mock.go Normal file
View File

@ -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")
}

View File

@ -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)

View File

@ -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{})

View File

@ -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)

View File

@ -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 {

View File

@ -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")
}

View File

@ -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) {