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

lightningnetwork / lnd / 13586005509

28 Feb 2025 10:14AM UTC coverage: 68.629% (+9.9%) from 58.77%
13586005509

Pull #9521

github

web-flow
Merge 37d3a70a5 into 8532955b3
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

129950 of 189351 relevant lines covered (68.63%)

23726.46 hits per line

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

83.62
/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/contractcourt"
28
        "github.com/lightningnetwork/lnd/graph/db/models"
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
// maxInflightHtlcs specifies the max number of inflight HTLCs. This number is
47
// chosen to be smaller than the default 483 so the test can run faster.
48
const maxInflightHtlcs = 50
49

50
var (
51
        alicePrivKey = []byte("alice priv key")
52
        bobPrivKey   = []byte("bob priv key")
53
        carolPrivKey = []byte("carol priv key")
54

55
        testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f882d7")
56
        testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d24ae")
57
        testRScalar   = new(btcec.ModNScalar)
58
        testSScalar   = new(btcec.ModNScalar)
59
        _             = testRScalar.SetByteSlice(testRBytes)
60
        _             = testSScalar.SetByteSlice(testSBytes)
61
        testSig       = ecdsa.NewSignature(testRScalar, testSScalar)
62

63
        wireSig, _ = lnwire.NewSigFromSignature(testSig)
64

65
        testBatchTimeout = 50 * time.Millisecond
66
)
67

68
var idSeqNum uint64
69

70
// genID generates a unique tuple to identify a test channel.
71
func genID() (lnwire.ChannelID, lnwire.ShortChannelID) {
197✔
72
        id := atomic.AddUint64(&idSeqNum, 1)
197✔
73

197✔
74
        var scratch [8]byte
197✔
75

197✔
76
        binary.BigEndian.PutUint64(scratch[:], id)
197✔
77
        hash1, _ := chainhash.NewHash(bytes.Repeat(scratch[:], 4))
197✔
78

197✔
79
        chanPoint1 := wire.NewOutPoint(hash1, uint32(id))
197✔
80
        chanID1 := lnwire.NewChanIDFromOutPoint(*chanPoint1)
197✔
81
        aliceChanID := lnwire.NewShortChanIDFromInt(id)
197✔
82

197✔
83
        return chanID1, aliceChanID
197✔
84
}
197✔
85

86
// genIDs generates ids for two test channels.
87
func genIDs() (lnwire.ChannelID, lnwire.ChannelID, lnwire.ShortChannelID,
88
        lnwire.ShortChannelID) {
84✔
89

84✔
90
        chanID1, aliceChanID := genID()
84✔
91
        chanID2, bobChanID := genID()
84✔
92

84✔
93
        return chanID1, chanID2, aliceChanID, bobChanID
84✔
94
}
84✔
95

96
// mockGetChanUpdateMessage helper function which returns topology update of
97
// the channel
98
func mockGetChanUpdateMessage(_ lnwire.ShortChannelID) (*lnwire.ChannelUpdate1,
99
        error) {
9✔
100

9✔
101
        return &lnwire.ChannelUpdate1{
9✔
102
                Signature: wireSig,
9✔
103
        }, nil
9✔
104
}
9✔
105

106
// generateRandomBytes returns securely generated random bytes.
107
// It will return an error if the system's secure random
108
// number generator fails to function correctly, in which
109
// case the caller should not continue.
110
func generateRandomBytes(n int) ([]byte, error) {
1,096✔
111
        b := make([]byte, n)
1,096✔
112

1,096✔
113
        // TODO(roasbeef): should use counter in tests (atomic) rather than
1,096✔
114
        // this
1,096✔
115

1,096✔
116
        _, err := crand.Read(b)
1,096✔
117
        // Note that Err == nil only if we read len(b) bytes.
1,096✔
118
        if err != nil {
1,096✔
119
                return nil, err
×
120
        }
×
121

122
        return b, nil
1,096✔
123
}
124

125
type testLightningChannel struct {
126
        channel *lnwallet.LightningChannel
127
        restore func() (*lnwallet.LightningChannel, error)
128
}
129

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

112✔
139
        aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(alicePrivKey)
112✔
140
        bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobPrivKey)
112✔
141

112✔
142
        channelCapacity := aliceAmount + bobAmount
112✔
143
        csvTimeoutAlice := uint32(5)
112✔
144
        csvTimeoutBob := uint32(4)
112✔
145
        isAliceInitiator := true
112✔
146

112✔
147
        aliceBounds := channeldb.ChannelStateBounds{
112✔
148
                MaxPendingAmount: lnwire.NewMSatFromSatoshis(
112✔
149
                        channelCapacity),
112✔
150
                ChanReserve:      aliceReserve,
112✔
151
                MinHTLC:          0,
112✔
152
                MaxAcceptedHtlcs: maxInflightHtlcs,
112✔
153
        }
112✔
154
        aliceCommitParams := channeldb.CommitmentParams{
112✔
155
                DustLimit: btcutil.Amount(200),
112✔
156
                CsvDelay:  uint16(csvTimeoutAlice),
112✔
157
        }
112✔
158

112✔
159
        bobBounds := channeldb.ChannelStateBounds{
112✔
160
                MaxPendingAmount: lnwire.NewMSatFromSatoshis(
112✔
161
                        channelCapacity),
112✔
162
                ChanReserve:      bobReserve,
112✔
163
                MinHTLC:          0,
112✔
164
                MaxAcceptedHtlcs: maxInflightHtlcs,
112✔
165
        }
112✔
166
        bobCommitParams := channeldb.CommitmentParams{
112✔
167
                DustLimit: btcutil.Amount(800),
112✔
168
                CsvDelay:  uint16(csvTimeoutBob),
112✔
169
        }
112✔
170

112✔
171
        var hash [sha256.Size]byte
112✔
172
        randomSeed, err := generateRandomBytes(sha256.Size)
112✔
173
        if err != nil {
112✔
174
                return nil, nil, err
×
175
        }
×
176
        copy(hash[:], randomSeed)
112✔
177

112✔
178
        prevOut := &wire.OutPoint{
112✔
179
                Hash:  chainhash.Hash(hash),
112✔
180
                Index: 0,
112✔
181
        }
112✔
182
        fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
112✔
183

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

112✔
223
        bobRoot, err := chainhash.NewHash(bobKeyPriv.Serialize())
112✔
224
        if err != nil {
112✔
225
                return nil, nil, err
×
226
        }
×
227
        bobPreimageProducer := shachain.NewRevocationProducer(*bobRoot)
112✔
228
        bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
112✔
229
        if err != nil {
112✔
230
                return nil, nil, err
×
231
        }
×
232
        bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
112✔
233

112✔
234
        aliceRoot, err := chainhash.NewHash(aliceKeyPriv.Serialize())
112✔
235
        if err != nil {
112✔
236
                return nil, nil, err
×
237
        }
×
238
        alicePreimageProducer := shachain.NewRevocationProducer(*aliceRoot)
112✔
239
        aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
112✔
240
        if err != nil {
112✔
241
                return nil, nil, err
×
242
        }
×
243
        aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
112✔
244

112✔
245
        aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(
112✔
246
                aliceAmount, bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint,
112✔
247
                bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit,
112✔
248
                isAliceInitiator, 0,
112✔
249
        )
112✔
250
        if err != nil {
112✔
251
                return nil, nil, err
×
252
        }
×
253

254
        dbAlice := channeldb.OpenForTesting(t, t.TempDir())
112✔
255
        dbBob := channeldb.OpenForTesting(t, t.TempDir())
112✔
256

112✔
257
        estimator := chainfee.NewStaticEstimator(6000, 0)
112✔
258
        feePerKw, err := estimator.EstimateFeePerKW(1)
112✔
259
        if err != nil {
112✔
260
                return nil, nil, err
×
261
        }
×
262
        commitFee := feePerKw.FeeForWeight(724)
112✔
263

112✔
264
        const broadcastHeight = 1
112✔
265
        bobAddr := &net.TCPAddr{
112✔
266
                IP:   net.ParseIP("127.0.0.1"),
112✔
267
                Port: 18555,
112✔
268
        }
112✔
269

112✔
270
        aliceAddr := &net.TCPAddr{
112✔
271
                IP:   net.ParseIP("127.0.0.1"),
112✔
272
                Port: 18556,
112✔
273
        }
112✔
274

112✔
275
        aliceCommit := channeldb.ChannelCommitment{
112✔
276
                CommitHeight:  0,
112✔
277
                LocalBalance:  lnwire.NewMSatFromSatoshis(aliceAmount - commitFee),
112✔
278
                RemoteBalance: lnwire.NewMSatFromSatoshis(bobAmount),
112✔
279
                CommitFee:     commitFee,
112✔
280
                FeePerKw:      btcutil.Amount(feePerKw),
112✔
281
                CommitTx:      aliceCommitTx,
112✔
282
                CommitSig:     bytes.Repeat([]byte{1}, 71),
112✔
283
        }
112✔
284
        bobCommit := channeldb.ChannelCommitment{
112✔
285
                CommitHeight:  0,
112✔
286
                LocalBalance:  lnwire.NewMSatFromSatoshis(bobAmount),
112✔
287
                RemoteBalance: lnwire.NewMSatFromSatoshis(aliceAmount - commitFee),
112✔
288
                CommitFee:     commitFee,
112✔
289
                FeePerKw:      btcutil.Amount(feePerKw),
112✔
290
                CommitTx:      bobCommitTx,
112✔
291
                CommitSig:     bytes.Repeat([]byte{1}, 71),
112✔
292
        }
112✔
293

112✔
294
        aliceChannelState := &channeldb.OpenChannel{
112✔
295
                LocalChanCfg:            aliceCfg,
112✔
296
                RemoteChanCfg:           bobCfg,
112✔
297
                IdentityPub:             aliceKeyPub,
112✔
298
                FundingOutpoint:         *prevOut,
112✔
299
                ChanType:                channeldb.SingleFunderTweaklessBit,
112✔
300
                IsInitiator:             isAliceInitiator,
112✔
301
                Capacity:                channelCapacity,
112✔
302
                RemoteCurrentRevocation: bobCommitPoint,
112✔
303
                RevocationProducer:      alicePreimageProducer,
112✔
304
                RevocationStore:         shachain.NewRevocationStore(),
112✔
305
                LocalCommitment:         aliceCommit,
112✔
306
                RemoteCommitment:        aliceCommit,
112✔
307
                ShortChannelID:          chanID,
112✔
308
                Db:                      dbAlice.ChannelStateDB(),
112✔
309
                Packager:                channeldb.NewChannelPackager(chanID),
112✔
310
                FundingTxn:              channels.TestFundingTx,
112✔
311
        }
112✔
312

112✔
313
        bobChannelState := &channeldb.OpenChannel{
112✔
314
                LocalChanCfg:            bobCfg,
112✔
315
                RemoteChanCfg:           aliceCfg,
112✔
316
                IdentityPub:             bobKeyPub,
112✔
317
                FundingOutpoint:         *prevOut,
112✔
318
                ChanType:                channeldb.SingleFunderTweaklessBit,
112✔
319
                IsInitiator:             !isAliceInitiator,
112✔
320
                Capacity:                channelCapacity,
112✔
321
                RemoteCurrentRevocation: aliceCommitPoint,
112✔
322
                RevocationProducer:      bobPreimageProducer,
112✔
323
                RevocationStore:         shachain.NewRevocationStore(),
112✔
324
                LocalCommitment:         bobCommit,
112✔
325
                RemoteCommitment:        bobCommit,
112✔
326
                ShortChannelID:          chanID,
112✔
327
                Db:                      dbBob.ChannelStateDB(),
112✔
328
                Packager:                channeldb.NewChannelPackager(chanID),
112✔
329
        }
112✔
330

112✔
331
        if err := aliceChannelState.SyncPending(bobAddr, broadcastHeight); err != nil {
112✔
332
                return nil, nil, err
×
333
        }
×
334

335
        if err := bobChannelState.SyncPending(aliceAddr, broadcastHeight); err != nil {
112✔
336
                return nil, nil, err
×
337
        }
×
338

339
        aliceSigner := input.NewMockSigner(
112✔
340
                []*btcec.PrivateKey{aliceKeyPriv}, nil,
112✔
341
        )
112✔
342
        bobSigner := input.NewMockSigner(
112✔
343
                []*btcec.PrivateKey{bobKeyPriv}, nil,
112✔
344
        )
112✔
345

112✔
346
        alicePool := lnwallet.NewSigPool(runtime.NumCPU(), aliceSigner)
112✔
347
        signerMock := lnwallet.NewDefaultAuxSignerMock(t)
112✔
348
        channelAlice, err := lnwallet.NewLightningChannel(
112✔
349
                aliceSigner, aliceChannelState, alicePool,
112✔
350
                lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
112✔
351
                lnwallet.WithAuxSigner(signerMock),
112✔
352
        )
112✔
353
        if err != nil {
112✔
354
                return nil, nil, err
×
355
        }
×
356
        alicePool.Start()
112✔
357

112✔
358
        bobPool := lnwallet.NewSigPool(runtime.NumCPU(), bobSigner)
112✔
359
        channelBob, err := lnwallet.NewLightningChannel(
112✔
360
                bobSigner, bobChannelState, bobPool,
112✔
361
                lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
112✔
362
                lnwallet.WithAuxSigner(signerMock),
112✔
363
        )
112✔
364
        if err != nil {
112✔
365
                return nil, nil, err
×
366
        }
×
367
        bobPool.Start()
112✔
368

112✔
369
        // Now that the channel are open, simulate the start of a session by
112✔
370
        // having Alice and Bob extend their revocation windows to each other.
112✔
371
        aliceNextRevoke, err := channelAlice.NextRevocationKey()
112✔
372
        if err != nil {
112✔
373
                return nil, nil, err
×
374
        }
×
375
        if err := channelBob.InitNextRevocation(aliceNextRevoke); err != nil {
112✔
376
                return nil, nil, err
×
377
        }
×
378

379
        bobNextRevoke, err := channelBob.NextRevocationKey()
112✔
380
        if err != nil {
112✔
381
                return nil, nil, err
×
382
        }
×
383
        if err := channelAlice.InitNextRevocation(bobNextRevoke); err != nil {
112✔
384
                return nil, nil, err
×
385
        }
×
386

387
        restoreAlice := func() (*lnwallet.LightningChannel, error) {
133✔
388
                aliceStoredChannels, err := dbAlice.ChannelStateDB().
21✔
389
                        FetchOpenChannels(aliceKeyPub)
21✔
390
                switch err {
21✔
391
                case nil:
21✔
392
                case kvdb.ErrDatabaseNotOpen:
×
393
                        dbAlice = channeldb.OpenForTesting(t, dbAlice.Path())
×
394

×
395
                        aliceStoredChannels, err = dbAlice.ChannelStateDB().
×
396
                                FetchOpenChannels(aliceKeyPub)
×
397
                        if err != nil {
×
398
                                return nil, errors.Errorf("unable to fetch alice "+
×
399
                                        "channel: %v", err)
×
400
                        }
×
401
                default:
×
402
                        return nil, errors.Errorf("unable to fetch alice channel: "+
×
403
                                "%v", err)
×
404
                }
405

406
                var aliceStoredChannel *channeldb.OpenChannel
21✔
407
                for _, channel := range aliceStoredChannels {
42✔
408
                        if channel.FundingOutpoint.String() == prevOut.String() {
42✔
409
                                aliceStoredChannel = channel
21✔
410
                                break
21✔
411
                        }
412
                }
413

414
                if aliceStoredChannel == nil {
21✔
415
                        return nil, errors.New("unable to find stored alice channel")
×
416
                }
×
417

418
                newAliceChannel, err := lnwallet.NewLightningChannel(
21✔
419
                        aliceSigner, aliceStoredChannel, alicePool,
21✔
420
                        lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
21✔
421
                        lnwallet.WithAuxSigner(signerMock),
21✔
422
                )
21✔
423
                if err != nil {
21✔
424
                        return nil, errors.Errorf("unable to create new channel: %v",
×
425
                                err)
×
426
                }
×
427

428
                return newAliceChannel, nil
21✔
429
        }
430

431
        restoreBob := func() (*lnwallet.LightningChannel, error) {
118✔
432
                bobStoredChannels, err := dbBob.ChannelStateDB().
6✔
433
                        FetchOpenChannels(bobKeyPub)
6✔
434
                switch err {
6✔
435
                case nil:
6✔
436
                case kvdb.ErrDatabaseNotOpen:
×
437
                        dbBob = channeldb.OpenForTesting(t, dbBob.Path())
×
438
                        if err != nil {
×
439
                                return nil, errors.Errorf("unable to reopen bob "+
×
440
                                        "db: %v", err)
×
441
                        }
×
442

443
                        bobStoredChannels, err = dbBob.ChannelStateDB().
×
444
                                FetchOpenChannels(bobKeyPub)
×
445
                        if err != nil {
×
446
                                return nil, errors.Errorf("unable to fetch bob "+
×
447
                                        "channel: %v", err)
×
448
                        }
×
449
                default:
×
450
                        return nil, errors.Errorf("unable to fetch bob channel: "+
×
451
                                "%v", err)
×
452
                }
453

454
                var bobStoredChannel *channeldb.OpenChannel
6✔
455
                for _, channel := range bobStoredChannels {
12✔
456
                        if channel.FundingOutpoint.String() == prevOut.String() {
12✔
457
                                bobStoredChannel = channel
6✔
458
                                break
6✔
459
                        }
460
                }
461

462
                if bobStoredChannel == nil {
6✔
463
                        return nil, errors.New("unable to find stored bob channel")
×
464
                }
×
465

466
                newBobChannel, err := lnwallet.NewLightningChannel(
6✔
467
                        bobSigner, bobStoredChannel, bobPool,
6✔
468
                        lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
6✔
469
                        lnwallet.WithAuxSigner(signerMock),
6✔
470
                )
6✔
471
                if err != nil {
6✔
472
                        return nil, errors.Errorf("unable to create new channel: %v",
×
473
                                err)
×
474
                }
×
475
                return newBobChannel, nil
6✔
476
        }
477

478
        testLightningChannelAlice := &testLightningChannel{
112✔
479
                channel: channelAlice,
112✔
480
                restore: restoreAlice,
112✔
481
        }
112✔
482

112✔
483
        testLightningChannelBob := &testLightningChannel{
112✔
484
                channel: channelBob,
112✔
485
                restore: restoreBob,
112✔
486
        }
112✔
487

112✔
488
        return testLightningChannelAlice, testLightningChannelBob, nil
112✔
489
}
490

491
// getChanID retrieves the channel point from an lnnwire message.
492
func getChanID(msg lnwire.Message) (lnwire.ChannelID, error) {
100✔
493
        var chanID lnwire.ChannelID
100✔
494
        switch msg := msg.(type) {
100✔
495
        case *lnwire.UpdateAddHTLC:
5✔
496
                chanID = msg.ChanID
5✔
497
        case *lnwire.UpdateFulfillHTLC:
4✔
498
                chanID = msg.ChanID
4✔
499
        case *lnwire.UpdateFailHTLC:
×
500
                chanID = msg.ChanID
×
501
        case *lnwire.RevokeAndAck:
22✔
502
                chanID = msg.ChanID
22✔
503
        case *lnwire.CommitSig:
22✔
504
                chanID = msg.ChanID
22✔
505
        case *lnwire.ChannelReestablish:
24✔
506
                chanID = msg.ChanID
24✔
507
        case *lnwire.ChannelReady:
20✔
508
                chanID = msg.ChanID
20✔
509
        case *lnwire.UpdateFee:
3✔
510
                chanID = msg.ChanID
3✔
511
        default:
×
512
                return chanID, fmt.Errorf("unknown type: %T", msg)
×
513
        }
514

515
        return chanID, nil
100✔
516
}
517

518
// generateHoldPayment generates the htlc add request by given path blob and
519
// invoice which should be added by destination peer.
520
func generatePaymentWithPreimage(invoiceAmt, htlcAmt lnwire.MilliSatoshi,
521
        timelock uint32, blob [lnwire.OnionPacketSize]byte,
522
        preimage *lntypes.Preimage, rhash, payAddr [32]byte) (
523
        *invoices.Invoice, *lnwire.UpdateAddHTLC, uint64, error) {
362✔
524

362✔
525
        // Create the db invoice. Normally the payment requests needs to be set,
362✔
526
        // because it is decoded in InvoiceRegistry to obtain the cltv expiry.
362✔
527
        // But because the mock registry used in tests is mocking the decode
362✔
528
        // step and always returning the value of testInvoiceCltvExpiry, we
362✔
529
        // don't need to bother here with creating and signing a payment
362✔
530
        // request.
362✔
531

362✔
532
        invoice := &invoices.Invoice{
362✔
533
                CreationDate: time.Now(),
362✔
534
                Terms: invoices.ContractTerm{
362✔
535
                        FinalCltvDelta:  testInvoiceCltvExpiry,
362✔
536
                        Value:           invoiceAmt,
362✔
537
                        PaymentPreimage: preimage,
362✔
538
                        PaymentAddr:     payAddr,
362✔
539
                        Features: lnwire.NewFeatureVector(
362✔
540
                                nil, lnwire.Features,
362✔
541
                        ),
362✔
542
                },
362✔
543
                HodlInvoice: preimage == nil,
362✔
544
        }
362✔
545

362✔
546
        htlc := &lnwire.UpdateAddHTLC{
362✔
547
                PaymentHash: rhash,
362✔
548
                Amount:      htlcAmt,
362✔
549
                Expiry:      timelock,
362✔
550
                OnionBlob:   blob,
362✔
551
        }
362✔
552

362✔
553
        pid, err := generateRandomBytes(8)
362✔
554
        if err != nil {
362✔
555
                return nil, nil, 0, err
×
556
        }
×
557
        paymentID := binary.BigEndian.Uint64(pid)
362✔
558

362✔
559
        return invoice, htlc, paymentID, nil
362✔
560
}
561

562
// generatePayment generates the htlc add request by given path blob and
563
// invoice which should be added by destination peer.
564
func generatePayment(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32,
565
        blob [lnwire.OnionPacketSize]byte) (*invoices.Invoice,
566
        *lnwire.UpdateAddHTLC, uint64, error) {
310✔
567

310✔
568
        var preimage lntypes.Preimage
310✔
569
        r, err := generateRandomBytes(sha256.Size)
310✔
570
        if err != nil {
310✔
571
                return nil, nil, 0, err
×
572
        }
×
573
        copy(preimage[:], r)
310✔
574

310✔
575
        rhash := sha256.Sum256(preimage[:])
310✔
576

310✔
577
        var payAddr [sha256.Size]byte
310✔
578
        r, err = generateRandomBytes(sha256.Size)
310✔
579
        if err != nil {
310✔
580
                return nil, nil, 0, err
×
581
        }
×
582
        copy(payAddr[:], r)
310✔
583

310✔
584
        return generatePaymentWithPreimage(
310✔
585
                invoiceAmt, htlcAmt, timelock, blob, &preimage, rhash, payAddr,
310✔
586
        )
310✔
587
}
588

589
// generateRoute generates the path blob by given array of peers.
590
func generateRoute(hops ...*hop.Payload) (
591
        [lnwire.OnionPacketSize]byte, error) {
362✔
592

362✔
593
        var blob [lnwire.OnionPacketSize]byte
362✔
594
        if len(hops) == 0 {
362✔
595
                return blob, errors.New("empty path")
×
596
        }
×
597

598
        iterator := newMockHopIterator(hops...)
362✔
599

362✔
600
        w := bytes.NewBuffer(blob[0:0])
362✔
601
        if err := iterator.EncodeNextHop(w); err != nil {
362✔
602
                return blob, err
×
603
        }
×
604

605
        return blob, nil
362✔
606

607
}
608

609
// threeHopNetwork is used for managing the created cluster of 3 hops.
610
type threeHopNetwork struct {
611
        aliceServer       *mockServer
612
        aliceChannelLink  *channelLink
613
        aliceOnionDecoder *mockIteratorDecoder
614

615
        bobServer            *mockServer
616
        firstBobChannelLink  *channelLink
617
        secondBobChannelLink *channelLink
618
        bobOnionDecoder      *mockIteratorDecoder
619

620
        carolServer       *mockServer
621
        carolChannelLink  *channelLink
622
        carolOnionDecoder *mockIteratorDecoder
623

624
        hopNetwork
625
}
626

627
// generateHops creates the per hop payload, the total amount to be sent, and
628
// also the time lock value needed to route an HTLC with the target amount over
629
// the specified path.
630
func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32,
631
        path ...*channelLink) (lnwire.MilliSatoshi, uint32, []*hop.Payload) {
243✔
632

243✔
633
        totalTimelock := startingHeight
243✔
634
        runningAmt := payAmt
243✔
635

243✔
636
        hops := make([]*hop.Payload, len(path))
243✔
637
        for i := len(path) - 1; i >= 0; i-- {
510✔
638
                // If this is the last hop, then the next hop is the special
267✔
639
                // "exit node". Otherwise, we look to the "prior" hop.
267✔
640
                nextHop := hop.Exit
267✔
641
                if i != len(path)-1 {
291✔
642
                        nextHop = path[i+1].channel.ShortChanID()
24✔
643
                }
24✔
644

645
                var timeLock uint32
267✔
646
                // If this is the last, hop, then the time lock will be their
267✔
647
                // specified delta policy plus our starting height.
267✔
648
                if i == len(path)-1 {
510✔
649
                        totalTimelock += testInvoiceCltvExpiry
243✔
650
                        timeLock = totalTimelock
243✔
651
                } else {
267✔
652
                        // Otherwise, the outgoing time lock should be the
24✔
653
                        // incoming timelock minus their specified delta.
24✔
654
                        delta := path[i+1].cfg.FwrdingPolicy.TimeLockDelta
24✔
655
                        totalTimelock += delta
24✔
656
                        timeLock = totalTimelock - delta
24✔
657
                }
24✔
658

659
                // Finally, we'll need to calculate the amount to forward. For
660
                // the last hop, it's just the payment amount.
661
                amount := payAmt
267✔
662
                if i != len(path)-1 {
291✔
663
                        prevHop := hops[i+1]
24✔
664
                        prevAmount := prevHop.ForwardingInfo().AmountToForward
24✔
665

24✔
666
                        fee := ExpectedFee(path[i].cfg.FwrdingPolicy, prevAmount)
24✔
667
                        runningAmt += fee
24✔
668

24✔
669
                        // Otherwise, for a node to forward an HTLC, then
24✔
670
                        // following inequality most hold true:
24✔
671
                        //     * amt_in - fee >= amt_to_forward
24✔
672
                        amount = runningAmt - fee
24✔
673
                }
24✔
674

675
                var nextHopBytes [8]byte
267✔
676
                binary.BigEndian.PutUint64(nextHopBytes[:], nextHop.ToUint64())
267✔
677

267✔
678
                hops[i] = hop.NewLegacyPayload(&sphinx.HopData{
267✔
679
                        Realm:         [1]byte{}, // hop.BitcoinNetwork
267✔
680
                        NextAddress:   nextHopBytes,
267✔
681
                        ForwardAmount: uint64(amount),
267✔
682
                        OutgoingCltv:  timeLock,
267✔
683
                })
267✔
684
        }
685

686
        return runningAmt, totalTimelock, hops
243✔
687
}
688

689
type paymentResponse struct {
690
        rhash lntypes.Hash
691
        err   chan error
692
}
693

694
func (r *paymentResponse) Wait(d time.Duration) (lntypes.Hash, error) {
241✔
695
        return r.rhash, waitForPaymentResult(r.err, d)
241✔
696
}
241✔
697

698
// waitForPaymentResult waits for either an error to be received on c or a
699
// timeout.
700
func waitForPaymentResult(c chan error, d time.Duration) error {
242✔
701
        select {
242✔
702
        case err := <-c:
239✔
703
                close(c)
239✔
704
                return err
239✔
705
        case <-time.After(d):
3✔
706
                return errors.New("htlc was not settled in time")
3✔
707
        }
708
}
709

710
// waitForPayFuncResult executes the given function and waits for a result with
711
// a timeout.
712
func waitForPayFuncResult(payFunc func() error, d time.Duration) error {
1✔
713
        errChan := make(chan error)
1✔
714
        go func() {
2✔
715
                errChan <- payFunc()
1✔
716
        }()
1✔
717

718
        return waitForPaymentResult(errChan, d)
1✔
719
}
720

721
// makePayment takes the destination node and amount as input, sends the
722
// payment and returns the error channel to wait for error to be received and
723
// invoice in order to check its status after the payment finished.
724
//
725
// With this function you can send payments:
726
// * from Alice to Bob
727
// * from Alice to Carol through the Bob
728
// * from Alice to some another peer through the Bob
729
func makePayment(sendingPeer, receivingPeer lnpeer.Peer,
730
        firstHop lnwire.ShortChannelID, hops []*hop.Payload,
731
        invoiceAmt, htlcAmt lnwire.MilliSatoshi,
732
        timelock uint32) *paymentResponse {
243✔
733

243✔
734
        paymentErr := make(chan error, 1)
243✔
735
        var rhash lntypes.Hash
243✔
736

243✔
737
        invoice, payFunc, err := preparePayment(sendingPeer, receivingPeer,
243✔
738
                firstHop, hops, invoiceAmt, htlcAmt, timelock,
243✔
739
        )
243✔
740
        if err != nil {
243✔
741
                paymentErr <- err
×
742
                return &paymentResponse{
×
743
                        rhash: rhash,
×
744
                        err:   paymentErr,
×
745
                }
×
746
        }
×
747

748
        rhash = invoice.Terms.PaymentPreimage.Hash()
243✔
749

243✔
750
        // Send payment and expose err channel.
243✔
751
        go func() {
486✔
752
                paymentErr <- payFunc()
243✔
753
        }()
243✔
754

755
        return &paymentResponse{
243✔
756
                rhash: rhash,
243✔
757
                err:   paymentErr,
243✔
758
        }
243✔
759
}
760

761
// preparePayment creates an invoice at the receivingPeer and returns a function
762
// that, when called, launches the payment from the sendingPeer.
763
func preparePayment(sendingPeer, receivingPeer lnpeer.Peer,
764
        firstHop lnwire.ShortChannelID, hops []*hop.Payload,
765
        invoiceAmt, htlcAmt lnwire.MilliSatoshi,
766
        timelock uint32) (*invoices.Invoice, func() error, error) {
244✔
767

244✔
768
        sender := sendingPeer.(*mockServer)
244✔
769
        receiver := receivingPeer.(*mockServer)
244✔
770

244✔
771
        // Generate route convert it to blob, and return next destination for
244✔
772
        // htlc add request.
244✔
773
        blob, err := generateRoute(hops...)
244✔
774
        if err != nil {
244✔
775
                return nil, nil, err
×
776
        }
×
777

778
        // Generate payment: invoice and htlc.
779
        invoice, htlc, pid, err := generatePayment(
244✔
780
                invoiceAmt, htlcAmt, timelock, blob,
244✔
781
        )
244✔
782
        if err != nil {
244✔
783
                return nil, nil, err
×
784
        }
×
785

786
        // Check who is last in the route and add invoice to server registry.
787
        hash := invoice.Terms.PaymentPreimage.Hash()
244✔
788
        if err := receiver.registry.AddInvoice(
244✔
789
                context.Background(), *invoice, hash,
244✔
790
        ); err != nil {
244✔
791
                return nil, nil, err
×
792
        }
×
793

794
        // Send payment and expose err channel.
795
        return invoice, func() error {
488✔
796
                err := sender.htlcSwitch.SendHTLC(
244✔
797
                        firstHop, pid, htlc,
244✔
798
                )
244✔
799
                if err != nil {
246✔
800
                        return err
2✔
801
                }
2✔
802
                resultChan, err := sender.htlcSwitch.GetAttemptResult(
242✔
803
                        pid, hash, newMockDeobfuscator(),
242✔
804
                )
242✔
805
                if err != nil {
242✔
806
                        return err
×
807
                }
×
808

809
                result, ok := <-resultChan
242✔
810
                if !ok {
246✔
811
                        return fmt.Errorf("shutting down")
4✔
812
                }
4✔
813

814
                if result.Error != nil {
353✔
815
                        return result.Error
115✔
816
                }
115✔
817

818
                return nil
123✔
819
        }, nil
820
}
821

822
// start starts the three hop network alice,bob,carol servers.
823
func (n *threeHopNetwork) start() error {
39✔
824
        if err := n.aliceServer.Start(); err != nil {
39✔
825
                return err
×
826
        }
×
827
        if err := n.bobServer.Start(); err != nil {
39✔
828
                return err
×
829
        }
×
830
        if err := n.carolServer.Start(); err != nil {
39✔
831
                return err
×
832
        }
×
833

834
        return waitLinksEligible(map[string]*channelLink{
39✔
835
                "alice":      n.aliceChannelLink,
39✔
836
                "bob first":  n.firstBobChannelLink,
39✔
837
                "bob second": n.secondBobChannelLink,
39✔
838
                "carol":      n.carolChannelLink,
39✔
839
        })
39✔
840
}
841

842
// stop stops nodes and cleanup its databases.
843
func (n *threeHopNetwork) stop() {
40✔
844
        done := make(chan struct{})
40✔
845
        go func() {
80✔
846
                n.aliceServer.Stop()
40✔
847
                done <- struct{}{}
40✔
848
        }()
40✔
849

850
        go func() {
80✔
851
                n.bobServer.Stop()
40✔
852
                done <- struct{}{}
40✔
853
        }()
40✔
854

855
        go func() {
80✔
856
                n.carolServer.Stop()
40✔
857
                done <- struct{}{}
40✔
858
        }()
40✔
859

860
        for i := 0; i < 3; i++ {
160✔
861
                <-done
120✔
862
        }
120✔
863
}
864

865
type clusterChannels struct {
866
        aliceToBob *lnwallet.LightningChannel
867
        bobToAlice *lnwallet.LightningChannel
868
        bobToCarol *lnwallet.LightningChannel
869
        carolToBob *lnwallet.LightningChannel
870
}
871

872
// createClusterChannels creates lightning channels which are needed for
873
// network cluster to be initialized.
874
func createClusterChannels(t *testing.T, aliceToBob, bobToCarol btcutil.Amount) (
875
        *clusterChannels, func() (*clusterChannels, error), error) {
37✔
876

37✔
877
        _, _, firstChanID, secondChanID := genIDs()
37✔
878

37✔
879
        // Create lightning channels between Alice<->Bob and Bob<->Carol
37✔
880
        aliceChannel, firstBobChannel, err := createTestChannel(t, alicePrivKey,
37✔
881
                bobPrivKey, aliceToBob, aliceToBob, 0, 0, firstChanID,
37✔
882
        )
37✔
883
        if err != nil {
37✔
884
                return nil, nil, errors.Errorf("unable to create "+
×
885
                        "alice<->bob channel: %v", err)
×
886
        }
×
887

888
        secondBobChannel, carolChannel, err := createTestChannel(t, bobPrivKey,
37✔
889
                carolPrivKey, bobToCarol, bobToCarol, 0, 0, secondChanID,
37✔
890
        )
37✔
891
        if err != nil {
37✔
892
                return nil, nil, errors.Errorf("unable to create "+
×
893
                        "bob<->carol channel: %v", err)
×
894
        }
×
895

896
        restoreFromDb := func() (*clusterChannels, error) {
40✔
897

3✔
898
                a2b, err := aliceChannel.restore()
3✔
899
                if err != nil {
3✔
900
                        return nil, err
×
901
                }
×
902

903
                b2a, err := firstBobChannel.restore()
3✔
904
                if err != nil {
3✔
905
                        return nil, err
×
906
                }
×
907

908
                b2c, err := secondBobChannel.restore()
3✔
909
                if err != nil {
3✔
910
                        return nil, err
×
911
                }
×
912

913
                c2b, err := carolChannel.restore()
3✔
914
                if err != nil {
3✔
915
                        return nil, err
×
916
                }
×
917

918
                return &clusterChannels{
3✔
919
                        aliceToBob: a2b,
3✔
920
                        bobToAlice: b2a,
3✔
921
                        bobToCarol: b2c,
3✔
922
                        carolToBob: c2b,
3✔
923
                }, nil
3✔
924
        }
925

926
        return &clusterChannels{
37✔
927
                aliceToBob: aliceChannel.channel,
37✔
928
                bobToAlice: firstBobChannel.channel,
37✔
929
                bobToCarol: secondBobChannel.channel,
37✔
930
                carolToBob: carolChannel.channel,
37✔
931
        }, restoreFromDb, nil
37✔
932
}
933

934
// newThreeHopNetwork function creates the following topology and returns the
935
// control object to manage this cluster:
936
//
937
// alice                      bob                             carol
938
// server - <-connection-> - server - - <-connection-> - - - server
939
//
940
//        |                           |                               |
941
//
942
// alice htlc                     bob htlc                          carol htlc
943
// switch                      switch        \                    switch
944
//
945
//        |                         |       \                       |
946
//        |                         |        \                       |
947
//
948
// alice                   first bob     second bob           carol
949
// channel link                      channel link   channel link      channel link
950
//
951
// This function takes server options which can be used to apply custom
952
// settings to alice, bob and carol.
953
func newThreeHopNetwork(t testing.TB, aliceChannel, firstBobChannel,
954
        secondBobChannel, carolChannel *lnwallet.LightningChannel,
955
        startingHeight uint32, opts ...serverOption) *threeHopNetwork {
39✔
956

39✔
957
        aliceDb := aliceChannel.State().Db.GetParentDB()
39✔
958
        bobDb := firstBobChannel.State().Db.GetParentDB()
39✔
959
        carolDb := carolChannel.State().Db.GetParentDB()
39✔
960

39✔
961
        hopNetwork := newHopNetwork()
39✔
962

39✔
963
        // Create three peers/servers.
39✔
964
        aliceServer, err := newMockServer(
39✔
965
                t, "alice", startingHeight, aliceDb, hopNetwork.defaultDelta,
39✔
966
        )
39✔
967
        require.NoError(t, err, "unable to create alice server")
39✔
968
        bobServer, err := newMockServer(
39✔
969
                t, "bob", startingHeight, bobDb, hopNetwork.defaultDelta,
39✔
970
        )
39✔
971
        require.NoError(t, err, "unable to create bob server")
39✔
972
        carolServer, err := newMockServer(
39✔
973
                t, "carol", startingHeight, carolDb, hopNetwork.defaultDelta,
39✔
974
        )
39✔
975
        require.NoError(t, err, "unable to create carol server")
39✔
976

39✔
977
        // Apply all additional functional options to the servers before
39✔
978
        // creating any links.
39✔
979
        for _, option := range opts {
42✔
980
                option(aliceServer, bobServer, carolServer)
3✔
981
        }
3✔
982

983
        // Create mock decoder instead of sphinx one in order to mock the route
984
        // which htlc should follow.
985
        aliceDecoder := newMockIteratorDecoder()
39✔
986
        bobDecoder := newMockIteratorDecoder()
39✔
987
        carolDecoder := newMockIteratorDecoder()
39✔
988

39✔
989
        aliceChannelLink, err := hopNetwork.createChannelLink(aliceServer,
39✔
990
                bobServer, aliceChannel, aliceDecoder,
39✔
991
        )
39✔
992
        if err != nil {
39✔
993
                t.Fatal(err)
×
994
        }
×
995

996
        firstBobChannelLink, err := hopNetwork.createChannelLink(bobServer,
39✔
997
                aliceServer, firstBobChannel, bobDecoder)
39✔
998
        if err != nil {
39✔
999
                t.Fatal(err)
×
1000
        }
×
1001

1002
        secondBobChannelLink, err := hopNetwork.createChannelLink(bobServer,
39✔
1003
                carolServer, secondBobChannel, bobDecoder)
39✔
1004
        if err != nil {
39✔
1005
                t.Fatal(err)
×
1006
        }
×
1007

1008
        carolChannelLink, err := hopNetwork.createChannelLink(carolServer,
39✔
1009
                bobServer, carolChannel, carolDecoder)
39✔
1010
        if err != nil {
39✔
1011
                t.Fatal(err)
×
1012
        }
×
1013

1014
        return &threeHopNetwork{
39✔
1015
                aliceServer:       aliceServer,
39✔
1016
                aliceChannelLink:  aliceChannelLink.(*channelLink),
39✔
1017
                aliceOnionDecoder: aliceDecoder,
39✔
1018

39✔
1019
                bobServer:            bobServer,
39✔
1020
                firstBobChannelLink:  firstBobChannelLink.(*channelLink),
39✔
1021
                secondBobChannelLink: secondBobChannelLink.(*channelLink),
39✔
1022
                bobOnionDecoder:      bobDecoder,
39✔
1023

39✔
1024
                carolServer:       carolServer,
39✔
1025
                carolChannelLink:  carolChannelLink.(*channelLink),
39✔
1026
                carolOnionDecoder: carolDecoder,
39✔
1027

39✔
1028
                hopNetwork: *hopNetwork,
39✔
1029
        }
39✔
1030
}
1031

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

1036
// serverOptionWithHtlcNotifier is a functional option for the creation of
1037
// three hop network servers which allows setting of htlc notifiers.
1038
// Note that these notifiers should be started and stopped by the calling
1039
// function.
1040
func serverOptionWithHtlcNotifier(alice, bob,
1041
        carol *HtlcNotifier) serverOption {
2✔
1042

2✔
1043
        return func(aliceServer, bobServer, carolServer *mockServer) {
4✔
1044
                aliceServer.htlcSwitch.cfg.HtlcNotifier = alice
2✔
1045
                bobServer.htlcSwitch.cfg.HtlcNotifier = bob
2✔
1046
                carolServer.htlcSwitch.cfg.HtlcNotifier = carol
2✔
1047
        }
2✔
1048
}
1049

1050
// serverOptionRejectHtlc is the functional option for setting the reject
1051
// htlc config option in each server's switch.
1052
func serverOptionRejectHtlc(alice, bob, carol bool) serverOption {
1✔
1053
        return func(aliceServer, bobServer, carolServer *mockServer) {
2✔
1054
                aliceServer.htlcSwitch.cfg.RejectHTLC = alice
1✔
1055
                bobServer.htlcSwitch.cfg.RejectHTLC = bob
1✔
1056
                carolServer.htlcSwitch.cfg.RejectHTLC = carol
1✔
1057
        }
1✔
1058
}
1059

1060
// createMirroredChannel creates two LightningChannel objects which represent
1061
// the state machines on either side of a single channel between alice and bob.
1062
func createMirroredChannel(t *testing.T, aliceToBob,
1063
        bobToAlice btcutil.Amount) (*testLightningChannel,
1064
        *testLightningChannel, error) {
5✔
1065

5✔
1066
        _, _, firstChanID, _ := genIDs()
5✔
1067

5✔
1068
        // Create lightning channels between Alice<->Bob for Alice and Bob
5✔
1069
        alice, bob, err := createTestChannel(t, alicePrivKey, bobPrivKey,
5✔
1070
                aliceToBob, bobToAlice, 0, 0, firstChanID,
5✔
1071
        )
5✔
1072
        if err != nil {
5✔
1073
                return nil, nil, errors.Errorf("unable to create "+
×
1074
                        "alice<->bob channel: %v", err)
×
1075
        }
×
1076

1077
        return alice, bob, nil
5✔
1078
}
1079

1080
// hopNetwork is the base struct for two and three hop networks
1081
type hopNetwork struct {
1082
        feeEstimator *mockFeeEstimator
1083
        globalPolicy models.ForwardingPolicy
1084
        obfuscator   hop.ErrorEncrypter
1085

1086
        defaultDelta uint32
1087
}
1088

1089
func newHopNetwork() *hopNetwork {
45✔
1090
        defaultDelta := uint32(6)
45✔
1091

45✔
1092
        globalPolicy := models.ForwardingPolicy{
45✔
1093
                MinHTLCOut:    lnwire.NewMSatFromSatoshis(5),
45✔
1094
                BaseFee:       lnwire.NewMSatFromSatoshis(1),
45✔
1095
                TimeLockDelta: defaultDelta,
45✔
1096
        }
45✔
1097
        obfuscator := NewMockObfuscator()
45✔
1098

45✔
1099
        return &hopNetwork{
45✔
1100
                feeEstimator: newMockFeeEstimator(),
45✔
1101
                globalPolicy: globalPolicy,
45✔
1102
                obfuscator:   obfuscator,
45✔
1103
                defaultDelta: defaultDelta,
45✔
1104
        }
45✔
1105
}
45✔
1106

1107
func (h *hopNetwork) createChannelLink(server, peer *mockServer,
1108
        channel *lnwallet.LightningChannel,
1109
        decoder *mockIteratorDecoder) (ChannelLink, error) {
168✔
1110

168✔
1111
        const (
168✔
1112
                fwdPkgTimeout       = 15 * time.Second
168✔
1113
                minFeeUpdateTimeout = 30 * time.Minute
168✔
1114
                maxFeeUpdateTimeout = 40 * time.Minute
168✔
1115
        )
168✔
1116

168✔
1117
        notifyUpdateChan := make(chan *contractcourt.ContractUpdate)
168✔
1118
        doneChan := make(chan struct{})
168✔
1119
        notifyContractUpdate := func(u *contractcourt.ContractUpdate) error {
3,725✔
1120
                select {
3,557✔
1121
                case notifyUpdateChan <- u:
3,545✔
1122
                case <-doneChan:
12✔
1123
                }
1124

1125
                return nil
3,557✔
1126
        }
1127

1128
        getAliases := func(
168✔
1129
                base lnwire.ShortChannelID) []lnwire.ShortChannelID {
336✔
1130

168✔
1131
                return nil
168✔
1132
        }
168✔
1133

1134
        forwardPackets := func(linkQuit <-chan struct{}, _ bool,
168✔
1135
                packets ...*htlcPacket) error {
717✔
1136

549✔
1137
                return server.htlcSwitch.ForwardPackets(linkQuit, packets...)
549✔
1138
        }
549✔
1139

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

1188
        go func() {
336✔
1189
                if chanLink, ok := link.(*channelLink); ok {
336✔
1190
                        for {
3,881✔
1191
                                select {
3,713✔
1192
                                case <-notifyUpdateChan:
3,545✔
1193
                                case <-chanLink.cg.Done():
168✔
1194
                                        close(doneChan)
168✔
1195
                                        return
168✔
1196
                                }
1197
                        }
1198
                }
1199
        }()
1200

1201
        return link, nil
168✔
1202
}
1203

1204
// twoHopNetwork is used for managing the created cluster of 2 hops.
1205
type twoHopNetwork struct {
1206
        hopNetwork
1207

1208
        aliceServer      *mockServer
1209
        aliceChannelLink *channelLink
1210

1211
        bobServer      *mockServer
1212
        bobChannelLink *channelLink
1213
}
1214

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

6✔
1235
        aliceDb := aliceChannel.State().Db.GetParentDB()
6✔
1236
        bobDb := bobChannel.State().Db.GetParentDB()
6✔
1237

6✔
1238
        hopNetwork := newHopNetwork()
6✔
1239

6✔
1240
        // Create two peers/servers.
6✔
1241
        aliceServer, err := newMockServer(
6✔
1242
                t, "alice", startingHeight, aliceDb, hopNetwork.defaultDelta,
6✔
1243
        )
6✔
1244
        require.NoError(t, err, "unable to create alice server")
6✔
1245
        bobServer, err := newMockServer(
6✔
1246
                t, "bob", startingHeight, bobDb, hopNetwork.defaultDelta,
6✔
1247
        )
6✔
1248
        require.NoError(t, err, "unable to create bob server")
6✔
1249

6✔
1250
        // Create mock decoder instead of sphinx one in order to mock the route
6✔
1251
        // which htlc should follow.
6✔
1252
        aliceDecoder := newMockIteratorDecoder()
6✔
1253
        bobDecoder := newMockIteratorDecoder()
6✔
1254

6✔
1255
        aliceChannelLink, err := hopNetwork.createChannelLink(
6✔
1256
                aliceServer, bobServer, aliceChannel, aliceDecoder,
6✔
1257
        )
6✔
1258
        if err != nil {
6✔
1259
                t.Fatal(err)
×
1260
        }
×
1261

1262
        bobChannelLink, err := hopNetwork.createChannelLink(
6✔
1263
                bobServer, aliceServer, bobChannel, bobDecoder,
6✔
1264
        )
6✔
1265
        if err != nil {
6✔
1266
                t.Fatal(err)
×
1267
        }
×
1268

1269
        n := &twoHopNetwork{
6✔
1270
                aliceServer:      aliceServer,
6✔
1271
                aliceChannelLink: aliceChannelLink.(*channelLink),
6✔
1272

6✔
1273
                bobServer:      bobServer,
6✔
1274
                bobChannelLink: bobChannelLink.(*channelLink),
6✔
1275

6✔
1276
                hopNetwork: *hopNetwork,
6✔
1277
        }
6✔
1278

6✔
1279
        require.NoError(t, n.start())
6✔
1280
        t.Cleanup(n.stop)
6✔
1281

6✔
1282
        return n
6✔
1283
}
1284

1285
// start starts the two hop network alice,bob servers.
1286
func (n *twoHopNetwork) start() error {
6✔
1287
        if err := n.aliceServer.Start(); err != nil {
6✔
1288
                return err
×
1289
        }
×
1290
        if err := n.bobServer.Start(); err != nil {
6✔
1291
                n.aliceServer.Stop()
×
1292
                return err
×
1293
        }
×
1294

1295
        return waitLinksEligible(map[string]*channelLink{
6✔
1296
                "alice": n.aliceChannelLink,
6✔
1297
                "bob":   n.bobChannelLink,
6✔
1298
        })
6✔
1299
}
1300

1301
// stop stops nodes and cleanup its databases.
1302
func (n *twoHopNetwork) stop() {
6✔
1303
        done := make(chan struct{})
6✔
1304
        go func() {
12✔
1305
                n.aliceServer.Stop()
6✔
1306
                done <- struct{}{}
6✔
1307
        }()
6✔
1308

1309
        go func() {
12✔
1310
                n.bobServer.Stop()
6✔
1311
                done <- struct{}{}
6✔
1312
        }()
6✔
1313

1314
        for i := 0; i < 2; i++ {
18✔
1315
                <-done
12✔
1316
        }
12✔
1317
}
1318

1319
func (n *twoHopNetwork) makeHoldPayment(sendingPeer, receivingPeer lnpeer.Peer,
1320
        firstHop lnwire.ShortChannelID, hops []*hop.Payload,
1321
        invoiceAmt, htlcAmt lnwire.MilliSatoshi,
1322
        timelock uint32, preimage lntypes.Preimage) chan error {
52✔
1323

52✔
1324
        paymentErr := make(chan error, 1)
52✔
1325

52✔
1326
        sender := sendingPeer.(*mockServer)
52✔
1327
        receiver := receivingPeer.(*mockServer)
52✔
1328

52✔
1329
        // Generate route convert it to blob, and return next destination for
52✔
1330
        // htlc add request.
52✔
1331
        blob, err := generateRoute(hops...)
52✔
1332
        if err != nil {
52✔
1333
                paymentErr <- err
×
1334
                return paymentErr
×
1335
        }
×
1336

1337
        rhash := preimage.Hash()
52✔
1338

52✔
1339
        var payAddr [32]byte
52✔
1340
        if _, err := crand.Read(payAddr[:]); err != nil {
52✔
1341
                panic(err)
×
1342
        }
1343

1344
        // Generate payment: invoice and htlc.
1345
        invoice, htlc, pid, err := generatePaymentWithPreimage(
52✔
1346
                invoiceAmt, htlcAmt, timelock, blob,
52✔
1347
                nil, rhash, payAddr,
52✔
1348
        )
52✔
1349
        if err != nil {
52✔
1350
                paymentErr <- err
×
1351
                return paymentErr
×
1352
        }
×
1353

1354
        // Check who is last in the route and add invoice to server registry.
1355
        if err := receiver.registry.AddInvoice(
52✔
1356
                context.Background(), *invoice, rhash,
52✔
1357
        ); err != nil {
52✔
1358
                paymentErr <- err
×
1359
                return paymentErr
×
1360
        }
×
1361

1362
        // Send payment and expose err channel.
1363
        err = sender.htlcSwitch.SendHTLC(firstHop, pid, htlc)
52✔
1364
        if err != nil {
52✔
1365
                paymentErr <- err
×
1366
                return paymentErr
×
1367
        }
×
1368

1369
        go func() {
104✔
1370
                resultChan, err := sender.htlcSwitch.GetAttemptResult(
52✔
1371
                        pid, rhash, newMockDeobfuscator(),
52✔
1372
                )
52✔
1373
                if err != nil {
52✔
1374
                        paymentErr <- err
×
1375
                        return
×
1376
                }
×
1377

1378
                result, ok := <-resultChan
52✔
1379
                if !ok {
52✔
1380
                        paymentErr <- fmt.Errorf("shutting down")
×
1381
                        return
×
1382
                }
×
1383

1384
                if result.Error != nil {
53✔
1385
                        paymentErr <- result.Error
1✔
1386
                        return
1✔
1387
                }
1✔
1388
                paymentErr <- nil
51✔
1389
        }()
1390

1391
        return paymentErr
52✔
1392
}
1393

1394
// waitLinksEligible blocks until all links the provided name-to-link map are
1395
// eligible to forward HTLCs.
1396
func waitLinksEligible(links map[string]*channelLink) error {
45✔
1397
        return wait.NoError(func() error {
90✔
1398
                for name, link := range links {
213✔
1399
                        if link.EligibleToForward() {
336✔
1400
                                continue
168✔
1401
                        }
1402
                        return fmt.Errorf("%s channel link not eligible", name)
×
1403
                }
1404
                return nil
45✔
1405
        }, 3*time.Second)
1406
}
1407

1408
// timeout implements a test level timeout.
1409
func timeout() func() {
4✔
1410
        done := make(chan struct{})
4✔
1411
        go func() {
8✔
1412
                select {
4✔
1413
                case <-time.After(20 * time.Second):
×
1414
                        pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
×
1415

×
1416
                        panic("test timeout")
×
1417
                case <-done:
4✔
1418
                }
1419
        }()
1420

1421
        return func() {
8✔
1422
                close(done)
4✔
1423
        }
4✔
1424
}
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