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

lightningnetwork / lnd / 13523316608

25 Feb 2025 02:12PM UTC coverage: 49.351% (-9.5%) from 58.835%
13523316608

Pull #9549

github

yyforyongyu
routing/chainview: refactor `TestFilteredChainView`

So each test has its own miner and chainView.
Pull Request #9549: Fix unit test flake `TestHistoricalConfDetailsTxIndex`

0 of 120 new or added lines in 1 file covered. (0.0%)

27196 existing lines in 434 files now uncovered.

100945 of 204543 relevant lines covered (49.35%)

1.54 hits per line

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

69.71
/htlcswitch/htlcnotifier.go
1
package htlcswitch
2

3
import (
4
        "fmt"
5
        "strings"
6
        "sync"
7
        "time"
8

9
        "github.com/lightningnetwork/lnd/channeldb"
10
        "github.com/lightningnetwork/lnd/graph/db/models"
11
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
12
        "github.com/lightningnetwork/lnd/lntypes"
13
        "github.com/lightningnetwork/lnd/lnwire"
14
        "github.com/lightningnetwork/lnd/subscribe"
15
)
16

17
// HtlcNotifier notifies clients of htlc forwards, failures and settles for
18
// htlcs that the switch handles. It takes subscriptions for its events and
19
// notifies them when htlc events occur. These are served on a best-effort
20
// basis; events are not persisted, delivery is not guaranteed (in the event
21
// of a crash in the switch, forward events may be lost) and some events may
22
// be replayed upon restart. Events consumed from this package should be
23
// de-duplicated by the htlc's unique combination of incoming+outgoing circuit
24
// and not relied upon for critical operations.
25
//
26
// The htlc notifier sends the following kinds of events:
27
// Forwarding Event:
28
// - Represents a htlc which is forwarded onward from our node.
29
// - Present for htlc forwards through our node and local sends.
30
//
31
// Link Failure Event:
32
//   - Indicates that a htlc has failed on our incoming or outgoing link,
33
//     with an incoming boolean which indicates where the failure occurred.
34
//   - Incoming link failures are present for failed attempts to pay one of
35
//     our invoices (insufficient amount or mpp timeout, for example) and for
36
//     forwards that we cannot decode to forward onwards.
37
//   - Outgoing link failures are present for forwards or local payments that
38
//     do not meet our outgoing link's policy (insufficient fees, for example)
39
//     and when we fail to forward the payment on (insufficient outgoing
40
//     capacity, or an unknown outgoing link).
41
//
42
// Forwarding Failure Event:
43
//   - Forwarding failures indicate that a htlc we forwarded has failed at
44
//     another node down the route.
45
//   - Present for local sends and htlc forwards which fail after they left
46
//     our node.
47
//
48
// Settle event:
49
//   - Settle events are present when a htlc which we added is settled through
50
//     the release of a preimage.
51
//   - Present for local receives, and successful local sends or forwards.
52
//
53
// Each htlc is identified by its incoming and outgoing circuit key. Htlcs,
54
// and their subsequent settles or fails, can be identified by the combination
55
// of incoming and outgoing circuits. Note that receives to our node will
56
// have a zero outgoing circuit key because the htlc terminates at our
57
// node, and sends from our node will have a zero incoming circuit key because
58
// the send originates at our node.
59
type HtlcNotifier struct {
60
        started sync.Once
61
        stopped sync.Once
62

63
        // now returns the current time, it is set in the htlcnotifier to allow
64
        // for timestamp mocking in tests.
65
        now func() time.Time
66

67
        ntfnServer *subscribe.Server
68
}
69

70
// NewHtlcNotifier creates a new HtlcNotifier which gets htlc forwarded,
71
// failed and settled events from links our node has established with peers
72
// and sends notifications to subscribing clients.
73
func NewHtlcNotifier(now func() time.Time) *HtlcNotifier {
3✔
74
        return &HtlcNotifier{
3✔
75
                now:        now,
3✔
76
                ntfnServer: subscribe.NewServer(),
3✔
77
        }
3✔
78
}
3✔
79

80
// Start starts the HtlcNotifier and all goroutines it needs to consume
81
// events and provide subscriptions to clients.
82
func (h *HtlcNotifier) Start() error {
3✔
83
        var err error
3✔
84
        h.started.Do(func() {
6✔
85
                log.Info("HtlcNotifier starting")
3✔
86
                err = h.ntfnServer.Start()
3✔
87
        })
3✔
88
        return err
3✔
89
}
90

91
// Stop signals the notifier for a graceful shutdown.
92
func (h *HtlcNotifier) Stop() error {
3✔
93
        var err error
3✔
94
        h.stopped.Do(func() {
6✔
95
                log.Info("HtlcNotifier shutting down...")
3✔
96
                defer log.Debug("HtlcNotifier shutdown complete")
3✔
97

3✔
98
                if err = h.ntfnServer.Stop(); err != nil {
3✔
99
                        log.Warnf("error stopping htlc notifier: %v", err)
×
100
                }
×
101
        })
102
        return err
3✔
103
}
104

105
// SubscribeHtlcEvents returns a subscribe.Client that will receive updates
106
// any time the server is made aware of a new event.
107
func (h *HtlcNotifier) SubscribeHtlcEvents() (*subscribe.Client, error) {
3✔
108
        return h.ntfnServer.Subscribe()
3✔
109
}
3✔
110

111
// HtlcKey uniquely identifies the htlc.
112
type HtlcKey struct {
113
        // IncomingCircuit is the channel an htlc id of the incoming htlc.
114
        IncomingCircuit models.CircuitKey
115

116
        // OutgoingCircuit is the channel and htlc id of the outgoing htlc.
117
        OutgoingCircuit models.CircuitKey
118
}
119

120
// String returns a string representation of a htlc key.
121
func (k HtlcKey) String() string {
×
122
        switch {
×
123
        case k.IncomingCircuit.ChanID == hop.Source:
×
124
                return k.OutgoingCircuit.String()
×
125

126
        case k.OutgoingCircuit.ChanID == hop.Exit:
×
127
                return k.IncomingCircuit.String()
×
128

129
        default:
×
130
                return fmt.Sprintf("%v -> %v", k.IncomingCircuit,
×
131
                        k.OutgoingCircuit)
×
132
        }
133
}
134

135
// HtlcInfo provides the details of a htlc that our node has processed. For
136
// forwards, incoming and outgoing values are set, whereas sends and receives
137
// will only have outgoing or incoming details set.
138
type HtlcInfo struct {
139
        // IncomingTimelock is the time lock of the htlc on our incoming
140
        // channel.
141
        IncomingTimeLock uint32
142

143
        // OutgoingTimelock is the time lock the htlc on our outgoing channel.
144
        OutgoingTimeLock uint32
145

146
        // IncomingAmt is the amount of the htlc on our incoming channel.
147
        IncomingAmt lnwire.MilliSatoshi
148

149
        // OutgoingAmt is the amount of the htlc on our outgoing channel.
150
        OutgoingAmt lnwire.MilliSatoshi
151
}
152

153
// String returns a string representation of a htlc.
154
func (h HtlcInfo) String() string {
×
155
        var details []string
×
156

×
157
        // If the incoming information is not zero, as is the case for a send,
×
158
        // we include the incoming amount and timelock.
×
159
        if h.IncomingAmt != 0 || h.IncomingTimeLock != 0 {
×
160
                str := fmt.Sprintf("incoming amount: %v, "+
×
161
                        "incoming timelock: %v", h.IncomingAmt,
×
162
                        h.IncomingTimeLock)
×
163

×
164
                details = append(details, str)
×
165
        }
×
166

167
        // If the outgoing information is not zero, as is the case for a
168
        // receive, we include the outgoing amount and timelock.
169
        if h.OutgoingAmt != 0 || h.OutgoingTimeLock != 0 {
×
170
                str := fmt.Sprintf("outgoing amount: %v, "+
×
171
                        "outgoing timelock: %v", h.OutgoingAmt,
×
172
                        h.OutgoingTimeLock)
×
173

×
174
                details = append(details, str)
×
175
        }
×
176

177
        return strings.Join(details, ", ")
×
178
}
179

180
// HtlcEventType represents the type of event that a htlc was part of.
181
type HtlcEventType int
182

183
const (
184
        // HtlcEventTypeSend represents a htlc that was part of a send from
185
        // our node.
186
        HtlcEventTypeSend HtlcEventType = iota
187

188
        // HtlcEventTypeReceive represents a htlc that was part of a receive
189
        // to our node.
190
        HtlcEventTypeReceive
191

192
        // HtlcEventTypeForward represents a htlc that was forwarded through
193
        // our node.
194
        HtlcEventTypeForward
195
)
196

197
// String returns a string representation of a htlc event type.
198
func (h HtlcEventType) String() string {
×
199
        switch h {
×
200
        case HtlcEventTypeSend:
×
201
                return "send"
×
202

203
        case HtlcEventTypeReceive:
×
204
                return "receive"
×
205

206
        case HtlcEventTypeForward:
×
207
                return "forward"
×
208

209
        default:
×
210
                return "unknown"
×
211
        }
212
}
213

214
// ForwardingEvent represents a htlc that was forwarded onwards from our node.
215
// Sends which originate from our node will report forward events with zero
216
// incoming circuits in their htlc key.
217
type ForwardingEvent struct {
218
        // HtlcKey uniquely identifies the htlc, and can be used to match the
219
        // forwarding event with subsequent settle/fail events.
220
        HtlcKey
221

222
        // HtlcInfo contains details about the htlc.
223
        HtlcInfo
224

225
        // HtlcEventType classifies the event as part of a local send or
226
        // receive, or as part of a forward.
227
        HtlcEventType
228

229
        // Timestamp is the time when this htlc was forwarded.
230
        Timestamp time.Time
231
}
232

233
// LinkFailEvent describes a htlc that failed on our incoming or outgoing
234
// link. The incoming bool is true for failures on incoming links, and false
235
// for failures on outgoing links. The failure reason is provided by a lnwire
236
// failure message which is enriched with a failure detail in the cases where
237
// the wire failure message does not contain full information about the
238
// failure.
239
type LinkFailEvent struct {
240
        // HtlcKey uniquely identifies the htlc.
241
        HtlcKey
242

243
        // HtlcInfo contains details about the htlc.
244
        HtlcInfo
245

246
        // HtlcEventType classifies the event as part of a local send or
247
        // receive, or as part of a forward.
248
        HtlcEventType
249

250
        // LinkError is the reason that we failed the htlc.
251
        LinkError *LinkError
252

253
        // Incoming is true if the htlc was failed on an incoming link.
254
        // If it failed on the outgoing link, it is false.
255
        Incoming bool
256

257
        // Timestamp is the time when the link failure occurred.
258
        Timestamp time.Time
259
}
260

261
// ForwardingFailEvent represents a htlc failure which occurred down the line
262
// after we forwarded a htlc onwards. An error is not included in this event
263
// because errors returned down the route are encrypted. HtlcInfo is not
264
// reliably available for forwarding failures, so it is omitted. These events
265
// should be matched with their corresponding forward event to obtain this
266
// information.
267
type ForwardingFailEvent struct {
268
        // HtlcKey uniquely identifies the htlc, and can be used to match the
269
        // htlc with its corresponding forwarding event.
270
        HtlcKey
271

272
        // HtlcEventType classifies the event as part of a local send or
273
        // receive, or as part of a forward.
274
        HtlcEventType
275

276
        // Timestamp is the time when the forwarding failure was received.
277
        Timestamp time.Time
278
}
279

280
// SettleEvent represents a htlc that was settled. HtlcInfo is not reliably
281
// available for forwarding failures, so it is omitted. These events should
282
// be matched with corresponding forward events or invoices (for receives)
283
// to obtain additional information about the htlc.
284
type SettleEvent struct {
285
        // HtlcKey uniquely identifies the htlc, and can be used to match
286
        // forwards with their corresponding forwarding event.
287
        HtlcKey
288

289
        // Preimage that was released for settling the htlc.
290
        Preimage lntypes.Preimage
291

292
        // HtlcEventType classifies the event as part of a local send or
293
        // receive, or as part of a forward.
294
        HtlcEventType
295

296
        // Timestamp is the time when this htlc was settled.
297
        Timestamp time.Time
298
}
299

300
type FinalHtlcEvent struct {
301
        CircuitKey
302

303
        Settled bool
304

305
        // Offchain is indicating whether the htlc was resolved off-chain.
306
        Offchain bool
307

308
        // Timestamp is the time when this htlc was settled.
309
        Timestamp time.Time
310
}
311

312
// NotifyForwardingEvent notifies the HtlcNotifier than a htlc has been
313
// forwarded.
314
//
315
// Note this is part of the htlcNotifier interface.
316
func (h *HtlcNotifier) NotifyForwardingEvent(key HtlcKey, info HtlcInfo,
317
        eventType HtlcEventType) {
3✔
318

3✔
319
        event := &ForwardingEvent{
3✔
320
                HtlcKey:       key,
3✔
321
                HtlcInfo:      info,
3✔
322
                HtlcEventType: eventType,
3✔
323
                Timestamp:     h.now(),
3✔
324
        }
3✔
325

3✔
326
        log.Tracef("Notifying forward event: %v over %v, %v", eventType, key,
3✔
327
                info)
3✔
328

3✔
329
        if err := h.ntfnServer.SendUpdate(event); err != nil {
3✔
330
                log.Warnf("Unable to send forwarding event: %v", err)
×
331
        }
×
332
}
333

334
// NotifyLinkFailEvent notifies that a htlc has failed on our incoming
335
// or outgoing link.
336
//
337
// Note this is part of the htlcNotifier interface.
338
func (h *HtlcNotifier) NotifyLinkFailEvent(key HtlcKey, info HtlcInfo,
339
        eventType HtlcEventType, linkErr *LinkError, incoming bool) {
3✔
340

3✔
341
        event := &LinkFailEvent{
3✔
342
                HtlcKey:       key,
3✔
343
                HtlcInfo:      info,
3✔
344
                HtlcEventType: eventType,
3✔
345
                LinkError:     linkErr,
3✔
346
                Incoming:      incoming,
3✔
347
                Timestamp:     h.now(),
3✔
348
        }
3✔
349

3✔
350
        log.Tracef("Notifying link failure event: %v over %v, %v", eventType,
3✔
351
                key, info)
3✔
352

3✔
353
        if err := h.ntfnServer.SendUpdate(event); err != nil {
3✔
354
                log.Warnf("Unable to send link fail event: %v", err)
×
355
        }
×
356
}
357

358
// NotifyForwardingFailEvent notifies the HtlcNotifier that a htlc we
359
// forwarded has failed down the line.
360
//
361
// Note this is part of the htlcNotifier interface.
362
func (h *HtlcNotifier) NotifyForwardingFailEvent(key HtlcKey,
363
        eventType HtlcEventType) {
3✔
364

3✔
365
        event := &ForwardingFailEvent{
3✔
366
                HtlcKey:       key,
3✔
367
                HtlcEventType: eventType,
3✔
368
                Timestamp:     h.now(),
3✔
369
        }
3✔
370

3✔
371
        log.Tracef("Notifying forwarding failure event: %v over %v", eventType,
3✔
372
                key)
3✔
373

3✔
374
        if err := h.ntfnServer.SendUpdate(event); err != nil {
3✔
375
                log.Warnf("Unable to send forwarding fail event: %v", err)
×
376
        }
×
377
}
378

379
// NotifySettleEvent notifies the HtlcNotifier that a htlc that we committed
380
// to as part of a forward or a receive to our node has been settled.
381
//
382
// Note this is part of the htlcNotifier interface.
383
func (h *HtlcNotifier) NotifySettleEvent(key HtlcKey,
384
        preimage lntypes.Preimage, eventType HtlcEventType) {
3✔
385

3✔
386
        event := &SettleEvent{
3✔
387
                HtlcKey:       key,
3✔
388
                Preimage:      preimage,
3✔
389
                HtlcEventType: eventType,
3✔
390
                Timestamp:     h.now(),
3✔
391
        }
3✔
392

3✔
393
        log.Tracef("Notifying settle event: %v over %v", eventType, key)
3✔
394

3✔
395
        if err := h.ntfnServer.SendUpdate(event); err != nil {
3✔
396
                log.Warnf("Unable to send settle event: %v", err)
×
397
        }
×
398
}
399

400
// NotifyFinalHtlcEvent notifies the HtlcNotifier that the final outcome for an
401
// htlc has been determined.
402
//
403
// Note this is part of the htlcNotifier interface.
404
func (h *HtlcNotifier) NotifyFinalHtlcEvent(key models.CircuitKey,
405
        info channeldb.FinalHtlcInfo) {
3✔
406

3✔
407
        event := &FinalHtlcEvent{
3✔
408
                CircuitKey: key,
3✔
409
                Settled:    info.Settled,
3✔
410
                Offchain:   info.Offchain,
3✔
411
                Timestamp:  h.now(),
3✔
412
        }
3✔
413

3✔
414
        log.Tracef("Notifying final settle event: %v", key)
3✔
415

3✔
416
        if err := h.ntfnServer.SendUpdate(event); err != nil {
3✔
417
                log.Warnf("Unable to send settle event: %v", err)
×
418
        }
×
419
}
420

421
// newHtlc key returns a htlc key for the packet provided. If the packet
422
// has a zero incoming channel ID, the packet is for one of our own sends,
423
// which has the payment id stashed in the incoming htlc id. If this is the
424
// case, we replace the incoming htlc id with zero so that the notifier
425
// consistently reports zero circuit keys for events that terminate or
426
// originate at our node.
427
func newHtlcKey(pkt *htlcPacket) HtlcKey {
3✔
428
        htlcKey := HtlcKey{
3✔
429
                IncomingCircuit: models.CircuitKey{
3✔
430
                        ChanID: pkt.incomingChanID,
3✔
431
                        HtlcID: pkt.incomingHTLCID,
3✔
432
                },
3✔
433
                OutgoingCircuit: CircuitKey{
3✔
434
                        ChanID: pkt.outgoingChanID,
3✔
435
                        HtlcID: pkt.outgoingHTLCID,
3✔
436
                },
3✔
437
        }
3✔
438

3✔
439
        // If the packet has a zero incoming channel ID, it is a send that was
3✔
440
        // initiated at our node. If this is the case, our internal pid is in
3✔
441
        // the incoming htlc ID, so we overwrite it with 0 for notification
3✔
442
        // purposes.
3✔
443
        if pkt.incomingChanID == hop.Source {
6✔
444
                htlcKey.IncomingCircuit.HtlcID = 0
3✔
445
        }
3✔
446

447
        return htlcKey
3✔
448
}
449

450
// newHtlcInfo returns HtlcInfo for the packet provided.
451
func newHtlcInfo(pkt *htlcPacket) HtlcInfo {
3✔
452
        return HtlcInfo{
3✔
453
                IncomingTimeLock: pkt.incomingTimeout,
3✔
454
                OutgoingTimeLock: pkt.outgoingTimeout,
3✔
455
                IncomingAmt:      pkt.incomingAmount,
3✔
456
                OutgoingAmt:      pkt.amount,
3✔
457
        }
3✔
458
}
3✔
459

460
// getEventType returns the htlc type based on the fields set in the htlc
461
// packet. Sends that originate at our node have the source (zero) incoming
462
// channel ID. Receives to our node have the exit (zero) outgoing channel ID
463
// and forwards have both fields set.
464
func getEventType(pkt *htlcPacket) HtlcEventType {
3✔
465
        switch {
3✔
466
        case pkt.incomingChanID == hop.Source:
3✔
467
                return HtlcEventTypeSend
3✔
468

UNCOV
469
        case pkt.outgoingChanID == hop.Exit:
×
UNCOV
470
                return HtlcEventTypeReceive
×
471

472
        default:
3✔
473
                return HtlcEventTypeForward
3✔
474
        }
475
}
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