Skip to content

Commit 4ea21ce

Browse files
authored
Merge pull request #238 from joostjager/loopout-record-htlc
loopout: record htlc tx hash
2 parents fc8f3c9 + e22524a commit 4ea21ce

12 files changed

+343
-47
lines changed

client_test.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/btcsuite/btcd/chaincfg"
11+
"github.com/btcsuite/btcd/chaincfg/chainhash"
1112
"github.com/btcsuite/btcutil"
1213
"github.com/lightninglabs/lndclient"
1314
"github.com/lightninglabs/loop/loopdb"
@@ -56,7 +57,7 @@ func TestSuccess(t *testing.T) {
5657
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
5758

5859
// Expect client to register for conf.
59-
confIntent := ctx.AssertRegisterConf()
60+
confIntent := ctx.AssertRegisterConf(false)
6061

6162
testSuccess(ctx, testRequest.Amount, *hash,
6263
signalPrepaymentResult, signalSwapPaymentResult, false,
@@ -82,7 +83,7 @@ func TestFailOffchain(t *testing.T) {
8283
signalSwapPaymentResult := ctx.AssertPaid(swapInvoiceDesc)
8384
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
8485

85-
ctx.AssertRegisterConf()
86+
ctx.AssertRegisterConf(false)
8687

8788
signalSwapPaymentResult(
8889
errors.New(lndclient.PaymentResultUnknownPaymentHash),
@@ -179,10 +180,17 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
179180
var receiverKey [33]byte
180181
copy(receiverKey[:], receiverPubKey.SerializeCompressed())
181182

182-
state := loopdb.StateInitiated
183+
update := loopdb.LoopEvent{
184+
SwapStateData: loopdb.SwapStateData{
185+
State: loopdb.StateInitiated,
186+
},
187+
}
188+
183189
if preimageRevealed {
184-
state = loopdb.StatePreimageRevealed
190+
update.State = loopdb.StatePreimageRevealed
191+
update.HtlcTxHash = &chainhash.Hash{1, 2, 6}
185192
}
193+
186194
pendingSwap := &loopdb.LoopOut{
187195
Contract: &loopdb.LoopOutContract{
188196
DestAddr: dest,
@@ -201,14 +209,8 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
201209
},
202210
},
203211
Loop: loopdb.Loop{
204-
Events: []*loopdb.LoopEvent{
205-
{
206-
SwapStateData: loopdb.SwapStateData{
207-
State: state,
208-
},
209-
},
210-
},
211-
Hash: hash,
212+
Events: []*loopdb.LoopEvent{&update},
213+
Hash: hash,
212214
},
213215
}
214216

@@ -230,7 +232,7 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
230232
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
231233

232234
// Expect client to register for conf.
233-
confIntent := ctx.AssertRegisterConf()
235+
confIntent := ctx.AssertRegisterConf(preimageRevealed)
234236

235237
signalSwapPaymentResult(nil)
236238
signalPrepaymentResult(nil)

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
237237
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
238238
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
239239
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
240+
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
240241
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
241242
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
242243
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

loopdb/meta.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ var (
3636
migrateCosts,
3737
migrateSwapPublicationDeadline,
3838
migrateLastHop,
39+
migrateUpdates,
3940
}
4041

4142
latestDBVersion = uint32(len(migrations))

loopdb/migration_04_updates.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package loopdb
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/btcsuite/btcd/chaincfg"
8+
"github.com/coreos/bbolt"
9+
)
10+
11+
// migrateUpdates migrates the swap updates to add an additional level of
12+
// nesting, allowing for optional keys to be added.
13+
func migrateUpdates(tx *bbolt.Tx, chainParams *chaincfg.Params) error {
14+
for _, key := range [][]byte{loopInBucketKey, loopOutBucketKey} {
15+
rootBucket := tx.Bucket(key)
16+
if rootBucket == nil {
17+
return fmt.Errorf("bucket %v does not exist", key)
18+
}
19+
20+
err := migrateSwapTypeUpdates(rootBucket)
21+
if err != nil {
22+
return err
23+
}
24+
}
25+
26+
return nil
27+
}
28+
29+
// migrateSwapTypeUpdates migrates updates for swaps in the specified bucket.
30+
func migrateSwapTypeUpdates(rootBucket *bbolt.Bucket) error {
31+
var swaps [][]byte
32+
33+
// Do not modify inside the for each.
34+
err := rootBucket.ForEach(func(swapHash, v []byte) error {
35+
// Only go into things that we know are sub-bucket
36+
// keys.
37+
if rootBucket.Bucket(swapHash) != nil {
38+
swaps = append(swaps, swapHash)
39+
}
40+
41+
return nil
42+
})
43+
if err != nil {
44+
return err
45+
}
46+
47+
// With the swaps listed, migrate them one by one.
48+
for _, swapHash := range swaps {
49+
swapBucket := rootBucket.Bucket(swapHash)
50+
if swapBucket == nil {
51+
return fmt.Errorf("swap bucket %x not found",
52+
swapHash)
53+
}
54+
55+
err := migrateSwapUpdates(swapBucket)
56+
if err != nil {
57+
return err
58+
}
59+
}
60+
61+
return nil
62+
}
63+
64+
// migrateSwapUpdates migrates updates for the swap stored in the specified
65+
// bucket.
66+
func migrateSwapUpdates(swapBucket *bbolt.Bucket) error {
67+
// With the main swap bucket obtained, we'll grab the
68+
// raw swap contract bytes.
69+
updatesBucket := swapBucket.Bucket(updatesBucketKey)
70+
if updatesBucket == nil {
71+
return errors.New("updates bucket not found")
72+
}
73+
74+
type state struct {
75+
id, state []byte
76+
}
77+
78+
var existingStates []state
79+
80+
// Do not modify inside the for each.
81+
err := updatesBucket.ForEach(func(k, v []byte) error {
82+
existingStates = append(existingStates, state{id: k, state: v})
83+
return nil
84+
})
85+
if err != nil {
86+
return err
87+
}
88+
89+
for _, existingState := range existingStates {
90+
// Delete the existing state key.
91+
err := updatesBucket.Delete(existingState.id)
92+
if err != nil {
93+
return err
94+
}
95+
96+
// Re-create as a bucket.
97+
updateBucket, err := updatesBucket.CreateBucket(
98+
existingState.id,
99+
)
100+
if err != nil {
101+
return err
102+
}
103+
104+
// Write back the basic state as a sub-key.
105+
err = updateBucket.Put(basicStateKey, existingState.state)
106+
if err != nil {
107+
return err
108+
}
109+
}
110+
111+
return nil
112+
}

loopdb/migration_04_updates_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package loopdb
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/btcsuite/btcd/chaincfg"
10+
"github.com/coreos/bbolt"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
// TestMigrationUpdates asserts that the swap updates migration is carried out
15+
// correctly.
16+
func TestMigrationUpdates(t *testing.T) {
17+
var (
18+
legacyDbVersion = Hex("00000003")
19+
)
20+
21+
legacyDb := map[string]interface{}{
22+
"metadata": map[string]interface{}{
23+
"dbp": legacyDbVersion,
24+
},
25+
"loop-in": map[string]interface{}{
26+
Hex("acae09fec9020b7996042613eede68a9eaf29eb28c21ea9943b19e344365a4bb"): map[string]interface{}{
27+
"contract": Hex("161b25277262bdb5c7c2827b975b2cbc7eb13e222b30cf88ea6daef4bcf22bdac4116c23071472cb000000000000ea6003f2f513a8fd7958b6a229dfb8835f6ab2c9c63cc3e138784d3e8c0e0ebbdd4e61033f26c40666977ed497eea4694d6dd3f07dbcf037089234ff665cd0a07fea329400007b8a00000000000059a600000000000009ca000077a20000000600000000000000000000000000000000000000000000000000000000000000000000"),
28+
"updates": map[string]interface{}{
29+
Hex("0000000000000001"): Hex("161b252772cb524508000000000000000000000000000000000000000000000000"),
30+
Hex("0000000000000002"): Hex("161b252837115e9b09ffffffffffff1f6a00000000000000000000000000000000"),
31+
Hex("0000000000000003"): Hex("161b252ab670360d0200000000000009ca00000000000000000000000000000000"),
32+
},
33+
},
34+
},
35+
"uncharge-swaps": map[string]interface{}{
36+
Hex("c3b3d7a145dbd2bab5aa1f505305f31ee432fe23b0801f065fac453dd9b1f923"): map[string]interface{}{
37+
"contract": Hex("161b2526643767387ca76e58c964a8f2b6c0a13392b2dea93bde260226a263fb836954054ed1756b000000000000c350fd11016c6e6263727431333337306e3170303072343775707035366c7671663836753565766135647868686c706c78303733756a70676e3979767977376130766a37746d307678793276683576716471327770657832757270307963717a7279787139377a76757173703570373232733970686a6e6e6e706c3778716e796a78353373706863346c396735306b396e347836703761793577707539306b6673397179397173717a353766676a7a67676838343439377375716b383436787a3333336a713036736c6b38637a323872657466363672796b7876396a746e6a3072683979666a6170777065617265713071396679797a666664676d6874687973617370757565746e6b72306b32376370326173366a750269d66fd2cea620dc06f1f7de7838f0c8b145b82c7033080c398862f3421a23230382cb637badbb07f9926a06ecd88b6150513ea0060dc8d6dc1c1fb623926b0a0f000077d400000000000b458c00000000000005f10000000000000024000077a22c6263727431713271756332666777737971376463617a73666e3332636a7874667671647671366a6c70706574fd0f016c6e626372743530313834306e317030307234377570703563776561306732396d30667434646432726167397870306e726d6a72396c33726b7a717037706a6c34337a6e6d6b64336c79337364713877646d6b7a757163717a7279787139377a767571737035616478717538766168643730743776747165777578366d6d64337977636639767835736476717567753833327230676e373466733971793971737168746773636638386e377664767136716e71307a657775366d7471616e326c7a306e7534737a72376c6b36646d343673336c78726572656e333972616b7a6c777378346c613538733966773630356d6767766b766879716e743339713976737367777879367571707236713273780000000600000000000003f20000000000000000161b25262710ce00"),
38+
"outgoing-chan-set": nil,
39+
"updates": map[string]interface{}{
40+
Hex("0000000000000001"): Hex("161b252a770e649b01000000000000053900000000000000000000000000000001"),
41+
Hex("0000000000000002"): Hex("161b252ab671bdd90200000000000005f10000000000001a9c0000000000000003"),
42+
},
43+
},
44+
},
45+
}
46+
47+
// Restore a legacy database.
48+
tempDirName, err := ioutil.TempDir("", "clientstore")
49+
require.NoError(t, err)
50+
defer os.RemoveAll(tempDirName)
51+
52+
tempPath := filepath.Join(tempDirName, dbFileName)
53+
db, err := bbolt.Open(tempPath, 0600, nil)
54+
require.NoError(t, err)
55+
56+
err = db.Update(func(tx *bbolt.Tx) error {
57+
return RestoreDB(tx, legacyDb)
58+
})
59+
60+
// Close database regardless of update result.
61+
db.Close()
62+
63+
// Assert update was successful.
64+
require.NoError(t, err)
65+
66+
// Open db and migrate to the latest version.
67+
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
68+
require.NoError(t, err)
69+
70+
// Fetch the legacy loop out swap and assert that the updates are still
71+
// there.
72+
outSwaps, err := store.FetchLoopOutSwaps()
73+
require.NoError(t, err)
74+
75+
outSwap := outSwaps[0]
76+
require.Len(t, outSwap.Events, 2)
77+
require.Equal(t, StateSuccess, outSwap.Events[1].State)
78+
79+
// Fetch the legacy loop in swap and assert that the updates are still
80+
// there.
81+
inSwaps, err := store.FetchLoopInSwaps()
82+
require.NoError(t, err)
83+
84+
inSwap := inSwaps[0]
85+
require.Len(t, inSwap.Events, 3)
86+
require.Equal(t, StateSuccess, outSwap.Events[1].State)
87+
}

loopdb/raw_db_test.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package loopdb
22

33
import (
44
"encoding/hex"
5-
"errors"
65
"fmt"
76
"strings"
87

@@ -88,6 +87,15 @@ func restoreDB(bucket *bbolt.Bucket, data map[string]interface{}) error {
8887
for k, v := range data {
8988
key := []byte(k)
9089

90+
// Store nil values.
91+
if v == nil {
92+
err := bucket.Put(key, nil)
93+
if err != nil {
94+
return err
95+
}
96+
continue
97+
}
98+
9199
switch value := v.(type) {
92100

93101
// Key contains value.
@@ -109,7 +117,7 @@ func restoreDB(bucket *bbolt.Bucket, data map[string]interface{}) error {
109117
}
110118

111119
default:
112-
return errors.New("invalid type")
120+
return fmt.Errorf("invalid type %T", value)
113121
}
114122
}
115123

0 commit comments

Comments
 (0)