Browse Source

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 1 year ago
parent
commit
1b306ad425
No known key found for this signature in database GPG Key ID: A61B9D4C393C59C7
14 changed files with 94 additions and 58 deletions
  1. +14
    -14
      client.go
  2. +3
    -1
      client_test.go
  3. +2
    -2
      interface.go
  4. +4
    -2
      loopdb/interface.go
  5. +7
    -6
      loopdb/loop.go
  6. +3
    -3
      loopdb/store.go
  7. +18
    -6
      loopdb/store_test.go
  8. +5
    -0
      loopdb/swapstate.go
  9. +6
    -1
      loopin.go
  10. +3
    -1
      loopin_test.go
  11. +6
    -1
      loopout.go
  12. +17
    -17
      store_mock_test.go
  13. +4
    -2
      swap.go
  14. +2
    -2
      testcontext_test.go

+ 14
- 14
client.go View File

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

+ 3
- 1
client_test.go View File

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

+ 2
- 2
interface.go View File

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

+ 4
- 2
loopdb/interface.go View File

@ -18,7 +18,8 @@ type SwapStore interface {
// 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.
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() ([]*LoopIn, error)
@ -29,7 +30,8 @@ type SwapStore interface {
// 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.
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() error

+ 7
- 6
loopdb/loop.go View File

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

+ 3
- 3
loopdb/store.go View File

@ -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
// bucket key so that this function can be used for both in and out swaps.
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 {
// 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.
func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time,
state SwapState) error {
state SwapStateData) error {
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.
func (s *boltSwapStore) UpdateLoopIn(hash lntypes.Hash, time time.Time,
state SwapState) error {
state SwapStateData) error {
return s.updateLoop(loopInBucketKey, hash, time, state)
}

+ 18
- 6
loopdb/store_test.go View File

@ -107,7 +107,7 @@ func TestLoopOutStore(t *testing.T) {
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",
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
// revealed. The state should be reflected here again.
err = store.UpdateLoopOut(
hash, testTime, StatePreimageRevealed,
hash, testTime,
SwapStateData{
State: StatePreimageRevealed,
},
)
if err != nil {
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
// properly updated.
err = store.UpdateLoopOut(
hash, testTime, StateFailInsufficientValue,
hash, testTime,
SwapStateData{
State: StateFailInsufficientValue,
},
)
if err != nil {
t.Fatal(err)
@ -229,7 +235,7 @@ func TestLoopInStore(t *testing.T) {
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",
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
// revealed. The state should be reflected here again.
err = store.UpdateLoopIn(
hash, testTime, StatePreimageRevealed,
hash, testTime,
SwapStateData{
State: StatePreimageRevealed,
},
)
if err != nil {
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
// properly updated.
err = store.UpdateLoopIn(
hash, testTime, StateFailInsufficientValue,
hash, testTime,
SwapStateData{
State: StateFailInsufficientValue,
},
)
if err != nil {
t.Fatal(err)

+ 5
- 0
loopdb/swapstate.go View File

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

+ 6
- 1
loopin.go View File

@ -616,7 +616,12 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context,
// persistState updates the swap state and sends out an update notification.
func (s *loopInSwap) persistState(ctx context.Context) error {
// 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 {
return err
}

+ 3
- 1
loopin_test.go View File

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

+ 6
- 1
loopout.go View File

@ -342,7 +342,12 @@ func (s *loopOutSwap) persistState(ctx context.Context) error {
s.lastUpdateTime = updateTime
// 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 {
return err
}

+ 17
- 17
store_mock_test.go View File

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

+ 4
- 2
swap.go View File

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

+ 2
- 2
testcontext_test.go View File

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

Loading…
Cancel
Save