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

lightningnetwork / lnd / 15574102646

11 Jun 2025 01:44AM UTC coverage: 68.554% (+9.9%) from 58.637%
15574102646

Pull #9652

github

web-flow
Merge eb863e46a into 92a5d35cf
Pull Request #9652: lnwallet/chancloser: fix flake in TestRbfCloseClosingNegotiationLocal

11 of 12 new or added lines in 1 file covered. (91.67%)

7276 existing lines in 84 files now uncovered.

134508 of 196208 relevant lines covered (68.55%)

44569.29 hits per line

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

88.51
/peer/test_utils.go
1
package peer
2

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

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

39
const (
40
        broadcastHeight = 100
41

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

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

51
var (
52
        testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
53
)
54

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

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

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

28✔
80
        params := createTestPeer(t)
28✔
81

28✔
82
        var (
28✔
83
                publishTx     = params.publishTx
28✔
84
                mockSwitch    = params.mockSwitch
28✔
85
                alicePeer     = params.peer
28✔
86
                notifier      = params.notifier
28✔
87
                aliceKeyPriv  = params.privKey
28✔
88
                dbAlice       = params.db
28✔
89
                chanStatusMgr = params.chanStatusMgr
28✔
90
        )
28✔
91

28✔
92
        err := chanStatusMgr.Start()
28✔
93
        require.NoError(t, err)
28✔
94
        t.Cleanup(func() {
56✔
95
                require.NoError(t, chanStatusMgr.Stop())
28✔
96
        })
28✔
97

98
        aliceKeyPub := alicePeer.IdentityKey()
28✔
99
        estimator := alicePeer.cfg.FeeEstimator
28✔
100

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

28✔
109
        prevOut := &wire.OutPoint{
28✔
110
                Hash:  channels.TestHdSeed,
28✔
111
                Index: 0,
28✔
112
        }
28✔
113
        fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
28✔
114

28✔
115
        bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
28✔
116
                channels.BobsPrivKey,
28✔
117
        )
28✔
118

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

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

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

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

205
        dbBob := channeldb.OpenForTesting(t, t.TempDir())
28✔
206

28✔
207
        feePerKw, err := estimator.EstimateFeePerKW(1)
28✔
208
        if err != nil {
28✔
209
                return nil, err
×
210
        }
×
211

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

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

237
        shortChanID := lnwire.NewShortChanIDFromInt(
28✔
238
                binary.BigEndian.Uint64(chanIDBytes[:]),
28✔
239
        )
28✔
240

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

28✔
276
        // Set custom values on the channel states.
28✔
277
        updateChan(aliceChannelState, bobChannelState)
28✔
278

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

284
        bobAddr := &net.TCPAddr{
28✔
285
                IP:   net.ParseIP("127.0.0.1"),
28✔
286
                Port: 18556,
28✔
287
        }
28✔
288

28✔
289
        if err := bobChannelState.SyncPending(bobAddr, 0); err != nil {
28✔
290
                return nil, err
×
291
        }
×
292

293
        aliceSigner := input.NewMockSigner(
28✔
294
                []*btcec.PrivateKey{aliceKeyPriv}, nil,
28✔
295
        )
28✔
296
        bobSigner := input.NewMockSigner(
28✔
297
                []*btcec.PrivateKey{bobKeyPriv}, nil,
28✔
298
        )
28✔
299

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

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

332
        alicePeer.remoteFeatures = lnwire.NewFeatureVector(
28✔
333
                nil, lnwire.Features,
28✔
334
        )
28✔
335

28✔
336
        chanID := lnwire.NewChanIDFromOutPoint(channelAlice.ChannelPoint())
28✔
337
        alicePeer.activeChannels.Store(chanID, channelAlice)
28✔
338

28✔
339
        alicePeer.cg.WgAdd(1)
28✔
340
        go alicePeer.channelManager()
28✔
341

28✔
342
        return &peerTestCtx{
28✔
343
                peer:       alicePeer,
28✔
344
                channel:    channelBob,
28✔
345
                notifier:   notifier,
28✔
346
                publishTx:  publishTx,
28✔
347
                mockSwitch: mockSwitch,
28✔
348
                mockConn:   params.mockConn,
28✔
349
        }, nil
28✔
350
}
351

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

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

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

368
// RemoveLink currently does nothing.
369
func (m *mockMessageSwitch) RemoveLink(cid lnwire.ChannelID) {}
16✔
370

371
// CreateAndAddLink currently returns a dummy value.
372
func (m *mockMessageSwitch) CreateAndAddLink(cfg htlcswitch.ChannelLinkConfig,
UNCOV
373
        lnChan *lnwallet.LightningChannel) error {
×
374

×
375
        return nil
×
376
}
×
377

378
// GetLinksByInterface returns the active links.
379
func (m *mockMessageSwitch) GetLinksByInterface(pub [33]byte) (
380
        []htlcswitch.ChannelUpdateHandler, error) {
38✔
381

38✔
382
        return m.links, nil
38✔
383
}
38✔
384

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

393
// newMockUpdateHandler creates a new mockUpdateHandler.
394
func newMockUpdateHandler(cid lnwire.ChannelID) *mockUpdateHandler {
18✔
395
        return &mockUpdateHandler{
18✔
396
                cid: cid,
18✔
397
        }
18✔
398
}
18✔
399

400
// HandleChannelUpdate currently does nothing.
UNCOV
401
func (m *mockUpdateHandler) HandleChannelUpdate(msg lnwire.Message) {}
×
402

403
// ChanID returns the mockUpdateHandler's cid.
404
func (m *mockUpdateHandler) ChanID() lnwire.ChannelID { return m.cid }
36✔
405

406
// Bandwidth currently returns a dummy value.
UNCOV
407
func (m *mockUpdateHandler) Bandwidth() lnwire.MilliSatoshi { return 0 }
×
408

409
// EligibleToForward currently returns a dummy value.
UNCOV
410
func (m *mockUpdateHandler) EligibleToForward() bool { return false }
×
411

412
// MayAddOutgoingHtlc currently returns nil.
UNCOV
413
func (m *mockUpdateHandler) MayAddOutgoingHtlc(lnwire.MilliSatoshi) error { return nil }
×
414

415
type mockMessageConn struct {
416
        t *testing.T
417

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

423
        // writtenMessages is a channel that our mock pushes written messages into.
424
        writtenMessages chan []byte
425

426
        readMessages   chan []byte
427
        curReadMessage []byte
428

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

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

UNCOV
440
func (m *mockUpdateHandler) EnableAdds(dir htlcswitch.LinkDirection) bool {
×
441
        if dir == htlcswitch.Outgoing {
×
442
                return m.isOutgoingAddBlocked.Swap(false)
×
443
        }
×
444

UNCOV
445
        return m.isIncomingAddBlocked.Swap(false)
×
446
}
447

448
func (m *mockUpdateHandler) DisableAdds(dir htlcswitch.LinkDirection) bool {
24✔
449
        if dir == htlcswitch.Outgoing {
40✔
450
                return !m.isOutgoingAddBlocked.Swap(true)
16✔
451
        }
16✔
452

453
        return !m.isIncomingAddBlocked.Swap(true)
8✔
454
}
455

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

UNCOV
464
        return false
×
465
}
466

467
func (m *mockUpdateHandler) OnFlushedOnce(hook func()) {
8✔
468
        hook()
8✔
469
}
8✔
470
func (m *mockUpdateHandler) OnCommitOnce(
471
        _ htlcswitch.LinkDirection, hook func(),
472
) {
16✔
473

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

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

×
482
        return c
×
483
}
×
484

485
func newMockConn(t *testing.T, expectedMessages int) *mockMessageConn {
40✔
486
        return &mockMessageConn{
40✔
487
                t:               t,
40✔
488
                writtenMessages: make(chan []byte, expectedMessages),
40✔
489
                readMessages:    make(chan []byte, 1),
40✔
490
        }
40✔
491
}
40✔
492

493
// SetWriteDeadline mocks setting write deadline for our conn.
494
func (m *mockMessageConn) SetWriteDeadline(time.Time) error {
26✔
495
        m.writeRaceDetectingCounter++
26✔
496
        return nil
26✔
497
}
26✔
498

499
// Flush mocks a message conn flush.
500
func (m *mockMessageConn) Flush() (int, error) {
26✔
501
        m.writeRaceDetectingCounter++
26✔
502
        return 0, nil
26✔
503
}
26✔
504

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

26✔
510
        msgCopy := make([]byte, len(msg))
26✔
511
        copy(msgCopy, msg)
26✔
512

26✔
513
        select {
26✔
514
        case m.writtenMessages <- msgCopy:
26✔
515
        case <-time.After(timeout):
×
516
                m.t.Fatalf("timeout sending message: %v", msgCopy)
×
517
        }
518

519
        return nil
26✔
520
}
521

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

UNCOV
529
        case <-time.After(timeout):
×
530
                m.t.Fatalf("timeout waiting for write: %v", expected)
×
531
        }
532
}
533

534
func (m *mockMessageConn) SetReadDeadline(t time.Time) error {
22✔
535
        m.readRaceDetectingCounter++
22✔
536
        return nil
22✔
537
}
22✔
538

539
func (m *mockMessageConn) ReadNextHeader() (uint32, error) {
14✔
540
        m.readRaceDetectingCounter++
14✔
541
        m.curReadMessage = <-m.readMessages
14✔
542
        return uint32(len(m.curReadMessage)), nil
14✔
543
}
14✔
544

545
func (m *mockMessageConn) ReadNextBody(buf []byte) ([]byte, error) {
8✔
546
        m.readRaceDetectingCounter++
8✔
547
        return m.curReadMessage, nil
8✔
548
}
8✔
549

550
func (m *mockMessageConn) RemoteAddr() net.Addr {
46✔
551
        return nil
46✔
552
}
46✔
553

554
func (m *mockMessageConn) LocalAddr() net.Addr {
6✔
555
        return nil
6✔
556
}
6✔
557

558
func (m *mockMessageConn) Close() error {
2✔
559
        return nil
2✔
560
}
2✔
561

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

38✔
570
        aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
38✔
571
                channels.AlicesPrivKey,
38✔
572
        )
38✔
573

38✔
574
        aliceKeySigner := keychain.NewPrivKeyMessageSigner(
38✔
575
                aliceKeyPriv, nodeKeyLocator,
38✔
576
        )
38✔
577

38✔
578
        aliceAddr := &net.TCPAddr{
38✔
579
                IP:   net.ParseIP("127.0.0.1"),
38✔
580
                Port: 18555,
38✔
581
        }
38✔
582
        cfgAddr := &lnwire.NetAddress{
38✔
583
                IdentityKey: aliceKeyPub,
38✔
584
                Address:     aliceAddr,
38✔
585
                ChainNet:    wire.SimNet,
38✔
586
        }
38✔
587

38✔
588
        errBuffer, err := queue.NewCircularBuffer(ErrorBufferSize)
38✔
589
        require.NoError(t, err)
38✔
590

38✔
591
        chainIO := &mock.ChainIO{
38✔
592
                BestHeight: broadcastHeight,
38✔
593
        }
38✔
594

38✔
595
        publishTx := make(chan *wire.MsgTx)
38✔
596
        wallet := &lnwallet.LightningWallet{
38✔
597
                WalletController: &mock.WalletController{
38✔
598
                        RootKey:               aliceKeyPriv,
38✔
599
                        PublishedTransactions: publishTx,
38✔
600
                },
38✔
601
        }
38✔
602

38✔
603
        const chanActiveTimeout = time.Minute
38✔
604

38✔
605
        dbAliceGraph := graphdb.MakeTestGraph(t)
38✔
606
        require.NoError(t, dbAliceGraph.Start())
38✔
607
        t.Cleanup(func() {
76✔
608
                require.NoError(t, dbAliceGraph.Stop())
38✔
609
        })
38✔
610

611
        dbAliceChannel := channeldb.OpenForTesting(t, t.TempDir())
38✔
612

38✔
613
        nodeSignerAlice := netann.NewNodeSigner(aliceKeySigner)
38✔
614

38✔
615
        chanStatusMgr, err := netann.NewChanStatusManager(&netann.
38✔
616
                ChanStatusConfig{
38✔
617
                ChanStatusSampleInterval: 30 * time.Second,
38✔
618
                ChanEnableTimeout:        chanActiveTimeout,
38✔
619
                ChanDisableTimeout:       2 * time.Minute,
38✔
620
                DB:                       dbAliceChannel.ChannelStateDB(),
38✔
621
                Graph:                    dbAliceGraph,
38✔
622
                MessageSigner:            nodeSignerAlice,
38✔
623
                OurPubKey:                aliceKeyPub,
38✔
624
                OurKeyLoc:                testKeyLoc,
38✔
625
                IsChannelActive: func(lnwire.ChannelID) bool {
38✔
UNCOV
626
                        return true
×
627
                },
×
628
                ApplyChannelUpdate: func(*lnwire.ChannelUpdate1,
629
                        *wire.OutPoint, bool) error {
×
630

×
631
                        return nil
×
632
                },
×
633
        })
634
        require.NoError(t, err)
38✔
635

38✔
636
        interceptableSwitchNotifier := &mock.ChainNotifier{
38✔
637
                EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
38✔
638
        }
38✔
639
        interceptableSwitchNotifier.EpochChan <- &chainntnfs.BlockEpoch{
38✔
640
                Height: 1,
38✔
641
        }
38✔
642

38✔
643
        interceptableSwitch, err := htlcswitch.NewInterceptableSwitch(
38✔
644
                &htlcswitch.InterceptableSwitchConfig{
38✔
645
                        CltvRejectDelta:    testCltvRejectDelta,
38✔
646
                        CltvInterceptDelta: testCltvRejectDelta + 3,
38✔
647
                        Notifier:           interceptableSwitchNotifier,
38✔
648
                },
38✔
649
        )
38✔
650
        require.NoError(t, err)
38✔
651

38✔
652
        // TODO(yy): create interface for lnwallet.LightningChannel so we can
38✔
653
        // easily mock it without the following setups.
38✔
654
        notifier := &mock.ChainNotifier{
38✔
655
                SpendChan: make(chan *chainntnfs.SpendDetail),
38✔
656
                EpochChan: make(chan *chainntnfs.BlockEpoch),
38✔
657
                ConfChan:  make(chan *chainntnfs.TxConfirmation),
38✔
658
        }
38✔
659

38✔
660
        mockSwitch := &mockMessageSwitch{}
38✔
661

38✔
662
        // TODO(yy): change ChannelNotifier to be an interface.
38✔
663
        channelNotifier := channelnotifier.New(dbAliceChannel.ChannelStateDB())
38✔
664
        require.NoError(t, channelNotifier.Start())
38✔
665
        t.Cleanup(func() {
76✔
666
                require.NoError(t, channelNotifier.Stop(),
38✔
667
                        "stop channel notifier failed")
38✔
668
        })
38✔
669

670
        writeBufferPool := pool.NewWriteBuffer(
38✔
671
                pool.DefaultWriteBufferGCInterval,
38✔
672
                pool.DefaultWriteBufferExpiryInterval,
38✔
673
        )
38✔
674

38✔
675
        writePool := pool.NewWrite(
38✔
676
                writeBufferPool, 1, timeout,
38✔
677
        )
38✔
678
        require.NoError(t, writePool.Start())
38✔
679

38✔
680
        readBufferPool := pool.NewReadBuffer(
38✔
681
                pool.DefaultReadBufferGCInterval,
38✔
682
                pool.DefaultReadBufferExpiryInterval,
38✔
683
        )
38✔
684

38✔
685
        readPool := pool.NewRead(
38✔
686
                readBufferPool, 1, timeout,
38✔
687
        )
38✔
688
        require.NoError(t, readPool.Start())
38✔
689

38✔
690
        mockConn := newMockConn(t, 1)
38✔
691

38✔
692
        receivedCustomChan := make(chan *customMsg)
38✔
693

38✔
694
        var pubKey [33]byte
38✔
695
        copy(pubKey[:], aliceKeyPub.SerializeCompressed())
38✔
696

38✔
697
        estimator := chainfee.NewStaticEstimator(12500, 0)
38✔
698

38✔
699
        cfg := &Config{
38✔
700
                Addr:              cfgAddr,
38✔
701
                PubKeyBytes:       pubKey,
38✔
702
                ErrorBuffer:       errBuffer,
38✔
703
                ChainIO:           chainIO,
38✔
704
                Switch:            mockSwitch,
38✔
705
                ChanActiveTimeout: chanActiveTimeout,
38✔
706
                InterceptSwitch:   interceptableSwitch,
38✔
707
                ChannelDB:         dbAliceChannel.ChannelStateDB(),
38✔
708
                FeeEstimator:      estimator,
38✔
709
                Wallet:            wallet,
38✔
710
                ChainNotifier:     notifier,
38✔
711
                ChanStatusMgr:     chanStatusMgr,
38✔
712
                Features: lnwire.NewFeatureVector(
38✔
713
                        nil, lnwire.Features,
38✔
714
                ),
38✔
715
                DisconnectPeer: func(b *btcec.PublicKey) error {
38✔
716
                        return nil
×
717
                },
×
718
                ChannelNotifier:               channelNotifier,
719
                PrunePersistentPeerConnection: func([33]byte) {},
2✔
720
                LegacyFeatures:                lnwire.EmptyFeatureVector(),
721
                WritePool:                     writePool,
722
                ReadPool:                      readPool,
723
                Conn:                          mockConn,
724
                HandleCustomMessage: func(
725
                        peer [33]byte, msg *lnwire.Custom) error {
2✔
726

2✔
727
                        receivedCustomChan <- &customMsg{
2✔
728
                                peer: peer,
2✔
729
                                msg:  *msg,
2✔
730
                        }
2✔
731

2✔
732
                        return nil
2✔
733
                },
2✔
734
                PongBuf: make([]byte, lnwire.MaxPongBytes),
735
                FetchLastChanUpdate: func(chanID lnwire.ShortChannelID,
736
                ) (*lnwire.ChannelUpdate1, error) {
4✔
737

4✔
738
                        return &lnwire.ChannelUpdate1{}, nil
4✔
739
                },
4✔
740
        }
741

742
        alicePeer := NewBrontide(*cfg)
38✔
743

38✔
744
        return &peerTestCtx{
38✔
745
                publishTx:     publishTx,
38✔
746
                mockSwitch:    mockSwitch,
38✔
747
                peer:          alicePeer,
38✔
748
                notifier:      notifier,
38✔
749
                db:            dbAliceChannel,
38✔
750
                privKey:       aliceKeyPriv,
38✔
751
                mockConn:      mockConn,
38✔
752
                customChan:    receivedCustomChan,
38✔
753
                chanStatusMgr: chanStatusMgr,
38✔
754
        }
38✔
755
}
756

757
// startPeer invokes the `Start` method on the specified peer and handles any
758
// initial startup messages for testing.
759
func startPeer(t *testing.T, mockConn *mockMessageConn,
760
        peer *Brontide) <-chan struct{} {
6✔
761

6✔
762
        // Start the peer in a goroutine so that we can handle and test for
6✔
763
        // startup messages. Successfully sending and receiving init message,
6✔
764
        // indicates a successful startup.
6✔
765
        done := make(chan struct{})
6✔
766
        go func() {
12✔
767
                require.NoError(t, peer.Start())
6✔
768
                close(done)
6✔
769
        }()
6✔
770

771
        // Receive the init message that should be the first message received on
772
        // startup.
773
        rawMsg, err := fn.RecvOrTimeout[[]byte](
6✔
774
                mockConn.writtenMessages, timeout,
6✔
775
        )
6✔
776
        require.NoError(t, err)
6✔
777

6✔
778
        msgReader := bytes.NewReader(rawMsg)
6✔
779
        nextMsg, err := lnwire.ReadMessage(msgReader, 0)
6✔
780
        require.NoError(t, err)
6✔
781

6✔
782
        _, ok := nextMsg.(*lnwire.Init)
6✔
783
        require.True(t, ok)
6✔
784

6✔
785
        // Write the reply for the init message to complete the startup.
6✔
786
        initReplyMsg := lnwire.NewInitMessage(
6✔
787
                lnwire.NewRawFeatureVector(
6✔
788
                        lnwire.DataLossProtectRequired,
6✔
789
                        lnwire.GossipQueriesOptional,
6✔
790
                ),
6✔
791
                lnwire.NewRawFeatureVector(),
6✔
792
        )
6✔
793

6✔
794
        var b bytes.Buffer
6✔
795
        _, err = lnwire.WriteMessage(&b, initReplyMsg, 0)
6✔
796
        require.NoError(t, err)
6✔
797

6✔
798
        ok = fn.SendOrQuit[[]byte, struct{}](
6✔
799
                mockConn.readMessages, b.Bytes(), make(chan struct{}),
6✔
800
        )
6✔
801
        require.True(t, ok)
6✔
802

6✔
803
        return done
6✔
804
}
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