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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

74.15
/htlcswitch/mock.go
1
package htlcswitch
2

3
import (
4
        "bytes"
5
        "context"
6
        "crypto/sha256"
7
        "encoding/binary"
8
        "fmt"
9
        "io"
10
        "net"
11
        "os"
12
        "path/filepath"
13
        "sync"
14
        "sync/atomic"
15
        "testing"
16
        "time"
17

18
        "github.com/btcsuite/btcd/btcec/v2"
19
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
20
        "github.com/btcsuite/btcd/btcutil"
21
        "github.com/btcsuite/btcd/wire"
22
        "github.com/go-errors/errors"
23
        sphinx "github.com/lightningnetwork/lightning-onion"
24
        "github.com/lightningnetwork/lnd/chainntnfs"
25
        "github.com/lightningnetwork/lnd/channeldb"
26
        "github.com/lightningnetwork/lnd/channeldb/models"
27
        "github.com/lightningnetwork/lnd/clock"
28
        "github.com/lightningnetwork/lnd/contractcourt"
29
        "github.com/lightningnetwork/lnd/fn"
30
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
31
        "github.com/lightningnetwork/lnd/invoices"
32
        "github.com/lightningnetwork/lnd/lnpeer"
33
        "github.com/lightningnetwork/lnd/lntest/mock"
34
        "github.com/lightningnetwork/lnd/lntypes"
35
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
36
        "github.com/lightningnetwork/lnd/lnwire"
37
        "github.com/lightningnetwork/lnd/ticker"
38
        "github.com/lightningnetwork/lnd/tlv"
39
)
40

41
func isAlias(scid lnwire.ShortChannelID) bool {
114✔
42
        return scid.BlockHeight >= 16_000_000 && scid.BlockHeight < 16_250_000
114✔
43
}
114✔
44

45
type mockPreimageCache struct {
46
        sync.Mutex
47
        preimageMap map[lntypes.Hash]lntypes.Preimage
48
}
49

50
func newMockPreimageCache() *mockPreimageCache {
273✔
51
        return &mockPreimageCache{
273✔
52
                preimageMap: make(map[lntypes.Hash]lntypes.Preimage),
273✔
53
        }
273✔
54
}
273✔
55

56
func (m *mockPreimageCache) LookupPreimage(
57
        hash lntypes.Hash) (lntypes.Preimage, bool) {
80✔
58

80✔
59
        m.Lock()
80✔
60
        defer m.Unlock()
80✔
61

80✔
62
        p, ok := m.preimageMap[hash]
80✔
63
        return p, ok
80✔
64
}
80✔
65

66
func (m *mockPreimageCache) AddPreimages(preimages ...lntypes.Preimage) error {
2,801✔
67
        m.Lock()
2,801✔
68
        defer m.Unlock()
2,801✔
69

2,801✔
70
        for _, preimage := range preimages {
3,459✔
71
                m.preimageMap[preimage.Hash()] = preimage
658✔
72
        }
658✔
73

74
        return nil
2,801✔
75
}
76

77
func (m *mockPreimageCache) SubscribeUpdates(
78
        chanID lnwire.ShortChannelID, htlc *channeldb.HTLC,
79
        payload *hop.Payload,
80
        nextHopOnionBlob []byte) (*contractcourt.WitnessSubscription, error) {
×
81

×
82
        return nil, nil
×
83
}
×
84

85
// TODO(yy): replace it with chainfee.MockEstimator.
86
type mockFeeEstimator struct {
87
        byteFeeIn chan chainfee.SatPerKWeight
88
        relayFee  chan chainfee.SatPerKWeight
89

90
        quit chan struct{}
91
}
92

93
func newMockFeeEstimator() *mockFeeEstimator {
92✔
94
        return &mockFeeEstimator{
92✔
95
                byteFeeIn: make(chan chainfee.SatPerKWeight),
92✔
96
                relayFee:  make(chan chainfee.SatPerKWeight),
92✔
97
                quit:      make(chan struct{}),
92✔
98
        }
92✔
99
}
92✔
100

101
func (m *mockFeeEstimator) EstimateFeePerKW(
102
        numBlocks uint32) (chainfee.SatPerKWeight, error) {
4✔
103

4✔
104
        select {
4✔
105
        case feeRate := <-m.byteFeeIn:
4✔
106
                return feeRate, nil
4✔
107
        case <-m.quit:
×
108
                return 0, fmt.Errorf("exiting")
×
109
        }
110
}
111

112
func (m *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
4✔
113
        select {
4✔
114
        case feeRate := <-m.relayFee:
4✔
115
                return feeRate
4✔
116
        case <-m.quit:
×
117
                return 0
×
118
        }
119
}
120

121
func (m *mockFeeEstimator) Start() error {
×
122
        return nil
×
123
}
×
124
func (m *mockFeeEstimator) Stop() error {
2✔
125
        close(m.quit)
2✔
126
        return nil
2✔
127
}
2✔
128

129
var _ chainfee.Estimator = (*mockFeeEstimator)(nil)
130

131
type mockForwardingLog struct {
132
        sync.Mutex
133

134
        events map[time.Time]channeldb.ForwardingEvent
135
}
136

137
func (m *mockForwardingLog) AddForwardingEvents(events []channeldb.ForwardingEvent) error {
17✔
138
        m.Lock()
17✔
139
        defer m.Unlock()
17✔
140

17✔
141
        for _, event := range events {
46✔
142
                m.events[event.Timestamp] = event
29✔
143
        }
29✔
144

145
        return nil
17✔
146
}
147

148
type mockServer struct {
149
        started  int32 // To be used atomically.
150
        shutdown int32 // To be used atomically.
151
        wg       sync.WaitGroup
152
        quit     chan struct{}
153

154
        t testing.TB
155

156
        name             string
157
        messages         chan lnwire.Message
158
        protocolTraceMtx sync.Mutex
159
        protocolTrace    []lnwire.Message
160

161
        id         [33]byte
162
        htlcSwitch *Switch
163

164
        registry         *mockInvoiceRegistry
165
        pCache           *mockPreimageCache
166
        interceptorFuncs []messageInterceptor
167
}
168

169
var _ lnpeer.Peer = (*mockServer)(nil)
170

171
func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error) {
341✔
172
        signAliasUpdate := func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature,
341✔
173
                error) {
354✔
174

13✔
175
                return testSig, nil
13✔
176
        }
13✔
177

178
        cfg := Config{
341✔
179
                DB:                   db,
341✔
180
                FetchAllOpenChannels: db.ChannelStateDB().FetchAllOpenChannels,
341✔
181
                FetchAllChannels:     db.ChannelStateDB().FetchAllChannels,
341✔
182
                FetchClosedChannels:  db.ChannelStateDB().FetchClosedChannels,
341✔
183
                SwitchPackager:       channeldb.NewSwitchPackager(),
341✔
184
                FwdingLog: &mockForwardingLog{
341✔
185
                        events: make(map[time.Time]channeldb.ForwardingEvent),
341✔
186
                },
341✔
187
                FetchLastChannelUpdate: func(scid lnwire.ShortChannelID) (
341✔
188
                        *lnwire.ChannelUpdate1, error) {
367✔
189

26✔
190
                        return &lnwire.ChannelUpdate1{
26✔
191
                                ShortChannelID: scid,
26✔
192
                        }, nil
26✔
193
                },
26✔
194
                Notifier: &mock.ChainNotifier{
195
                        SpendChan: make(chan *chainntnfs.SpendDetail),
196
                        EpochChan: make(chan *chainntnfs.BlockEpoch),
197
                        ConfChan:  make(chan *chainntnfs.TxConfirmation),
198
                },
199
                FwdEventTicker: ticker.NewForce(
200
                        DefaultFwdEventInterval,
201
                ),
202
                LogEventTicker:         ticker.NewForce(DefaultLogInterval),
203
                AckEventTicker:         ticker.NewForce(DefaultAckInterval),
204
                HtlcNotifier:           &mockHTLCNotifier{},
205
                Clock:                  clock.NewDefaultClock(),
206
                MailboxDeliveryTimeout: time.Hour,
207
                MaxFeeExposure:         DefaultMaxFeeExposure,
208
                SignAliasUpdate:        signAliasUpdate,
209
                IsAlias:                isAlias,
210
        }
211

212
        return New(cfg, startingHeight)
341✔
213
}
214

215
func initSwitchWithTempDB(t testing.TB, startingHeight uint32) (*Switch,
216
        error) {
149✔
217

149✔
218
        tempPath := filepath.Join(t.TempDir(), "switchdb")
149✔
219
        db, err := channeldb.Open(tempPath)
149✔
220
        if err != nil {
149✔
221
                return nil, err
×
222
        }
×
223
        t.Cleanup(func() { db.Close() })
298✔
224

225
        s, err := initSwitchWithDB(startingHeight, db)
149✔
226
        if err != nil {
149✔
227
                return nil, err
×
228
        }
×
229

230
        return s, nil
149✔
231
}
232

233
func newMockServer(t testing.TB, name string, startingHeight uint32,
234
        db *channeldb.DB, defaultDelta uint32) (*mockServer, error) {
226✔
235

226✔
236
        var id [33]byte
226✔
237
        h := sha256.Sum256([]byte(name))
226✔
238
        copy(id[:], h[:])
226✔
239

226✔
240
        pCache := newMockPreimageCache()
226✔
241

226✔
242
        var (
226✔
243
                htlcSwitch *Switch
226✔
244
                err        error
226✔
245
        )
226✔
246
        if db == nil {
323✔
247
                htlcSwitch, err = initSwitchWithTempDB(t, startingHeight)
97✔
248
        } else {
226✔
249
                htlcSwitch, err = initSwitchWithDB(startingHeight, db)
129✔
250
        }
129✔
251
        if err != nil {
226✔
252
                return nil, err
×
253
        }
×
254

255
        t.Cleanup(func() { _ = htlcSwitch.Stop() })
452✔
256

257
        registry := newMockRegistry(defaultDelta)
226✔
258

226✔
259
        t.Cleanup(func() { registry.cleanup() })
452✔
260

261
        return &mockServer{
226✔
262
                t:                t,
226✔
263
                id:               id,
226✔
264
                name:             name,
226✔
265
                messages:         make(chan lnwire.Message, 3000),
226✔
266
                quit:             make(chan struct{}),
226✔
267
                registry:         registry,
226✔
268
                htlcSwitch:       htlcSwitch,
226✔
269
                pCache:           pCache,
226✔
270
                interceptorFuncs: make([]messageInterceptor, 0),
226✔
271
        }, nil
226✔
272
}
273

274
func (s *mockServer) Start() error {
129✔
275
        if !atomic.CompareAndSwapInt32(&s.started, 0, 1) {
129✔
276
                return errors.New("mock server already started")
×
277
        }
×
278

279
        if err := s.htlcSwitch.Start(); err != nil {
129✔
280
                return err
×
281
        }
×
282

283
        s.wg.Add(1)
129✔
284
        go func() {
258✔
285
                defer s.wg.Done()
129✔
286

129✔
287
                defer func() {
252✔
288
                        s.htlcSwitch.Stop()
123✔
289
                }()
123✔
290

291
                for {
7,918✔
292
                        select {
7,789✔
293
                        case msg := <-s.messages:
7,660✔
294
                                s.protocolTraceMtx.Lock()
7,660✔
295
                                s.protocolTrace = append(s.protocolTrace, msg)
7,660✔
296
                                s.protocolTraceMtx.Unlock()
7,660✔
297

7,660✔
298
                                var shouldSkip bool
7,660✔
299

7,660✔
300
                                for _, interceptor := range s.interceptorFuncs {
7,761✔
301
                                        skip, err := interceptor(msg)
101✔
302
                                        if err != nil {
101✔
303
                                                s.t.Fatalf("%v: error in the "+
×
304
                                                        "interceptor: %v", s.name, err)
×
305
                                                return
×
306
                                        }
×
307
                                        shouldSkip = shouldSkip || skip
101✔
308
                                }
309

310
                                if shouldSkip {
7,665✔
311
                                        continue
5✔
312
                                }
313

314
                                if err := s.readHandler(msg); err != nil {
7,655✔
315
                                        s.t.Fatal(err)
×
316
                                        return
×
317
                                }
×
318
                        case <-s.quit:
123✔
319
                                return
123✔
320
                        }
321
                }
322
        }()
323

324
        return nil
129✔
325
}
326

327
func (s *mockServer) QuitSignal() <-chan struct{} {
×
328
        return s.quit
×
329
}
×
330

331
// mockHopIterator represents the test version of hop iterator which instead
332
// of encrypting the path in onion blob just stores the path as a list of hops.
333
type mockHopIterator struct {
334
        hops []*hop.Payload
335
}
336

337
func newMockHopIterator(hops ...*hop.Payload) hop.Iterator {
2,285✔
338
        return &mockHopIterator{hops: hops}
2,285✔
339
}
2,285✔
340

341
func (r *mockHopIterator) HopPayload() (*hop.Payload, hop.RouteRole, error) {
1,488✔
342
        h := r.hops[0]
1,488✔
343
        r.hops = r.hops[1:]
1,488✔
344
        return h, hop.RouteRoleCleartext, nil
1,488✔
345
}
1,488✔
346

347
func (r *mockHopIterator) ExtraOnionBlob() []byte {
×
348
        return nil
×
349
}
×
350

351
func (r *mockHopIterator) ExtractErrorEncrypter(
352
        extracter hop.ErrorEncrypterExtracter, _ bool) (hop.ErrorEncrypter,
353
        lnwire.FailCode) {
1,488✔
354

1,488✔
355
        return extracter(nil)
1,488✔
356
}
1,488✔
357

358
func (r *mockHopIterator) EncodeNextHop(w io.Writer) error {
831✔
359
        var hopLength [4]byte
831✔
360
        binary.BigEndian.PutUint32(hopLength[:], uint32(len(r.hops)))
831✔
361

831✔
362
        if _, err := w.Write(hopLength[:]); err != nil {
831✔
363
                return err
×
364
        }
×
365

366
        for _, hop := range r.hops {
1,702✔
367
                fwdInfo := hop.ForwardingInfo()
871✔
368
                if err := encodeFwdInfo(w, &fwdInfo); err != nil {
871✔
369
                        return err
×
370
                }
×
371
        }
372

373
        return nil
831✔
374
}
375

376
func encodeFwdInfo(w io.Writer, f *hop.ForwardingInfo) error {
871✔
377
        if err := binary.Write(w, binary.BigEndian, f.NextHop); err != nil {
871✔
378
                return err
×
379
        }
×
380

381
        if err := binary.Write(w, binary.BigEndian, f.AmountToForward); err != nil {
871✔
382
                return err
×
383
        }
×
384

385
        if err := binary.Write(w, binary.BigEndian, f.OutgoingCTLV); err != nil {
871✔
386
                return err
×
387
        }
×
388

389
        return nil
871✔
390
}
391

392
var _ hop.Iterator = (*mockHopIterator)(nil)
393

394
// mockObfuscator mock implementation of the failure obfuscator which only
395
// encodes the failure and do not makes any onion obfuscation.
396
type mockObfuscator struct {
397
        ogPacket *sphinx.OnionPacket
398
        failure  lnwire.FailureMessage
399
}
400

401
// NewMockObfuscator initializes a dummy mockObfuscator used for testing.
402
func NewMockObfuscator() hop.ErrorEncrypter {
1,679✔
403
        return &mockObfuscator{}
1,679✔
404
}
1,679✔
405

406
func (o *mockObfuscator) OnionPacket() *sphinx.OnionPacket {
×
407
        return o.ogPacket
×
408
}
×
409

410
func (o *mockObfuscator) Type() hop.EncrypterType {
234✔
411
        return hop.EncrypterTypeMock
234✔
412
}
234✔
413

414
func (o *mockObfuscator) Encode(w io.Writer) error {
113✔
415
        return nil
113✔
416
}
113✔
417

418
func (o *mockObfuscator) Decode(r io.Reader) error {
66✔
419
        return nil
66✔
420
}
66✔
421

422
func (o *mockObfuscator) Reextract(
423
        extracter hop.ErrorEncrypterExtracter) error {
66✔
424

66✔
425
        return nil
66✔
426
}
66✔
427

428
var fakeHmac = []byte("hmachmachmachmachmachmachmachmac")
429

430
func (o *mockObfuscator) EncryptFirstHop(failure lnwire.FailureMessage) (
431
        lnwire.OpaqueReason, error) {
146✔
432

146✔
433
        o.failure = failure
146✔
434

146✔
435
        var b bytes.Buffer
146✔
436
        b.Write(fakeHmac)
146✔
437

146✔
438
        if err := lnwire.EncodeFailure(&b, failure, 0); err != nil {
146✔
439
                return nil, err
×
440
        }
×
441
        return b.Bytes(), nil
146✔
442
}
443

444
func (o *mockObfuscator) IntermediateEncrypt(reason lnwire.OpaqueReason) lnwire.OpaqueReason {
6✔
445
        return reason
6✔
446
}
6✔
447

448
func (o *mockObfuscator) EncryptMalformedError(reason lnwire.OpaqueReason) lnwire.OpaqueReason {
2✔
449
        var b bytes.Buffer
2✔
450
        b.Write(fakeHmac)
2✔
451

2✔
452
        b.Write(reason)
2✔
453

2✔
454
        return b.Bytes()
2✔
455
}
2✔
456

457
// mockDeobfuscator mock implementation of the failure deobfuscator which
458
// only decodes the failure do not makes any onion obfuscation.
459
type mockDeobfuscator struct{}
460

461
func newMockDeobfuscator() ErrorDecrypter {
741✔
462
        return &mockDeobfuscator{}
741✔
463
}
741✔
464

465
func (o *mockDeobfuscator) DecryptError(reason lnwire.OpaqueReason) (
466
        *ForwardingError, error) {
120✔
467

120✔
468
        if !bytes.Equal(reason[:32], fakeHmac) {
120✔
469
                return nil, errors.New("fake decryption error")
×
470
        }
×
471
        reason = reason[32:]
120✔
472

120✔
473
        r := bytes.NewReader(reason)
120✔
474
        failure, err := lnwire.DecodeFailure(r, 0)
120✔
475
        if err != nil {
120✔
476
                return nil, err
×
477
        }
×
478

479
        return NewForwardingError(failure, 1), nil
120✔
480
}
481

482
var _ ErrorDecrypter = (*mockDeobfuscator)(nil)
483

484
// mockIteratorDecoder test version of hop iterator decoder which decodes the
485
// encoded array of hops.
486
type mockIteratorDecoder struct {
487
        mu sync.RWMutex
488

489
        responses map[[32]byte][]hop.DecodeHopIteratorResponse
490

491
        decodeFail bool
492
}
493

494
func newMockIteratorDecoder() *mockIteratorDecoder {
176✔
495
        return &mockIteratorDecoder{
176✔
496
                responses: make(map[[32]byte][]hop.DecodeHopIteratorResponse),
176✔
497
        }
176✔
498
}
176✔
499

500
func (p *mockIteratorDecoder) DecodeHopIterator(r io.Reader, rHash []byte,
501
        cltv uint32) (hop.Iterator, lnwire.FailCode) {
1,490✔
502

1,490✔
503
        var b [4]byte
1,490✔
504
        _, err := r.Read(b[:])
1,490✔
505
        if err != nil {
1,490✔
506
                return nil, lnwire.CodeTemporaryChannelFailure
×
507
        }
×
508
        hopLength := binary.BigEndian.Uint32(b[:])
1,490✔
509

1,490✔
510
        hops := make([]*hop.Payload, hopLength)
1,490✔
511
        for i := uint32(0); i < hopLength; i++ {
3,017✔
512
                var f hop.ForwardingInfo
1,527✔
513
                if err := decodeFwdInfo(r, &f); err != nil {
1,527✔
514
                        return nil, lnwire.CodeTemporaryChannelFailure
×
515
                }
×
516

517
                var nextHopBytes [8]byte
1,527✔
518
                binary.BigEndian.PutUint64(nextHopBytes[:], f.NextHop.ToUint64())
1,527✔
519

1,527✔
520
                hops[i] = hop.NewLegacyPayload(&sphinx.HopData{
1,527✔
521
                        Realm:         [1]byte{}, // hop.BitcoinNetwork
1,527✔
522
                        NextAddress:   nextHopBytes,
1,527✔
523
                        ForwardAmount: uint64(f.AmountToForward),
1,527✔
524
                        OutgoingCltv:  f.OutgoingCTLV,
1,527✔
525
                })
1,527✔
526
        }
527

528
        return newMockHopIterator(hops...), lnwire.CodeNone
1,490✔
529
}
530

531
func (p *mockIteratorDecoder) DecodeHopIterators(id []byte,
532
        reqs []hop.DecodeHopIteratorRequest) (
533
        []hop.DecodeHopIteratorResponse, error) {
2,580✔
534

2,580✔
535
        idHash := sha256.Sum256(id)
2,580✔
536

2,580✔
537
        p.mu.RLock()
2,580✔
538
        if resps, ok := p.responses[idHash]; ok {
2,580✔
539
                p.mu.RUnlock()
×
540
                return resps, nil
×
541
        }
×
542
        p.mu.RUnlock()
2,580✔
543

2,580✔
544
        batchSize := len(reqs)
2,580✔
545

2,580✔
546
        resps := make([]hop.DecodeHopIteratorResponse, 0, batchSize)
2,580✔
547
        for _, req := range reqs {
4,070✔
548
                iterator, failcode := p.DecodeHopIterator(
1,490✔
549
                        req.OnionReader, req.RHash, req.IncomingCltv,
1,490✔
550
                )
1,490✔
551

1,490✔
552
                if p.decodeFail {
1,492✔
553
                        failcode = lnwire.CodeTemporaryChannelFailure
2✔
554
                }
2✔
555

556
                resp := hop.DecodeHopIteratorResponse{
1,490✔
557
                        HopIterator: iterator,
1,490✔
558
                        FailCode:    failcode,
1,490✔
559
                }
1,490✔
560
                resps = append(resps, resp)
1,490✔
561
        }
562

563
        p.mu.Lock()
2,580✔
564
        p.responses[idHash] = resps
2,580✔
565
        p.mu.Unlock()
2,580✔
566

2,580✔
567
        return resps, nil
2,580✔
568
}
569

570
func decodeFwdInfo(r io.Reader, f *hop.ForwardingInfo) error {
1,527✔
571
        if err := binary.Read(r, binary.BigEndian, &f.NextHop); err != nil {
1,527✔
572
                return err
×
573
        }
×
574

575
        if err := binary.Read(r, binary.BigEndian, &f.AmountToForward); err != nil {
1,527✔
576
                return err
×
577
        }
×
578

579
        if err := binary.Read(r, binary.BigEndian, &f.OutgoingCTLV); err != nil {
1,527✔
580
                return err
×
581
        }
×
582

583
        return nil
1,527✔
584
}
585

586
// messageInterceptor is function that handles the incoming peer messages and
587
// may decide should the peer skip the message or not.
588
type messageInterceptor func(m lnwire.Message) (bool, error)
589

590
// Record is used to set the function which will be triggered when new
591
// lnwire message was received.
592
func (s *mockServer) intersect(f messageInterceptor) {
16✔
593
        s.interceptorFuncs = append(s.interceptorFuncs, f)
16✔
594
}
16✔
595

596
func (s *mockServer) SendMessage(sync bool, msgs ...lnwire.Message) error {
7,667✔
597

7,667✔
598
        for _, msg := range msgs {
15,334✔
599
                select {
7,667✔
600
                case s.messages <- msg:
7,663✔
601
                case <-s.quit:
4✔
602
                        return errors.New("server is stopped")
4✔
603
                }
604
        }
605

606
        return nil
7,663✔
607
}
608

609
func (s *mockServer) SendMessageLazy(sync bool, msgs ...lnwire.Message) error {
×
610
        panic("not implemented")
×
611
}
612

613
func (s *mockServer) readHandler(message lnwire.Message) error {
7,655✔
614
        var targetChan lnwire.ChannelID
7,655✔
615

7,655✔
616
        switch msg := message.(type) {
7,655✔
617
        case *lnwire.UpdateAddHTLC:
1,466✔
618
                targetChan = msg.ChanID
1,466✔
619
        case *lnwire.UpdateFulfillHTLC:
635✔
620
                targetChan = msg.ChanID
635✔
621
        case *lnwire.UpdateFailHTLC:
118✔
622
                targetChan = msg.ChanID
118✔
623
        case *lnwire.UpdateFailMalformedHTLC:
3✔
624
                targetChan = msg.ChanID
3✔
625
        case *lnwire.RevokeAndAck:
2,544✔
626
                targetChan = msg.ChanID
2,544✔
627
        case *lnwire.CommitSig:
2,552✔
628
                targetChan = msg.ChanID
2,552✔
629
        case *lnwire.ChannelReady:
164✔
630
                // Ignore
164✔
631
                return nil
164✔
632
        case *lnwire.ChannelReestablish:
168✔
633
                targetChan = msg.ChanID
168✔
634
        case *lnwire.UpdateFee:
3✔
635
                targetChan = msg.ChanID
3✔
636
        case *lnwire.Stfu:
2✔
637
                targetChan = msg.ChanID
2✔
638
        default:
×
639
                return fmt.Errorf("unknown message type: %T", msg)
×
640
        }
641

642
        // Dispatch the commitment update message to the proper channel link
643
        // dedicated to this channel. If the link is not found, we will discard
644
        // the message.
645
        link, err := s.htlcSwitch.GetLink(targetChan)
7,491✔
646
        if err != nil {
7,491✔
647
                return nil
×
648
        }
×
649

650
        // Create goroutine for this, in order to be able to properly stop
651
        // the server when handler stacked (server unavailable)
652
        link.HandleChannelUpdate(message)
7,491✔
653

7,491✔
654
        return nil
7,491✔
655
}
656

657
func (s *mockServer) PubKey() [33]byte {
817✔
658
        return s.id
817✔
659
}
817✔
660

661
func (s *mockServer) IdentityKey() *btcec.PublicKey {
×
662
        pubkey, _ := btcec.ParsePubKey(s.id[:])
×
663
        return pubkey
×
664
}
×
665

666
func (s *mockServer) Address() net.Addr {
×
667
        return nil
×
668
}
×
669

670
func (s *mockServer) AddNewChannel(channel *lnpeer.NewChannel,
671
        cancel <-chan struct{}) error {
×
672

×
673
        return nil
×
674
}
×
675

676
func (s *mockServer) AddPendingChannel(_ lnwire.ChannelID,
677
        cancel <-chan struct{}) error {
×
678

×
679
        return nil
×
680
}
×
681

682
func (s *mockServer) RemovePendingChannel(_ lnwire.ChannelID) error {
×
683
        return nil
×
684
}
×
685

686
func (s *mockServer) WipeChannel(*wire.OutPoint) {}
×
687

688
func (s *mockServer) LocalFeatures() *lnwire.FeatureVector {
×
689
        return nil
×
690
}
×
691

692
func (s *mockServer) RemoteFeatures() *lnwire.FeatureVector {
×
693
        return nil
×
694
}
×
695

696
func (s *mockServer) Disconnect(err error) {}
×
697

698
func (s *mockServer) Stop() error {
132✔
699
        if !atomic.CompareAndSwapInt32(&s.shutdown, 0, 1) {
141✔
700
                return nil
9✔
701
        }
9✔
702

703
        close(s.quit)
123✔
704
        s.wg.Wait()
123✔
705

123✔
706
        return nil
123✔
707
}
708

709
func (s *mockServer) String() string {
×
710
        return s.name
×
711
}
×
712

713
type mockChannelLink struct {
714
        htlcSwitch *Switch
715

716
        shortChanID lnwire.ShortChannelID
717

718
        // Only used for zero-conf channels.
719
        realScid lnwire.ShortChannelID
720

721
        aliases []lnwire.ShortChannelID
722

723
        chanID lnwire.ChannelID
724

725
        peer lnpeer.Peer
726

727
        mailBox MailBox
728

729
        packets chan *htlcPacket
730

731
        eligible bool
732

733
        unadvertised bool
734

735
        zeroConf bool
736

737
        optionFeature bool
738

739
        htlcID uint64
740

741
        checkHtlcTransitResult *LinkError
742

743
        checkHtlcForwardResult *LinkError
744

745
        failAliasUpdate func(sid lnwire.ShortChannelID,
746
                incoming bool) *lnwire.ChannelUpdate1
747

748
        confirmedZC bool
749
}
750

751
// completeCircuit is a helper method for adding the finalized payment circuit
752
// to the switch's circuit map. In testing, this should be executed after
753
// receiving an htlc from the downstream packets channel.
754
func (f *mockChannelLink) completeCircuit(pkt *htlcPacket) error {
31✔
755
        switch htlc := pkt.htlc.(type) {
31✔
756
        case *lnwire.UpdateAddHTLC:
14✔
757
                pkt.outgoingChanID = f.shortChanID
14✔
758
                pkt.outgoingHTLCID = f.htlcID
14✔
759
                htlc.ID = f.htlcID
14✔
760

14✔
761
                keystone := Keystone{pkt.inKey(), pkt.outKey()}
14✔
762
                err := f.htlcSwitch.circuits.OpenCircuits(keystone)
14✔
763
                if err != nil {
14✔
764
                        return err
×
765
                }
×
766

767
                f.htlcID++
14✔
768

769
        case *lnwire.UpdateFulfillHTLC, *lnwire.UpdateFailHTLC:
17✔
770
                if pkt.circuit != nil {
27✔
771
                        err := f.htlcSwitch.teardownCircuit(pkt)
10✔
772
                        if err != nil {
10✔
773
                                return err
×
774
                        }
×
775
                }
776
        }
777

778
        f.mailBox.AckPacket(pkt.inKey())
31✔
779

31✔
780
        return nil
31✔
781
}
782

783
func (f *mockChannelLink) deleteCircuit(pkt *htlcPacket) error {
1✔
784
        return f.htlcSwitch.circuits.DeleteCircuits(pkt.inKey())
1✔
785
}
1✔
786

787
func newMockChannelLink(htlcSwitch *Switch, chanID lnwire.ChannelID,
788
        shortChanID, realScid lnwire.ShortChannelID, peer lnpeer.Peer,
789
        eligible, unadvertised, zeroConf, optionFeature bool,
790
) *mockChannelLink {
118✔
791

118✔
792
        aliases := make([]lnwire.ShortChannelID, 0)
118✔
793
        var realConfirmed bool
118✔
794

118✔
795
        if zeroConf {
134✔
796
                aliases = append(aliases, shortChanID)
16✔
797
        }
16✔
798

799
        if realScid != hop.Source {
130✔
800
                realConfirmed = true
12✔
801
        }
12✔
802

803
        return &mockChannelLink{
118✔
804
                htlcSwitch:    htlcSwitch,
118✔
805
                chanID:        chanID,
118✔
806
                shortChanID:   shortChanID,
118✔
807
                realScid:      realScid,
118✔
808
                peer:          peer,
118✔
809
                eligible:      eligible,
118✔
810
                unadvertised:  unadvertised,
118✔
811
                zeroConf:      zeroConf,
118✔
812
                optionFeature: optionFeature,
118✔
813
                aliases:       aliases,
118✔
814
                confirmedZC:   realConfirmed,
118✔
815
        }
118✔
816
}
817

818
// addAlias is not part of any interface method.
819
func (f *mockChannelLink) addAlias(alias lnwire.ShortChannelID) {
22✔
820
        f.aliases = append(f.aliases, alias)
22✔
821
}
22✔
822

823
func (f *mockChannelLink) handleSwitchPacket(pkt *htlcPacket) error {
40✔
824
        f.mailBox.AddPacket(pkt)
40✔
825
        return nil
40✔
826
}
40✔
827

828
func (f *mockChannelLink) getDustSum(whoseCommit lntypes.ChannelParty,
829
        dryRunFee fn.Option[chainfee.SatPerKWeight]) lnwire.MilliSatoshi {
150✔
830

150✔
831
        return 0
150✔
832
}
150✔
833

834
func (f *mockChannelLink) getFeeRate() chainfee.SatPerKWeight {
76✔
835
        return 0
76✔
836
}
76✔
837

838
func (f *mockChannelLink) getDustClosure() dustClosure {
198✔
839
        dustLimit := btcutil.Amount(400)
198✔
840
        return dustHelper(
198✔
841
                channeldb.SingleFunderTweaklessBit, dustLimit, dustLimit,
198✔
842
        )
198✔
843
}
198✔
844

845
func (f *mockChannelLink) getCommitFee(remote bool) btcutil.Amount {
×
846
        return 0
×
847
}
×
848

849
func (f *mockChannelLink) HandleChannelUpdate(lnwire.Message) {
×
850
}
×
851

852
func (f *mockChannelLink) UpdateForwardingPolicy(_ models.ForwardingPolicy) {
×
853
}
×
854
func (f *mockChannelLink) CheckHtlcForward([32]byte, lnwire.MilliSatoshi,
855
        lnwire.MilliSatoshi, uint32, uint32, models.InboundFee, uint32,
856
        lnwire.ShortChannelID) *LinkError {
37✔
857

37✔
858
        return f.checkHtlcForwardResult
37✔
859
}
37✔
860

861
func (f *mockChannelLink) CheckHtlcTransit(payHash [32]byte,
862
        amt lnwire.MilliSatoshi, timeout uint32,
863
        heightNow uint32) *LinkError {
9✔
864

9✔
865
        return f.checkHtlcTransitResult
9✔
866
}
9✔
867

868
func (f *mockChannelLink) Stats() (
869
        uint64, lnwire.MilliSatoshi, lnwire.MilliSatoshi) {
2✔
870

2✔
871
        return 0, 0, 0
2✔
872
}
2✔
873

874
func (f *mockChannelLink) AttachMailBox(mailBox MailBox) {
122✔
875
        f.mailBox = mailBox
122✔
876
        f.packets = mailBox.PacketOutBox()
122✔
877
        mailBox.SetDustClosure(f.getDustClosure())
122✔
878
}
122✔
879

880
func (f *mockChannelLink) attachFailAliasUpdate(closure func(
881
        sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate1) {
122✔
882

122✔
883
        f.failAliasUpdate = closure
122✔
884
}
122✔
885

886
func (f *mockChannelLink) getAliases() []lnwire.ShortChannelID {
130✔
887
        return f.aliases
130✔
888
}
130✔
889

890
func (f *mockChannelLink) isZeroConf() bool {
121✔
891
        return f.zeroConf
121✔
892
}
121✔
893

894
func (f *mockChannelLink) negotiatedAliasFeature() bool {
105✔
895
        return f.optionFeature
105✔
896
}
105✔
897

898
func (f *mockChannelLink) confirmedScid() lnwire.ShortChannelID {
13✔
899
        return f.realScid
13✔
900
}
13✔
901

902
func (f *mockChannelLink) zeroConfConfirmed() bool {
16✔
903
        return f.confirmedZC
16✔
904
}
16✔
905

906
func (f *mockChannelLink) Start() error {
122✔
907
        f.mailBox.ResetMessages()
122✔
908
        f.mailBox.ResetPackets()
122✔
909
        return nil
122✔
910
}
122✔
911

912
func (f *mockChannelLink) ChanID() lnwire.ChannelID {
926✔
913
        return f.chanID
926✔
914
}
926✔
915

916
func (f *mockChannelLink) ShortChanID() lnwire.ShortChannelID {
693✔
917
        return f.shortChanID
693✔
918
}
693✔
919

920
func (f *mockChannelLink) Bandwidth() lnwire.MilliSatoshi {
×
921
        return 99999999
×
922
}
×
923

924
func (f *mockChannelLink) PeerPubKey() [33]byte {
280✔
925
        return f.peer.PubKey()
280✔
926
}
280✔
927

928
func (f *mockChannelLink) ChannelPoint() wire.OutPoint {
×
929
        return wire.OutPoint{}
×
930
}
×
931

932
func (f *mockChannelLink) Stop()                                        {}
122✔
933
func (f *mockChannelLink) EligibleToForward() bool                      { return f.eligible }
53✔
934
func (f *mockChannelLink) MayAddOutgoingHtlc(lnwire.MilliSatoshi) error { return nil }
×
935
func (f *mockChannelLink) setLiveShortChanID(sid lnwire.ShortChannelID) { f.shortChanID = sid }
×
936
func (f *mockChannelLink) IsUnadvertised() bool                         { return f.unadvertised }
5✔
937
func (f *mockChannelLink) UpdateShortChanID() (lnwire.ShortChannelID, error) {
1✔
938
        f.eligible = true
1✔
939
        return f.shortChanID, nil
1✔
940
}
1✔
941

942
func (f *mockChannelLink) EnableAdds(linkDirection LinkDirection) bool {
×
943
        // TODO(proofofkeags): Implement
×
944
        return true
×
945
}
×
946

947
func (f *mockChannelLink) DisableAdds(linkDirection LinkDirection) bool {
×
948
        // TODO(proofofkeags): Implement
×
949
        return true
×
950
}
×
951
func (f *mockChannelLink) IsFlushing(linkDirection LinkDirection) bool {
×
952
        // TODO(proofofkeags): Implement
×
953
        return false
×
954
}
×
955
func (f *mockChannelLink) OnFlushedOnce(func()) {
×
956
        // TODO(proofofkeags): Implement
×
957
}
×
958
func (f *mockChannelLink) OnCommitOnce(LinkDirection, func()) {
×
959
        // TODO(proofofkeags): Implement
×
960
}
×
NEW
961
func (f *mockChannelLink) InitStfu() <-chan fn.Result[lntypes.ChannelParty] {
×
NEW
962
        // TODO(proofofkeags): Implement
×
NEW
963
        c := make(chan fn.Result[lntypes.ChannelParty], 1)
×
NEW
964

×
NEW
965
        c <- fn.Errf[lntypes.ChannelParty]("InitStfu not implemented")
×
NEW
966

×
NEW
967
        return c
×
NEW
968
}
×
969

970
func (f *mockChannelLink) FundingCustomBlob() fn.Option[tlv.Blob] {
×
971
        return fn.None[tlv.Blob]()
×
972
}
×
973

974
func (f *mockChannelLink) CommitmentCustomBlob() fn.Option[tlv.Blob] {
×
975
        return fn.None[tlv.Blob]()
×
976
}
×
977

978
var _ ChannelLink = (*mockChannelLink)(nil)
979

980
func newDB() (*channeldb.DB, func(), error) {
258✔
981
        // First, create a temporary directory to be used for the duration of
258✔
982
        // this test.
258✔
983
        tempDirName, err := os.MkdirTemp("", "channeldb")
258✔
984
        if err != nil {
258✔
985
                return nil, nil, err
×
986
        }
×
987

988
        // Next, create channeldb for the first time.
989
        cdb, err := channeldb.Open(tempDirName)
258✔
990
        if err != nil {
258✔
991
                os.RemoveAll(tempDirName)
×
992
                return nil, nil, err
×
993
        }
×
994

995
        cleanUp := func() {
516✔
996
                cdb.Close()
258✔
997
                os.RemoveAll(tempDirName)
258✔
998
        }
258✔
999

1000
        return cdb, cleanUp, nil
258✔
1001
}
1002

1003
const testInvoiceCltvExpiry = 6
1004

1005
type mockInvoiceRegistry struct {
1006
        settleChan chan lntypes.Hash
1007

1008
        registry *invoices.InvoiceRegistry
1009

1010
        cleanup func()
1011
}
1012

1013
type mockChainNotifier struct {
1014
        chainntnfs.ChainNotifier
1015
}
1016

1017
// RegisterBlockEpochNtfn mocks a successful call to register block
1018
// notifications.
1019
func (m *mockChainNotifier) RegisterBlockEpochNtfn(*chainntnfs.BlockEpoch) (
1020
        *chainntnfs.BlockEpochEvent, error) {
258✔
1021

258✔
1022
        return &chainntnfs.BlockEpochEvent{
258✔
1023
                Cancel: func() {},
258✔
1024
        }, nil
1025
}
1026

1027
func newMockRegistry(minDelta uint32) *mockInvoiceRegistry {
258✔
1028
        cdb, cleanup, err := newDB()
258✔
1029
        if err != nil {
258✔
1030
                panic(err)
×
1031
        }
1032

1033
        modifierMock := &invoices.MockHtlcModifier{}
258✔
1034
        registry := invoices.NewRegistry(
258✔
1035
                cdb,
258✔
1036
                invoices.NewInvoiceExpiryWatcher(
258✔
1037
                        clock.NewDefaultClock(), 0, 0, nil,
258✔
1038
                        &mockChainNotifier{},
258✔
1039
                ),
258✔
1040
                &invoices.RegistryConfig{
258✔
1041
                        FinalCltvRejectDelta: 5,
258✔
1042
                        HtlcInterceptor:      modifierMock,
258✔
1043
                },
258✔
1044
        )
258✔
1045
        registry.Start()
258✔
1046

258✔
1047
        return &mockInvoiceRegistry{
258✔
1048
                registry: registry,
258✔
1049
                cleanup:  cleanup,
258✔
1050
        }
258✔
1051
}
1052

1053
func (i *mockInvoiceRegistry) LookupInvoice(ctx context.Context,
1054
        rHash lntypes.Hash) (invoices.Invoice, error) {
14✔
1055

14✔
1056
        return i.registry.LookupInvoice(ctx, rHash)
14✔
1057
}
14✔
1058

1059
func (i *mockInvoiceRegistry) SettleHodlInvoice(
1060
        ctx context.Context, preimage lntypes.Preimage) error {
487✔
1061

487✔
1062
        return i.registry.SettleHodlInvoice(ctx, preimage)
487✔
1063
}
487✔
1064

1065
func (i *mockInvoiceRegistry) NotifyExitHopHtlc(rhash lntypes.Hash,
1066
        amt lnwire.MilliSatoshi, expiry uint32, currentHeight int32,
1067
        circuitKey models.CircuitKey, hodlChan chan<- interface{},
1068
        wireCustomRecords lnwire.CustomRecords,
1069
        payload invoices.Payload) (invoices.HtlcResolution, error) {
635✔
1070

635✔
1071
        event, err := i.registry.NotifyExitHopHtlc(
635✔
1072
                rhash, amt, expiry, currentHeight, circuitKey,
635✔
1073
                hodlChan, wireCustomRecords, payload,
635✔
1074
        )
635✔
1075
        if err != nil {
635✔
1076
                return nil, err
×
1077
        }
×
1078
        if i.settleChan != nil {
642✔
1079
                i.settleChan <- rhash
7✔
1080
        }
7✔
1081

1082
        return event, nil
635✔
1083
}
1084

1085
func (i *mockInvoiceRegistry) CancelInvoice(ctx context.Context,
1086
        payHash lntypes.Hash) error {
2✔
1087

2✔
1088
        return i.registry.CancelInvoice(ctx, payHash)
2✔
1089
}
2✔
1090

1091
func (i *mockInvoiceRegistry) AddInvoice(ctx context.Context,
1092
        invoice invoices.Invoice, paymentHash lntypes.Hash) error {
760✔
1093

760✔
1094
        _, err := i.registry.AddInvoice(ctx, &invoice, paymentHash)
760✔
1095
        return err
760✔
1096
}
760✔
1097

1098
func (i *mockInvoiceRegistry) HodlUnsubscribeAll(
1099
        subscriber chan<- interface{}) {
202✔
1100

202✔
1101
        i.registry.HodlUnsubscribeAll(subscriber)
202✔
1102
}
202✔
1103

1104
var _ InvoiceDatabase = (*mockInvoiceRegistry)(nil)
1105

1106
type mockCircuitMap struct {
1107
        lookup chan *PaymentCircuit
1108
}
1109

1110
var _ CircuitMap = (*mockCircuitMap)(nil)
1111

1112
func (m *mockCircuitMap) OpenCircuits(...Keystone) error {
×
1113
        return nil
×
1114
}
×
1115

1116
func (m *mockCircuitMap) TrimOpenCircuits(chanID lnwire.ShortChannelID,
1117
        start uint64) error {
×
1118
        return nil
×
1119
}
×
1120

1121
func (m *mockCircuitMap) DeleteCircuits(inKeys ...CircuitKey) error {
×
1122
        return nil
×
1123
}
×
1124

1125
func (m *mockCircuitMap) CommitCircuits(
1126
        circuit ...*PaymentCircuit) (*CircuitFwdActions, error) {
×
1127

×
1128
        return nil, nil
×
1129
}
×
1130

1131
func (m *mockCircuitMap) CloseCircuit(outKey CircuitKey) (*PaymentCircuit,
1132
        error) {
×
1133
        return nil, nil
×
1134
}
×
1135

1136
func (m *mockCircuitMap) FailCircuit(inKey CircuitKey) (*PaymentCircuit,
1137
        error) {
×
1138
        return nil, nil
×
1139
}
×
1140

1141
func (m *mockCircuitMap) LookupCircuit(inKey CircuitKey) *PaymentCircuit {
3✔
1142
        return <-m.lookup
3✔
1143
}
3✔
1144

1145
func (m *mockCircuitMap) LookupOpenCircuit(outKey CircuitKey) *PaymentCircuit {
×
1146
        return nil
×
1147
}
×
1148

1149
func (m *mockCircuitMap) LookupByPaymentHash(hash [32]byte) []*PaymentCircuit {
×
1150
        return nil
×
1151
}
×
1152

1153
func (m *mockCircuitMap) NumPending() int {
×
1154
        return 0
×
1155
}
×
1156

1157
func (m *mockCircuitMap) NumOpen() int {
×
1158
        return 0
×
1159
}
×
1160

1161
type mockOnionErrorDecryptor struct {
1162
        sourceIdx int
1163
        message   []byte
1164
        err       error
1165
}
1166

1167
func (m *mockOnionErrorDecryptor) DecryptError(encryptedData []byte) (
1168
        *sphinx.DecryptedError, error) {
2✔
1169

2✔
1170
        return &sphinx.DecryptedError{
2✔
1171
                SenderIdx: m.sourceIdx,
2✔
1172
                Message:   m.message,
2✔
1173
        }, m.err
2✔
1174
}
2✔
1175

1176
var _ htlcNotifier = (*mockHTLCNotifier)(nil)
1177

1178
type mockHTLCNotifier struct {
1179
        htlcNotifier //nolint:unused
1180
}
1181

1182
func (h *mockHTLCNotifier) NotifyForwardingEvent(key HtlcKey, info HtlcInfo,
1183
        eventType HtlcEventType) {
1,511✔
1184

1,511✔
1185
}
1,511✔
1186

1187
func (h *mockHTLCNotifier) NotifyLinkFailEvent(key HtlcKey, info HtlcInfo,
1188
        eventType HtlcEventType, linkErr *LinkError,
1189
        incoming bool) {
119✔
1190

119✔
1191
}
119✔
1192

1193
func (h *mockHTLCNotifier) NotifyForwardingFailEvent(key HtlcKey,
1194
        eventType HtlcEventType) {
129✔
1195

129✔
1196
}
129✔
1197

1198
func (h *mockHTLCNotifier) NotifySettleEvent(key HtlcKey,
1199
        preimage lntypes.Preimage, eventType HtlcEventType) {
1,260✔
1200

1,260✔
1201
}
1,260✔
1202

1203
func (h *mockHTLCNotifier) NotifyFinalHtlcEvent(key models.CircuitKey,
1204
        info channeldb.FinalHtlcInfo) {
763✔
1205

763✔
1206
}
763✔
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