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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 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/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.
UNCOV
71
func genID() (lnwire.ChannelID, lnwire.ShortChannelID) {
×
UNCOV
72
        id := atomic.AddUint64(&idSeqNum, 1)
×
UNCOV
73

×
UNCOV
74
        var scratch [8]byte
×
UNCOV
75

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

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

×
UNCOV
83
        return chanID1, aliceChanID
×
UNCOV
84
}
×
85

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

×
UNCOV
90
        chanID1, aliceChanID := genID()
×
UNCOV
91
        chanID2, bobChanID := genID()
×
UNCOV
92

×
UNCOV
93
        return chanID1, chanID2, aliceChanID, bobChanID
×
UNCOV
94
}
×
95

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

×
UNCOV
101
        return &lnwire.ChannelUpdate1{
×
UNCOV
102
                Signature: wireSig,
×
UNCOV
103
        }, nil
×
UNCOV
104
}
×
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.
UNCOV
110
func generateRandomBytes(n int) ([]byte, error) {
×
UNCOV
111
        b := make([]byte, n)
×
UNCOV
112

×
UNCOV
113
        // TODO(roasbeef): should use counter in tests (atomic) rather than
×
UNCOV
114
        // this
×
UNCOV
115

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

UNCOV
122
        return b, nil
×
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,
UNCOV
137
        *testLightningChannel, error) {
×
UNCOV
138

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

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

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

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

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

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

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

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

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

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

UNCOV
254
        dbAlice := channeldb.OpenForTesting(t, t.TempDir())
×
UNCOV
255
        dbBob := channeldb.OpenForTesting(t, t.TempDir())
×
UNCOV
256

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
387
        restoreAlice := func() (*lnwallet.LightningChannel, error) {
×
UNCOV
388
                aliceStoredChannels, err := dbAlice.ChannelStateDB().
×
UNCOV
389
                        FetchOpenChannels(aliceKeyPub)
×
UNCOV
390
                switch err {
×
UNCOV
391
                case nil:
×
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

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

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

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

UNCOV
428
                return newAliceChannel, nil
×
429
        }
430

UNCOV
431
        restoreBob := func() (*lnwallet.LightningChannel, error) {
×
UNCOV
432
                bobStoredChannels, err := dbBob.ChannelStateDB().
×
UNCOV
433
                        FetchOpenChannels(bobKeyPub)
×
UNCOV
434
                switch err {
×
UNCOV
435
                case nil:
×
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

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

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

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

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

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

×
UNCOV
488
        return testLightningChannelAlice, testLightningChannelBob, nil
×
489
}
490

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

UNCOV
515
        return chanID, nil
×
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) (
UNCOV
523
        *invoices.Invoice, *lnwire.UpdateAddHTLC, uint64, error) {
×
UNCOV
524

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

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

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

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

×
UNCOV
559
        return invoice, htlc, paymentID, nil
×
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,
UNCOV
566
        *lnwire.UpdateAddHTLC, uint64, error) {
×
UNCOV
567

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

×
UNCOV
575
        rhash := sha256.Sum256(preimage[:])
×
UNCOV
576

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

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

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

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

UNCOV
598
        iterator := newMockHopIterator(hops...)
×
UNCOV
599

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

UNCOV
605
        return blob, nil
×
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,
UNCOV
631
        path ...*channelLink) (lnwire.MilliSatoshi, uint32, []*hop.Payload) {
×
UNCOV
632

×
UNCOV
633
        totalTimelock := startingHeight
×
UNCOV
634
        runningAmt := payAmt
×
UNCOV
635

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

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

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

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

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

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

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

UNCOV
686
        return runningAmt, totalTimelock, hops
×
687
}
688

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

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

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

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

UNCOV
718
        return waitForPaymentResult(errChan, d)
×
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,
UNCOV
732
        timelock uint32) *paymentResponse {
×
UNCOV
733

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

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

UNCOV
748
        rhash = invoice.Terms.PaymentPreimage.Hash()
×
UNCOV
749

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

UNCOV
755
        return &paymentResponse{
×
UNCOV
756
                rhash: rhash,
×
UNCOV
757
                err:   paymentErr,
×
UNCOV
758
        }
×
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,
UNCOV
766
        timelock uint32) (*invoices.Invoice, func() error, error) {
×
UNCOV
767

×
UNCOV
768
        sender := sendingPeer.(*mockServer)
×
UNCOV
769
        receiver := receivingPeer.(*mockServer)
×
UNCOV
770

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

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

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

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

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

UNCOV
814
                if result.Error != nil {
×
UNCOV
815
                        return result.Error
×
UNCOV
816
                }
×
817

UNCOV
818
                return nil
×
819
        }, nil
820
}
821

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

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

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

UNCOV
850
        go func() {
×
UNCOV
851
                n.bobServer.Stop()
×
UNCOV
852
                done <- struct{}{}
×
UNCOV
853
        }()
×
854

UNCOV
855
        go func() {
×
UNCOV
856
                n.carolServer.Stop()
×
UNCOV
857
                done <- struct{}{}
×
UNCOV
858
        }()
×
859

UNCOV
860
        for i := 0; i < 3; i++ {
×
UNCOV
861
                <-done
×
UNCOV
862
        }
×
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) (
UNCOV
875
        *clusterChannels, func() (*clusterChannels, error), error) {
×
UNCOV
876

×
UNCOV
877
        _, _, firstChanID, secondChanID := genIDs()
×
UNCOV
878

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

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

UNCOV
896
        restoreFromDb := func() (*clusterChannels, error) {
×
UNCOV
897

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

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

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

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

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

UNCOV
926
        return &clusterChannels{
×
UNCOV
927
                aliceToBob: aliceChannel.channel,
×
UNCOV
928
                bobToAlice: firstBobChannel.channel,
×
UNCOV
929
                bobToCarol: secondBobChannel.channel,
×
UNCOV
930
                carolToBob: carolChannel.channel,
×
UNCOV
931
        }, restoreFromDb, nil
×
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,
UNCOV
955
        startingHeight uint32, opts ...serverOption) *threeHopNetwork {
×
UNCOV
956

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

×
UNCOV
961
        hopNetwork := newHopNetwork()
×
UNCOV
962

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

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

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

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

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

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

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

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

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

×
UNCOV
1024
                carolServer:       carolServer,
×
UNCOV
1025
                carolChannelLink:  carolChannelLink.(*channelLink),
×
UNCOV
1026
                carolOnionDecoder: carolDecoder,
×
UNCOV
1027

×
UNCOV
1028
                hopNetwork: *hopNetwork,
×
UNCOV
1029
        }
×
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,
UNCOV
1041
        carol *HtlcNotifier) serverOption {
×
UNCOV
1042

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

1050
// serverOptionRejectHtlc is the functional option for setting the reject
1051
// htlc config option in each server's switch.
UNCOV
1052
func serverOptionRejectHtlc(alice, bob, carol bool) serverOption {
×
UNCOV
1053
        return func(aliceServer, bobServer, carolServer *mockServer) {
×
UNCOV
1054
                aliceServer.htlcSwitch.cfg.RejectHTLC = alice
×
UNCOV
1055
                bobServer.htlcSwitch.cfg.RejectHTLC = bob
×
UNCOV
1056
                carolServer.htlcSwitch.cfg.RejectHTLC = carol
×
UNCOV
1057
        }
×
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,
UNCOV
1064
        *testLightningChannel, error) {
×
UNCOV
1065

×
UNCOV
1066
        _, _, firstChanID, _ := genIDs()
×
UNCOV
1067

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

UNCOV
1077
        return alice, bob, nil
×
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

UNCOV
1089
func newHopNetwork() *hopNetwork {
×
UNCOV
1090
        defaultDelta := uint32(6)
×
UNCOV
1091

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

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

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

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

×
UNCOV
1117
        notifyUpdateChan := make(chan *contractcourt.ContractUpdate)
×
UNCOV
1118
        doneChan := make(chan struct{})
×
UNCOV
1119
        notifyContractUpdate := func(u *contractcourt.ContractUpdate) error {
×
UNCOV
1120
                select {
×
UNCOV
1121
                case notifyUpdateChan <- u:
×
UNCOV
1122
                case <-doneChan:
×
1123
                }
1124

UNCOV
1125
                return nil
×
1126
        }
1127

UNCOV
1128
        getAliases := func(
×
UNCOV
1129
                base lnwire.ShortChannelID) []lnwire.ShortChannelID {
×
UNCOV
1130

×
UNCOV
1131
                return nil
×
UNCOV
1132
        }
×
1133

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

×
UNCOV
1137
                return server.htlcSwitch.ForwardPackets(linkQuit, packets...)
×
UNCOV
1138
        }
×
1139

1140
        //nolint:ll
UNCOV
1141
        link := NewChannelLink(
×
UNCOV
1142
                ChannelLinkConfig{
×
UNCOV
1143
                        BestHeight:         server.htlcSwitch.BestHeight,
×
UNCOV
1144
                        FwrdingPolicy:      h.globalPolicy,
×
UNCOV
1145
                        Peer:               peer,
×
UNCOV
1146
                        Circuits:           server.htlcSwitch.CircuitModifier(),
×
UNCOV
1147
                        ForwardPackets:     forwardPackets,
×
UNCOV
1148
                        DecodeHopIterators: decoder.DecodeHopIterators,
×
UNCOV
1149
                        ExtractErrorEncrypter: func(*btcec.PublicKey) (
×
UNCOV
1150
                                hop.ErrorEncrypter, lnwire.FailCode) {
×
UNCOV
1151
                                return h.obfuscator, lnwire.CodeNone
×
UNCOV
1152
                        },
×
1153
                        FetchLastChannelUpdate: mockGetChanUpdateMessage,
1154
                        Registry:               server.registry,
1155
                        FeeEstimator:           h.feeEstimator,
1156
                        PreimageCache:          server.pCache,
UNCOV
1157
                        UpdateContractSignals: func(*contractcourt.ContractSignals) error {
×
UNCOV
1158
                                return nil
×
UNCOV
1159
                        },
×
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,
UNCOV
1169
                        OnChannelFailure:        func(lnwire.ChannelID, lnwire.ShortChannelID, LinkFailureError) {},
×
1170
                        OutgoingCltvRejectDelta: 3,
1171
                        MaxOutgoingCltvExpiry:   DefaultMaxOutgoingCltvExpiry,
1172
                        MaxFeeAllocation:        DefaultMaxLinkFeeAllocation,
1173
                        MaxAnchorsCommitFeeRate: chainfee.SatPerKVByte(10 * 1000).FeePerKWeight(),
UNCOV
1174
                        NotifyActiveLink:        func(wire.OutPoint) {},
×
UNCOV
1175
                        NotifyActiveChannel:     func(wire.OutPoint) {},
×
UNCOV
1176
                        NotifyInactiveChannel:   func(wire.OutPoint) {},
×
UNCOV
1177
                        NotifyInactiveLinkEvent: func(wire.OutPoint) {},
×
1178
                        HtlcNotifier:            server.htlcSwitch.cfg.HtlcNotifier,
1179
                        GetAliases:              getAliases,
UNCOV
1180
                        ShouldFwdExpEndorsement: func() bool { return true },
×
1181
                },
1182
                channel,
1183
        )
UNCOV
1184
        if err := server.htlcSwitch.AddLink(link); err != nil {
×
1185
                return nil, fmt.Errorf("unable to add channel link: %w", err)
×
1186
        }
×
1187

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

UNCOV
1201
        return link, nil
×
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,
UNCOV
1233
        startingHeight uint32) *twoHopNetwork {
×
UNCOV
1234

×
UNCOV
1235
        aliceDb := aliceChannel.State().Db.GetParentDB()
×
UNCOV
1236
        bobDb := bobChannel.State().Db.GetParentDB()
×
UNCOV
1237

×
UNCOV
1238
        hopNetwork := newHopNetwork()
×
UNCOV
1239

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

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

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

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

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

×
UNCOV
1273
                bobServer:      bobServer,
×
UNCOV
1274
                bobChannelLink: bobChannelLink.(*channelLink),
×
UNCOV
1275

×
UNCOV
1276
                hopNetwork: *hopNetwork,
×
UNCOV
1277
        }
×
UNCOV
1278

×
UNCOV
1279
        require.NoError(t, n.start())
×
UNCOV
1280
        t.Cleanup(n.stop)
×
UNCOV
1281

×
UNCOV
1282
        return n
×
1283
}
1284

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

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

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

UNCOV
1309
        go func() {
×
UNCOV
1310
                n.bobServer.Stop()
×
UNCOV
1311
                done <- struct{}{}
×
UNCOV
1312
        }()
×
1313

UNCOV
1314
        for i := 0; i < 2; i++ {
×
UNCOV
1315
                <-done
×
UNCOV
1316
        }
×
1317
}
1318

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

×
UNCOV
1324
        paymentErr := make(chan error, 1)
×
UNCOV
1325

×
UNCOV
1326
        sender := sendingPeer.(*mockServer)
×
UNCOV
1327
        receiver := receivingPeer.(*mockServer)
×
UNCOV
1328

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

UNCOV
1337
        rhash := preimage.Hash()
×
UNCOV
1338

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

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

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

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

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

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

UNCOV
1384
                if result.Error != nil {
×
UNCOV
1385
                        paymentErr <- result.Error
×
UNCOV
1386
                        return
×
UNCOV
1387
                }
×
UNCOV
1388
                paymentErr <- nil
×
1389
        }()
1390

UNCOV
1391
        return paymentErr
×
1392
}
1393

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

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

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

UNCOV
1421
        return func() {
×
UNCOV
1422
                close(done)
×
UNCOV
1423
        }
×
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