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

lightningnetwork / lnd / 14350940652

09 Apr 2025 06:57AM UTC coverage: 58.625%. First build
14350940652

Pull #9691

github

web-flow
Merge d50df36db into ac052988c
Pull Request #9691: htlcswitch+peer: thread context through in preparation for passing to graph DB calls

187 of 266 new or added lines in 15 files covered. (70.3%)

97184 of 165773 relevant lines covered (58.62%)

1.82 hits per line

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

0.0
/peer/test_utils.go
1
package peer
2

3
import (
4
        "bytes"
5
        "context"
6
        crand "crypto/rand"
7
        "encoding/binary"
8
        "io"
9
        "math/rand"
10
        "net"
11
        "sync/atomic"
12
        "testing"
13
        "time"
14

15
        "github.com/btcsuite/btcd/btcec/v2"
16
        "github.com/btcsuite/btcd/btcutil"
17
        "github.com/btcsuite/btcd/chaincfg/chainhash"
18
        "github.com/btcsuite/btcd/wire"
19
        "github.com/lightningnetwork/lnd/chainntnfs"
20
        "github.com/lightningnetwork/lnd/channeldb"
21
        "github.com/lightningnetwork/lnd/channelnotifier"
22
        "github.com/lightningnetwork/lnd/fn/v2"
23
        graphdb "github.com/lightningnetwork/lnd/graph/db"
24
        "github.com/lightningnetwork/lnd/htlcswitch"
25
        "github.com/lightningnetwork/lnd/input"
26
        "github.com/lightningnetwork/lnd/keychain"
27
        "github.com/lightningnetwork/lnd/kvdb"
28
        "github.com/lightningnetwork/lnd/lntest/channels"
29
        "github.com/lightningnetwork/lnd/lntest/mock"
30
        "github.com/lightningnetwork/lnd/lntypes"
31
        "github.com/lightningnetwork/lnd/lnwallet"
32
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
33
        "github.com/lightningnetwork/lnd/lnwire"
34
        "github.com/lightningnetwork/lnd/netann"
35
        "github.com/lightningnetwork/lnd/pool"
36
        "github.com/lightningnetwork/lnd/queue"
37
        "github.com/lightningnetwork/lnd/shachain"
38
        "github.com/stretchr/testify/require"
39
)
40

41
const (
42
        broadcastHeight = 100
43

44
        // timeout is a timeout value to use for tests which need to wait for
45
        // a return value on a channel.
46
        timeout = time.Second * 5
47

48
        // testCltvRejectDelta is the minimum delta between expiry and current
49
        // height below which htlcs are rejected.
50
        testCltvRejectDelta = 13
51
)
52

53
var (
54
        testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
55
)
56

57
// noUpdate is a function which can be used as a parameter in
58
// createTestPeerWithChannel to call the setup code with no custom values on
59
// the channels set up.
60
var noUpdate = func(a, b *channeldb.OpenChannel) {}
×
61

62
type peerTestCtx struct {
63
        peer          *Brontide
64
        channel       *lnwallet.LightningChannel
65
        notifier      *mock.ChainNotifier
66
        publishTx     <-chan *wire.MsgTx
67
        mockSwitch    *mockMessageSwitch
68
        db            *channeldb.DB
69
        privKey       *btcec.PrivateKey
70
        mockConn      *mockMessageConn
71
        customChan    chan *customMsg
72
        chanStatusMgr *netann.ChanStatusManager
73
}
74

75
// createTestPeerWithChannel creates a channel between two nodes, and returns a
76
// peer for one of the nodes, together with the channel seen from both nodes.
77
// It takes an updateChan function which can be used to modify the default
78
// values on the channel states for each peer.
79
func createTestPeerWithChannel(t *testing.T, updateChan func(a,
80
        b *channeldb.OpenChannel)) (*peerTestCtx, error) {
×
81

×
82
        params := createTestPeer(t)
×
83

×
84
        var (
×
85
                publishTx     = params.publishTx
×
86
                mockSwitch    = params.mockSwitch
×
87
                alicePeer     = params.peer
×
88
                notifier      = params.notifier
×
89
                aliceKeyPriv  = params.privKey
×
90
                dbAlice       = params.db
×
91
                chanStatusMgr = params.chanStatusMgr
×
92
        )
×
93

×
94
        err := chanStatusMgr.Start()
×
95
        require.NoError(t, err)
×
96
        t.Cleanup(func() {
×
97
                require.NoError(t, chanStatusMgr.Stop())
×
98
        })
×
99

100
        aliceKeyPub := alicePeer.IdentityKey()
×
101
        estimator := alicePeer.cfg.FeeEstimator
×
102

×
103
        channelCapacity := btcutil.Amount(10 * 1e8)
×
104
        channelBal := channelCapacity / 2
×
105
        aliceDustLimit := btcutil.Amount(200)
×
106
        bobDustLimit := btcutil.Amount(1300)
×
107
        csvTimeoutAlice := uint32(5)
×
108
        csvTimeoutBob := uint32(4)
×
109
        isAliceInitiator := true
×
110

×
111
        prevOut := &wire.OutPoint{
×
112
                Hash:  channels.TestHdSeed,
×
113
                Index: 0,
×
114
        }
×
115
        fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
×
116

×
117
        bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
×
118
                channels.BobsPrivKey,
×
119
        )
×
120

×
121
        aliceCfg := channeldb.ChannelConfig{
×
122
                ChannelStateBounds: channeldb.ChannelStateBounds{
×
123
                        MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()),
×
124
                        ChanReserve:      btcutil.Amount(rand.Int63()),
×
125
                        MinHTLC:          lnwire.MilliSatoshi(rand.Int63()),
×
126
                        MaxAcceptedHtlcs: uint16(rand.Int31()),
×
127
                },
×
128
                CommitmentParams: channeldb.CommitmentParams{
×
129
                        DustLimit: aliceDustLimit,
×
130
                        CsvDelay:  uint16(csvTimeoutAlice),
×
131
                },
×
132
                MultiSigKey: keychain.KeyDescriptor{
×
133
                        PubKey: aliceKeyPub,
×
134
                },
×
135
                RevocationBasePoint: keychain.KeyDescriptor{
×
136
                        PubKey: aliceKeyPub,
×
137
                },
×
138
                PaymentBasePoint: keychain.KeyDescriptor{
×
139
                        PubKey: aliceKeyPub,
×
140
                },
×
141
                DelayBasePoint: keychain.KeyDescriptor{
×
142
                        PubKey: aliceKeyPub,
×
143
                },
×
144
                HtlcBasePoint: keychain.KeyDescriptor{
×
145
                        PubKey: aliceKeyPub,
×
146
                },
×
147
        }
×
148
        bobCfg := channeldb.ChannelConfig{
×
149
                ChannelStateBounds: channeldb.ChannelStateBounds{
×
150
                        MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()),
×
151
                        ChanReserve:      btcutil.Amount(rand.Int63()),
×
152
                        MinHTLC:          lnwire.MilliSatoshi(rand.Int63()),
×
153
                        MaxAcceptedHtlcs: uint16(rand.Int31()),
×
154
                },
×
155
                CommitmentParams: channeldb.CommitmentParams{
×
156
                        DustLimit: bobDustLimit,
×
157
                        CsvDelay:  uint16(csvTimeoutBob),
×
158
                },
×
159
                MultiSigKey: keychain.KeyDescriptor{
×
160
                        PubKey: bobKeyPub,
×
161
                },
×
162
                RevocationBasePoint: keychain.KeyDescriptor{
×
163
                        PubKey: bobKeyPub,
×
164
                },
×
165
                PaymentBasePoint: keychain.KeyDescriptor{
×
166
                        PubKey: bobKeyPub,
×
167
                },
×
168
                DelayBasePoint: keychain.KeyDescriptor{
×
169
                        PubKey: bobKeyPub,
×
170
                },
×
171
                HtlcBasePoint: keychain.KeyDescriptor{
×
172
                        PubKey: bobKeyPub,
×
173
                },
×
174
        }
×
175

×
176
        bobRoot, err := chainhash.NewHash(bobKeyPriv.Serialize())
×
177
        if err != nil {
×
178
                return nil, err
×
179
        }
×
180
        bobPreimageProducer := shachain.NewRevocationProducer(*bobRoot)
×
181
        bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
×
182
        if err != nil {
×
183
                return nil, err
×
184
        }
×
185
        bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
×
186

×
187
        aliceRoot, err := chainhash.NewHash(aliceKeyPriv.Serialize())
×
188
        if err != nil {
×
189
                return nil, err
×
190
        }
×
191
        alicePreimageProducer := shachain.NewRevocationProducer(*aliceRoot)
×
192
        aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
×
193
        if err != nil {
×
194
                return nil, err
×
195
        }
×
196
        aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
×
197

×
198
        aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(
×
199
                channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint,
×
200
                bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit,
×
201
                isAliceInitiator, 0,
×
202
        )
×
203
        if err != nil {
×
204
                return nil, err
×
205
        }
×
206

207
        dbBob := channeldb.OpenForTesting(t, t.TempDir())
×
208

×
209
        feePerKw, err := estimator.EstimateFeePerKW(1)
×
210
        if err != nil {
×
211
                return nil, err
×
212
        }
×
213

214
        // TODO(roasbeef): need to factor in commit fee?
215
        aliceCommit := channeldb.ChannelCommitment{
×
216
                CommitHeight:  0,
×
217
                LocalBalance:  lnwire.NewMSatFromSatoshis(channelBal),
×
218
                RemoteBalance: lnwire.NewMSatFromSatoshis(channelBal),
×
219
                FeePerKw:      btcutil.Amount(feePerKw),
×
220
                CommitFee:     feePerKw.FeeForWeight(input.CommitWeight),
×
221
                CommitTx:      aliceCommitTx,
×
222
                CommitSig:     bytes.Repeat([]byte{1}, 71),
×
223
        }
×
224
        bobCommit := channeldb.ChannelCommitment{
×
225
                CommitHeight:  0,
×
226
                LocalBalance:  lnwire.NewMSatFromSatoshis(channelBal),
×
227
                RemoteBalance: lnwire.NewMSatFromSatoshis(channelBal),
×
228
                FeePerKw:      btcutil.Amount(feePerKw),
×
229
                CommitFee:     feePerKw.FeeForWeight(input.CommitWeight),
×
230
                CommitTx:      bobCommitTx,
×
231
                CommitSig:     bytes.Repeat([]byte{1}, 71),
×
232
        }
×
233

×
234
        var chanIDBytes [8]byte
×
235
        if _, err := io.ReadFull(crand.Reader, chanIDBytes[:]); err != nil {
×
236
                return nil, err
×
237
        }
×
238

239
        shortChanID := lnwire.NewShortChanIDFromInt(
×
240
                binary.BigEndian.Uint64(chanIDBytes[:]),
×
241
        )
×
242

×
243
        aliceChannelState := &channeldb.OpenChannel{
×
244
                LocalChanCfg:            aliceCfg,
×
245
                RemoteChanCfg:           bobCfg,
×
246
                IdentityPub:             aliceKeyPub,
×
247
                FundingOutpoint:         *prevOut,
×
248
                ShortChannelID:          shortChanID,
×
249
                ChanType:                channeldb.SingleFunderTweaklessBit,
×
250
                IsInitiator:             isAliceInitiator,
×
251
                Capacity:                channelCapacity,
×
252
                RemoteCurrentRevocation: bobCommitPoint,
×
253
                RevocationProducer:      alicePreimageProducer,
×
254
                RevocationStore:         shachain.NewRevocationStore(),
×
255
                LocalCommitment:         aliceCommit,
×
256
                RemoteCommitment:        aliceCommit,
×
257
                Db:                      dbAlice.ChannelStateDB(),
×
258
                Packager:                channeldb.NewChannelPackager(shortChanID),
×
259
                FundingTxn:              channels.TestFundingTx,
×
260
        }
×
261
        bobChannelState := &channeldb.OpenChannel{
×
262
                LocalChanCfg:            bobCfg,
×
263
                RemoteChanCfg:           aliceCfg,
×
264
                IdentityPub:             bobKeyPub,
×
265
                FundingOutpoint:         *prevOut,
×
266
                ChanType:                channeldb.SingleFunderTweaklessBit,
×
267
                IsInitiator:             !isAliceInitiator,
×
268
                Capacity:                channelCapacity,
×
269
                RemoteCurrentRevocation: aliceCommitPoint,
×
270
                RevocationProducer:      bobPreimageProducer,
×
271
                RevocationStore:         shachain.NewRevocationStore(),
×
272
                LocalCommitment:         bobCommit,
×
273
                RemoteCommitment:        bobCommit,
×
274
                Db:                      dbBob.ChannelStateDB(),
×
275
                Packager:                channeldb.NewChannelPackager(shortChanID),
×
276
        }
×
277

×
278
        // Set custom values on the channel states.
×
279
        updateChan(aliceChannelState, bobChannelState)
×
280

×
281
        aliceAddr := alicePeer.cfg.Addr.Address
×
282
        if err := aliceChannelState.SyncPending(aliceAddr, 0); err != nil {
×
283
                return nil, err
×
284
        }
×
285

286
        bobAddr := &net.TCPAddr{
×
287
                IP:   net.ParseIP("127.0.0.1"),
×
288
                Port: 18556,
×
289
        }
×
290

×
291
        if err := bobChannelState.SyncPending(bobAddr, 0); err != nil {
×
292
                return nil, err
×
293
        }
×
294

295
        aliceSigner := input.NewMockSigner(
×
296
                []*btcec.PrivateKey{aliceKeyPriv}, nil,
×
297
        )
×
298
        bobSigner := input.NewMockSigner(
×
299
                []*btcec.PrivateKey{bobKeyPriv}, nil,
×
300
        )
×
301

×
302
        alicePool := lnwallet.NewSigPool(1, aliceSigner)
×
303
        channelAlice, err := lnwallet.NewLightningChannel(
×
304
                aliceSigner, aliceChannelState, alicePool,
×
305
                lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
×
306
                lnwallet.WithAuxSigner(lnwallet.NewAuxSignerMock(
×
307
                        lnwallet.EmptyMockJobHandler,
×
308
                )),
×
309
        )
×
310
        if err != nil {
×
311
                return nil, err
×
312
        }
×
313
        _ = alicePool.Start()
×
314
        t.Cleanup(func() {
×
315
                require.NoError(t, alicePool.Stop())
×
316
        })
×
317

318
        bobPool := lnwallet.NewSigPool(1, bobSigner)
×
319
        channelBob, err := lnwallet.NewLightningChannel(
×
320
                bobSigner, bobChannelState, bobPool,
×
321
                lnwallet.WithLeafStore(&lnwallet.MockAuxLeafStore{}),
×
322
                lnwallet.WithAuxSigner(lnwallet.NewAuxSignerMock(
×
323
                        lnwallet.EmptyMockJobHandler,
×
324
                )),
×
325
        )
×
326
        if err != nil {
×
327
                return nil, err
×
328
        }
×
329
        _ = bobPool.Start()
×
330
        t.Cleanup(func() {
×
331
                require.NoError(t, bobPool.Stop())
×
332
        })
×
333

334
        alicePeer.remoteFeatures = lnwire.NewFeatureVector(
×
335
                nil, lnwire.Features,
×
336
        )
×
337

×
338
        chanID := lnwire.NewChanIDFromOutPoint(channelAlice.ChannelPoint())
×
339
        alicePeer.activeChannels.Store(chanID, channelAlice)
×
340

×
341
        alicePeer.cg.WgAdd(1)
×
NEW
342
        go alicePeer.channelManager(context.Background())
×
343

×
344
        return &peerTestCtx{
×
345
                peer:       alicePeer,
×
346
                channel:    channelBob,
×
347
                notifier:   notifier,
×
348
                publishTx:  publishTx,
×
349
                mockSwitch: mockSwitch,
×
350
                mockConn:   params.mockConn,
×
351
        }, nil
×
352
}
353

354
// mockMessageSwitch is a mock implementation of the messageSwitch interface
355
// used for testing without relying on a *htlcswitch.Switch in unit tests.
356
type mockMessageSwitch struct {
357
        links []htlcswitch.ChannelUpdateHandler
358
}
359

360
// BestHeight currently returns a dummy value.
361
func (m *mockMessageSwitch) BestHeight() uint32 {
×
362
        return 0
×
363
}
×
364

365
// CircuitModifier currently returns a dummy value.
366
func (m *mockMessageSwitch) CircuitModifier() htlcswitch.CircuitModifier {
×
367
        return nil
×
368
}
×
369

370
// RemoveLink currently does nothing.
371
func (m *mockMessageSwitch) RemoveLink(cid lnwire.ChannelID) {}
×
372

373
// CreateAndAddLink currently returns a dummy value.
374
func (m *mockMessageSwitch) CreateAndAddLink(_ context.Context,
375
        cfg htlcswitch.ChannelLinkConfig,
376
        lnChan *lnwallet.LightningChannel) error {
×
377

×
378
        return nil
×
379
}
×
380

381
// GetLinksByInterface returns the active links.
382
func (m *mockMessageSwitch) GetLinksByInterface(pub [33]byte) (
383
        []htlcswitch.ChannelUpdateHandler, error) {
×
384

×
385
        return m.links, nil
×
386
}
×
387

388
// mockUpdateHandler is a mock implementation of the ChannelUpdateHandler
389
// interface. It is used in mockMessageSwitch's GetLinksByInterface method.
390
type mockUpdateHandler struct {
391
        cid                  lnwire.ChannelID
392
        isOutgoingAddBlocked atomic.Bool
393
        isIncomingAddBlocked atomic.Bool
394
}
395

396
// newMockUpdateHandler creates a new mockUpdateHandler.
397
func newMockUpdateHandler(cid lnwire.ChannelID) *mockUpdateHandler {
×
398
        return &mockUpdateHandler{
×
399
                cid: cid,
×
400
        }
×
401
}
×
402

403
// HandleChannelUpdate currently does nothing.
404
func (m *mockUpdateHandler) HandleChannelUpdate(msg lnwire.Message) {}
×
405

406
// ChanID returns the mockUpdateHandler's cid.
407
func (m *mockUpdateHandler) ChanID() lnwire.ChannelID { return m.cid }
×
408

409
// Bandwidth currently returns a dummy value.
410
func (m *mockUpdateHandler) Bandwidth() lnwire.MilliSatoshi { return 0 }
×
411

412
// EligibleToForward currently returns a dummy value.
413
func (m *mockUpdateHandler) EligibleToForward() bool { return false }
×
414

415
// MayAddOutgoingHtlc currently returns nil.
416
func (m *mockUpdateHandler) MayAddOutgoingHtlc(lnwire.MilliSatoshi) error { return nil }
×
417

418
type mockMessageConn struct {
419
        t *testing.T
420

421
        // MessageConn embeds our interface so that the mock does not need to
422
        // implement every function. The mock will panic if an unspecified function
423
        // is called.
424
        MessageConn
425

426
        // writtenMessages is a channel that our mock pushes written messages into.
427
        writtenMessages chan []byte
428

429
        readMessages   chan []byte
430
        curReadMessage []byte
431

432
        // writeRaceDetectingCounter is incremented on any function call
433
        // associated with writing to the connection. The race detector will
434
        // trigger on this counter if a data race exists.
435
        writeRaceDetectingCounter int
436

437
        // readRaceDetectingCounter is incremented on any function call
438
        // associated with reading from the connection. The race detector will
439
        // trigger on this counter if a data race exists.
440
        readRaceDetectingCounter int
441
}
442

443
func (m *mockUpdateHandler) EnableAdds(dir htlcswitch.LinkDirection) bool {
×
444
        if dir == htlcswitch.Outgoing {
×
445
                return m.isOutgoingAddBlocked.Swap(false)
×
446
        }
×
447

448
        return m.isIncomingAddBlocked.Swap(false)
×
449
}
450

451
func (m *mockUpdateHandler) DisableAdds(dir htlcswitch.LinkDirection) bool {
×
452
        if dir == htlcswitch.Outgoing {
×
453
                return !m.isOutgoingAddBlocked.Swap(true)
×
454
        }
×
455

456
        return !m.isIncomingAddBlocked.Swap(true)
×
457
}
458

459
func (m *mockUpdateHandler) IsFlushing(dir htlcswitch.LinkDirection) bool {
×
460
        switch dir {
×
461
        case htlcswitch.Outgoing:
×
462
                return m.isOutgoingAddBlocked.Load()
×
463
        case htlcswitch.Incoming:
×
464
                return m.isIncomingAddBlocked.Load()
×
465
        }
466

467
        return false
×
468
}
469

470
func (m *mockUpdateHandler) OnFlushedOnce(hook func()) {
×
471
        hook()
×
472
}
×
473
func (m *mockUpdateHandler) OnCommitOnce(
474
        _ htlcswitch.LinkDirection, hook func(),
475
) {
×
476

×
477
        hook()
×
478
}
×
479
func (m *mockUpdateHandler) InitStfu() <-chan fn.Result[lntypes.ChannelParty] {
×
480
        // TODO(proofofkeags): Implement
×
481
        c := make(chan fn.Result[lntypes.ChannelParty], 1)
×
482

×
483
        c <- fn.Errf[lntypes.ChannelParty]("InitStfu not yet implemented")
×
484

×
485
        return c
×
486
}
×
487

488
func newMockConn(t *testing.T, expectedMessages int) *mockMessageConn {
×
489
        return &mockMessageConn{
×
490
                t:               t,
×
491
                writtenMessages: make(chan []byte, expectedMessages),
×
492
                readMessages:    make(chan []byte, 1),
×
493
        }
×
494
}
×
495

496
// SetWriteDeadline mocks setting write deadline for our conn.
497
func (m *mockMessageConn) SetWriteDeadline(time.Time) error {
×
498
        m.writeRaceDetectingCounter++
×
499
        return nil
×
500
}
×
501

502
// Flush mocks a message conn flush.
503
func (m *mockMessageConn) Flush() (int, error) {
×
504
        m.writeRaceDetectingCounter++
×
505
        return 0, nil
×
506
}
×
507

508
// WriteMessage mocks sending of a message on our connection. It will push
509
// the bytes sent into the mock's writtenMessages channel.
510
func (m *mockMessageConn) WriteMessage(msg []byte) error {
×
511
        m.writeRaceDetectingCounter++
×
512

×
513
        msgCopy := make([]byte, len(msg))
×
514
        copy(msgCopy, msg)
×
515

×
516
        select {
×
517
        case m.writtenMessages <- msgCopy:
×
518
        case <-time.After(timeout):
×
519
                m.t.Fatalf("timeout sending message: %v", msgCopy)
×
520
        }
521

522
        return nil
×
523
}
524

525
// assertWrite asserts that our mock as had WriteMessage called with the byte
526
// slice we expect.
527
func (m *mockMessageConn) assertWrite(expected []byte) {
×
528
        select {
×
529
        case actual := <-m.writtenMessages:
×
530
                require.Equal(m.t, expected, actual)
×
531

532
        case <-time.After(timeout):
×
533
                m.t.Fatalf("timeout waiting for write: %v", expected)
×
534
        }
535
}
536

537
func (m *mockMessageConn) SetReadDeadline(t time.Time) error {
×
538
        m.readRaceDetectingCounter++
×
539
        return nil
×
540
}
×
541

542
func (m *mockMessageConn) ReadNextHeader() (uint32, error) {
×
543
        m.readRaceDetectingCounter++
×
544
        m.curReadMessage = <-m.readMessages
×
545
        return uint32(len(m.curReadMessage)), nil
×
546
}
×
547

548
func (m *mockMessageConn) ReadNextBody(buf []byte) ([]byte, error) {
×
549
        m.readRaceDetectingCounter++
×
550
        return m.curReadMessage, nil
×
551
}
×
552

553
func (m *mockMessageConn) RemoteAddr() net.Addr {
×
554
        return nil
×
555
}
×
556

557
func (m *mockMessageConn) LocalAddr() net.Addr {
×
558
        return nil
×
559
}
×
560

561
func (m *mockMessageConn) Close() error {
×
562
        return nil
×
563
}
×
564

565
// createTestPeer creates a new peer for testing and returns a context struct
566
// containing necessary handles and mock objects for conducting tests on peer
567
// functionalities.
568
func createTestPeer(t *testing.T) *peerTestCtx {
×
569
        nodeKeyLocator := keychain.KeyLocator{
×
570
                Family: keychain.KeyFamilyNodeKey,
×
571
        }
×
572

×
573
        aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
×
574
                channels.AlicesPrivKey,
×
575
        )
×
576

×
577
        aliceKeySigner := keychain.NewPrivKeyMessageSigner(
×
578
                aliceKeyPriv, nodeKeyLocator,
×
579
        )
×
580

×
581
        aliceAddr := &net.TCPAddr{
×
582
                IP:   net.ParseIP("127.0.0.1"),
×
583
                Port: 18555,
×
584
        }
×
585
        cfgAddr := &lnwire.NetAddress{
×
586
                IdentityKey: aliceKeyPub,
×
587
                Address:     aliceAddr,
×
588
                ChainNet:    wire.SimNet,
×
589
        }
×
590

×
591
        errBuffer, err := queue.NewCircularBuffer(ErrorBufferSize)
×
592
        require.NoError(t, err)
×
593

×
594
        chainIO := &mock.ChainIO{
×
595
                BestHeight: broadcastHeight,
×
596
        }
×
597

×
598
        publishTx := make(chan *wire.MsgTx)
×
599
        wallet := &lnwallet.LightningWallet{
×
600
                WalletController: &mock.WalletController{
×
601
                        RootKey:               aliceKeyPriv,
×
602
                        PublishedTransactions: publishTx,
×
603
                },
×
604
        }
×
605

×
606
        const chanActiveTimeout = time.Minute
×
607

×
608
        dbPath := t.TempDir()
×
609

×
610
        graphBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
611
                DBPath:            dbPath,
×
612
                DBFileName:        "graph.db",
×
613
                NoFreelistSync:    true,
×
614
                AutoCompact:       false,
×
615
                AutoCompactMinAge: kvdb.DefaultBoltAutoCompactMinAge,
×
616
                DBTimeout:         kvdb.DefaultDBTimeout,
×
617
        })
×
618
        require.NoError(t, err)
×
619

×
620
        dbAliceGraph, err := graphdb.NewChannelGraph(&graphdb.Config{
×
621
                KVDB: graphBackend,
×
622
        })
×
623
        require.NoError(t, err)
×
624
        require.NoError(t, dbAliceGraph.Start())
×
625
        t.Cleanup(func() {
×
626
                require.NoError(t, dbAliceGraph.Stop())
×
627
        })
×
628

629
        dbAliceChannel := channeldb.OpenForTesting(t, dbPath)
×
630

×
631
        nodeSignerAlice := netann.NewNodeSigner(aliceKeySigner)
×
632

×
633
        chanStatusMgr, err := netann.NewChanStatusManager(&netann.
×
634
                ChanStatusConfig{
×
635
                ChanStatusSampleInterval: 30 * time.Second,
×
636
                ChanEnableTimeout:        chanActiveTimeout,
×
637
                ChanDisableTimeout:       2 * time.Minute,
×
638
                DB:                       dbAliceChannel.ChannelStateDB(),
×
639
                Graph:                    dbAliceGraph,
×
640
                MessageSigner:            nodeSignerAlice,
×
641
                OurPubKey:                aliceKeyPub,
×
642
                OurKeyLoc:                testKeyLoc,
×
643
                IsChannelActive: func(lnwire.ChannelID) bool {
×
644
                        return true
×
645
                },
×
646
                ApplyChannelUpdate: func(*lnwire.ChannelUpdate1,
647
                        *wire.OutPoint, bool) error {
×
648

×
649
                        return nil
×
650
                },
×
651
        })
652
        require.NoError(t, err)
×
653

×
654
        interceptableSwitchNotifier := &mock.ChainNotifier{
×
655
                EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
×
656
        }
×
657
        interceptableSwitchNotifier.EpochChan <- &chainntnfs.BlockEpoch{
×
658
                Height: 1,
×
659
        }
×
660

×
661
        interceptableSwitch, err := htlcswitch.NewInterceptableSwitch(
×
662
                &htlcswitch.InterceptableSwitchConfig{
×
663
                        CltvRejectDelta:    testCltvRejectDelta,
×
664
                        CltvInterceptDelta: testCltvRejectDelta + 3,
×
665
                        Notifier:           interceptableSwitchNotifier,
×
666
                },
×
667
        )
×
668
        require.NoError(t, err)
×
669

×
670
        // TODO(yy): create interface for lnwallet.LightningChannel so we can
×
671
        // easily mock it without the following setups.
×
672
        notifier := &mock.ChainNotifier{
×
673
                SpendChan: make(chan *chainntnfs.SpendDetail),
×
674
                EpochChan: make(chan *chainntnfs.BlockEpoch),
×
675
                ConfChan:  make(chan *chainntnfs.TxConfirmation),
×
676
        }
×
677

×
678
        mockSwitch := &mockMessageSwitch{}
×
679

×
680
        // TODO(yy): change ChannelNotifier to be an interface.
×
681
        channelNotifier := channelnotifier.New(dbAliceChannel.ChannelStateDB())
×
682
        require.NoError(t, channelNotifier.Start())
×
683
        t.Cleanup(func() {
×
684
                require.NoError(t, channelNotifier.Stop(),
×
685
                        "stop channel notifier failed")
×
686
        })
×
687

688
        writeBufferPool := pool.NewWriteBuffer(
×
689
                pool.DefaultWriteBufferGCInterval,
×
690
                pool.DefaultWriteBufferExpiryInterval,
×
691
        )
×
692

×
693
        writePool := pool.NewWrite(
×
694
                writeBufferPool, 1, timeout,
×
695
        )
×
696
        require.NoError(t, writePool.Start())
×
697

×
698
        readBufferPool := pool.NewReadBuffer(
×
699
                pool.DefaultReadBufferGCInterval,
×
700
                pool.DefaultReadBufferExpiryInterval,
×
701
        )
×
702

×
703
        readPool := pool.NewRead(
×
704
                readBufferPool, 1, timeout,
×
705
        )
×
706
        require.NoError(t, readPool.Start())
×
707

×
708
        mockConn := newMockConn(t, 1)
×
709

×
710
        receivedCustomChan := make(chan *customMsg)
×
711

×
712
        var pubKey [33]byte
×
713
        copy(pubKey[:], aliceKeyPub.SerializeCompressed())
×
714

×
715
        estimator := chainfee.NewStaticEstimator(12500, 0)
×
716

×
717
        cfg := &Config{
×
718
                Addr:              cfgAddr,
×
719
                PubKeyBytes:       pubKey,
×
720
                ErrorBuffer:       errBuffer,
×
721
                ChainIO:           chainIO,
×
722
                Switch:            mockSwitch,
×
723
                ChanActiveTimeout: chanActiveTimeout,
×
724
                InterceptSwitch:   interceptableSwitch,
×
725
                ChannelDB:         dbAliceChannel.ChannelStateDB(),
×
726
                FeeEstimator:      estimator,
×
727
                Wallet:            wallet,
×
728
                ChainNotifier:     notifier,
×
729
                ChanStatusMgr:     chanStatusMgr,
×
730
                Features: lnwire.NewFeatureVector(
×
731
                        nil, lnwire.Features,
×
732
                ),
×
733
                DisconnectPeer: func(b *btcec.PublicKey) error {
×
734
                        return nil
×
735
                },
×
736
                ChannelNotifier:               channelNotifier,
737
                PrunePersistentPeerConnection: func([33]byte) {},
×
738
                LegacyFeatures:                lnwire.EmptyFeatureVector(),
739
                WritePool:                     writePool,
740
                ReadPool:                      readPool,
741
                Conn:                          mockConn,
742
                HandleCustomMessage: func(
743
                        peer [33]byte, msg *lnwire.Custom) error {
×
744

×
745
                        receivedCustomChan <- &customMsg{
×
746
                                peer: peer,
×
747
                                msg:  *msg,
×
748
                        }
×
749

×
750
                        return nil
×
751
                },
×
752
                PongBuf: make([]byte, lnwire.MaxPongBytes),
753
                FetchLastChanUpdate: func(_ context.Context,
754
                        _ lnwire.ShortChannelID) (*lnwire.ChannelUpdate1,
NEW
755
                        error) {
×
756

×
757
                        return &lnwire.ChannelUpdate1{}, nil
×
758
                },
×
759
        }
760

761
        alicePeer := NewBrontide(*cfg)
×
762

×
763
        return &peerTestCtx{
×
764
                publishTx:     publishTx,
×
765
                mockSwitch:    mockSwitch,
×
766
                peer:          alicePeer,
×
767
                notifier:      notifier,
×
768
                db:            dbAliceChannel,
×
769
                privKey:       aliceKeyPriv,
×
770
                mockConn:      mockConn,
×
771
                customChan:    receivedCustomChan,
×
772
                chanStatusMgr: chanStatusMgr,
×
773
        }
×
774
}
775

776
// startPeer invokes the `Start` method on the specified peer and handles any
777
// initial startup messages for testing.
778
func startPeer(t *testing.T, mockConn *mockMessageConn,
779
        peer *Brontide) <-chan struct{} {
×
780

×
781
        // Start the peer in a goroutine so that we can handle and test for
×
782
        // startup messages. Successfully sending and receiving init message,
×
783
        // indicates a successful startup.
×
784
        done := make(chan struct{})
×
785
        go func() {
×
NEW
786
                require.NoError(t, peer.Start(context.Background()))
×
787
                close(done)
×
788
        }()
×
789

790
        // Receive the init message that should be the first message received on
791
        // startup.
792
        rawMsg, err := fn.RecvOrTimeout[[]byte](
×
793
                mockConn.writtenMessages, timeout,
×
794
        )
×
795
        require.NoError(t, err)
×
796

×
797
        msgReader := bytes.NewReader(rawMsg)
×
798
        nextMsg, err := lnwire.ReadMessage(msgReader, 0)
×
799
        require.NoError(t, err)
×
800

×
801
        _, ok := nextMsg.(*lnwire.Init)
×
802
        require.True(t, ok)
×
803

×
804
        // Write the reply for the init message to complete the startup.
×
805
        initReplyMsg := lnwire.NewInitMessage(
×
806
                lnwire.NewRawFeatureVector(
×
807
                        lnwire.DataLossProtectRequired,
×
808
                        lnwire.GossipQueriesOptional,
×
809
                ),
×
810
                lnwire.NewRawFeatureVector(),
×
811
        )
×
812

×
813
        var b bytes.Buffer
×
814
        _, err = lnwire.WriteMessage(&b, initReplyMsg, 0)
×
815
        require.NoError(t, err)
×
816

×
817
        ok = fn.SendOrQuit[[]byte, struct{}](
×
818
                mockConn.readMessages, b.Bytes(), make(chan struct{}),
×
819
        )
×
820
        require.True(t, ok)
×
821

×
822
        return done
×
823
}
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