loopdb: replace swap state enum by state data object

This commits lays down the foundation in the database for adding more
persistent state data to swaps.
pull/55/head
Joost Jager 5 years ago
parent eece3adad1
commit 1b306ad425
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7

@ -138,12 +138,12 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
} }
swaps = append(swaps, &SwapInfo{ swaps = append(swaps, &SwapInfo{
SwapType: TypeOut, SwapType: TypeOut,
SwapContract: swp.Contract.SwapContract, SwapContract: swp.Contract.SwapContract,
State: swp.State(), SwapStateData: swp.State(),
SwapHash: swp.Hash, SwapHash: swp.Hash,
LastUpdate: swp.LastUpdateTime(), LastUpdate: swp.LastUpdateTime(),
HtlcAddress: htlc.Address, HtlcAddress: htlc.Address,
}) })
} }
@ -158,12 +158,12 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
} }
swaps = append(swaps, &SwapInfo{ swaps = append(swaps, &SwapInfo{
SwapType: TypeIn, SwapType: TypeIn,
SwapContract: swp.Contract.SwapContract, SwapContract: swp.Contract.SwapContract,
State: swp.State(), SwapStateData: swp.State(),
SwapHash: swp.Hash, SwapHash: swp.Hash,
LastUpdate: swp.LastUpdateTime(), LastUpdate: swp.LastUpdateTime(),
HtlcAddress: htlc.Address, HtlcAddress: htlc.Address,
}) })
} }
@ -259,7 +259,7 @@ func (s *Client) resumeSwaps(ctx context.Context,
} }
for _, pend := range loopOutSwaps { for _, pend := range loopOutSwaps {
if pend.State().Type() != loopdb.StateTypePending { if pend.State().State.Type() != loopdb.StateTypePending {
continue continue
} }
swap, err := resumeLoopOutSwap(ctx, swapCfg, pend) swap, err := resumeLoopOutSwap(ctx, swapCfg, pend)
@ -272,7 +272,7 @@ func (s *Client) resumeSwaps(ctx context.Context,
} }
for _, pend := range loopInSwaps { for _, pend := range loopInSwaps {
if pend.State().Type() != loopdb.StateTypePending { if pend.State().State.Type() != loopdb.StateTypePending {
continue continue
} }
swap, err := resumeLoopInSwap(ctx, swapCfg, pend) swap, err := resumeLoopInSwap(ctx, swapCfg, pend)

@ -202,7 +202,9 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
Loop: loopdb.Loop{ Loop: loopdb.Loop{
Events: []*loopdb.LoopEvent{ Events: []*loopdb.LoopEvent{
{ {
State: state, SwapStateData: loopdb.SwapStateData{
State: state,
},
}, },
}, },
Hash: hash, Hash: hash,

@ -280,12 +280,12 @@ func (t Type) String() string {
// SwapInfo exposes common info fields for loop in and loop out swaps. // SwapInfo exposes common info fields for loop in and loop out swaps.
type SwapInfo struct { type SwapInfo struct {
loopdb.SwapStateData
LastUpdate time.Time LastUpdate time.Time
SwapHash lntypes.Hash SwapHash lntypes.Hash
State loopdb.SwapState
SwapType Type SwapType Type
loopdb.SwapContract loopdb.SwapContract

@ -18,7 +18,8 @@ type SwapStore interface {
// UpdateLoopOut stores a new event for a target loop out swap. This // 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 // appends to the event log for a particular swap as it goes through
// the various stages in its lifetime. // the various stages in its lifetime.
UpdateLoopOut(hash lntypes.Hash, time time.Time, state SwapState) error UpdateLoopOut(hash lntypes.Hash, time time.Time,
state SwapStateData) error
// FetchLoopInSwaps returns all swaps currently in the store. // FetchLoopInSwaps returns all swaps currently in the store.
FetchLoopInSwaps() ([]*LoopIn, error) FetchLoopInSwaps() ([]*LoopIn, error)
@ -29,7 +30,8 @@ type SwapStore interface {
// UpdateLoopIn stores a new event for a target loop in swap. This // 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 // appends to the event log for a particular swap as it goes through
// the various stages in its lifetime. // the various stages in its lifetime.
UpdateLoopIn(hash lntypes.Hash, time time.Time, state SwapState) error UpdateLoopIn(hash lntypes.Hash, time time.Time,
state SwapStateData) error
// Close closes the underlying database. // Close closes the underlying database.
Close() error Close() error

@ -53,21 +53,22 @@ type Loop struct {
// LoopEvent contains the dynamic data of a swap. // LoopEvent contains the dynamic data of a swap.
type LoopEvent struct { type LoopEvent struct {
// State is the new state for this swap as a result of this event. SwapStateData
State SwapState
// Time is the time that this swap had its state changed. // Time is the time that this swap had its state changed.
Time time.Time Time time.Time
} }
// State returns the most recent state of this swap. // State returns the most recent state of this swap.
func (s *Loop) State() SwapState { func (s *Loop) State() SwapStateData {
lastUpdate := s.LastUpdate() lastUpdate := s.LastUpdate()
if lastUpdate == nil { if lastUpdate == nil {
return StateInitiated return SwapStateData{
State: StateInitiated,
}
} }
return lastUpdate.State return lastUpdate.SwapStateData
} }
// LastUpdate returns the most recent update of this swap. // LastUpdate returns the most recent update of this swap.
@ -84,7 +85,7 @@ func (s *Loop) LastUpdate() *LoopEvent {
// serializeLoopEvent serializes a state update of a swap. This is used for both // serializeLoopEvent serializes a state update of a swap. This is used for both
// in and out swaps. // in and out swaps.
func serializeLoopEvent(time time.Time, state SwapState) ( func serializeLoopEvent(time time.Time, state SwapStateData) (
[]byte, error) { []byte, error) {
var b bytes.Buffer var b bytes.Buffer

@ -346,7 +346,7 @@ func (s *boltSwapStore) CreateLoopIn(hash lntypes.Hash,
// updateLoop saves a new swap state transition to the store. It takes in a // updateLoop saves a new swap state transition to the store. It takes in a
// bucket key so that this function can be used for both in and out swaps. // bucket key so that this function can be used for both in and out swaps.
func (s *boltSwapStore) updateLoop(bucketKey []byte, hash lntypes.Hash, func (s *boltSwapStore) updateLoop(bucketKey []byte, hash lntypes.Hash,
time time.Time, state SwapState) error { time time.Time, state SwapStateData) error {
return s.db.Update(func(tx *bbolt.Tx) error { return s.db.Update(func(tx *bbolt.Tx) error {
// Starting from the root bucket, we'll traverse the bucket // Starting from the root bucket, we'll traverse the bucket
@ -386,7 +386,7 @@ func (s *boltSwapStore) updateLoop(bucketKey []byte, hash lntypes.Hash,
// //
// NOTE: Part of the loopdb.SwapStore interface. // NOTE: Part of the loopdb.SwapStore interface.
func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time, func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time,
state SwapState) error { state SwapStateData) error {
return s.updateLoop(loopOutBucketKey, hash, time, state) return s.updateLoop(loopOutBucketKey, hash, time, state)
} }
@ -396,7 +396,7 @@ func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time,
// //
// NOTE: Part of the loopdb.SwapStore interface. // NOTE: Part of the loopdb.SwapStore interface.
func (s *boltSwapStore) UpdateLoopIn(hash lntypes.Hash, time time.Time, func (s *boltSwapStore) UpdateLoopIn(hash lntypes.Hash, time time.Time,
state SwapState) error { state SwapStateData) error {
return s.updateLoop(loopInBucketKey, hash, time, state) return s.updateLoop(loopInBucketKey, hash, time, state)
} }

@ -107,7 +107,7 @@ func TestLoopOutStore(t *testing.T) {
t.Fatal("invalid pending swap data") t.Fatal("invalid pending swap data")
} }
if swaps[0].State() != expectedState { if swaps[0].State().State != expectedState {
t.Fatalf("expected state %v, but got %v", t.Fatalf("expected state %v, but got %v",
expectedState, swaps[0].State(), expectedState, swaps[0].State(),
) )
@ -130,7 +130,10 @@ func TestLoopOutStore(t *testing.T) {
// Next, we'll update to the next state of the pre-image being // Next, we'll update to the next state of the pre-image being
// revealed. The state should be reflected here again. // revealed. The state should be reflected here again.
err = store.UpdateLoopOut( err = store.UpdateLoopOut(
hash, testTime, StatePreimageRevealed, hash, testTime,
SwapStateData{
State: StatePreimageRevealed,
},
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -140,7 +143,10 @@ func TestLoopOutStore(t *testing.T) {
// Next, we'll update to the final state to ensure that the state is // Next, we'll update to the final state to ensure that the state is
// properly updated. // properly updated.
err = store.UpdateLoopOut( err = store.UpdateLoopOut(
hash, testTime, StateFailInsufficientValue, hash, testTime,
SwapStateData{
State: StateFailInsufficientValue,
},
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -229,7 +235,7 @@ func TestLoopInStore(t *testing.T) {
t.Fatal("invalid pending swap data") t.Fatal("invalid pending swap data")
} }
if swaps[0].State() != expectedState { if swaps[0].State().State != expectedState {
t.Fatalf("expected state %v, but got %v", t.Fatalf("expected state %v, but got %v",
expectedState, swaps[0].State(), expectedState, swaps[0].State(),
) )
@ -252,7 +258,10 @@ func TestLoopInStore(t *testing.T) {
// Next, we'll update to the next state of the pre-image being // Next, we'll update to the next state of the pre-image being
// revealed. The state should be reflected here again. // revealed. The state should be reflected here again.
err = store.UpdateLoopIn( err = store.UpdateLoopIn(
hash, testTime, StatePreimageRevealed, hash, testTime,
SwapStateData{
State: StatePreimageRevealed,
},
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -262,7 +271,10 @@ func TestLoopInStore(t *testing.T) {
// Next, we'll update to the final state to ensure that the state is // Next, we'll update to the final state to ensure that the state is
// properly updated. // properly updated.
err = store.UpdateLoopIn( err = store.UpdateLoopIn(
hash, testTime, StateFailInsufficientValue, hash, testTime,
SwapStateData{
State: StateFailInsufficientValue,
},
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

@ -125,3 +125,8 @@ func (s SwapState) String() string {
return "Unknown" return "Unknown"
} }
} }
// SwapStateData is all persistent data to describe the current swap state.
type SwapStateData struct {
State SwapState
}

@ -616,7 +616,12 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context,
// persistState updates the swap state and sends out an update notification. // persistState updates the swap state and sends out an update notification.
func (s *loopInSwap) persistState(ctx context.Context) error { func (s *loopInSwap) persistState(ctx context.Context) error {
// Update state in store. // Update state in store.
err := s.store.UpdateLoopIn(s.hash, s.lastUpdateTime, s.state) err := s.store.UpdateLoopIn(
s.hash, s.lastUpdateTime,
loopdb.SwapStateData{
State: s.state,
},
)
if err != nil { if err != nil {
return err return err
} }

@ -248,7 +248,9 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool) {
Loop: loopdb.Loop{ Loop: loopdb.Loop{
Events: []*loopdb.LoopEvent{ Events: []*loopdb.LoopEvent{
{ {
State: state, SwapStateData: loopdb.SwapStateData{
State: state,
},
}, },
}, },
Hash: testPreimage.Hash(), Hash: testPreimage.Hash(),

@ -342,7 +342,12 @@ func (s *loopOutSwap) persistState(ctx context.Context) error {
s.lastUpdateTime = updateTime s.lastUpdateTime = updateTime
// Update state in store. // Update state in store.
err := s.store.UpdateLoopOut(s.hash, updateTime, s.state) err := s.store.UpdateLoopOut(
s.hash, updateTime,
loopdb.SwapStateData{
State: s.state,
},
)
if err != nil { if err != nil {
return err return err
} }

@ -13,14 +13,14 @@ import (
// storeMock implements a mock client swap store. // storeMock implements a mock client swap store.
type storeMock struct { type storeMock struct {
loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract
loopOutUpdates map[lntypes.Hash][]loopdb.SwapState loopOutUpdates map[lntypes.Hash][]loopdb.SwapStateData
loopOutStoreChan chan loopdb.LoopOutContract loopOutStoreChan chan loopdb.LoopOutContract
loopOutUpdateChan chan loopdb.SwapState loopOutUpdateChan chan loopdb.SwapStateData
loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract
loopInUpdates map[lntypes.Hash][]loopdb.SwapState loopInUpdates map[lntypes.Hash][]loopdb.SwapStateData
loopInStoreChan chan loopdb.LoopInContract loopInStoreChan chan loopdb.LoopInContract
loopInUpdateChan chan loopdb.SwapState loopInUpdateChan chan loopdb.SwapStateData
t *testing.T t *testing.T
} }
@ -34,14 +34,14 @@ type finishData struct {
func newStoreMock(t *testing.T) *storeMock { func newStoreMock(t *testing.T) *storeMock {
return &storeMock{ return &storeMock{
loopOutStoreChan: make(chan loopdb.LoopOutContract, 1), loopOutStoreChan: make(chan loopdb.LoopOutContract, 1),
loopOutUpdateChan: make(chan loopdb.SwapState, 1), loopOutUpdateChan: make(chan loopdb.SwapStateData, 1),
loopOutSwaps: make(map[lntypes.Hash]*loopdb.LoopOutContract), loopOutSwaps: make(map[lntypes.Hash]*loopdb.LoopOutContract),
loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapState), loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
loopInStoreChan: make(chan loopdb.LoopInContract, 1), loopInStoreChan: make(chan loopdb.LoopInContract, 1),
loopInUpdateChan: make(chan loopdb.SwapState, 1), loopInUpdateChan: make(chan loopdb.SwapStateData, 1),
loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract), loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract),
loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapState), loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
t: t, t: t,
} }
} }
@ -57,7 +57,7 @@ func (s *storeMock) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) {
events := make([]*loopdb.LoopEvent, len(updates)) events := make([]*loopdb.LoopEvent, len(updates))
for i, u := range updates { for i, u := range updates {
events[i] = &loopdb.LoopEvent{ events[i] = &loopdb.LoopEvent{
State: u, SwapStateData: u,
} }
} }
@ -86,7 +86,7 @@ func (s *storeMock) CreateLoopOut(hash lntypes.Hash,
} }
s.loopOutSwaps[hash] = swap s.loopOutSwaps[hash] = swap
s.loopOutUpdates[hash] = []loopdb.SwapState{} s.loopOutUpdates[hash] = []loopdb.SwapStateData{}
s.loopOutStoreChan <- *swap s.loopOutStoreChan <- *swap
return nil return nil
@ -101,7 +101,7 @@ func (s *storeMock) FetchLoopInSwaps() ([]*loopdb.LoopIn, error) {
events := make([]*loopdb.LoopEvent, len(updates)) events := make([]*loopdb.LoopEvent, len(updates))
for i, u := range updates { for i, u := range updates {
events[i] = &loopdb.LoopEvent{ events[i] = &loopdb.LoopEvent{
State: u, SwapStateData: u,
} }
} }
@ -130,7 +130,7 @@ func (s *storeMock) CreateLoopIn(hash lntypes.Hash,
} }
s.loopInSwaps[hash] = swap s.loopInSwaps[hash] = swap
s.loopInUpdates[hash] = []loopdb.SwapState{} s.loopInUpdates[hash] = []loopdb.SwapStateData{}
s.loopInStoreChan <- *swap s.loopInStoreChan <- *swap
return nil return nil
@ -142,7 +142,7 @@ func (s *storeMock) CreateLoopIn(hash lntypes.Hash,
// //
// NOTE: Part of the loopdb.SwapStore interface. // NOTE: Part of the loopdb.SwapStore interface.
func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time, func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time,
state loopdb.SwapState) error { state loopdb.SwapStateData) error {
updates, ok := s.loopOutUpdates[hash] updates, ok := s.loopOutUpdates[hash]
if !ok { if !ok {
@ -162,7 +162,7 @@ func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time,
// //
// NOTE: Part of the loopdb.SwapStore interface. // NOTE: Part of the loopdb.SwapStore interface.
func (s *storeMock) UpdateLoopIn(hash lntypes.Hash, time time.Time, func (s *storeMock) UpdateLoopIn(hash lntypes.Hash, time time.Time,
state loopdb.SwapState) error { state loopdb.SwapStateData) error {
updates, ok := s.loopInUpdates[hash] updates, ok := s.loopInUpdates[hash]
if !ok { if !ok {
@ -215,7 +215,7 @@ func (s *storeMock) assertLoopInState(expectedState loopdb.SwapState) {
s.t.Helper() s.t.Helper()
state := <-s.loopOutUpdateChan state := <-s.loopOutUpdateChan
if state != expectedState { if state.State != expectedState {
s.t.Fatalf("unexpected state") s.t.Fatalf("unexpected state")
} }
} }
@ -226,7 +226,7 @@ func (s *storeMock) assertStorePreimageReveal() {
select { select {
case state := <-s.loopOutUpdateChan: case state := <-s.loopOutUpdateChan:
if state != loopdb.StatePreimageRevealed { if state.State != loopdb.StatePreimageRevealed {
s.t.Fatalf("unexpected state") s.t.Fatalf("unexpected state")
} }
case <-time.After(test.Timeout): case <-time.After(test.Timeout):
@ -239,7 +239,7 @@ func (s *storeMock) assertStoreFinished(expectedResult loopdb.SwapState) {
select { select {
case state := <-s.loopOutUpdateChan: case state := <-s.loopOutUpdateChan:
if state != expectedResult { if state.State != expectedResult {
s.t.Fatalf("expected result %v, but got %v", s.t.Fatalf("expected result %v, but got %v",
expectedResult, state) expectedResult, state)
} }

@ -68,8 +68,10 @@ func (s *swapKit) sendUpdate(ctx context.Context) error {
SwapHash: s.hash, SwapHash: s.hash,
SwapType: s.swapType, SwapType: s.swapType,
LastUpdate: s.lastUpdateTime, LastUpdate: s.lastUpdateTime,
State: s.state, SwapStateData: loopdb.SwapStateData{
HtlcAddress: s.htlc.Address, State: s.state,
},
HtlcAddress: s.htlc.Address,
} }
s.log.Infof("state %v", info.State) s.log.Infof("state %v", info.State)

@ -79,9 +79,9 @@ func createClientTestContext(t *testing.T,
for _, s := range pendingSwaps { for _, s := range pendingSwaps {
store.loopOutSwaps[s.Hash] = s.Contract store.loopOutSwaps[s.Hash] = s.Contract
updates := []loopdb.SwapState{} updates := []loopdb.SwapStateData{}
for _, e := range s.Events { for _, e := range s.Events {
updates = append(updates, e.State) updates = append(updates, e.SwapStateData)
} }
store.loopOutUpdates[s.Hash] = updates store.loopOutUpdates[s.Hash] = updates
} }

Loading…
Cancel
Save