• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 11170835610

03 Oct 2024 10:41PM UTC coverage: 49.188% (-9.6%) from 58.738%
11170835610

push

github

web-flow
Merge pull request #9154 from ziggie1984/master

multi: bump btcd version.

3 of 6 new or added lines in 6 files covered. (50.0%)

26110 existing lines in 428 files now uncovered.

97359 of 197934 relevant lines covered (49.19%)

1.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/htlcswitch/test_utils.go
1
package htlcswitch
2

3
import (
4
        "bytes"
5
        "context"
6
        crand "crypto/rand"
7
        "crypto/sha256"
8
        "encoding/binary"
9
        "encoding/hex"
10
        "fmt"
11
        "net"
12
        "os"
13
        "runtime"
14
        "runtime/pprof"
15
        "sync/atomic"
16
        "testing"
17
        "time"
18

19
        "github.com/btcsuite/btcd/btcec/v2"
20
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
21
        "github.com/btcsuite/btcd/btcutil"
22
        "github.com/btcsuite/btcd/chaincfg/chainhash"
23
        "github.com/btcsuite/btcd/wire"
24
        "github.com/go-errors/errors"
25
        sphinx "github.com/lightningnetwork/lightning-onion"
26
        "github.com/lightningnetwork/lnd/channeldb"
27
        "github.com/lightningnetwork/lnd/channeldb/models"
28
        "github.com/lightningnetwork/lnd/contractcourt"
29
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
30
        "github.com/lightningnetwork/lnd/input"
31
        "github.com/lightningnetwork/lnd/invoices"
32
        "github.com/lightningnetwork/lnd/keychain"
33
        "github.com/lightningnetwork/lnd/kvdb"
34
        "github.com/lightningnetwork/lnd/lnpeer"
35
        "github.com/lightningnetwork/lnd/lntest/channels"
36
        "github.com/lightningnetwork/lnd/lntest/wait"
37
        "github.com/lightningnetwork/lnd/lntypes"
38
        "github.com/lightningnetwork/lnd/lnwallet"
39
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
40
        "github.com/lightningnetwork/lnd/lnwire"
41
        "github.com/lightningnetwork/lnd/shachain"
42
        "github.com/lightningnetwork/lnd/ticker"
43
        "github.com/stretchr/testify/require"
44
)
45

46
var (
47
        alicePrivKey = []byte("alice priv key")
48
        bobPrivKey   = []byte("bob priv key")
49
        carolPrivKey = []byte("carol priv key")
50

51
        testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f882d7")
52
        testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d24ae")
53
        testRScalar   = new(btcec.ModNScalar)
54
        testSScalar   = new(btcec.ModNScalar)
55
        _             = testRScalar.SetByteSlice(testRBytes)
56
        _             = testSScalar.SetByteSlice(testSBytes)
57
        testSig       = ecdsa.NewSignature(testRScalar, testSScalar)
58

59
        wireSig, _ = lnwire.NewSigFromSignature(testSig)
60

61
        testBatchTimeout = 50 * time.Millisecond
62
)
63

64
var idSeqNum uint64
65

66
// genID generates a unique tuple to identify a test channel.
UNCOV
67
func genID() (lnwire.ChannelID, lnwire.ShortChannelID) {
×
UNCOV
68
        id := atomic.AddUint64(&idSeqNum, 1)
×
UNCOV
69

×
UNCOV
70
        var scratch [8]byte
×
UNCOV
71

×
UNCOV
72
        binary.BigEndian.PutUint64(scratch[:], id)
×
UNCOV
73
        hash1, _ := chainhash.NewHash(bytes.Repeat(scratch[:], 4))
×
UNCOV
74

×
UNCOV
75
        chanPoint1 := wire.NewOutPoint(hash1, uint32(id))
×
UNCOV
76
        chanID1 := lnwire.NewChanIDFromOutPoint(*chanPoint1)
×
UNCOV
77
        aliceChanID := lnwire.NewShortChanIDFromInt(id)
×
UNCOV
78

×
UNCOV
79
        return chanID1, aliceChanID
×
UNCOV
80
}
×
81

82
// genIDs generates ids for two test channels.
83
func genIDs() (lnwire.ChannelID, lnwire.ChannelID, lnwire.ShortChannelID,
UNCOV
84
        lnwire.ShortChannelID) {
×
UNCOV
85

×
UNCOV
86
        chanID1, aliceChanID := genID()
×
UNCOV
87
        chanID2, bobChanID := genID()
×
UNCOV
88

×
UNCOV
89
        return chanID1, chanID2, aliceChanID, bobChanID
×
UNCOV
90
}
×
91

92
// mockGetChanUpdateMessage helper function which returns topology update of
93
// the channel
94
func mockGetChanUpdateMessage(_ lnwire.ShortChannelID) (*lnwire.ChannelUpdate1,
UNCOV
95
        error) {
×
UNCOV
96

×
UNCOV
97
        return &lnwire.ChannelUpdate1{
×
UNCOV
98
                Signature: wireSig,
×
UNCOV
99
        }, nil
×
UNCOV
100
}
×
101

102
// generateRandomBytes returns securely generated random bytes.
103
// It will return an error if the system's secure random
104
// number generator fails to function correctly, in which
105
// case the caller should not continue.
UNCOV
106
func generateRandomBytes(n int) ([]byte, error) {
×
UNCOV
107
        b := make([]byte, n)
×
UNCOV
108

×
UNCOV
109
        // TODO(roasbeef): should use counter in tests (atomic) rather than
×
UNCOV
110
        // this
×
UNCOV
111

×
UNCOV
112
        _, err := crand.Read(b)
×
UNCOV
113
        // Note that Err == nil only if we read len(b) bytes.
×
UNCOV
114
        if err != nil {
×
115
                return nil, err
×
116
        }
×
117

UNCOV
118
        return b, nil
×
119
}
120

121
type testLightningChannel struct {
122
        channel *lnwallet.LightningChannel
123
        restore func() (*lnwallet.LightningChannel, error)
124
}
125

126
// createTestChannel creates the channel and returns our and remote channels
127
// representations.
128
//
129
// TODO(roasbeef): need to factor out, similar func re-used in many parts of codebase
130
func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte,
131
        aliceAmount, bobAmount, aliceReserve, bobReserve btcutil.Amount,
132
        chanID lnwire.ShortChannelID) (*testLightningChannel,
UNCOV
133
        *testLightningChannel, error) {
×
UNCOV
134

×
UNCOV
135
        aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(alicePrivKey)
×
UNCOV
136
        bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobPrivKey)
×
UNCOV
137

×
UNCOV
138
        channelCapacity := aliceAmount + bobAmount
×
UNCOV
139
        csvTimeoutAlice := uint32(5)
×
UNCOV
140
        csvTimeoutBob := uint32(4)
×
UNCOV
141
        isAliceInitiator := true
×
UNCOV
142

×
UNCOV
143
        aliceBounds := channeldb.ChannelStateBounds{
×
UNCOV
144
                MaxPendingAmount: lnwire.NewMSatFromSatoshis(
×
UNCOV
145
                        channelCapacity),
×
UNCOV
146
                ChanReserve:      aliceReserve,
×
UNCOV
147
                MinHTLC:          0,
×
UNCOV
148
                MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
×
UNCOV
149
        }
×
UNCOV
150
        aliceCommitParams := channeldb.CommitmentParams{
×
UNCOV
151
                DustLimit: btcutil.Amount(200),
×
UNCOV
152
                CsvDelay:  uint16(csvTimeoutAlice),
×
UNCOV
153
        }
×
UNCOV
154

×
UNCOV
155
        bobBounds := channeldb.ChannelStateBounds{
×
UNCOV
156
                MaxPendingAmount: lnwire.NewMSatFromSatoshis(
×
UNCOV
157
                        channelCapacity),
×
UNCOV
158
                ChanReserve:      bobReserve,
×
UNCOV
159
                MinHTLC:          0,
×
UNCOV
160
                MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
×
UNCOV
161
        }
×
UNCOV
162
        bobCommitParams := channeldb.CommitmentParams{
×
UNCOV
163
                DustLimit: btcutil.Amount(800),
×
UNCOV
164
                CsvDelay:  uint16(csvTimeoutBob),
×
UNCOV
165
        }
×
UNCOV
166

×
UNCOV
167
        var hash [sha256.Size]byte
×
UNCOV
168
        randomSeed, err := generateRandomBytes(sha256.Size)
×
UNCOV
169
        if err != nil {
×
170
                return nil, nil, err
×
171
        }
×
UNCOV
172
        copy(hash[:], randomSeed)
×
UNCOV
173

×
UNCOV
174
        prevOut := &wire.OutPoint{
×
UNCOV
175
                Hash:  chainhash.Hash(hash),
×
UNCOV
176
                Index: 0,
×
UNCOV
177
        }
×
UNCOV
178
        fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
×
UNCOV
179

×
UNCOV
180
        aliceCfg := channeldb.ChannelConfig{
×
UNCOV
181
                ChannelStateBounds: aliceBounds,
×
UNCOV
182
                CommitmentParams:   aliceCommitParams,
×
UNCOV
183
                MultiSigKey: keychain.KeyDescriptor{
×
UNCOV
184
                        PubKey: aliceKeyPub,
×
UNCOV
185
                },
×
UNCOV
186
                RevocationBasePoint: keychain.KeyDescriptor{
×
UNCOV
187
                        PubKey: aliceKeyPub,
×
UNCOV
188
                },
×
UNCOV
189
                PaymentBasePoint: keychain.KeyDescriptor{
×
UNCOV
190
                        PubKey: aliceKeyPub,
×
UNCOV
191
                },
×
UNCOV
192
                DelayBasePoint: keychain.KeyDescriptor{
×
UNCOV
193
                        PubKey: aliceKeyPub,
×
UNCOV
194
                },
×
UNCOV
195
                HtlcBasePoint: keychain.KeyDescriptor{
×
UNCOV
196
                        PubKey: aliceKeyPub,
×
UNCOV
197
                },
×
UNCOV
198
        }
×
UNCOV
199
        bobCfg := channeldb.ChannelConfig{
×
UNCOV
200
                ChannelStateBounds: bobBounds,
×
UNCOV
201
                CommitmentParams:   bobCommitParams,
×
UNCOV
202
                MultiSigKey: keychain.KeyDescriptor{
×
UNCOV
203
                        PubKey: bobKeyPub,
×
UNCOV
204
                },
×
UNCOV
205
                RevocationBasePoint: keychain.KeyDescriptor{
×
UNCOV
206
                        PubKey: bobKeyPub,
×
UNCOV
207
                },
×
UNCOV
208
                PaymentBasePoint: keychain.KeyDescriptor{
×
UNCOV
209
                        PubKey: bobKeyPub,
×
UNCOV
210
                },
×
UNCOV
211
                DelayBasePoint: keychain.KeyDescriptor{
×
UNCOV
212
                        PubKey: bobKeyPub,
×
UNCOV
213
                },
×
UNCOV
214
                HtlcBasePoint: keychain.KeyDescriptor{
×
UNCOV
215
                        PubKey: bobKeyPub,
×
UNCOV
216
                },
×
UNCOV
217
        }
×
UNCOV
218

×
UNCOV
219
        bobRoot, err := chainhash.NewHash(bobKeyPriv.Serialize())
×
UNCOV
220
        if err != nil {
×
221
                return nil, nil, err
×
222
        }
×
UNCOV
223
        bobPreimageProducer := shachain.NewRevocationProducer(*bobRoot)
×
UNCOV
224
        bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
×
UNCOV
225
        if err != nil {
×
226
                return nil, nil, err
×
227
        }
×
UNCOV
228
        bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
×
UNCOV
229

×
UNCOV
230
        aliceRoot, err := chainhash.NewHash(aliceKeyPriv.Serialize())
×
UNCOV
231
        if err != nil {
×
232
                return nil, nil, err
×
233
        }
×
UNCOV
234
        alicePreimageProducer := shachain.NewRevocationProducer(*aliceRoot)
×
UNCOV
235
        aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
×
UNCOV
236
        if err != nil {
×
237
                return nil, nil, err
×
238
        }
×
UNCOV
239
        aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
×
UNCOV
240

×
UNCOV
241
        aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(
×
UNCOV
242
                aliceAmount, bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint,
×
UNCOV
243
                bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit,
×
UNCOV
244
                isAliceInitiator, 0,
×
UNCOV
245
        )
×
UNCOV
246
        if err != nil {
×
247
                return nil, nil, err
×
248
        }
×
249

UNCOV
250
        dbAlice, err := channeldb.Open(t.TempDir())
×
UNCOV
251
        if err != nil {
×
252
                return nil, nil, err
×
253
        }
×
UNCOV
254
        t.Cleanup(func() {
×
UNCOV
255
                require.NoError(t, dbAlice.Close())
×
UNCOV
256
        })
×
257

UNCOV
258
        dbBob, err := channeldb.Open(t.TempDir())
×
UNCOV
259
        if err != nil {
×
260
                return nil, nil, err
×
261
        }
×
UNCOV
262
        t.Cleanup(func() {
×
UNCOV
263
                require.NoError(t, dbBob.Close())
×
UNCOV
264
        })
×
265

UNCOV
266
        estimator := chainfee.NewStaticEstimator(6000, 0)
×
UNCOV
267
        feePerKw, err := estimator.EstimateFeePerKW(1)
×
UNCOV
268
        if err != nil {
×
269
                return nil, nil, err
×
270
        }
×
UNCOV
271
        commitFee := feePerKw.FeeForWeight(724)
×
UNCOV
272

×
UNCOV
273
        const broadcastHeight = 1
×
UNCOV
274
        bobAddr := &net.TCPAddr{
×
UNCOV
275
                IP:   net.ParseIP("127.0.0.1"),
×
UNCOV
276
                Port: 18555,
×
UNCOV
277
        }
×
UNCOV
278

×
UNCOV
279
        aliceAddr := &net.TCPAddr{
×
UNCOV
280
                IP:   net.ParseIP("127.0.0.1"),
×
UNCOV
281
                Port: 18556,
×
UNCOV
282
        }
×
UNCOV
283

×
UNCOV
284
        aliceCommit := channeldb.ChannelCommitment{
×
UNCOV
285
                CommitHeight:  0,
×
UNCOV
286
                LocalBalance:  lnwire.NewMSatFromSatoshis(aliceAmount - commitFee),
×
UNCOV
287
                RemoteBalance: lnwire.NewMSatFromSatoshis(bobAmount),
×
UNCOV
288
                CommitFee:     commitFee,
×
UNCOV
289
                FeePerKw:      btcutil.Amount(feePerKw),
×
UNCOV
290
                CommitTx:      aliceCommitTx,
×
UNCOV
291
                CommitSig:     bytes.Repeat([]byte{1}, 71),
×
UNCOV
292
        }
×
UNCOV
293
        bobCommit := channeldb.ChannelCommitment{
×
UNCOV
294
                CommitHeight:  0,
×
UNCOV
295
                LocalBalance:  lnwire.NewMSatFromSatoshis(bobAmount),
×
UNCOV
296
                RemoteBalance: lnwire.NewMSatFromSatoshis(aliceAmount - commitFee),
×
UNCOV
297
                CommitFee:     commitFee,
×
UNCOV
298
                FeePerKw:      btcutil.Amount(feePerKw),
×
UNCOV
299
                CommitTx:      bobCommitTx,
×
UNCOV
300
                CommitSig:     bytes.Repeat([]byte{1}, 71),
×
UNCOV
301
        }
×
UNCOV
302

×
UNCOV
303
        aliceChannelState := &channeldb.OpenChannel{
×
UNCOV
304
                LocalChanCfg:            aliceCfg,
×
UNCOV
305
                RemoteChanCfg:           bobCfg,
×
UNCOV
306
                IdentityPub:             aliceKeyPub,
×
UNCOV
307
                FundingOutpoint:         *prevOut,
×
UNCOV
308
                ChanType:                channeldb.SingleFunderTweaklessBit,
×
UNCOV
309
                IsInitiator:             isAliceInitiator,
×
UNCOV
310
                Capacity:                channelCapacity,
×
UNCOV
311
                RemoteCurrentRevocation: bobCommitPoint,
×
UNCOV
312
                RevocationProducer:      alicePreimageProducer,
×
UNCOV
313
                RevocationStore:         shachain.NewRevocationStore(),
×
UNCOV
314
                LocalCommitment:         aliceCommit,
×
UNCOV
315
                RemoteCommitment:        aliceCommit,
×
UNCOV
316
                ShortChannelID:          chanID,
×
UNCOV
317
                Db:                      dbAlice.ChannelStateDB(),
×
UNCOV
318
                Packager:                channeldb.NewChannelPackager(chanID),
×
UNCOV
319
                FundingTxn:              channels.TestFundingTx,
×
UNCOV
320
        }
×
UNCOV
321

×
UNCOV
322
        bobChannelState := &channeldb.OpenChannel{
×
UNCOV
323
                LocalChanCfg:            bobCfg,
×
UNCOV
324
                RemoteChanCfg:           aliceCfg,
×
UNCOV
325
                IdentityPub:             bobKeyPub,
×
UNCOV
326
                FundingOutpoint:         *prevOut,
×
UNCOV
327
                ChanType:                channeldb.SingleFunderTweaklessBit,
×
UNCOV
328
                IsInitiator:             !isAliceInitiator,
×
UNCOV
329
                Capacity:                channelCapacity,
×
UNCOV
330
                RemoteCurrentRevocation: aliceCommitPoint,
×
UNCOV
331
                RevocationProducer:      bobPreimageProducer,
×
UNCOV
332
                RevocationStore:         shachain.NewRevocationStore(),
×
UNCOV
333
                LocalCommitment:         bobCommit,
×
UNCOV
334
                RemoteCommitment:        bobCommit,
×
UNCOV
335
                ShortChannelID:          chanID,
×
UNCOV
336
                Db:                      dbBob.ChannelStateDB(),
×
UNCOV
337
                Packager:                channeldb.NewChannelPackager(chanID),
×
UNCOV
338
        }
×
UNCOV
339

×
UNCOV
340
        if err := aliceChannelState.SyncPending(bobAddr, broadcastHeight); err != nil {
×
341
                return nil, nil, err
×
342
        }
×
343

UNCOV
344
        if err := bobChannelState.SyncPending(aliceAddr, broadcastHeight); err != nil {
×
345
                return nil, nil, err
×
346
        }
×
347

UNCOV
348
        aliceSigner := input.NewMockSigner(
×
UNCOV
349
                []*btcec.PrivateKey{aliceKeyPriv}, nil,
×
UNCOV
350
        )
×
UNCOV
351
        bobSigner := input.NewMockSigner(
×
UNCOV
352
                []*btcec.PrivateKey{bobKeyPriv}, nil,
×
UNCOV
353
        )
×
UNCOV
354

×
UNCOV
355
        alicePool := lnwallet.NewSigPool(runtime.NumCPU(), aliceSigner)
×
UNCOV
356
        signerMock := lnwallet.NewDefaultAuxSignerMock(t)
×
UNCOV
357
        channelAlice, err := lnwallet.NewLightningChannel(
×
UNCOV
358
                aliceSigner, aliceChannelState, alicePool,
×
UNCOV
359
                lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
×
UNCOV
360
                lnwallet.WithAuxSigner(signerMock),
×
UNCOV
361
        )
×
UNCOV
362
        if err != nil {
×
363
                return nil, nil, err
×
364
        }
×
UNCOV
365
        alicePool.Start()
×
UNCOV
366

×
UNCOV
367
        bobPool := lnwallet.NewSigPool(runtime.NumCPU(), bobSigner)
×
UNCOV
368
        channelBob, err := lnwallet.NewLightningChannel(
×
UNCOV
369
                bobSigner, bobChannelState, bobPool,
×
UNCOV
370
                lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
×
UNCOV
371
                lnwallet.WithAuxSigner(signerMock),
×
UNCOV
372
        )
×
UNCOV
373
        if err != nil {
×
374
                return nil, nil, err
×
375
        }
×
UNCOV
376
        bobPool.Start()
×
UNCOV
377

×
UNCOV
378
        // Now that the channel are open, simulate the start of a session by
×
UNCOV
379
        // having Alice and Bob extend their revocation windows to each other.
×
UNCOV
380
        aliceNextRevoke, err := channelAlice.NextRevocationKey()
×
UNCOV
381
        if err != nil {
×
382
                return nil, nil, err
×
383
        }
×
UNCOV
384
        if err := channelBob.InitNextRevocation(aliceNextRevoke); err != nil {
×
385
                return nil, nil, err
×
386
        }
×
387

UNCOV
388
        bobNextRevoke, err := channelBob.NextRevocationKey()
×
UNCOV
389
        if err != nil {
×
390
                return nil, nil, err
×
391
        }
×
UNCOV
392
        if err := channelAlice.InitNextRevocation(bobNextRevoke); err != nil {
×
393
                return nil, nil, err
×
394
        }
×
395

UNCOV
396
        restoreAlice := func() (*lnwallet.LightningChannel, error) {
×
UNCOV
397
                aliceStoredChannels, err := dbAlice.ChannelStateDB().
×
UNCOV
398
                        FetchOpenChannels(aliceKeyPub)
×
UNCOV
399
                switch err {
×
UNCOV
400
                case nil:
×
401
                case kvdb.ErrDatabaseNotOpen:
×
402
                        dbAlice, err = channeldb.Open(dbAlice.Path())
×
403
                        if err != nil {
×
404
                                return nil, errors.Errorf("unable to reopen alice "+
×
405
                                        "db: %v", err)
×
406
                        }
×
407

408
                        aliceStoredChannels, err = dbAlice.ChannelStateDB().
×
409
                                FetchOpenChannels(aliceKeyPub)
×
410
                        if err != nil {
×
411
                                return nil, errors.Errorf("unable to fetch alice "+
×
412
                                        "channel: %v", err)
×
413
                        }
×
414
                default:
×
415
                        return nil, errors.Errorf("unable to fetch alice channel: "+
×
416
                                "%v", err)
×
417
                }
418

UNCOV
419
                var aliceStoredChannel *channeldb.OpenChannel
×
UNCOV
420
                for _, channel := range aliceStoredChannels {
×
UNCOV
421
                        if channel.FundingOutpoint.String() == prevOut.String() {
×
UNCOV
422
                                aliceStoredChannel = channel
×
UNCOV
423
                                break
×
424
                        }
425
                }
426

UNCOV
427
                if aliceStoredChannel == nil {
×
428
                        return nil, errors.New("unable to find stored alice channel")
×
429
                }
×
430

UNCOV
431
                newAliceChannel, err := lnwallet.NewLightningChannel(
×
UNCOV
432
                        aliceSigner, aliceStoredChannel, alicePool,
×
UNCOV
433
                        lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
×
UNCOV
434
                        lnwallet.WithAuxSigner(signerMock),
×
UNCOV
435
                )
×
UNCOV
436
                if err != nil {
×
437
                        return nil, errors.Errorf("unable to create new channel: %v",
×
438
                                err)
×
439
                }
×
440

UNCOV
441
                return newAliceChannel, nil
×
442
        }
443

UNCOV
444
        restoreBob := func() (*lnwallet.LightningChannel, error) {
×
UNCOV
445
                bobStoredChannels, err := dbBob.ChannelStateDB().
×
UNCOV
446
                        FetchOpenChannels(bobKeyPub)
×
UNCOV
447
                switch err {
×
UNCOV
448
                case nil:
×
449
                case kvdb.ErrDatabaseNotOpen:
×
450
                        dbBob, err = channeldb.Open(dbBob.Path())
×
451
                        if err != nil {
×
452
                                return nil, errors.Errorf("unable to reopen bob "+
×
453
                                        "db: %v", err)
×
454
                        }
×
455

456
                        bobStoredChannels, err = dbBob.ChannelStateDB().
×
457
                                FetchOpenChannels(bobKeyPub)
×
458
                        if err != nil {
×
459
                                return nil, errors.Errorf("unable to fetch bob "+
×
460
                                        "channel: %v", err)
×
461
                        }
×
462
                default:
×
463
                        return nil, errors.Errorf("unable to fetch bob channel: "+
×
464
                                "%v", err)
×
465
                }
466

UNCOV
467
                var bobStoredChannel *channeldb.OpenChannel
×
UNCOV
468
                for _, channel := range bobStoredChannels {
×
UNCOV
469
                        if channel.FundingOutpoint.String() == prevOut.String() {
×
UNCOV
470
                                bobStoredChannel = channel
×
UNCOV
471
                                break
×
472
                        }
473
                }
474

UNCOV
475
                if bobStoredChannel == nil {
×
476
                        return nil, errors.New("unable to find stored bob channel")
×
477
                }
×
478

UNCOV
479
                newBobChannel, err := lnwallet.NewLightningChannel(
×
UNCOV
480
                        bobSigner, bobStoredChannel, bobPool,
×
UNCOV
481
                        lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
×
UNCOV
482
                        lnwallet.WithAuxSigner(signerMock),
×
UNCOV
483
                )
×
UNCOV
484
                if err != nil {
×
485
                        return nil, errors.Errorf("unable to create new channel: %v",
×
486
                                err)
×
487
                }
×
UNCOV
488
                return newBobChannel, nil
×
489
        }
490

UNCOV
491
        testLightningChannelAlice := &testLightningChannel{
×
UNCOV
492
                channel: channelAlice,
×
UNCOV
493
                restore: restoreAlice,
×
UNCOV
494
        }
×
UNCOV
495

×
UNCOV
496
        testLightningChannelBob := &testLightningChannel{
×
UNCOV
497
                channel: channelBob,
×
UNCOV
498
                restore: restoreBob,
×
UNCOV
499
        }
×
UNCOV
500

×
UNCOV
501
        return testLightningChannelAlice, testLightningChannelBob, nil
×
502
}
503

504
// getChanID retrieves the channel point from an lnnwire message.
UNCOV
505
func getChanID(msg lnwire.Message) (lnwire.ChannelID, error) {
×
UNCOV
506
        var chanID lnwire.ChannelID
×
UNCOV
507
        switch msg := msg.(type) {
×
UNCOV
508
        case *lnwire.UpdateAddHTLC:
×
UNCOV
509
                chanID = msg.ChanID
×
UNCOV
510
        case *lnwire.UpdateFulfillHTLC:
×
UNCOV
511
                chanID = msg.ChanID
×
512
        case *lnwire.UpdateFailHTLC:
×
513
                chanID = msg.ChanID
×
UNCOV
514
        case *lnwire.RevokeAndAck:
×
UNCOV
515
                chanID = msg.ChanID
×
UNCOV
516
        case *lnwire.CommitSig:
×
UNCOV
517
                chanID = msg.ChanID
×
UNCOV
518
        case *lnwire.ChannelReestablish:
×
UNCOV
519
                chanID = msg.ChanID
×
UNCOV
520
        case *lnwire.ChannelReady:
×
UNCOV
521
                chanID = msg.ChanID
×
UNCOV
522
        case *lnwire.UpdateFee:
×
UNCOV
523
                chanID = msg.ChanID
×
524
        default:
×
525
                return chanID, fmt.Errorf("unknown type: %T", msg)
×
526
        }
527

UNCOV
528
        return chanID, nil
×
529
}
530

531
// generateHoldPayment generates the htlc add request by given path blob and
532
// invoice which should be added by destination peer.
533
func generatePaymentWithPreimage(invoiceAmt, htlcAmt lnwire.MilliSatoshi,
534
        timelock uint32, blob [lnwire.OnionPacketSize]byte,
535
        preimage *lntypes.Preimage, rhash, payAddr [32]byte) (
UNCOV
536
        *invoices.Invoice, *lnwire.UpdateAddHTLC, uint64, error) {
×
UNCOV
537

×
UNCOV
538
        // Create the db invoice. Normally the payment requests needs to be set,
×
UNCOV
539
        // because it is decoded in InvoiceRegistry to obtain the cltv expiry.
×
UNCOV
540
        // But because the mock registry used in tests is mocking the decode
×
UNCOV
541
        // step and always returning the value of testInvoiceCltvExpiry, we
×
UNCOV
542
        // don't need to bother here with creating and signing a payment
×
UNCOV
543
        // request.
×
UNCOV
544

×
UNCOV
545
        invoice := &invoices.Invoice{
×
UNCOV
546
                CreationDate: time.Now(),
×
UNCOV
547
                Terms: invoices.ContractTerm{
×
UNCOV
548
                        FinalCltvDelta:  testInvoiceCltvExpiry,
×
UNCOV
549
                        Value:           invoiceAmt,
×
UNCOV
550
                        PaymentPreimage: preimage,
×
UNCOV
551
                        PaymentAddr:     payAddr,
×
UNCOV
552
                        Features: lnwire.NewFeatureVector(
×
UNCOV
553
                                nil, lnwire.Features,
×
UNCOV
554
                        ),
×
UNCOV
555
                },
×
UNCOV
556
                HodlInvoice: preimage == nil,
×
UNCOV
557
        }
×
UNCOV
558

×
UNCOV
559
        htlc := &lnwire.UpdateAddHTLC{
×
UNCOV
560
                PaymentHash: rhash,
×
UNCOV
561
                Amount:      htlcAmt,
×
UNCOV
562
                Expiry:      timelock,
×
UNCOV
563
                OnionBlob:   blob,
×
UNCOV
564
        }
×
UNCOV
565

×
UNCOV
566
        pid, err := generateRandomBytes(8)
×
UNCOV
567
        if err != nil {
×
568
                return nil, nil, 0, err
×
569
        }
×
UNCOV
570
        paymentID := binary.BigEndian.Uint64(pid)
×
UNCOV
571

×
UNCOV
572
        return invoice, htlc, paymentID, nil
×
573
}
574

575
// generatePayment generates the htlc add request by given path blob and
576
// invoice which should be added by destination peer.
577
func generatePayment(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32,
578
        blob [lnwire.OnionPacketSize]byte) (*invoices.Invoice,
UNCOV
579
        *lnwire.UpdateAddHTLC, uint64, error) {
×
UNCOV
580

×
UNCOV
581
        var preimage lntypes.Preimage
×
UNCOV
582
        r, err := generateRandomBytes(sha256.Size)
×
UNCOV
583
        if err != nil {
×
584
                return nil, nil, 0, err
×
585
        }
×
UNCOV
586
        copy(preimage[:], r)
×
UNCOV
587

×
UNCOV
588
        rhash := sha256.Sum256(preimage[:])
×
UNCOV
589

×
UNCOV
590
        var payAddr [sha256.Size]byte
×
UNCOV
591
        r, err = generateRandomBytes(sha256.Size)
×
UNCOV
592
        if err != nil {
×
593
                return nil, nil, 0, err
×
594
        }
×
UNCOV
595
        copy(payAddr[:], r)
×
UNCOV
596

×
UNCOV
597
        return generatePaymentWithPreimage(
×
UNCOV
598
                invoiceAmt, htlcAmt, timelock, blob, &preimage, rhash, payAddr,
×
UNCOV
599
        )
×
600
}
601

602
// generateRoute generates the path blob by given array of peers.
603
func generateRoute(hops ...*hop.Payload) (
UNCOV
604
        [lnwire.OnionPacketSize]byte, error) {
×
UNCOV
605

×
UNCOV
606
        var blob [lnwire.OnionPacketSize]byte
×
UNCOV
607
        if len(hops) == 0 {
×
608
                return blob, errors.New("empty path")
×
609
        }
×
610

UNCOV
611
        iterator := newMockHopIterator(hops...)
×
UNCOV
612

×
UNCOV
613
        w := bytes.NewBuffer(blob[0:0])
×
UNCOV
614
        if err := iterator.EncodeNextHop(w); err != nil {
×
615
                return blob, err
×
616
        }
×
617

UNCOV
618
        return blob, nil
×
619

620
}
621

622
// threeHopNetwork is used for managing the created cluster of 3 hops.
623
type threeHopNetwork struct {
624
        aliceServer       *mockServer
625
        aliceChannelLink  *channelLink
626
        aliceOnionDecoder *mockIteratorDecoder
627

628
        bobServer            *mockServer
629
        firstBobChannelLink  *channelLink
630
        secondBobChannelLink *channelLink
631
        bobOnionDecoder      *mockIteratorDecoder
632

633
        carolServer       *mockServer
634
        carolChannelLink  *channelLink
635
        carolOnionDecoder *mockIteratorDecoder
636

637
        hopNetwork
638
}
639

640
// generateHops creates the per hop payload, the total amount to be sent, and
641
// also the time lock value needed to route an HTLC with the target amount over
642
// the specified path.
643
func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32,
UNCOV
644
        path ...*channelLink) (lnwire.MilliSatoshi, uint32, []*hop.Payload) {
×
UNCOV
645

×
UNCOV
646
        totalTimelock := startingHeight
×
UNCOV
647
        runningAmt := payAmt
×
UNCOV
648

×
UNCOV
649
        hops := make([]*hop.Payload, len(path))
×
UNCOV
650
        for i := len(path) - 1; i >= 0; i-- {
×
UNCOV
651
                // If this is the last hop, then the next hop is the special
×
UNCOV
652
                // "exit node". Otherwise, we look to the "prior" hop.
×
UNCOV
653
                nextHop := hop.Exit
×
UNCOV
654
                if i != len(path)-1 {
×
UNCOV
655
                        nextHop = path[i+1].channel.ShortChanID()
×
UNCOV
656
                }
×
657

UNCOV
658
                var timeLock uint32
×
UNCOV
659
                // If this is the last, hop, then the time lock will be their
×
UNCOV
660
                // specified delta policy plus our starting height.
×
UNCOV
661
                if i == len(path)-1 {
×
UNCOV
662
                        totalTimelock += testInvoiceCltvExpiry
×
UNCOV
663
                        timeLock = totalTimelock
×
UNCOV
664
                } else {
×
UNCOV
665
                        // Otherwise, the outgoing time lock should be the
×
UNCOV
666
                        // incoming timelock minus their specified delta.
×
UNCOV
667
                        delta := path[i+1].cfg.FwrdingPolicy.TimeLockDelta
×
UNCOV
668
                        totalTimelock += delta
×
UNCOV
669
                        timeLock = totalTimelock - delta
×
UNCOV
670
                }
×
671

672
                // Finally, we'll need to calculate the amount to forward. For
673
                // the last hop, it's just the payment amount.
UNCOV
674
                amount := payAmt
×
UNCOV
675
                if i != len(path)-1 {
×
UNCOV
676
                        prevHop := hops[i+1]
×
UNCOV
677
                        prevAmount := prevHop.ForwardingInfo().AmountToForward
×
UNCOV
678

×
UNCOV
679
                        fee := ExpectedFee(path[i].cfg.FwrdingPolicy, prevAmount)
×
UNCOV
680
                        runningAmt += fee
×
UNCOV
681

×
UNCOV
682
                        // Otherwise, for a node to forward an HTLC, then
×
UNCOV
683
                        // following inequality most hold true:
×
UNCOV
684
                        //     * amt_in - fee >= amt_to_forward
×
UNCOV
685
                        amount = runningAmt - fee
×
UNCOV
686
                }
×
687

UNCOV
688
                var nextHopBytes [8]byte
×
UNCOV
689
                binary.BigEndian.PutUint64(nextHopBytes[:], nextHop.ToUint64())
×
UNCOV
690

×
UNCOV
691
                hops[i] = hop.NewLegacyPayload(&sphinx.HopData{
×
UNCOV
692
                        Realm:         [1]byte{}, // hop.BitcoinNetwork
×
UNCOV
693
                        NextAddress:   nextHopBytes,
×
UNCOV
694
                        ForwardAmount: uint64(amount),
×
UNCOV
695
                        OutgoingCltv:  timeLock,
×
UNCOV
696
                })
×
697
        }
698

UNCOV
699
        return runningAmt, totalTimelock, hops
×
700
}
701

702
type paymentResponse struct {
703
        rhash lntypes.Hash
704
        err   chan error
705
}
706

UNCOV
707
func (r *paymentResponse) Wait(d time.Duration) (lntypes.Hash, error) {
×
UNCOV
708
        return r.rhash, waitForPaymentResult(r.err, d)
×
UNCOV
709
}
×
710

711
// waitForPaymentResult waits for either an error to be received on c or a
712
// timeout.
UNCOV
713
func waitForPaymentResult(c chan error, d time.Duration) error {
×
UNCOV
714
        select {
×
UNCOV
715
        case err := <-c:
×
UNCOV
716
                close(c)
×
UNCOV
717
                return err
×
UNCOV
718
        case <-time.After(d):
×
UNCOV
719
                return errors.New("htlc was not settled in time")
×
720
        }
721
}
722

723
// waitForPayFuncResult executes the given function and waits for a result with
724
// a timeout.
UNCOV
725
func waitForPayFuncResult(payFunc func() error, d time.Duration) error {
×
UNCOV
726
        errChan := make(chan error)
×
UNCOV
727
        go func() {
×
UNCOV
728
                errChan <- payFunc()
×
UNCOV
729
        }()
×
730

UNCOV
731
        return waitForPaymentResult(errChan, d)
×
732
}
733

734
// makePayment takes the destination node and amount as input, sends the
735
// payment and returns the error channel to wait for error to be received and
736
// invoice in order to check its status after the payment finished.
737
//
738
// With this function you can send payments:
739
// * from Alice to Bob
740
// * from Alice to Carol through the Bob
741
// * from Alice to some another peer through the Bob
742
func makePayment(sendingPeer, receivingPeer lnpeer.Peer,
743
        firstHop lnwire.ShortChannelID, hops []*hop.Payload,
744
        invoiceAmt, htlcAmt lnwire.MilliSatoshi,
UNCOV
745
        timelock uint32) *paymentResponse {
×
UNCOV
746

×
UNCOV
747
        paymentErr := make(chan error, 1)
×
UNCOV
748
        var rhash lntypes.Hash
×
UNCOV
749

×
UNCOV
750
        invoice, payFunc, err := preparePayment(sendingPeer, receivingPeer,
×
UNCOV
751
                firstHop, hops, invoiceAmt, htlcAmt, timelock,
×
UNCOV
752
        )
×
UNCOV
753
        if err != nil {
×
754
                paymentErr <- err
×
755
                return &paymentResponse{
×
756
                        rhash: rhash,
×
757
                        err:   paymentErr,
×
758
                }
×
759
        }
×
760

UNCOV
761
        rhash = invoice.Terms.PaymentPreimage.Hash()
×
UNCOV
762

×
UNCOV
763
        // Send payment and expose err channel.
×
UNCOV
764
        go func() {
×
UNCOV
765
                paymentErr <- payFunc()
×
UNCOV
766
        }()
×
767

UNCOV
768
        return &paymentResponse{
×
UNCOV
769
                rhash: rhash,
×
UNCOV
770
                err:   paymentErr,
×
UNCOV
771
        }
×
772
}
773

774
// preparePayment creates an invoice at the receivingPeer and returns a function
775
// that, when called, launches the payment from the sendingPeer.
776
func preparePayment(sendingPeer, receivingPeer lnpeer.Peer,
777
        firstHop lnwire.ShortChannelID, hops []*hop.Payload,
778
        invoiceAmt, htlcAmt lnwire.MilliSatoshi,
UNCOV
779
        timelock uint32) (*invoices.Invoice, func() error, error) {
×
UNCOV
780

×
UNCOV
781
        sender := sendingPeer.(*mockServer)
×
UNCOV
782
        receiver := receivingPeer.(*mockServer)
×
UNCOV
783

×
UNCOV
784
        // Generate route convert it to blob, and return next destination for
×
UNCOV
785
        // htlc add request.
×
UNCOV
786
        blob, err := generateRoute(hops...)
×
UNCOV
787
        if err != nil {
×
788
                return nil, nil, err
×
789
        }
×
790

791
        // Generate payment: invoice and htlc.
UNCOV
792
        invoice, htlc, pid, err := generatePayment(
×
UNCOV
793
                invoiceAmt, htlcAmt, timelock, blob,
×
UNCOV
794
        )
×
UNCOV
795
        if err != nil {
×
796
                return nil, nil, err
×
797
        }
×
798

799
        // Check who is last in the route and add invoice to server registry.
UNCOV
800
        hash := invoice.Terms.PaymentPreimage.Hash()
×
UNCOV
801
        if err := receiver.registry.AddInvoice(
×
UNCOV
802
                context.Background(), *invoice, hash,
×
UNCOV
803
        ); err != nil {
×
804
                return nil, nil, err
×
805
        }
×
806

807
        // Send payment and expose err channel.
UNCOV
808
        return invoice, func() error {
×
UNCOV
809
                err := sender.htlcSwitch.SendHTLC(
×
UNCOV
810
                        firstHop, pid, htlc,
×
UNCOV
811
                )
×
UNCOV
812
                if err != nil {
×
UNCOV
813
                        return err
×
UNCOV
814
                }
×
UNCOV
815
                resultChan, err := sender.htlcSwitch.GetAttemptResult(
×
UNCOV
816
                        pid, hash, newMockDeobfuscator(),
×
UNCOV
817
                )
×
UNCOV
818
                if err != nil {
×
819
                        return err
×
820
                }
×
821

UNCOV
822
                result, ok := <-resultChan
×
UNCOV
823
                if !ok {
×
UNCOV
824
                        return fmt.Errorf("shutting down")
×
UNCOV
825
                }
×
826

UNCOV
827
                if result.Error != nil {
×
UNCOV
828
                        return result.Error
×
UNCOV
829
                }
×
830

UNCOV
831
                return nil
×
832
        }, nil
833
}
834

835
// start starts the three hop network alice,bob,carol servers.
UNCOV
836
func (n *threeHopNetwork) start() error {
×
UNCOV
837
        if err := n.aliceServer.Start(); err != nil {
×
838
                return err
×
839
        }
×
UNCOV
840
        if err := n.bobServer.Start(); err != nil {
×
841
                return err
×
842
        }
×
UNCOV
843
        if err := n.carolServer.Start(); err != nil {
×
844
                return err
×
845
        }
×
846

UNCOV
847
        return waitLinksEligible(map[string]*channelLink{
×
UNCOV
848
                "alice":      n.aliceChannelLink,
×
UNCOV
849
                "bob first":  n.firstBobChannelLink,
×
UNCOV
850
                "bob second": n.secondBobChannelLink,
×
UNCOV
851
                "carol":      n.carolChannelLink,
×
UNCOV
852
        })
×
853
}
854

855
// stop stops nodes and cleanup its databases.
UNCOV
856
func (n *threeHopNetwork) stop() {
×
UNCOV
857
        done := make(chan struct{})
×
UNCOV
858
        go func() {
×
UNCOV
859
                n.aliceServer.Stop()
×
UNCOV
860
                done <- struct{}{}
×
UNCOV
861
        }()
×
862

UNCOV
863
        go func() {
×
UNCOV
864
                n.bobServer.Stop()
×
UNCOV
865
                done <- struct{}{}
×
UNCOV
866
        }()
×
867

UNCOV
868
        go func() {
×
UNCOV
869
                n.carolServer.Stop()
×
UNCOV
870
                done <- struct{}{}
×
UNCOV
871
        }()
×
872

UNCOV
873
        for i := 0; i < 3; i++ {
×
UNCOV
874
                <-done
×
UNCOV
875
        }
×
876
}
877

878
type clusterChannels struct {
879
        aliceToBob *lnwallet.LightningChannel
880
        bobToAlice *lnwallet.LightningChannel
881
        bobToCarol *lnwallet.LightningChannel
882
        carolToBob *lnwallet.LightningChannel
883
}
884

885
// createClusterChannels creates lightning channels which are needed for
886
// network cluster to be initialized.
887
func createClusterChannels(t *testing.T, aliceToBob, bobToCarol btcutil.Amount) (
UNCOV
888
        *clusterChannels, func() (*clusterChannels, error), error) {
×
UNCOV
889

×
UNCOV
890
        _, _, firstChanID, secondChanID := genIDs()
×
UNCOV
891

×
UNCOV
892
        // Create lightning channels between Alice<->Bob and Bob<->Carol
×
UNCOV
893
        aliceChannel, firstBobChannel, err := createTestChannel(t, alicePrivKey,
×
UNCOV
894
                bobPrivKey, aliceToBob, aliceToBob, 0, 0, firstChanID,
×
UNCOV
895
        )
×
UNCOV
896
        if err != nil {
×
897
                return nil, nil, errors.Errorf("unable to create "+
×
898
                        "alice<->bob channel: %v", err)
×
899
        }
×
900

UNCOV
901
        secondBobChannel, carolChannel, err := createTestChannel(t, bobPrivKey,
×
UNCOV
902
                carolPrivKey, bobToCarol, bobToCarol, 0, 0, secondChanID,
×
UNCOV
903
        )
×
UNCOV
904
        if err != nil {
×
905
                return nil, nil, errors.Errorf("unable to create "+
×
906
                        "bob<->carol channel: %v", err)
×
907
        }
×
908

UNCOV
909
        restoreFromDb := func() (*clusterChannels, error) {
×
UNCOV
910

×
UNCOV
911
                a2b, err := aliceChannel.restore()
×
UNCOV
912
                if err != nil {
×
913
                        return nil, err
×
914
                }
×
915

UNCOV
916
                b2a, err := firstBobChannel.restore()
×
UNCOV
917
                if err != nil {
×
918
                        return nil, err
×
919
                }
×
920

UNCOV
921
                b2c, err := secondBobChannel.restore()
×
UNCOV
922
                if err != nil {
×
923
                        return nil, err
×
924
                }
×
925

UNCOV
926
                c2b, err := carolChannel.restore()
×
UNCOV
927
                if err != nil {
×
928
                        return nil, err
×
929
                }
×
930

UNCOV
931
                return &clusterChannels{
×
UNCOV
932
                        aliceToBob: a2b,
×
UNCOV
933
                        bobToAlice: b2a,
×
UNCOV
934
                        bobToCarol: b2c,
×
UNCOV
935
                        carolToBob: c2b,
×
UNCOV
936
                }, nil
×
937
        }
938

UNCOV
939
        return &clusterChannels{
×
UNCOV
940
                aliceToBob: aliceChannel.channel,
×
UNCOV
941
                bobToAlice: firstBobChannel.channel,
×
UNCOV
942
                bobToCarol: secondBobChannel.channel,
×
UNCOV
943
                carolToBob: carolChannel.channel,
×
UNCOV
944
        }, restoreFromDb, nil
×
945
}
946

947
// newThreeHopNetwork function creates the following topology and returns the
948
// control object to manage this cluster:
949
//
950
// alice                      bob                             carol
951
// server - <-connection-> - server - - <-connection-> - - - server
952
//
953
//        |                           |                               |
954
//
955
// alice htlc                     bob htlc                          carol htlc
956
// switch                      switch        \                    switch
957
//
958
//        |                         |       \                       |
959
//        |                         |        \                       |
960
//
961
// alice                   first bob     second bob           carol
962
// channel link                      channel link   channel link      channel link
963
//
964
// This function takes server options which can be used to apply custom
965
// settings to alice, bob and carol.
966
func newThreeHopNetwork(t testing.TB, aliceChannel, firstBobChannel,
967
        secondBobChannel, carolChannel *lnwallet.LightningChannel,
UNCOV
968
        startingHeight uint32, opts ...serverOption) *threeHopNetwork {
×
UNCOV
969

×
UNCOV
970
        aliceDb := aliceChannel.State().Db.GetParentDB()
×
UNCOV
971
        bobDb := firstBobChannel.State().Db.GetParentDB()
×
UNCOV
972
        carolDb := carolChannel.State().Db.GetParentDB()
×
UNCOV
973

×
UNCOV
974
        hopNetwork := newHopNetwork()
×
UNCOV
975

×
UNCOV
976
        // Create three peers/servers.
×
UNCOV
977
        aliceServer, err := newMockServer(
×
UNCOV
978
                t, "alice", startingHeight, aliceDb, hopNetwork.defaultDelta,
×
UNCOV
979
        )
×
UNCOV
980
        require.NoError(t, err, "unable to create alice server")
×
UNCOV
981
        bobServer, err := newMockServer(
×
UNCOV
982
                t, "bob", startingHeight, bobDb, hopNetwork.defaultDelta,
×
UNCOV
983
        )
×
UNCOV
984
        require.NoError(t, err, "unable to create bob server")
×
UNCOV
985
        carolServer, err := newMockServer(
×
UNCOV
986
                t, "carol", startingHeight, carolDb, hopNetwork.defaultDelta,
×
UNCOV
987
        )
×
UNCOV
988
        require.NoError(t, err, "unable to create carol server")
×
UNCOV
989

×
UNCOV
990
        // Apply all additional functional options to the servers before
×
UNCOV
991
        // creating any links.
×
UNCOV
992
        for _, option := range opts {
×
UNCOV
993
                option(aliceServer, bobServer, carolServer)
×
UNCOV
994
        }
×
995

996
        // Create mock decoder instead of sphinx one in order to mock the route
997
        // which htlc should follow.
UNCOV
998
        aliceDecoder := newMockIteratorDecoder()
×
UNCOV
999
        bobDecoder := newMockIteratorDecoder()
×
UNCOV
1000
        carolDecoder := newMockIteratorDecoder()
×
UNCOV
1001

×
UNCOV
1002
        aliceChannelLink, err := hopNetwork.createChannelLink(aliceServer,
×
UNCOV
1003
                bobServer, aliceChannel, aliceDecoder,
×
UNCOV
1004
        )
×
UNCOV
1005
        if err != nil {
×
1006
                t.Fatal(err)
×
1007
        }
×
1008

UNCOV
1009
        firstBobChannelLink, err := hopNetwork.createChannelLink(bobServer,
×
UNCOV
1010
                aliceServer, firstBobChannel, bobDecoder)
×
UNCOV
1011
        if err != nil {
×
1012
                t.Fatal(err)
×
1013
        }
×
1014

UNCOV
1015
        secondBobChannelLink, err := hopNetwork.createChannelLink(bobServer,
×
UNCOV
1016
                carolServer, secondBobChannel, bobDecoder)
×
UNCOV
1017
        if err != nil {
×
1018
                t.Fatal(err)
×
1019
        }
×
1020

UNCOV
1021
        carolChannelLink, err := hopNetwork.createChannelLink(carolServer,
×
UNCOV
1022
                bobServer, carolChannel, carolDecoder)
×
UNCOV
1023
        if err != nil {
×
1024
                t.Fatal(err)
×
1025
        }
×
1026

UNCOV
1027
        return &threeHopNetwork{
×
UNCOV
1028
                aliceServer:       aliceServer,
×
UNCOV
1029
                aliceChannelLink:  aliceChannelLink.(*channelLink),
×
UNCOV
1030
                aliceOnionDecoder: aliceDecoder,
×
UNCOV
1031

×
UNCOV
1032
                bobServer:            bobServer,
×
UNCOV
1033
                firstBobChannelLink:  firstBobChannelLink.(*channelLink),
×
UNCOV
1034
                secondBobChannelLink: secondBobChannelLink.(*channelLink),
×
UNCOV
1035
                bobOnionDecoder:      bobDecoder,
×
UNCOV
1036

×
UNCOV
1037
                carolServer:       carolServer,
×
UNCOV
1038
                carolChannelLink:  carolChannelLink.(*channelLink),
×
UNCOV
1039
                carolOnionDecoder: carolDecoder,
×
UNCOV
1040

×
UNCOV
1041
                hopNetwork: *hopNetwork,
×
UNCOV
1042
        }
×
1043
}
1044

1045
// serverOption is a function which alters the three servers created for
1046
// a three hop network to allow custom settings on each server.
1047
type serverOption func(aliceServer, bobServer, carolServer *mockServer)
1048

1049
// serverOptionWithHtlcNotifier is a functional option for the creation of
1050
// three hop network servers which allows setting of htlc notifiers.
1051
// Note that these notifiers should be started and stopped by the calling
1052
// function.
1053
func serverOptionWithHtlcNotifier(alice, bob,
UNCOV
1054
        carol *HtlcNotifier) serverOption {
×
UNCOV
1055

×
UNCOV
1056
        return func(aliceServer, bobServer, carolServer *mockServer) {
×
UNCOV
1057
                aliceServer.htlcSwitch.cfg.HtlcNotifier = alice
×
UNCOV
1058
                bobServer.htlcSwitch.cfg.HtlcNotifier = bob
×
UNCOV
1059
                carolServer.htlcSwitch.cfg.HtlcNotifier = carol
×
UNCOV
1060
        }
×
1061
}
1062

1063
// serverOptionRejectHtlc is the functional option for setting the reject
1064
// htlc config option in each server's switch.
UNCOV
1065
func serverOptionRejectHtlc(alice, bob, carol bool) serverOption {
×
UNCOV
1066
        return func(aliceServer, bobServer, carolServer *mockServer) {
×
UNCOV
1067
                aliceServer.htlcSwitch.cfg.RejectHTLC = alice
×
UNCOV
1068
                bobServer.htlcSwitch.cfg.RejectHTLC = bob
×
UNCOV
1069
                carolServer.htlcSwitch.cfg.RejectHTLC = carol
×
UNCOV
1070
        }
×
1071
}
1072

1073
// createMirroredChannel creates two LightningChannel objects which represent
1074
// the state machines on either side of a single channel between alice and bob.
1075
func createMirroredChannel(t *testing.T, aliceToBob,
1076
        bobToAlice btcutil.Amount) (*testLightningChannel,
UNCOV
1077
        *testLightningChannel, error) {
×
UNCOV
1078

×
UNCOV
1079
        _, _, firstChanID, _ := genIDs()
×
UNCOV
1080

×
UNCOV
1081
        // Create lightning channels between Alice<->Bob for Alice and Bob
×
UNCOV
1082
        alice, bob, err := createTestChannel(t, alicePrivKey, bobPrivKey,
×
UNCOV
1083
                aliceToBob, bobToAlice, 0, 0, firstChanID,
×
UNCOV
1084
        )
×
UNCOV
1085
        if err != nil {
×
1086
                return nil, nil, errors.Errorf("unable to create "+
×
1087
                        "alice<->bob channel: %v", err)
×
1088
        }
×
1089

UNCOV
1090
        return alice, bob, nil
×
1091
}
1092

1093
// hopNetwork is the base struct for two and three hop networks
1094
type hopNetwork struct {
1095
        feeEstimator *mockFeeEstimator
1096
        globalPolicy models.ForwardingPolicy
1097
        obfuscator   hop.ErrorEncrypter
1098

1099
        defaultDelta uint32
1100
}
1101

UNCOV
1102
func newHopNetwork() *hopNetwork {
×
UNCOV
1103
        defaultDelta := uint32(6)
×
UNCOV
1104

×
UNCOV
1105
        globalPolicy := models.ForwardingPolicy{
×
UNCOV
1106
                MinHTLCOut:    lnwire.NewMSatFromSatoshis(5),
×
UNCOV
1107
                BaseFee:       lnwire.NewMSatFromSatoshis(1),
×
UNCOV
1108
                TimeLockDelta: defaultDelta,
×
UNCOV
1109
        }
×
UNCOV
1110
        obfuscator := NewMockObfuscator()
×
UNCOV
1111

×
UNCOV
1112
        return &hopNetwork{
×
UNCOV
1113
                feeEstimator: newMockFeeEstimator(),
×
UNCOV
1114
                globalPolicy: globalPolicy,
×
UNCOV
1115
                obfuscator:   obfuscator,
×
UNCOV
1116
                defaultDelta: defaultDelta,
×
UNCOV
1117
        }
×
UNCOV
1118
}
×
1119

1120
func (h *hopNetwork) createChannelLink(server, peer *mockServer,
1121
        channel *lnwallet.LightningChannel,
UNCOV
1122
        decoder *mockIteratorDecoder) (ChannelLink, error) {
×
UNCOV
1123

×
UNCOV
1124
        const (
×
UNCOV
1125
                fwdPkgTimeout       = 15 * time.Second
×
UNCOV
1126
                minFeeUpdateTimeout = 30 * time.Minute
×
UNCOV
1127
                maxFeeUpdateTimeout = 40 * time.Minute
×
UNCOV
1128
        )
×
UNCOV
1129

×
UNCOV
1130
        notifyUpdateChan := make(chan *contractcourt.ContractUpdate)
×
UNCOV
1131
        doneChan := make(chan struct{})
×
UNCOV
1132
        notifyContractUpdate := func(u *contractcourt.ContractUpdate) error {
×
UNCOV
1133
                select {
×
UNCOV
1134
                case notifyUpdateChan <- u:
×
UNCOV
1135
                case <-doneChan:
×
1136
                }
1137

UNCOV
1138
                return nil
×
1139
        }
1140

UNCOV
1141
        getAliases := func(
×
UNCOV
1142
                base lnwire.ShortChannelID) []lnwire.ShortChannelID {
×
UNCOV
1143

×
UNCOV
1144
                return nil
×
UNCOV
1145
        }
×
1146

UNCOV
1147
        link := NewChannelLink(
×
UNCOV
1148
                ChannelLinkConfig{
×
UNCOV
1149
                        BestHeight:    server.htlcSwitch.BestHeight,
×
UNCOV
1150
                        FwrdingPolicy: h.globalPolicy,
×
UNCOV
1151
                        Peer:          peer,
×
UNCOV
1152
                        Circuits:      server.htlcSwitch.CircuitModifier(),
×
UNCOV
1153
                        ForwardPackets: func(linkQuit chan struct{}, _ bool, packets ...*htlcPacket) error {
×
UNCOV
1154
                                return server.htlcSwitch.ForwardPackets(linkQuit, packets...)
×
UNCOV
1155
                        },
×
1156
                        DecodeHopIterators: decoder.DecodeHopIterators,
1157
                        ExtractErrorEncrypter: func(*btcec.PublicKey) (
UNCOV
1158
                                hop.ErrorEncrypter, lnwire.FailCode) {
×
UNCOV
1159
                                return h.obfuscator, lnwire.CodeNone
×
UNCOV
1160
                        },
×
1161
                        FetchLastChannelUpdate: mockGetChanUpdateMessage,
1162
                        Registry:               server.registry,
1163
                        FeeEstimator:           h.feeEstimator,
1164
                        PreimageCache:          server.pCache,
UNCOV
1165
                        UpdateContractSignals: func(*contractcourt.ContractSignals) error {
×
UNCOV
1166
                                return nil
×
UNCOV
1167
                        },
×
1168
                        NotifyContractUpdate:    notifyContractUpdate,
1169
                        ChainEvents:             &contractcourt.ChainEventSubscription{},
1170
                        SyncStates:              true,
1171
                        BatchSize:               10,
1172
                        BatchTicker:             ticker.NewForce(testBatchTimeout),
1173
                        FwdPkgGCTicker:          ticker.NewForce(fwdPkgTimeout),
1174
                        PendingCommitTicker:     ticker.New(2 * time.Minute),
1175
                        MinUpdateTimeout:        minFeeUpdateTimeout,
1176
                        MaxUpdateTimeout:        maxFeeUpdateTimeout,
UNCOV
1177
                        OnChannelFailure:        func(lnwire.ChannelID, lnwire.ShortChannelID, LinkFailureError) {},
×
1178
                        OutgoingCltvRejectDelta: 3,
1179
                        MaxOutgoingCltvExpiry:   DefaultMaxOutgoingCltvExpiry,
1180
                        MaxFeeAllocation:        DefaultMaxLinkFeeAllocation,
1181
                        MaxAnchorsCommitFeeRate: chainfee.SatPerKVByte(10 * 1000).FeePerKWeight(),
UNCOV
1182
                        NotifyActiveLink:        func(wire.OutPoint) {},
×
UNCOV
1183
                        NotifyActiveChannel:     func(wire.OutPoint) {},
×
UNCOV
1184
                        NotifyInactiveChannel:   func(wire.OutPoint) {},
×
UNCOV
1185
                        NotifyInactiveLinkEvent: func(wire.OutPoint) {},
×
1186
                        HtlcNotifier:            server.htlcSwitch.cfg.HtlcNotifier,
1187
                        GetAliases:              getAliases,
1188
                },
1189
                channel,
1190
        )
UNCOV
1191
        if err := server.htlcSwitch.AddLink(link); err != nil {
×
1192
                return nil, fmt.Errorf("unable to add channel link: %w", err)
×
1193
        }
×
1194

UNCOV
1195
        go func() {
×
UNCOV
1196
                for {
×
UNCOV
1197
                        select {
×
UNCOV
1198
                        case <-notifyUpdateChan:
×
UNCOV
1199
                        case <-link.(*channelLink).quit:
×
UNCOV
1200
                                close(doneChan)
×
UNCOV
1201
                                return
×
1202
                        }
1203
                }
1204
        }()
1205

UNCOV
1206
        return link, nil
×
1207
}
1208

1209
// twoHopNetwork is used for managing the created cluster of 2 hops.
1210
type twoHopNetwork struct {
1211
        hopNetwork
1212

1213
        aliceServer      *mockServer
1214
        aliceChannelLink *channelLink
1215

1216
        bobServer      *mockServer
1217
        bobChannelLink *channelLink
1218
}
1219

1220
// newTwoHopNetwork function creates and starts the following topology and
1221
// returns the control object to manage this cluster:
1222
//
1223
// alice                      bob
1224
// server - <-connection-> - server
1225
//
1226
//        |                      |
1227
//
1228
// alice htlc               bob htlc
1229
// switch                   switch
1230
//
1231
//        |                      |
1232
//        |                      |
1233
//
1234
// alice                      bob
1235
// channel link           channel link.
1236
func newTwoHopNetwork(t testing.TB,
1237
        aliceChannel, bobChannel *lnwallet.LightningChannel,
UNCOV
1238
        startingHeight uint32) *twoHopNetwork {
×
UNCOV
1239

×
UNCOV
1240
        aliceDb := aliceChannel.State().Db.GetParentDB()
×
UNCOV
1241
        bobDb := bobChannel.State().Db.GetParentDB()
×
UNCOV
1242

×
UNCOV
1243
        hopNetwork := newHopNetwork()
×
UNCOV
1244

×
UNCOV
1245
        // Create two peers/servers.
×
UNCOV
1246
        aliceServer, err := newMockServer(
×
UNCOV
1247
                t, "alice", startingHeight, aliceDb, hopNetwork.defaultDelta,
×
UNCOV
1248
        )
×
UNCOV
1249
        require.NoError(t, err, "unable to create alice server")
×
UNCOV
1250
        bobServer, err := newMockServer(
×
UNCOV
1251
                t, "bob", startingHeight, bobDb, hopNetwork.defaultDelta,
×
UNCOV
1252
        )
×
UNCOV
1253
        require.NoError(t, err, "unable to create bob server")
×
UNCOV
1254

×
UNCOV
1255
        // Create mock decoder instead of sphinx one in order to mock the route
×
UNCOV
1256
        // which htlc should follow.
×
UNCOV
1257
        aliceDecoder := newMockIteratorDecoder()
×
UNCOV
1258
        bobDecoder := newMockIteratorDecoder()
×
UNCOV
1259

×
UNCOV
1260
        aliceChannelLink, err := hopNetwork.createChannelLink(
×
UNCOV
1261
                aliceServer, bobServer, aliceChannel, aliceDecoder,
×
UNCOV
1262
        )
×
UNCOV
1263
        if err != nil {
×
1264
                t.Fatal(err)
×
1265
        }
×
1266

UNCOV
1267
        bobChannelLink, err := hopNetwork.createChannelLink(
×
UNCOV
1268
                bobServer, aliceServer, bobChannel, bobDecoder,
×
UNCOV
1269
        )
×
UNCOV
1270
        if err != nil {
×
1271
                t.Fatal(err)
×
1272
        }
×
1273

UNCOV
1274
        n := &twoHopNetwork{
×
UNCOV
1275
                aliceServer:      aliceServer,
×
UNCOV
1276
                aliceChannelLink: aliceChannelLink.(*channelLink),
×
UNCOV
1277

×
UNCOV
1278
                bobServer:      bobServer,
×
UNCOV
1279
                bobChannelLink: bobChannelLink.(*channelLink),
×
UNCOV
1280

×
UNCOV
1281
                hopNetwork: *hopNetwork,
×
UNCOV
1282
        }
×
UNCOV
1283

×
UNCOV
1284
        require.NoError(t, n.start())
×
UNCOV
1285
        t.Cleanup(n.stop)
×
UNCOV
1286

×
UNCOV
1287
        return n
×
1288
}
1289

1290
// start starts the two hop network alice,bob servers.
UNCOV
1291
func (n *twoHopNetwork) start() error {
×
UNCOV
1292
        if err := n.aliceServer.Start(); err != nil {
×
1293
                return err
×
1294
        }
×
UNCOV
1295
        if err := n.bobServer.Start(); err != nil {
×
1296
                n.aliceServer.Stop()
×
1297
                return err
×
1298
        }
×
1299

UNCOV
1300
        return waitLinksEligible(map[string]*channelLink{
×
UNCOV
1301
                "alice": n.aliceChannelLink,
×
UNCOV
1302
                "bob":   n.bobChannelLink,
×
UNCOV
1303
        })
×
1304
}
1305

1306
// stop stops nodes and cleanup its databases.
UNCOV
1307
func (n *twoHopNetwork) stop() {
×
UNCOV
1308
        done := make(chan struct{})
×
UNCOV
1309
        go func() {
×
UNCOV
1310
                n.aliceServer.Stop()
×
UNCOV
1311
                done <- struct{}{}
×
UNCOV
1312
        }()
×
1313

UNCOV
1314
        go func() {
×
UNCOV
1315
                n.bobServer.Stop()
×
UNCOV
1316
                done <- struct{}{}
×
UNCOV
1317
        }()
×
1318

UNCOV
1319
        for i := 0; i < 2; i++ {
×
UNCOV
1320
                <-done
×
UNCOV
1321
        }
×
1322
}
1323

1324
func (n *twoHopNetwork) makeHoldPayment(sendingPeer, receivingPeer lnpeer.Peer,
1325
        firstHop lnwire.ShortChannelID, hops []*hop.Payload,
1326
        invoiceAmt, htlcAmt lnwire.MilliSatoshi,
UNCOV
1327
        timelock uint32, preimage lntypes.Preimage) chan error {
×
UNCOV
1328

×
UNCOV
1329
        paymentErr := make(chan error, 1)
×
UNCOV
1330

×
UNCOV
1331
        sender := sendingPeer.(*mockServer)
×
UNCOV
1332
        receiver := receivingPeer.(*mockServer)
×
UNCOV
1333

×
UNCOV
1334
        // Generate route convert it to blob, and return next destination for
×
UNCOV
1335
        // htlc add request.
×
UNCOV
1336
        blob, err := generateRoute(hops...)
×
UNCOV
1337
        if err != nil {
×
1338
                paymentErr <- err
×
1339
                return paymentErr
×
1340
        }
×
1341

UNCOV
1342
        rhash := preimage.Hash()
×
UNCOV
1343

×
UNCOV
1344
        var payAddr [32]byte
×
UNCOV
1345
        if _, err := crand.Read(payAddr[:]); err != nil {
×
1346
                panic(err)
×
1347
        }
1348

1349
        // Generate payment: invoice and htlc.
UNCOV
1350
        invoice, htlc, pid, err := generatePaymentWithPreimage(
×
UNCOV
1351
                invoiceAmt, htlcAmt, timelock, blob,
×
UNCOV
1352
                nil, rhash, payAddr,
×
UNCOV
1353
        )
×
UNCOV
1354
        if err != nil {
×
1355
                paymentErr <- err
×
1356
                return paymentErr
×
1357
        }
×
1358

1359
        // Check who is last in the route and add invoice to server registry.
UNCOV
1360
        if err := receiver.registry.AddInvoice(
×
UNCOV
1361
                context.Background(), *invoice, rhash,
×
UNCOV
1362
        ); err != nil {
×
1363
                paymentErr <- err
×
1364
                return paymentErr
×
1365
        }
×
1366

1367
        // Send payment and expose err channel.
UNCOV
1368
        err = sender.htlcSwitch.SendHTLC(firstHop, pid, htlc)
×
UNCOV
1369
        if err != nil {
×
1370
                paymentErr <- err
×
1371
                return paymentErr
×
1372
        }
×
1373

UNCOV
1374
        go func() {
×
UNCOV
1375
                resultChan, err := sender.htlcSwitch.GetAttemptResult(
×
UNCOV
1376
                        pid, rhash, newMockDeobfuscator(),
×
UNCOV
1377
                )
×
UNCOV
1378
                if err != nil {
×
1379
                        paymentErr <- err
×
1380
                        return
×
1381
                }
×
1382

UNCOV
1383
                result, ok := <-resultChan
×
UNCOV
1384
                if !ok {
×
1385
                        paymentErr <- fmt.Errorf("shutting down")
×
1386
                        return
×
1387
                }
×
1388

UNCOV
1389
                if result.Error != nil {
×
UNCOV
1390
                        paymentErr <- result.Error
×
UNCOV
1391
                        return
×
UNCOV
1392
                }
×
UNCOV
1393
                paymentErr <- nil
×
1394
        }()
1395

UNCOV
1396
        return paymentErr
×
1397
}
1398

1399
// waitLinksEligible blocks until all links the provided name-to-link map are
1400
// eligible to forward HTLCs.
UNCOV
1401
func waitLinksEligible(links map[string]*channelLink) error {
×
UNCOV
1402
        return wait.NoError(func() error {
×
UNCOV
1403
                for name, link := range links {
×
UNCOV
1404
                        if link.EligibleToForward() {
×
UNCOV
1405
                                continue
×
1406
                        }
1407
                        return fmt.Errorf("%s channel link not eligible", name)
×
1408
                }
UNCOV
1409
                return nil
×
1410
        }, 3*time.Second)
1411
}
1412

1413
// timeout implements a test level timeout.
UNCOV
1414
func timeout() func() {
×
UNCOV
1415
        done := make(chan struct{})
×
UNCOV
1416
        go func() {
×
UNCOV
1417
                select {
×
1418
                case <-time.After(20 * time.Second):
×
1419
                        pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
×
1420

×
1421
                        panic("test timeout")
×
UNCOV
1422
                case <-done:
×
1423
                }
1424
        }()
1425

UNCOV
1426
        return func() {
×
UNCOV
1427
                close(done)
×
UNCOV
1428
        }
×
1429
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc