2019-03-07 02:22:46 +00:00
|
|
|
package loop
|
2019-03-06 20:13:50 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
"github.com/lightninglabs/loop/loopdb"
|
2019-03-06 23:29:44 +00:00
|
|
|
"github.com/lightninglabs/loop/test"
|
2019-03-06 20:13:50 +00:00
|
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
|
|
)
|
|
|
|
|
|
|
|
// storeMock implements a mock client swap store.
|
|
|
|
type storeMock struct {
|
2019-03-07 04:32:24 +00:00
|
|
|
loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract
|
2019-05-15 11:55:41 +00:00
|
|
|
loopOutUpdates map[lntypes.Hash][]loopdb.SwapStateData
|
2019-03-07 04:32:24 +00:00
|
|
|
loopOutStoreChan chan loopdb.LoopOutContract
|
2019-05-15 11:55:41 +00:00
|
|
|
loopOutUpdateChan chan loopdb.SwapStateData
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract
|
2019-05-15 11:55:41 +00:00
|
|
|
loopInUpdates map[lntypes.Hash][]loopdb.SwapStateData
|
2019-03-12 15:09:57 +00:00
|
|
|
loopInStoreChan chan loopdb.LoopInContract
|
2019-05-15 11:55:41 +00:00
|
|
|
loopInUpdateChan chan loopdb.SwapStateData
|
2019-03-12 15:09:57 +00:00
|
|
|
|
2019-03-06 20:13:50 +00:00
|
|
|
t *testing.T
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewStoreMock instantiates a new mock store.
|
|
|
|
func newStoreMock(t *testing.T) *storeMock {
|
|
|
|
return &storeMock{
|
2019-03-07 04:32:24 +00:00
|
|
|
loopOutStoreChan: make(chan loopdb.LoopOutContract, 1),
|
2019-05-15 11:55:41 +00:00
|
|
|
loopOutUpdateChan: make(chan loopdb.SwapStateData, 1),
|
2019-03-07 04:32:24 +00:00
|
|
|
loopOutSwaps: make(map[lntypes.Hash]*loopdb.LoopOutContract),
|
2019-05-15 11:55:41 +00:00
|
|
|
loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
loopInStoreChan: make(chan loopdb.LoopInContract, 1),
|
2019-05-15 11:55:41 +00:00
|
|
|
loopInUpdateChan: make(chan loopdb.SwapStateData, 1),
|
2019-03-12 15:09:57 +00:00
|
|
|
loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract),
|
2019-05-15 11:55:41 +00:00
|
|
|
loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
|
2019-03-12 15:09:57 +00:00
|
|
|
t: t,
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
// FetchLoopOutSwaps returns all swaps currently in the store.
|
|
|
|
//
|
|
|
|
// NOTE: Part of the loopdb.SwapStore interface.
|
|
|
|
func (s *storeMock) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) {
|
|
|
|
result := []*loopdb.LoopOut{}
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
for hash, contract := range s.loopOutSwaps {
|
|
|
|
updates := s.loopOutUpdates[hash]
|
2019-03-12 15:09:57 +00:00
|
|
|
events := make([]*loopdb.LoopEvent, len(updates))
|
2019-03-06 20:13:50 +00:00
|
|
|
for i, u := range updates {
|
2019-03-12 15:09:57 +00:00
|
|
|
events[i] = &loopdb.LoopEvent{
|
2019-05-15 11:55:41 +00:00
|
|
|
SwapStateData: u,
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
swap := &loopdb.LoopOut{
|
2019-03-12 15:09:57 +00:00
|
|
|
Loop: loopdb.Loop{
|
|
|
|
Hash: hash,
|
|
|
|
Events: events,
|
|
|
|
},
|
2019-03-06 20:13:50 +00:00
|
|
|
Contract: contract,
|
|
|
|
}
|
|
|
|
result = append(result, swap)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
// CreateLoopOut adds an initiated swap to the store.
|
|
|
|
//
|
|
|
|
// NOTE: Part of the loopdb.SwapStore interface.
|
|
|
|
func (s *storeMock) CreateLoopOut(hash lntypes.Hash,
|
|
|
|
swap *loopdb.LoopOutContract) error {
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
_, ok := s.loopOutSwaps[hash]
|
2019-03-06 20:13:50 +00:00
|
|
|
if ok {
|
|
|
|
return errors.New("swap already exists")
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
s.loopOutSwaps[hash] = swap
|
2019-05-15 11:55:41 +00:00
|
|
|
s.loopOutUpdates[hash] = []loopdb.SwapStateData{}
|
2019-03-07 04:32:24 +00:00
|
|
|
s.loopOutStoreChan <- *swap
|
2019-03-06 20:13:50 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
// FetchLoopInSwaps returns all in swaps currently in the store.
|
|
|
|
func (s *storeMock) FetchLoopInSwaps() ([]*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{
|
2019-05-15 11:55:41 +00:00
|
|
|
SwapStateData: u,
|
2019-03-12 15:09:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(hash lntypes.Hash,
|
|
|
|
swap *loopdb.LoopInContract) error {
|
|
|
|
|
|
|
|
_, ok := s.loopInSwaps[hash]
|
|
|
|
if ok {
|
|
|
|
return errors.New("swap already exists")
|
|
|
|
}
|
|
|
|
|
|
|
|
s.loopInSwaps[hash] = swap
|
2019-05-15 11:55:41 +00:00
|
|
|
s.loopInUpdates[hash] = []loopdb.SwapStateData{}
|
2019-03-12 15:09:57 +00:00
|
|
|
s.loopInStoreChan <- *swap
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
// 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(hash lntypes.Hash, time time.Time,
|
2019-05-15 11:55:41 +00:00
|
|
|
state loopdb.SwapStateData) error {
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
updates, ok := s.loopOutUpdates[hash]
|
2019-03-06 20:13:50 +00:00
|
|
|
if !ok {
|
|
|
|
return errors.New("swap does not exists")
|
|
|
|
}
|
|
|
|
|
|
|
|
updates = append(updates, state)
|
2019-03-07 04:32:24 +00:00
|
|
|
s.loopOutUpdates[hash] = updates
|
|
|
|
s.loopOutUpdateChan <- state
|
2019-03-06 20:13:50 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
// 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(hash lntypes.Hash, time time.Time,
|
2019-05-15 11:55:41 +00:00
|
|
|
state loopdb.SwapStateData) error {
|
2019-03-12 15:09:57 +00:00
|
|
|
|
|
|
|
updates, ok := s.loopInUpdates[hash]
|
|
|
|
if !ok {
|
|
|
|
return errors.New("swap does not exists")
|
|
|
|
}
|
|
|
|
|
|
|
|
updates = append(updates, state)
|
2019-10-01 00:11:32 +00:00
|
|
|
s.loopInUpdates[hash] = updates
|
|
|
|
s.loopInUpdateChan <- state
|
2019-03-12 15:09:57 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
func (s *storeMock) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-06 20:13:50 +00:00
|
|
|
func (s *storeMock) isDone() error {
|
|
|
|
select {
|
2019-03-07 04:32:24 +00:00
|
|
|
case <-s.loopOutStoreChan:
|
2019-03-06 20:13:50 +00:00
|
|
|
return errors.New("storeChan not empty")
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
2019-03-07 04:32:24 +00:00
|
|
|
case <-s.loopOutUpdateChan:
|
2019-03-06 20:13:50 +00:00
|
|
|
return errors.New("updateChan not empty")
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
func (s *storeMock) assertLoopOutStored() {
|
2019-03-06 20:13:50 +00:00
|
|
|
s.t.Helper()
|
|
|
|
|
|
|
|
select {
|
2019-03-07 04:32:24 +00:00
|
|
|
case <-s.loopOutStoreChan:
|
2019-03-06 20:13:50 +00:00
|
|
|
case <-time.After(test.Timeout):
|
|
|
|
s.t.Fatalf("expected swap to be stored")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 15:21:19 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
func (s *storeMock) assertLoopInStored() {
|
|
|
|
s.t.Helper()
|
|
|
|
|
|
|
|
<-s.loopInStoreChan
|
|
|
|
}
|
|
|
|
|
2020-06-25 10:35:22 +00:00
|
|
|
// assertLoopInState asserts that a specified state transition is persisted to
|
|
|
|
// disk.
|
|
|
|
func (s *storeMock) assertLoopInState(
|
|
|
|
expectedState loopdb.SwapState) loopdb.SwapStateData {
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
s.t.Helper()
|
|
|
|
|
2019-10-01 00:11:32 +00:00
|
|
|
state := <-s.loopInUpdateChan
|
2019-05-15 11:55:41 +00:00
|
|
|
if state.State != expectedState {
|
2019-10-01 00:11:32 +00:00
|
|
|
s.t.Fatalf("expected state %v, got %v", expectedState, state)
|
2019-03-12 15:09:57 +00:00
|
|
|
}
|
2020-06-25 10:35:22 +00:00
|
|
|
|
|
|
|
return state
|
2019-03-12 15:09:57 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 20:13:50 +00:00
|
|
|
func (s *storeMock) assertStorePreimageReveal() {
|
|
|
|
|
|
|
|
s.t.Helper()
|
|
|
|
|
|
|
|
select {
|
2019-03-07 04:32:24 +00:00
|
|
|
case state := <-s.loopOutUpdateChan:
|
2019-05-15 11:55:41 +00:00
|
|
|
if state.State != loopdb.StatePreimageRevealed {
|
2019-03-06 20:13:50 +00:00
|
|
|
s.t.Fatalf("unexpected state")
|
|
|
|
}
|
|
|
|
case <-time.After(test.Timeout):
|
|
|
|
s.t.Fatalf("expected swap to be marked as preimage revealed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:32:24 +00:00
|
|
|
func (s *storeMock) assertStoreFinished(expectedResult loopdb.SwapState) {
|
2019-03-06 20:13:50 +00:00
|
|
|
s.t.Helper()
|
|
|
|
|
|
|
|
select {
|
2019-03-07 04:32:24 +00:00
|
|
|
case state := <-s.loopOutUpdateChan:
|
2019-05-15 11:55:41 +00:00
|
|
|
if state.State != expectedResult {
|
2019-03-06 20:13:50 +00:00
|
|
|
s.t.Fatalf("expected result %v, but got %v",
|
|
|
|
expectedResult, state)
|
|
|
|
}
|
|
|
|
case <-time.After(test.Timeout):
|
|
|
|
s.t.Fatalf("expected swap to be finished")
|
|
|
|
}
|
|
|
|
}
|