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

lightningnetwork / lnd / 13035292482

29 Jan 2025 03:59PM UTC coverage: 49.3% (-9.5%) from 58.777%
13035292482

Pull #9456

github

mohamedawnallah
docs: update release-notes-0.19.0.md

In this commit, we warn users about the removal
of RPCs `SendToRoute`, `SendToRouteSync`, `SendPayment`,
and `SendPaymentSync` in the next release 0.20.
Pull Request #9456: lnrpc+docs: deprecate warning `SendToRoute`, `SendToRouteSync`, `SendPayment`, and `SendPaymentSync` in Release 0.19

100634 of 204126 relevant lines covered (49.3%)

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

×
74
        var scratch [8]byte
×
75

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

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

×
83
        return chanID1, aliceChanID
×
84
}
×
85

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

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

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

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

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

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

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

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,
137
        *testLightningChannel, error) {
×
138

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

428
                return newAliceChannel, nil
×
429
        }
430

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

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

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

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

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

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

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

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

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

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

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

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

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

×
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,
566
        *lnwire.UpdateAddHTLC, uint64, error) {
×
567

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

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

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

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

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

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

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

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

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

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

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

645
                var timeLock uint32
×
646
                // If this is the last, hop, then the time lock will be their
×
647
                // specified delta policy plus our starting height.
×
648
                if i == len(path)-1 {
×
649
                        totalTimelock += testInvoiceCltvExpiry
×
650
                        timeLock = totalTimelock
×
651
                } else {
×
652
                        // Otherwise, the outgoing time lock should be the
×
653
                        // incoming timelock minus their specified delta.
×
654
                        delta := path[i+1].cfg.FwrdingPolicy.TimeLockDelta
×
655
                        totalTimelock += delta
×
656
                        timeLock = totalTimelock - delta
×
657
                }
×
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
×
662
                if i != len(path)-1 {
×
663
                        prevHop := hops[i+1]
×
664
                        prevAmount := prevHop.ForwardingInfo().AmountToForward
×
665

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

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

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

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

686
        return runningAmt, totalTimelock, hops
×
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) {
×
695
        return r.rhash, waitForPaymentResult(r.err, d)
×
696
}
×
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 {
×
701
        select {
×
702
        case err := <-c:
×
703
                close(c)
×
704
                return err
×
705
        case <-time.After(d):
×
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.
712
func waitForPayFuncResult(payFunc func() error, d time.Duration) error {
×
713
        errChan := make(chan error)
×
714
        go func() {
×
715
                errChan <- payFunc()
×
716
        }()
×
717

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,
732
        timelock uint32) *paymentResponse {
×
733

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

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

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

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

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

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

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

778
        // Generate payment: invoice and htlc.
779
        invoice, htlc, pid, err := generatePayment(
×
780
                invoiceAmt, htlcAmt, timelock, blob,
×
781
        )
×
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.
787
        hash := invoice.Terms.PaymentPreimage.Hash()
×
788
        if err := receiver.registry.AddInvoice(
×
789
                context.Background(), *invoice, hash,
×
790
        ); err != nil {
×
791
                return nil, nil, err
×
792
        }
×
793

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

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

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

818
                return nil
×
819
        }, nil
820
}
821

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

×
961
        hopNetwork := newHopNetwork()
×
962

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

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

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

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

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

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

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

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

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

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

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

×
1043
        return func(aliceServer, bobServer, carolServer *mockServer) {
×
1044
                aliceServer.htlcSwitch.cfg.HtlcNotifier = alice
×
1045
                bobServer.htlcSwitch.cfg.HtlcNotifier = bob
×
1046
                carolServer.htlcSwitch.cfg.HtlcNotifier = carol
×
1047
        }
×
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 {
×
1053
        return func(aliceServer, bobServer, carolServer *mockServer) {
×
1054
                aliceServer.htlcSwitch.cfg.RejectHTLC = alice
×
1055
                bobServer.htlcSwitch.cfg.RejectHTLC = bob
×
1056
                carolServer.htlcSwitch.cfg.RejectHTLC = carol
×
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,
1064
        *testLightningChannel, error) {
×
1065

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

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

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

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

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

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

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

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

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

1125
                return nil
×
1126
        }
1127

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

×
1131
                return nil
×
1132
        }
×
1133

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

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

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

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

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,
1233
        startingHeight uint32) *twoHopNetwork {
×
1234

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

×
1238
        hopNetwork := newHopNetwork()
×
1239

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

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

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

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

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

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

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

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

×
1282
        return n
×
1283
}
1284

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

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

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

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

1314
        for i := 0; i < 2; i++ {
×
1315
                <-done
×
1316
        }
×
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 {
×
1323

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

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

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

1337
        rhash := preimage.Hash()
×
1338

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

1344
        // Generate payment: invoice and htlc.
1345
        invoice, htlc, pid, err := generatePaymentWithPreimage(
×
1346
                invoiceAmt, htlcAmt, timelock, blob,
×
1347
                nil, rhash, payAddr,
×
1348
        )
×
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.
1355
        if err := receiver.registry.AddInvoice(
×
1356
                context.Background(), *invoice, rhash,
×
1357
        ); err != nil {
×
1358
                paymentErr <- err
×
1359
                return paymentErr
×
1360
        }
×
1361

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

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

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

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

1391
        return paymentErr
×
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 {
×
1397
        return wait.NoError(func() error {
×
1398
                for name, link := range links {
×
1399
                        if link.EligibleToForward() {
×
1400
                                continue
×
1401
                        }
1402
                        return fmt.Errorf("%s channel link not eligible", name)
×
1403
                }
1404
                return nil
×
1405
        }, 3*time.Second)
1406
}
1407

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

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

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