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

lightningnetwork / lnd / 12309105782

13 Dec 2024 03:34AM UTC coverage: 57.472% (+8.6%) from 48.92%
12309105782

Pull #9140

github

starius
htlcswitch: fix linter warnings
Pull Request #9140: htlcswitch: use fn.GoroutineManager

54 of 81 new or added lines in 2 files covered. (66.67%)

19134 existing lines in 242 files now uncovered.

101926 of 177349 relevant lines covered (57.47%)

24901.64 hits per line

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

71.09
/htlcswitch/switch.go
1
package htlcswitch
2

3
import (
4
        "bytes"
5
        "context"
6
        "errors"
7
        "fmt"
8
        "math/rand"
9
        "sync"
10
        "sync/atomic"
11
        "time"
12

13
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
14
        "github.com/btcsuite/btcd/btcutil"
15
        "github.com/btcsuite/btcd/wire"
16
        "github.com/davecgh/go-spew/spew"
17
        "github.com/lightningnetwork/lnd/chainntnfs"
18
        "github.com/lightningnetwork/lnd/channeldb"
19
        "github.com/lightningnetwork/lnd/clock"
20
        "github.com/lightningnetwork/lnd/contractcourt"
21
        "github.com/lightningnetwork/lnd/fn/v2"
22
        "github.com/lightningnetwork/lnd/graph/db/models"
23
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
24
        "github.com/lightningnetwork/lnd/kvdb"
25
        "github.com/lightningnetwork/lnd/lntypes"
26
        "github.com/lightningnetwork/lnd/lnutils"
27
        "github.com/lightningnetwork/lnd/lnwallet"
28
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
29
        "github.com/lightningnetwork/lnd/lnwire"
30
        "github.com/lightningnetwork/lnd/ticker"
31
)
32

33
const (
34
        // DefaultFwdEventInterval is the duration between attempts to flush
35
        // pending forwarding events to disk.
36
        DefaultFwdEventInterval = 15 * time.Second
37

38
        // DefaultLogInterval is the duration between attempts to log statistics
39
        // about forwarding events.
40
        DefaultLogInterval = 10 * time.Second
41

42
        // DefaultAckInterval is the duration between attempts to ack any settle
43
        // fails in a forwarding package.
44
        DefaultAckInterval = 15 * time.Second
45

46
        // DefaultMailboxDeliveryTimeout is the duration after which Adds will
47
        // be cancelled if they could not get added to an outgoing commitment.
48
        DefaultMailboxDeliveryTimeout = time.Minute
49
)
50

51
var (
52
        // ErrChannelLinkNotFound is used when channel link hasn't been found.
53
        ErrChannelLinkNotFound = errors.New("channel link not found")
54

55
        // ErrDuplicateAdd signals that the ADD htlc was already forwarded
56
        // through the switch and is locked into another commitment txn.
57
        ErrDuplicateAdd = errors.New("duplicate add HTLC detected")
58

59
        // ErrUnknownErrorDecryptor signals that we were unable to locate the
60
        // error decryptor for this payment. This is likely due to restarting
61
        // the daemon.
62
        ErrUnknownErrorDecryptor = errors.New("unknown error decryptor")
63

64
        // ErrSwitchExiting signaled when the switch has received a shutdown
65
        // request.
66
        ErrSwitchExiting = errors.New("htlcswitch shutting down")
67

68
        // ErrNoLinksFound is an error returned when we attempt to retrieve the
69
        // active links in the switch for a specific destination.
70
        ErrNoLinksFound = errors.New("no channel links found")
71

72
        // ErrUnreadableFailureMessage is returned when the failure message
73
        // cannot be decrypted.
74
        ErrUnreadableFailureMessage = errors.New("unreadable failure message")
75

76
        // ErrLocalAddFailed signals that the ADD htlc for a local payment
77
        // failed to be processed.
78
        ErrLocalAddFailed = errors.New("local add HTLC failed")
79

80
        // errFeeExposureExceeded is only surfaced to callers of SendHTLC and
81
        // signals that sending the HTLC would exceed the outgoing link's fee
82
        // exposure threshold.
83
        errFeeExposureExceeded = errors.New("fee exposure exceeded")
84

85
        // DefaultMaxFeeExposure is the default threshold after which we'll
86
        // fail payments if they increase our fee exposure. This is currently
87
        // set to 500m msats.
88
        DefaultMaxFeeExposure = lnwire.MilliSatoshi(500_000_000)
89

90
        // background is a shortcut for context.Background.
91
        background = context.Background()
92
)
93

94
// plexPacket encapsulates switch packet and adds error channel to receive
95
// error from request handler.
96
type plexPacket struct {
97
        pkt *htlcPacket
98
        err chan error
99
}
100

101
// ChanClose represents a request which close a particular channel specified by
102
// its id.
103
type ChanClose struct {
104
        // CloseType is a variable which signals the type of channel closure the
105
        // peer should execute.
106
        CloseType contractcourt.ChannelCloseType
107

108
        // ChanPoint represent the id of the channel which should be closed.
109
        ChanPoint *wire.OutPoint
110

111
        // TargetFeePerKw is the ideal fee that was specified by the caller.
112
        // This value is only utilized if the closure type is CloseRegular.
113
        // This will be the starting offered fee when the fee negotiation
114
        // process for the cooperative closure transaction kicks off.
115
        TargetFeePerKw chainfee.SatPerKWeight
116

117
        // MaxFee is the highest fee the caller is willing to pay.
118
        //
119
        // NOTE: This field is only respected if the caller is the initiator of
120
        // the channel.
121
        MaxFee chainfee.SatPerKWeight
122

123
        // DeliveryScript is an optional delivery script to pay funds out to.
124
        DeliveryScript lnwire.DeliveryAddress
125

126
        // Updates is used by request creator to receive the notifications about
127
        // execution of the close channel request.
128
        Updates chan interface{}
129

130
        // Err is used by request creator to receive request execution error.
131
        Err chan error
132
}
133

134
// Config defines the configuration for the service. ALL elements within the
135
// configuration MUST be non-nil for the service to carry out its duties.
136
type Config struct {
137
        // FwdingLog is an interface that will be used by the switch to log
138
        // forwarding events. A forwarding event happens each time a payment
139
        // circuit is successfully completed. So when we forward an HTLC, and a
140
        // settle is eventually received.
141
        FwdingLog ForwardingLog
142

143
        // LocalChannelClose kicks-off the workflow to execute a cooperative or
144
        // forced unilateral closure of the channel initiated by a local
145
        // subsystem.
146
        LocalChannelClose func(pubKey []byte, request *ChanClose)
147

148
        // DB is the database backend that will be used to back the switch's
149
        // persistent circuit map.
150
        DB kvdb.Backend
151

152
        // FetchAllOpenChannels is a function that fetches all currently open
153
        // channels from the channel database.
154
        FetchAllOpenChannels func() ([]*channeldb.OpenChannel, error)
155

156
        // FetchAllChannels is a function that fetches all pending open, open,
157
        // and waiting close channels from the database.
158
        FetchAllChannels func() ([]*channeldb.OpenChannel, error)
159

160
        // FetchClosedChannels is a function that fetches all closed channels
161
        // from the channel database.
162
        FetchClosedChannels func(
163
                pendingOnly bool) ([]*channeldb.ChannelCloseSummary, error)
164

165
        // SwitchPackager provides access to the forwarding packages of all
166
        // active channels. This gives the switch the ability to read arbitrary
167
        // forwarding packages, and ack settles and fails contained within them.
168
        SwitchPackager channeldb.FwdOperator
169

170
        // ExtractErrorEncrypter is an interface allowing switch to reextract
171
        // error encrypters stored in the circuit map on restarts, since they
172
        // are not stored directly within the database.
173
        ExtractErrorEncrypter hop.ErrorEncrypterExtracter
174

175
        // FetchLastChannelUpdate retrieves the latest routing policy for a
176
        // target channel. This channel will typically be the outgoing channel
177
        // specified when we receive an incoming HTLC.  This will be used to
178
        // provide payment senders our latest policy when sending encrypted
179
        // error messages.
180
        FetchLastChannelUpdate func(lnwire.ShortChannelID) (
181
                *lnwire.ChannelUpdate1, error)
182

183
        // Notifier is an instance of a chain notifier that we'll use to signal
184
        // the switch when a new block has arrived.
185
        Notifier chainntnfs.ChainNotifier
186

187
        // HtlcNotifier is an instance of a htlcNotifier which we will pipe htlc
188
        // events through.
189
        HtlcNotifier htlcNotifier
190

191
        // FwdEventTicker is a signal that instructs the htlcswitch to flush any
192
        // pending forwarding events.
193
        FwdEventTicker ticker.Ticker
194

195
        // LogEventTicker is a signal instructing the htlcswitch to log
196
        // aggregate stats about it's forwarding during the last interval.
197
        LogEventTicker ticker.Ticker
198

199
        // AckEventTicker is a signal instructing the htlcswitch to ack any settle
200
        // fails in forwarding packages.
201
        AckEventTicker ticker.Ticker
202

203
        // AllowCircularRoute is true if the user has configured their node to
204
        // allow forwards that arrive and depart our node over the same channel.
205
        AllowCircularRoute bool
206

207
        // RejectHTLC is a flag that instructs the htlcswitch to reject any
208
        // HTLCs that are not from the source hop.
209
        RejectHTLC bool
210

211
        // Clock is a time source for the switch.
212
        Clock clock.Clock
213

214
        // MailboxDeliveryTimeout is the interval after which Adds will be
215
        // cancelled if they have not been yet been delivered to a link. The
216
        // computed deadline will expiry this long after the Adds are added to
217
        // a mailbox via AddPacket.
218
        MailboxDeliveryTimeout time.Duration
219

220
        // MaxFeeExposure is the threshold in milli-satoshis after which we'll
221
        // fail incoming or outgoing payments for a particular channel.
222
        MaxFeeExposure lnwire.MilliSatoshi
223

224
        // SignAliasUpdate is used when sending FailureMessages backwards for
225
        // option_scid_alias channels. This avoids a potential privacy leak by
226
        // replacing the public, confirmed SCID with the alias in the
227
        // ChannelUpdate.
228
        SignAliasUpdate func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature,
229
                error)
230

231
        // IsAlias returns whether or not a given SCID is an alias.
232
        IsAlias func(scid lnwire.ShortChannelID) bool
233
}
234

235
// Switch is the central messaging bus for all incoming/outgoing HTLCs.
236
// Connected peers with active channels are treated as named interfaces which
237
// refer to active channels as links. A link is the switch's message
238
// communication point with the goroutine that manages an active channel. New
239
// links are registered each time a channel is created, and unregistered once
240
// the channel is closed. The switch manages the hand-off process for multi-hop
241
// HTLCs, forwarding HTLCs initiated from within the daemon, and finally
242
// notifies users local-systems concerning their outstanding payment requests.
243
type Switch struct {
244
        started  int32 // To be used atomically.
245
        shutdown int32 // To be used atomically.
246

247
        // bestHeight is the best known height of the main chain. The links will
248
        // be used this information to govern decisions based on HTLC timeouts.
249
        // This will be retrieved by the registered links atomically.
250
        bestHeight uint32
251

252
        // gm starts and stops tasks in goroutines and waits for them.
253
        gm *fn.GoroutineManager
254

255
        // cfg is a copy of the configuration struct that the htlc switch
256
        // service was initialized with.
257
        cfg *Config
258

259
        // networkResults stores the results of payments initiated by the user.
260
        // The store is used to later look up the payments and notify the
261
        // user of the result when they are complete. Each payment attempt
262
        // should be given a unique integer ID when it is created, otherwise
263
        // results might be overwritten.
264
        networkResults *networkResultStore
265

266
        // circuits is storage for payment circuits which are used to
267
        // forward the settle/fail htlc updates back to the add htlc initiator.
268
        circuits CircuitMap
269

270
        // mailOrchestrator manages the lifecycle of mailboxes used throughout
271
        // the switch, and facilitates delayed delivery of packets to links that
272
        // later come online.
273
        mailOrchestrator *mailOrchestrator
274

275
        // indexMtx is a read/write mutex that protects the set of indexes
276
        // below.
277
        indexMtx sync.RWMutex
278

279
        // pendingLinkIndex holds links that have not had their final, live
280
        // short_chan_id assigned.
281
        pendingLinkIndex map[lnwire.ChannelID]ChannelLink
282

283
        // links is a map of channel id and channel link which manages
284
        // this channel.
285
        linkIndex map[lnwire.ChannelID]ChannelLink
286

287
        // forwardingIndex is an index which is consulted by the switch when it
288
        // needs to locate the next hop to forward an incoming/outgoing HTLC
289
        // update to/from.
290
        //
291
        // TODO(roasbeef): eventually add a NetworkHop mapping before the
292
        // ChannelLink
293
        forwardingIndex map[lnwire.ShortChannelID]ChannelLink
294

295
        // interfaceIndex maps the compressed public key of a peer to all the
296
        // channels that the switch maintains with that peer.
297
        interfaceIndex map[[33]byte]map[lnwire.ChannelID]ChannelLink
298

299
        // linkStopIndex stores the currently stopping ChannelLinks,
300
        // represented by their ChannelID. The key is the link's ChannelID and
301
        // the value is a chan that is closed when the link has fully stopped.
302
        // This map is only added to if RemoveLink is called and is not added
303
        // to when the Switch is shutting down and calls Stop() on each link.
304
        //
305
        // MUST be used with the indexMtx.
306
        linkStopIndex map[lnwire.ChannelID]chan struct{}
307

308
        // htlcPlex is the channel which all connected links use to coordinate
309
        // the setup/teardown of Sphinx (onion routing) payment circuits.
310
        // Active links forward any add/settle messages over this channel each
311
        // state transition, sending new adds/settles which are fully locked
312
        // in.
313
        htlcPlex chan *plexPacket
314

315
        // chanCloseRequests is used to transfer the channel close request to
316
        // the channel close handler.
317
        chanCloseRequests chan *ChanClose
318

319
        // resolutionMsgs is the channel that all external contract resolution
320
        // messages will be sent over.
321
        resolutionMsgs chan *resolutionMsg
322

323
        // pendingFwdingEvents is the set of forwarding events which have been
324
        // collected during the current interval, but hasn't yet been written
325
        // to the forwarding log.
326
        fwdEventMtx         sync.Mutex
327
        pendingFwdingEvents []channeldb.ForwardingEvent
328

329
        // blockEpochStream is an active block epoch event stream backed by an
330
        // active ChainNotifier instance. This will be used to retrieve the
331
        // latest height of the chain.
332
        blockEpochStream *chainntnfs.BlockEpochEvent
333

334
        // pendingSettleFails is the set of settle/fail entries that we need to
335
        // ack in the forwarding package of the outgoing link. This was added to
336
        // make pipelining settles more efficient.
337
        pendingSettleFails []channeldb.SettleFailRef
338

339
        // resMsgStore is used to store the set of ResolutionMsg that come from
340
        // contractcourt. This is used so the Switch can properly forward them,
341
        // even on restarts.
342
        resMsgStore *resolutionStore
343

344
        // aliasToReal is a map used for option-scid-alias feature-bit links.
345
        // The alias SCID is the key and the real, confirmed SCID is the value.
346
        // If the channel is unconfirmed, there will not be a mapping for it.
347
        // Since channels can have multiple aliases, this map is essentially a
348
        // N->1 mapping for a channel. This MUST be accessed with the indexMtx.
349
        aliasToReal map[lnwire.ShortChannelID]lnwire.ShortChannelID
350

351
        // baseIndex is a map used for option-scid-alias feature-bit links.
352
        // The value is the SCID of the link's ShortChannelID. This value may
353
        // be an alias for zero-conf channels or a confirmed SCID for
354
        // non-zero-conf channels with the option-scid-alias feature-bit. The
355
        // key includes the value itself and also any other aliases. This MUST
356
        // be accessed with the indexMtx.
357
        baseIndex map[lnwire.ShortChannelID]lnwire.ShortChannelID
358
}
359

360
// New creates the new instance of htlc switch.
361
func New(cfg Config, currentHeight uint32) (*Switch, error) {
342✔
362
        resStore := newResolutionStore(cfg.DB)
342✔
363

342✔
364
        circuitMap, err := NewCircuitMap(&CircuitMapConfig{
342✔
365
                DB:                    cfg.DB,
342✔
366
                FetchAllOpenChannels:  cfg.FetchAllOpenChannels,
342✔
367
                FetchClosedChannels:   cfg.FetchClosedChannels,
342✔
368
                ExtractErrorEncrypter: cfg.ExtractErrorEncrypter,
342✔
369
                CheckResolutionMsg:    resStore.checkResolutionMsg,
342✔
370
        })
342✔
371
        if err != nil {
342✔
372
                return nil, err
×
373
        }
×
374

375
        gm := fn.NewGoroutineManager()
342✔
376

342✔
377
        s := &Switch{
342✔
378
                bestHeight:        currentHeight,
342✔
379
                gm:                gm,
342✔
380
                cfg:               &cfg,
342✔
381
                circuits:          circuitMap,
342✔
382
                linkIndex:         make(map[lnwire.ChannelID]ChannelLink),
342✔
383
                forwardingIndex:   make(map[lnwire.ShortChannelID]ChannelLink),
342✔
384
                interfaceIndex:    make(map[[33]byte]map[lnwire.ChannelID]ChannelLink),
342✔
385
                pendingLinkIndex:  make(map[lnwire.ChannelID]ChannelLink),
342✔
386
                linkStopIndex:     make(map[lnwire.ChannelID]chan struct{}),
342✔
387
                networkResults:    newNetworkResultStore(cfg.DB),
342✔
388
                htlcPlex:          make(chan *plexPacket),
342✔
389
                chanCloseRequests: make(chan *ChanClose),
342✔
390
                resolutionMsgs:    make(chan *resolutionMsg),
342✔
391
                resMsgStore:       resStore,
342✔
392
        }
342✔
393

342✔
394
        s.aliasToReal = make(map[lnwire.ShortChannelID]lnwire.ShortChannelID)
342✔
395
        s.baseIndex = make(map[lnwire.ShortChannelID]lnwire.ShortChannelID)
342✔
396

342✔
397
        s.mailOrchestrator = newMailOrchestrator(&mailOrchConfig{
342✔
398
                forwardPackets:    s.ForwardPackets,
342✔
399
                clock:             s.cfg.Clock,
342✔
400
                expiry:            s.cfg.MailboxDeliveryTimeout,
342✔
401
                failMailboxUpdate: s.failMailboxUpdate,
342✔
402
        })
342✔
403

342✔
404
        return s, nil
342✔
405
}
406

407
// resolutionMsg is a struct that wraps an existing ResolutionMsg with a done
408
// channel. We'll use this channel to synchronize delivery of the message with
409
// the caller.
410
type resolutionMsg struct {
411
        contractcourt.ResolutionMsg
412

413
        errChan chan error
414
}
415

416
// ProcessContractResolution is called by active contract resolvers once a
417
// contract they are watching over has been fully resolved. The message carries
418
// an external signal that *would* have been sent if the outgoing channel
419
// didn't need to go to the chain in order to fulfill a contract. We'll process
420
// this message just as if it came from an active outgoing channel.
421
func (s *Switch) ProcessContractResolution(msg contractcourt.ResolutionMsg) error {
1✔
422
        errChan := make(chan error, 1)
1✔
423

1✔
424
        select {
1✔
425
        case s.resolutionMsgs <- &resolutionMsg{
426
                ResolutionMsg: msg,
427
                errChan:       errChan,
428
        }:
1✔
NEW
429
        case <-s.gm.Done():
×
430
                return ErrSwitchExiting
×
431
        }
432

433
        select {
1✔
434
        case err := <-errChan:
1✔
435
                return err
1✔
NEW
436
        case <-s.gm.Done():
×
437
                return ErrSwitchExiting
×
438
        }
439
}
440

441
// HasAttemptResult reads the network result store to fetch the specified
442
// attempt. Returns true if the attempt result exists.
UNCOV
443
func (s *Switch) HasAttemptResult(attemptID uint64) (bool, error) {
×
UNCOV
444
        _, err := s.networkResults.getResult(attemptID)
×
UNCOV
445
        if err == nil {
×
446
                return true, nil
×
447
        }
×
448

UNCOV
449
        if !errors.Is(err, ErrPaymentIDNotFound) {
×
450
                return false, err
×
451
        }
×
452

UNCOV
453
        return false, nil
×
454
}
455

456
// GetAttemptResult returns the result of the HTLC attempt with the given
457
// attemptID. The paymentHash should be set to the payment's overall hash, or
458
// in case of AMP payments the payment's unique identifier.
459
//
460
// The method returns a channel where the HTLC attempt result will be sent when
461
// available, or an error is encountered during forwarding. When a result is
462
// received on the channel, the HTLC is guaranteed to no longer be in flight.
463
// The switch shutting down is signaled by closing the channel. If the
464
// attemptID is unknown, ErrPaymentIDNotFound will be returned.
465
func (s *Switch) GetAttemptResult(attemptID uint64, paymentHash lntypes.Hash,
466
        deobfuscator ErrorDecrypter) (<-chan *PaymentResult, error) {
1,307✔
467

1,307✔
468
        var (
1,307✔
469
                nChan <-chan *networkResult
1,307✔
470
                err   error
1,307✔
471
                inKey = CircuitKey{
1,307✔
472
                        ChanID: hop.Source,
1,307✔
473
                        HtlcID: attemptID,
1,307✔
474
                }
1,307✔
475
        )
1,307✔
476

1,307✔
477
        // If the HTLC is not found in the circuit map, check whether a result
1,307✔
478
        // is already available.
1,307✔
479
        // Assumption: no one will add this attempt ID other than the caller.
1,307✔
480
        if s.circuits.LookupCircuit(inKey) == nil {
1,312✔
481
                res, err := s.networkResults.getResult(attemptID)
5✔
482
                if err != nil {
7✔
483
                        return nil, err
2✔
484
                }
2✔
485
                c := make(chan *networkResult, 1)
3✔
486
                c <- res
3✔
487
                nChan = c
3✔
488
        } else {
1,302✔
489
                // The HTLC was committed to the circuits, subscribe for a
1,302✔
490
                // result.
1,302✔
491
                nChan, err = s.networkResults.subscribeResult(attemptID)
1,302✔
492
                if err != nil {
1,302✔
493
                        return nil, err
×
494
                }
×
495
        }
496

497
        resultChan := make(chan *PaymentResult, 1)
1,305✔
498

1,305✔
499
        // Since the attempt was known, we can start a goroutine that can
1,305✔
500
        // extract the result when it is available, and pass it on to the
1,305✔
501
        // caller.
1,305✔
502
        ok := s.gm.Go(background, func(ctx context.Context) {
2,610✔
503
                var n *networkResult
1,305✔
504
                select {
1,305✔
505
                case n = <-nChan:
301✔
506
                case <-s.gm.Done():
1,004✔
507
                        // We close the result channel to signal a shutdown. We
1,004✔
508
                        // don't send any result in this case since the HTLC is
1,004✔
509
                        // still in flight.
1,004✔
510
                        close(resultChan)
1,004✔
511
                        return
1,004✔
512
                }
513

514
                log.Debugf("Received network result %T for attemptID=%v", n.msg,
301✔
515
                        attemptID)
301✔
516

301✔
517
                // Extract the result and pass it to the result channel.
301✔
518
                result, err := s.extractResult(
301✔
519
                        deobfuscator, n, attemptID, paymentHash,
301✔
520
                )
301✔
521
                if err != nil {
301✔
522
                        e := fmt.Errorf("unable to extract result: %w", err)
×
523
                        log.Error(e)
×
524
                        resultChan <- &PaymentResult{
×
525
                                Error: e,
×
526
                        }
×
527
                        return
×
528
                }
×
529
                resultChan <- result
301✔
530
        })
531
        // The switch shutting down is signaled by closing the channel.
532
        if !ok {
1,305✔
NEW
533
                close(resultChan)
×
NEW
534
        }
×
535

536
        return resultChan, nil
1,305✔
537
}
538

539
// CleanStore calls the underlying result store, telling it is safe to delete
540
// all entries except the ones in the keepPids map. This should be called
541
// preiodically to let the switch clean up payment results that we have
542
// handled.
UNCOV
543
func (s *Switch) CleanStore(keepPids map[uint64]struct{}) error {
×
UNCOV
544
        return s.networkResults.cleanStore(keepPids)
×
UNCOV
545
}
×
546

547
// SendHTLC is used by other subsystems which aren't belong to htlc switch
548
// package in order to send the htlc update. The attemptID used MUST be unique
549
// for this HTLC, and MUST be used only once, otherwise the switch might reject
550
// it.
551
func (s *Switch) SendHTLC(firstHop lnwire.ShortChannelID, attemptID uint64,
552
        htlc *lnwire.UpdateAddHTLC) error {
416✔
553

416✔
554
        // Generate and send new update packet, if error will be received on
416✔
555
        // this stage it means that packet haven't left boundaries of our
416✔
556
        // system and something wrong happened.
416✔
557
        packet := &htlcPacket{
416✔
558
                incomingChanID: hop.Source,
416✔
559
                incomingHTLCID: attemptID,
416✔
560
                outgoingChanID: firstHop,
416✔
561
                htlc:           htlc,
416✔
562
                amount:         htlc.Amount,
416✔
563
        }
416✔
564

416✔
565
        // Attempt to fetch the target link before creating a circuit so that
416✔
566
        // we don't leave dangling circuits. The getLocalLink method does not
416✔
567
        // require the circuit variable to be set on the *htlcPacket.
416✔
568
        link, linkErr := s.getLocalLink(packet, htlc)
416✔
569
        if linkErr != nil {
420✔
570
                // Notify the htlc notifier of a link failure on our outgoing
4✔
571
                // link. Incoming timelock/amount values are not set because
4✔
572
                // they are not present for local sends.
4✔
573
                s.cfg.HtlcNotifier.NotifyLinkFailEvent(
4✔
574
                        newHtlcKey(packet),
4✔
575
                        HtlcInfo{
4✔
576
                                OutgoingTimeLock: htlc.Expiry,
4✔
577
                                OutgoingAmt:      htlc.Amount,
4✔
578
                        },
4✔
579
                        HtlcEventTypeSend,
4✔
580
                        linkErr,
4✔
581
                        false,
4✔
582
                )
4✔
583

4✔
584
                return linkErr
4✔
585
        }
4✔
586

587
        // Evaluate whether this HTLC would bypass our fee exposure. If it
588
        // does, don't send it out and instead return an error.
589
        if s.dustExceedsFeeThreshold(link, htlc.Amount, false) {
413✔
590
                // Notify the htlc notifier of a link failure on our outgoing
1✔
591
                // link. We use the FailTemporaryChannelFailure in place of a
1✔
592
                // more descriptive error message.
1✔
593
                linkErr := NewLinkError(
1✔
594
                        &lnwire.FailTemporaryChannelFailure{},
1✔
595
                )
1✔
596
                s.cfg.HtlcNotifier.NotifyLinkFailEvent(
1✔
597
                        newHtlcKey(packet),
1✔
598
                        HtlcInfo{
1✔
599
                                OutgoingTimeLock: htlc.Expiry,
1✔
600
                                OutgoingAmt:      htlc.Amount,
1✔
601
                        },
1✔
602
                        HtlcEventTypeSend,
1✔
603
                        linkErr,
1✔
604
                        false,
1✔
605
                )
1✔
606

1✔
607
                return errFeeExposureExceeded
1✔
608
        }
1✔
609

610
        circuit := newPaymentCircuit(&htlc.PaymentHash, packet)
411✔
611
        actions, err := s.circuits.CommitCircuits(circuit)
411✔
612
        if err != nil {
411✔
613
                log.Errorf("unable to commit circuit in switch: %v", err)
×
614
                return err
×
615
        }
×
616

617
        // Drop duplicate packet if it has already been seen.
618
        switch {
411✔
619
        case len(actions.Drops) == 1:
1✔
620
                return ErrDuplicateAdd
1✔
621

622
        case len(actions.Fails) == 1:
×
623
                return ErrLocalAddFailed
×
624
        }
625

626
        // Give the packet to the link's mailbox so that HTLC's are properly
627
        // canceled back if the mailbox timeout elapses.
628
        packet.circuit = circuit
410✔
629

410✔
630
        return link.handleSwitchPacket(packet)
410✔
631
}
632

633
// UpdateForwardingPolicies sends a message to the switch to update the
634
// forwarding policies for the set of target channels, keyed in chanPolicies.
635
//
636
// NOTE: This function is synchronous and will block until either the
637
// forwarding policies for all links have been updated, or the switch shuts
638
// down.
639
func (s *Switch) UpdateForwardingPolicies(
UNCOV
640
        chanPolicies map[wire.OutPoint]models.ForwardingPolicy) {
×
UNCOV
641

×
UNCOV
642
        log.Tracef("Updating link policies: %v", lnutils.SpewLogClosure(
×
UNCOV
643
                chanPolicies))
×
UNCOV
644

×
UNCOV
645
        s.indexMtx.RLock()
×
UNCOV
646

×
UNCOV
647
        // Update each link in chanPolicies.
×
UNCOV
648
        for targetLink, policy := range chanPolicies {
×
UNCOV
649
                cid := lnwire.NewChanIDFromOutPoint(targetLink)
×
UNCOV
650

×
UNCOV
651
                link, ok := s.linkIndex[cid]
×
UNCOV
652
                if !ok {
×
653
                        log.Debugf("Unable to find ChannelPoint(%v) to update "+
×
654
                                "link policy", targetLink)
×
655
                        continue
×
656
                }
657

UNCOV
658
                link.UpdateForwardingPolicy(policy)
×
659
        }
660

UNCOV
661
        s.indexMtx.RUnlock()
×
662
}
663

664
// IsForwardedHTLC checks for a given channel and htlc index if it is related
665
// to an opened circuit that represents a forwarded payment.
666
func (s *Switch) IsForwardedHTLC(chanID lnwire.ShortChannelID,
667
        htlcIndex uint64) bool {
2✔
668

2✔
669
        circuit := s.circuits.LookupOpenCircuit(models.CircuitKey{
2✔
670
                ChanID: chanID,
2✔
671
                HtlcID: htlcIndex,
2✔
672
        })
2✔
673
        return circuit != nil && circuit.Incoming.ChanID != hop.Source
2✔
674
}
2✔
675

676
// ForwardPackets adds a list of packets to the switch for processing. Fails
677
// and settles are added on a first past, simultaneously constructing circuits
678
// for any adds. After persisting the circuits, another pass of the adds is
679
// given to forward them through the router. The sending link's quit channel is
680
// used to prevent deadlocks when the switch stops a link in the midst of
681
// forwarding.
682
func (s *Switch) ForwardPackets(linkQuit <-chan struct{},
683
        packets ...*htlcPacket) error {
870✔
684

870✔
685
        var (
870✔
686
                // fwdChan is a buffered channel used to receive err msgs from
870✔
687
                // the htlcPlex when forwarding this batch.
870✔
688
                fwdChan = make(chan error, len(packets))
870✔
689

870✔
690
                // numSent keeps a running count of how many packets are
870✔
691
                // forwarded to the switch, which determines how many responses
870✔
692
                // we will wait for on the fwdChan..
870✔
693
                numSent int
870✔
694
        )
870✔
695

870✔
696
        // No packets, nothing to do.
870✔
697
        if len(packets) == 0 {
1,091✔
698
                return nil
221✔
699
        }
221✔
700

701
        // Setup a barrier to prevent the background tasks from processing
702
        // responses until this function returns to the user.
703
        var wg sync.WaitGroup
649✔
704
        wg.Add(1)
649✔
705
        defer wg.Done()
649✔
706

649✔
707
        // Before spawning the following goroutine to proxy our error responses,
649✔
708
        // check to see if we have already been issued a shutdown request. If
649✔
709
        // so, we exit early to avoid incrementing the switch's waitgroup while
649✔
710
        // it is already in the process of shutting down.
649✔
711
        select {
649✔
712
        case <-linkQuit:
×
713
                return nil
×
714

715
        case <-s.gm.Done():
1✔
716
                return nil
1✔
717

718
        default:
648✔
719
                // Spawn a goroutine to log the errors returned from failed
648✔
720
                // packets.
648✔
721
                ok := s.gm.Go(background, func(ctx context.Context) {
1,296✔
722
                        s.logFwdErrs(ctx, &numSent, &wg, fwdChan)
648✔
723
                })
648✔
724
                if !ok {
648✔
NEW
725
                        return nil
×
NEW
726
                }
×
727
        }
728

729
        // Make a first pass over the packets, forwarding any settles or fails.
730
        // As adds are found, we create a circuit and append it to our set of
731
        // circuits to be written to disk.
732
        var circuits []*PaymentCircuit
648✔
733
        var addBatch []*htlcPacket
648✔
734
        for _, packet := range packets {
1,296✔
735
                switch htlc := packet.htlc.(type) {
648✔
736
                case *lnwire.UpdateAddHTLC:
87✔
737
                        circuit := newPaymentCircuit(&htlc.PaymentHash, packet)
87✔
738
                        packet.circuit = circuit
87✔
739
                        circuits = append(circuits, circuit)
87✔
740
                        addBatch = append(addBatch, packet)
87✔
741
                default:
561✔
742
                        err := s.routeAsync(packet, fwdChan, linkQuit)
561✔
743
                        if err != nil {
571✔
744
                                return fmt.Errorf("failed to forward packet %w",
10✔
745
                                        err)
10✔
746
                        }
10✔
747
                        numSent++
536✔
748
                }
749
        }
750

751
        // If this batch did not contain any circuits to commit, we can return
752
        // early.
753
        if len(circuits) == 0 {
1,159✔
754
                return nil
536✔
755
        }
536✔
756

757
        // Write any circuits that we found to disk.
758
        actions, err := s.circuits.CommitCircuits(circuits...)
87✔
759
        if err != nil {
87✔
760
                log.Errorf("unable to commit circuits in switch: %v", err)
×
761
        }
×
762

763
        // Split the htlc packets by comparing an in-order seek to the head of
764
        // the added, dropped, or failed circuits.
765
        //
766
        // NOTE: This assumes each list is guaranteed to be a subsequence of the
767
        // circuits, and that the union of the sets results in the original set
768
        // of circuits.
769
        var addedPackets, failedPackets []*htlcPacket
87✔
770
        for _, packet := range addBatch {
174✔
771
                switch {
87✔
772
                case len(actions.Adds) > 0 && packet.circuit == actions.Adds[0]:
83✔
773
                        addedPackets = append(addedPackets, packet)
83✔
774
                        actions.Adds = actions.Adds[1:]
83✔
775

776
                case len(actions.Drops) > 0 && packet.circuit == actions.Drops[0]:
1✔
777
                        actions.Drops = actions.Drops[1:]
1✔
778

779
                case len(actions.Fails) > 0 && packet.circuit == actions.Fails[0]:
3✔
780
                        failedPackets = append(failedPackets, packet)
3✔
781
                        actions.Fails = actions.Fails[1:]
3✔
782
                }
783
        }
784

785
        // Now, forward any packets for circuits that were successfully added to
786
        // the switch's circuit map.
787
        for _, packet := range addedPackets {
170✔
788
                err := s.routeAsync(packet, fwdChan, linkQuit)
83✔
789
                if err != nil {
84✔
790
                        return fmt.Errorf("failed to forward packet %w", err)
1✔
791
                }
1✔
792
                numSent++
82✔
793
        }
794

795
        // Lastly, for any packets that failed, this implies that they were
796
        // left in a half added state, which can happen when recovering from
797
        // failures.
798
        if len(failedPackets) > 0 {
89✔
799
                var failure lnwire.FailureMessage
3✔
800
                incomingID := failedPackets[0].incomingChanID
3✔
801

3✔
802
                // If the incoming channel is an option_scid_alias channel,
3✔
803
                // then we'll need to replace the SCID in the ChannelUpdate.
3✔
804
                update := s.failAliasUpdate(incomingID, true)
3✔
805
                if update == nil {
4✔
806
                        // Fallback to the original non-option behavior.
1✔
807
                        update, err := s.cfg.FetchLastChannelUpdate(
1✔
808
                                incomingID,
1✔
809
                        )
1✔
810
                        if err != nil {
1✔
811
                                failure = &lnwire.FailTemporaryNodeFailure{}
×
812
                        } else {
1✔
813
                                failure = lnwire.NewTemporaryChannelFailure(
1✔
814
                                        update,
1✔
815
                                )
1✔
816
                        }
1✔
817
                } else {
2✔
818
                        // This is an option_scid_alias channel.
2✔
819
                        failure = lnwire.NewTemporaryChannelFailure(update)
2✔
820
                }
2✔
821

822
                linkError := NewDetailedLinkError(
3✔
823
                        failure, OutgoingFailureIncompleteForward,
3✔
824
                )
3✔
825

3✔
826
                for _, packet := range failedPackets {
6✔
827
                        // We don't handle the error here since this method
3✔
828
                        // always returns an error.
3✔
829
                        _ = s.failAddPacket(packet, linkError)
3✔
830
                }
3✔
831
        }
832

833
        return nil
86✔
834
}
835

836
// logFwdErrs logs any errors received on `fwdChan`.
837
func (s *Switch) logFwdErrs(ctx context.Context, num *int, wg *sync.WaitGroup,
838
        fwdChan chan error) {
648✔
839

648✔
840
        // Wait here until the outer function has finished persisting
648✔
841
        // and routing the packets. This guarantees we don't read from num until
648✔
842
        // the value is accurate.
648✔
843
        wg.Wait()
648✔
844

648✔
845
        numSent := *num
648✔
846
        for i := 0; i < numSent; i++ {
1,266✔
847
                select {
618✔
848
                case err := <-fwdChan:
617✔
849
                        if err != nil {
640✔
850
                                log.Errorf("Unhandled error while reforwarding htlc "+
23✔
851
                                        "settle/fail over htlcswitch: %v", err)
23✔
852
                        }
23✔
853

854
                case <-s.gm.Done():
1✔
855
                        log.Errorf("unable to forward htlc packet " +
1✔
856
                                "htlc switch was stopped")
1✔
857
                        return
1✔
858
                }
859
        }
860
}
861

862
// routeAsync sends a packet through the htlc switch, using the provided err
863
// chan to propagate errors back to the caller. The link's quit channel is
864
// provided so that the send can be canceled if either the link or the switch
865
// receive a shutdown requuest. This method does not wait for a response from
866
// the htlcForwarder before returning.
867
func (s *Switch) routeAsync(packet *htlcPacket, errChan chan error,
868
        linkQuit <-chan struct{}) error {
644✔
869

644✔
870
        command := &plexPacket{
644✔
871
                pkt: packet,
644✔
872
                err: errChan,
644✔
873
        }
644✔
874

644✔
875
        select {
644✔
876
        case s.htlcPlex <- command:
618✔
877
                return nil
618✔
878
        case <-linkQuit:
11✔
879
                return ErrLinkShuttingDown
11✔
NEW
880
        case <-s.gm.Done():
×
881
                return errors.New("htlc switch was stopped")
×
882
        }
883
}
884

885
// getLocalLink handles the addition of a htlc for a send that originates from
886
// our node. It returns the link that the htlc should be forwarded outwards on,
887
// and a link error if the htlc cannot be forwarded.
888
func (s *Switch) getLocalLink(pkt *htlcPacket, htlc *lnwire.UpdateAddHTLC) (
889
        ChannelLink, *LinkError) {
416✔
890

416✔
891
        // Try to find links by node destination.
416✔
892
        s.indexMtx.RLock()
416✔
893
        link, err := s.getLinkByShortID(pkt.outgoingChanID)
416✔
894
        defer s.indexMtx.RUnlock()
416✔
895
        if err != nil {
417✔
896
                // If the link was not found for the outgoingChanID, an outside
1✔
897
                // subsystem may be using the confirmed SCID of a zero-conf
1✔
898
                // channel. In this case, we'll consult the Switch maps to see
1✔
899
                // if an alias exists and use the alias to lookup the link.
1✔
900
                // This extra step is a consequence of not updating the Switch
1✔
901
                // forwardingIndex when a zero-conf channel is confirmed. We
1✔
902
                // don't need to change the outgoingChanID since the link will
1✔
903
                // do that upon receiving the packet.
1✔
904
                baseScid, ok := s.baseIndex[pkt.outgoingChanID]
1✔
905
                if !ok {
1✔
UNCOV
906
                        log.Errorf("Link %v not found", pkt.outgoingChanID)
×
UNCOV
907
                        return nil, NewLinkError(&lnwire.FailUnknownNextPeer{})
×
UNCOV
908
                }
×
909

910
                // The base SCID was found, so we'll use that to fetch the
911
                // link.
912
                link, err = s.getLinkByShortID(baseScid)
1✔
913
                if err != nil {
1✔
914
                        log.Errorf("Link %v not found", baseScid)
×
915
                        return nil, NewLinkError(&lnwire.FailUnknownNextPeer{})
×
916
                }
×
917
        }
918

919
        if !link.EligibleToForward() {
417✔
920
                log.Errorf("Link %v is not available to forward",
1✔
921
                        pkt.outgoingChanID)
1✔
922

1✔
923
                // The update does not need to be populated as the error
1✔
924
                // will be returned back to the router.
1✔
925
                return nil, NewDetailedLinkError(
1✔
926
                        lnwire.NewTemporaryChannelFailure(nil),
1✔
927
                        OutgoingFailureLinkNotEligible,
1✔
928
                )
1✔
929
        }
1✔
930

931
        // Ensure that the htlc satisfies the outgoing channel policy.
932
        currentHeight := atomic.LoadUint32(&s.bestHeight)
415✔
933
        htlcErr := link.CheckHtlcTransit(
415✔
934
                htlc.PaymentHash, htlc.Amount, htlc.Expiry, currentHeight,
415✔
935
                htlc.CustomRecords,
415✔
936
        )
415✔
937
        if htlcErr != nil {
418✔
938
                log.Errorf("Link %v policy for local forward not "+
3✔
939
                        "satisfied", pkt.outgoingChanID)
3✔
940
                return nil, htlcErr
3✔
941
        }
3✔
942
        return link, nil
412✔
943
}
944

945
// handleLocalResponse processes a Settle or Fail responding to a
946
// locally-initiated payment. This is handled asynchronously to avoid blocking
947
// the main event loop within the switch, as these operations can require
948
// multiple db transactions. The guarantees of the circuit map are stringent
949
// enough such that we are able to tolerate reordering of these operations
950
// without side effects. The primary operations handled are:
951
//  1. Save the payment result to the pending payment store.
952
//  2. Notify subscribers about the payment result.
953
//  3. Ack settle/fail references, to avoid resending this response internally
954
//  4. Teardown the closing circuit in the circuit map
955
//
956
// NOTE: This method MUST be spawned as a goroutine.
957
func (s *Switch) handleLocalResponse(pkt *htlcPacket) {
304✔
958
        attemptID := pkt.incomingHTLCID
304✔
959

304✔
960
        // The error reason will be unencypted in case this a local
304✔
961
        // failure or a converted error.
304✔
962
        unencrypted := pkt.localFailure || pkt.convertedError
304✔
963
        n := &networkResult{
304✔
964
                msg:          pkt.htlc,
304✔
965
                unencrypted:  unencrypted,
304✔
966
                isResolution: pkt.isResolution,
304✔
967
        }
304✔
968

304✔
969
        // Store the result to the db. This will also notify subscribers about
304✔
970
        // the result.
304✔
971
        if err := s.networkResults.storeResult(attemptID, n); err != nil {
304✔
972
                log.Errorf("Unable to store attempt result for pid=%v: %v",
×
973
                        attemptID, err)
×
974
                return
×
975
        }
×
976

977
        // First, we'll clean up any fwdpkg references, circuit entries, and
978
        // mark in our db that the payment for this payment hash has either
979
        // succeeded or failed.
980
        //
981
        // If this response is contained in a forwarding package, we'll start by
982
        // acking the settle/fail so that we don't continue to retransmit the
983
        // HTLC internally.
984
        if pkt.destRef != nil {
422✔
985
                if err := s.ackSettleFail(*pkt.destRef); err != nil {
118✔
986
                        log.Warnf("Unable to ack settle/fail reference: %s: %v",
×
987
                                *pkt.destRef, err)
×
988
                        return
×
989
                }
×
990
        }
991

992
        // Next, we'll remove the circuit since we are about to complete an
993
        // fulfill/fail of this HTLC. Since we've already removed the
994
        // settle/fail fwdpkg reference, the response from the peer cannot be
995
        // replayed internally if this step fails. If this happens, this logic
996
        // will be executed when a provided resolution message comes through.
997
        // This can only happen if the circuit is still open, which is why this
998
        // ordering is chosen.
999
        if err := s.teardownCircuit(pkt); err != nil {
304✔
1000
                log.Errorf("Unable to teardown circuit %s: %v",
×
1001
                        pkt.inKey(), err)
×
1002
                return
×
1003
        }
×
1004

1005
        // Finally, notify on the htlc failure or success that has been handled.
1006
        key := newHtlcKey(pkt)
304✔
1007
        eventType := getEventType(pkt)
304✔
1008

304✔
1009
        switch htlc := pkt.htlc.(type) {
304✔
1010
        case *lnwire.UpdateFulfillHTLC:
180✔
1011
                s.cfg.HtlcNotifier.NotifySettleEvent(key, htlc.PaymentPreimage,
180✔
1012
                        eventType)
180✔
1013

1014
        case *lnwire.UpdateFailHTLC:
124✔
1015
                s.cfg.HtlcNotifier.NotifyForwardingFailEvent(key, eventType)
124✔
1016
        }
1017
}
1018

1019
// extractResult uses the given deobfuscator to extract the payment result from
1020
// the given network message.
1021
func (s *Switch) extractResult(deobfuscator ErrorDecrypter, n *networkResult,
1022
        attemptID uint64, paymentHash lntypes.Hash) (*PaymentResult, error) {
301✔
1023

301✔
1024
        switch htlc := n.msg.(type) {
301✔
1025

1026
        // We've received a settle update which means we can finalize the user
1027
        // payment and return successful response.
1028
        case *lnwire.UpdateFulfillHTLC:
177✔
1029
                return &PaymentResult{
177✔
1030
                        Preimage: htlc.PaymentPreimage,
177✔
1031
                }, nil
177✔
1032

1033
        // We've received a fail update which means we can finalize the
1034
        // user payment and return fail response.
1035
        case *lnwire.UpdateFailHTLC:
124✔
1036
                // TODO(yy): construct deobfuscator here to avoid creating it
124✔
1037
                // in paymentLifecycle even for settled HTLCs.
124✔
1038
                paymentErr := s.parseFailedPayment(
124✔
1039
                        deobfuscator, attemptID, paymentHash, n.unencrypted,
124✔
1040
                        n.isResolution, htlc,
124✔
1041
                )
124✔
1042

124✔
1043
                return &PaymentResult{
124✔
1044
                        Error: paymentErr,
124✔
1045
                }, nil
124✔
1046

1047
        default:
×
1048
                return nil, fmt.Errorf("received unknown response type: %T",
×
1049
                        htlc)
×
1050
        }
1051
}
1052

1053
// parseFailedPayment determines the appropriate failure message to return to
1054
// a user initiated payment. The three cases handled are:
1055
//  1. An unencrypted failure, which should already plaintext.
1056
//  2. A resolution from the chain arbitrator, which possibly has no failure
1057
//     reason attached.
1058
//  3. A failure from the remote party, which will need to be decrypted using
1059
//     the payment deobfuscator.
1060
func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
1061
        attemptID uint64, paymentHash lntypes.Hash, unencrypted,
1062
        isResolution bool, htlc *lnwire.UpdateFailHTLC) error {
124✔
1063

124✔
1064
        switch {
124✔
1065

1066
        // The payment never cleared the link, so we don't need to
1067
        // decrypt the error, simply decode it them report back to the
1068
        // user.
1069
        case unencrypted:
5✔
1070
                r := bytes.NewReader(htlc.Reason)
5✔
1071
                failureMsg, err := lnwire.DecodeFailure(r, 0)
5✔
1072
                if err != nil {
5✔
1073
                        // If we could not decode the failure reason, return a link
×
1074
                        // error indicating that we failed to decode the onion.
×
1075
                        linkError := NewDetailedLinkError(
×
1076
                                // As this didn't even clear the link, we don't
×
1077
                                // need to apply an update here since it goes
×
1078
                                // directly to the router.
×
1079
                                lnwire.NewTemporaryChannelFailure(nil),
×
1080
                                OutgoingFailureDecodeError,
×
1081
                        )
×
1082

×
1083
                        log.Errorf("%v: (hash=%v, pid=%d): %v",
×
1084
                                linkError.FailureDetail.FailureString(),
×
1085
                                paymentHash, attemptID, err)
×
1086

×
1087
                        return linkError
×
1088
                }
×
1089

1090
                // If we successfully decoded the failure reason, return it.
1091
                return NewLinkError(failureMsg)
5✔
1092

1093
        // A payment had to be timed out on chain before it got past
1094
        // the first hop. In this case, we'll report a permanent
1095
        // channel failure as this means us, or the remote party had to
1096
        // go on chain.
UNCOV
1097
        case isResolution && htlc.Reason == nil:
×
UNCOV
1098
                linkError := NewDetailedLinkError(
×
UNCOV
1099
                        &lnwire.FailPermanentChannelFailure{},
×
UNCOV
1100
                        OutgoingFailureOnChainTimeout,
×
UNCOV
1101
                )
×
UNCOV
1102

×
UNCOV
1103
                log.Infof("%v: hash=%v, pid=%d",
×
UNCOV
1104
                        linkError.FailureDetail.FailureString(),
×
UNCOV
1105
                        paymentHash, attemptID)
×
UNCOV
1106

×
UNCOV
1107
                return linkError
×
1108

1109
        // A regular multi-hop payment error that we'll need to
1110
        // decrypt.
1111
        default:
119✔
1112
                // We'll attempt to fully decrypt the onion encrypted
119✔
1113
                // error. If we're unable to then we'll bail early.
119✔
1114
                failure, err := deobfuscator.DecryptError(htlc.Reason)
119✔
1115
                if err != nil {
120✔
1116
                        log.Errorf("unable to de-obfuscate onion failure "+
1✔
1117
                                "(hash=%v, pid=%d): %v",
1✔
1118
                                paymentHash, attemptID, err)
1✔
1119

1✔
1120
                        return ErrUnreadableFailureMessage
1✔
1121
                }
1✔
1122

1123
                return failure
118✔
1124
        }
1125
}
1126

1127
// handlePacketForward is used in cases when we need forward the htlc update
1128
// from one channel link to another and be able to propagate the settle/fail
1129
// updates back. This behaviour is achieved by creation of payment circuits.
1130
func (s *Switch) handlePacketForward(packet *htlcPacket) error {
619✔
1131
        switch htlc := packet.htlc.(type) {
619✔
1132
        // Channel link forwarded us a new htlc, therefore we initiate the
1133
        // payment circuit within our internal state so we can properly forward
1134
        // the ultimate settle message back latter.
1135
        case *lnwire.UpdateAddHTLC:
82✔
1136
                return s.handlePacketAdd(packet, htlc)
82✔
1137

1138
        case *lnwire.UpdateFulfillHTLC:
399✔
1139
                return s.handlePacketSettle(packet)
399✔
1140

1141
        // Channel link forwarded us an update_fail_htlc message.
1142
        //
1143
        // NOTE: when the channel link receives an update_fail_malformed_htlc
1144
        // from upstream, it will convert the message into update_fail_htlc and
1145
        // forward it. Thus there's no need to catch `UpdateFailMalformedHTLC`
1146
        // here.
1147
        case *lnwire.UpdateFailHTLC:
138✔
1148
                return s.handlePacketFail(packet, htlc)
138✔
1149

1150
        default:
×
1151
                return fmt.Errorf("wrong update type: %T", htlc)
×
1152
        }
1153
}
1154

1155
// checkCircularForward checks whether a forward is circular (arrives and
1156
// departs on the same link) and returns a link error if the switch is
1157
// configured to disallow this behaviour.
1158
func (s *Switch) checkCircularForward(incoming, outgoing lnwire.ShortChannelID,
1159
        allowCircular bool, paymentHash lntypes.Hash) *LinkError {
90✔
1160

90✔
1161
        // If they are equal, we can skip the alias mapping checks.
90✔
1162
        if incoming == outgoing {
94✔
1163
                // The switch may be configured to allow circular routes, so
4✔
1164
                // just log and return nil.
4✔
1165
                if allowCircular {
6✔
1166
                        log.Debugf("allowing circular route over link: %v "+
2✔
1167
                                "(payment hash: %x)", incoming, paymentHash)
2✔
1168
                        return nil
2✔
1169
                }
2✔
1170

1171
                // Otherwise, we'll return a temporary channel failure.
1172
                return NewDetailedLinkError(
2✔
1173
                        lnwire.NewTemporaryChannelFailure(nil),
2✔
1174
                        OutgoingFailureCircularRoute,
2✔
1175
                )
2✔
1176
        }
1177

1178
        // We'll fetch the "base" SCID from the baseIndex for the incoming and
1179
        // outgoing SCIDs. If either one does not have a base SCID, then the
1180
        // two channels are not equal since one will be a channel that does not
1181
        // need a mapping and SCID equality was checked above. If the "base"
1182
        // SCIDs are equal, then this is a circular route. Otherwise, it isn't.
1183
        s.indexMtx.RLock()
86✔
1184
        incomingBaseScid, ok := s.baseIndex[incoming]
86✔
1185
        if !ok {
166✔
1186
                // This channel does not use baseIndex, bail out.
80✔
1187
                s.indexMtx.RUnlock()
80✔
1188
                return nil
80✔
1189
        }
80✔
1190

1191
        outgoingBaseScid, ok := s.baseIndex[outgoing]
6✔
1192
        if !ok {
8✔
1193
                // This channel does not use baseIndex, bail out.
2✔
1194
                s.indexMtx.RUnlock()
2✔
1195
                return nil
2✔
1196
        }
2✔
1197
        s.indexMtx.RUnlock()
4✔
1198

4✔
1199
        // Check base SCID equality.
4✔
1200
        if incomingBaseScid != outgoingBaseScid {
4✔
UNCOV
1201
                // The base SCIDs are not equal so these are not the same
×
UNCOV
1202
                // channel.
×
UNCOV
1203
                return nil
×
UNCOV
1204
        }
×
1205

1206
        // If the incoming and outgoing link are equal, the htlc is part of a
1207
        // circular route which may be used to lock up our liquidity. If the
1208
        // switch is configured to allow circular routes, log that we are
1209
        // allowing the route then return nil.
1210
        if allowCircular {
6✔
1211
                log.Debugf("allowing circular route over link: %v "+
2✔
1212
                        "(payment hash: %x)", incoming, paymentHash)
2✔
1213
                return nil
2✔
1214
        }
2✔
1215

1216
        // If our node disallows circular routes, return a temporary channel
1217
        // failure. There is nothing wrong with the policy used by the remote
1218
        // node, so we do not include a channel update.
1219
        return NewDetailedLinkError(
2✔
1220
                lnwire.NewTemporaryChannelFailure(nil),
2✔
1221
                OutgoingFailureCircularRoute,
2✔
1222
        )
2✔
1223
}
1224

1225
// failAddPacket encrypts a fail packet back to an add packet's source.
1226
// The ciphertext will be derived from the failure message proivded by context.
1227
// This method returns the failErr if all other steps complete successfully.
1228
func (s *Switch) failAddPacket(packet *htlcPacket, failure *LinkError) error {
26✔
1229
        // Encrypt the failure so that the sender will be able to read the error
26✔
1230
        // message. Since we failed this packet, we use EncryptFirstHop to
26✔
1231
        // obfuscate the failure for their eyes only.
26✔
1232
        reason, err := packet.obfuscator.EncryptFirstHop(failure.WireMessage())
26✔
1233
        if err != nil {
26✔
1234
                err := fmt.Errorf("unable to obfuscate "+
×
1235
                        "error: %v", err)
×
1236
                log.Error(err)
×
1237
                return err
×
1238
        }
×
1239

1240
        log.Error(failure.Error())
26✔
1241

26✔
1242
        // Create a failure packet for this htlc. The full set of
26✔
1243
        // information about the htlc failure is included so that they can
26✔
1244
        // be included in link failure notifications.
26✔
1245
        failPkt := &htlcPacket{
26✔
1246
                sourceRef:       packet.sourceRef,
26✔
1247
                incomingChanID:  packet.incomingChanID,
26✔
1248
                incomingHTLCID:  packet.incomingHTLCID,
26✔
1249
                outgoingChanID:  packet.outgoingChanID,
26✔
1250
                outgoingHTLCID:  packet.outgoingHTLCID,
26✔
1251
                incomingAmount:  packet.incomingAmount,
26✔
1252
                amount:          packet.amount,
26✔
1253
                incomingTimeout: packet.incomingTimeout,
26✔
1254
                outgoingTimeout: packet.outgoingTimeout,
26✔
1255
                circuit:         packet.circuit,
26✔
1256
                obfuscator:      packet.obfuscator,
26✔
1257
                linkFailure:     failure,
26✔
1258
                htlc: &lnwire.UpdateFailHTLC{
26✔
1259
                        Reason: reason,
26✔
1260
                },
26✔
1261
        }
26✔
1262

26✔
1263
        // Route a fail packet back to the source link.
26✔
1264
        err = s.mailOrchestrator.Deliver(failPkt.incomingChanID, failPkt)
26✔
1265
        if err != nil {
26✔
1266
                err = fmt.Errorf("source chanid=%v unable to "+
×
1267
                        "handle switch packet: %v",
×
1268
                        packet.incomingChanID, err)
×
1269
                log.Error(err)
×
1270
                return err
×
1271
        }
×
1272

1273
        return failure
26✔
1274
}
1275

1276
// closeCircuit accepts a settle or fail htlc and the associated htlc packet and
1277
// attempts to determine the source that forwarded this htlc. This method will
1278
// set the incoming chan and htlc ID of the given packet if the source was
1279
// found, and will properly [re]encrypt any failure messages.
1280
func (s *Switch) closeCircuit(pkt *htlcPacket) (*PaymentCircuit, error) {
537✔
1281
        // If the packet has its source, that means it was failed locally by
537✔
1282
        // the outgoing link. We fail it here to make sure only one response
537✔
1283
        // makes it through the switch.
537✔
1284
        if pkt.hasSource {
548✔
1285
                circuit, err := s.circuits.FailCircuit(pkt.inKey())
11✔
1286
                switch err {
11✔
1287

1288
                // Circuit successfully closed.
1289
                case nil:
11✔
1290
                        return circuit, nil
11✔
1291

1292
                // Circuit was previously closed, but has not been deleted.
1293
                // We'll just drop this response until the circuit has been
1294
                // fully removed.
1295
                case ErrCircuitClosing:
×
1296
                        return nil, err
×
1297

1298
                // Failed to close circuit because it does not exist. This is
1299
                // likely because the circuit was already successfully closed.
1300
                // Since this packet failed locally, there is no forwarding
1301
                // package entry to acknowledge.
1302
                case ErrUnknownCircuit:
×
1303
                        return nil, err
×
1304

1305
                // Unexpected error.
1306
                default:
×
1307
                        return nil, err
×
1308
                }
1309
        }
1310

1311
        // Otherwise, this is packet was received from the remote party.  Use
1312
        // circuit map to find the incoming link to receive the settle/fail.
1313
        circuit, err := s.circuits.CloseCircuit(pkt.outKey())
526✔
1314
        switch err {
526✔
1315

1316
        // Open circuit successfully closed.
1317
        case nil:
336✔
1318
                pkt.incomingChanID = circuit.Incoming.ChanID
336✔
1319
                pkt.incomingHTLCID = circuit.Incoming.HtlcID
336✔
1320
                pkt.circuit = circuit
336✔
1321
                pkt.sourceRef = &circuit.AddRef
336✔
1322

336✔
1323
                pktType := "SETTLE"
336✔
1324
                if _, ok := pkt.htlc.(*lnwire.UpdateFailHTLC); ok {
463✔
1325
                        pktType = "FAIL"
127✔
1326
                }
127✔
1327

1328
                log.Debugf("Closed completed %s circuit for %x: "+
336✔
1329
                        "(%s, %d) <-> (%s, %d)", pktType, pkt.circuit.PaymentHash,
336✔
1330
                        pkt.incomingChanID, pkt.incomingHTLCID,
336✔
1331
                        pkt.outgoingChanID, pkt.outgoingHTLCID)
336✔
1332

336✔
1333
                return circuit, nil
336✔
1334

1335
        // Circuit was previously closed, but has not been deleted. We'll just
1336
        // drop this response until the circuit has been removed.
UNCOV
1337
        case ErrCircuitClosing:
×
UNCOV
1338
                return nil, err
×
1339

1340
        // Failed to close circuit because it does not exist. This is likely
1341
        // because the circuit was already successfully closed.
1342
        case ErrUnknownCircuit:
190✔
1343
                if pkt.destRef != nil {
379✔
1344
                        // Add this SettleFailRef to the set of pending settle/fail entries
189✔
1345
                        // awaiting acknowledgement.
189✔
1346
                        s.pendingSettleFails = append(s.pendingSettleFails, *pkt.destRef)
189✔
1347
                }
189✔
1348

1349
                // If this is a settle, we will not log an error message as settles
1350
                // are expected to hit the ErrUnknownCircuit case. The only way fails
1351
                // can hit this case if the link restarts after having just sent a fail
1352
                // to the switch.
1353
                _, isSettle := pkt.htlc.(*lnwire.UpdateFulfillHTLC)
190✔
1354
                if !isSettle {
190✔
UNCOV
1355
                        err := fmt.Errorf("unable to find target channel "+
×
UNCOV
1356
                                "for HTLC fail: channel ID = %s, "+
×
UNCOV
1357
                                "HTLC ID = %d", pkt.outgoingChanID,
×
UNCOV
1358
                                pkt.outgoingHTLCID)
×
UNCOV
1359
                        log.Error(err)
×
UNCOV
1360

×
UNCOV
1361
                        return nil, err
×
UNCOV
1362
                }
×
1363

1364
                return nil, nil
190✔
1365

1366
        // Unexpected error.
1367
        default:
×
1368
                return nil, err
×
1369
        }
1370
}
1371

1372
// ackSettleFail is used by the switch to ACK any settle/fail entries in the
1373
// forwarding package of the outgoing link for a payment circuit. We do this if
1374
// we're the originator of the payment, so the link stops attempting to
1375
// re-broadcast.
1376
func (s *Switch) ackSettleFail(settleFailRefs ...channeldb.SettleFailRef) error {
118✔
1377
        return kvdb.Batch(s.cfg.DB, func(tx kvdb.RwTx) error {
236✔
1378
                return s.cfg.SwitchPackager.AckSettleFails(tx, settleFailRefs...)
118✔
1379
        })
118✔
1380
}
1381

1382
// teardownCircuit removes a pending or open circuit from the switch's circuit
1383
// map and prints useful logging statements regarding the outcome.
1384
func (s *Switch) teardownCircuit(pkt *htlcPacket) error {
314✔
1385
        var pktType string
314✔
1386
        switch htlc := pkt.htlc.(type) {
314✔
1387
        case *lnwire.UpdateFulfillHTLC:
186✔
1388
                pktType = "SETTLE"
186✔
1389
        case *lnwire.UpdateFailHTLC:
128✔
1390
                pktType = "FAIL"
128✔
1391
        default:
×
1392
                return fmt.Errorf("cannot tear down packet of type: %T", htlc)
×
1393
        }
1394

1395
        var paymentHash lntypes.Hash
314✔
1396

314✔
1397
        // Perform a defensive check to make sure we don't try to access a nil
314✔
1398
        // circuit.
314✔
1399
        circuit := pkt.circuit
314✔
1400
        if circuit != nil {
628✔
1401
                copy(paymentHash[:], circuit.PaymentHash[:])
314✔
1402
        }
314✔
1403

1404
        log.Debugf("Tearing down circuit with %s pkt, removing circuit=%v "+
314✔
1405
                "with keystone=%v", pktType, pkt.inKey(), pkt.outKey())
314✔
1406

314✔
1407
        err := s.circuits.DeleteCircuits(pkt.inKey())
314✔
1408
        if err != nil {
314✔
1409
                log.Warnf("Failed to tear down circuit (%s, %d) <-> (%s, %d) "+
×
1410
                        "with payment_hash=%v using %s pkt", pkt.incomingChanID,
×
1411
                        pkt.incomingHTLCID, pkt.outgoingChanID,
×
1412
                        pkt.outgoingHTLCID, pkt.circuit.PaymentHash, pktType)
×
1413

×
1414
                return err
×
1415
        }
×
1416

1417
        log.Debugf("Closed %s circuit for %v: (%s, %d) <-> (%s, %d)", pktType,
314✔
1418
                paymentHash, pkt.incomingChanID, pkt.incomingHTLCID,
314✔
1419
                pkt.outgoingChanID, pkt.outgoingHTLCID)
314✔
1420

314✔
1421
        return nil
314✔
1422
}
1423

1424
// CloseLink creates and sends the close channel command to the target link
1425
// directing the specified closure type. If the closure type is CloseRegular,
1426
// targetFeePerKw parameter should be the ideal fee-per-kw that will be used as
1427
// a starting point for close negotiation. The deliveryScript parameter is an
1428
// optional parameter which sets a user specified script to close out to.
1429
func (s *Switch) CloseLink(chanPoint *wire.OutPoint,
1430
        closeType contractcourt.ChannelCloseType,
1431
        targetFeePerKw, maxFee chainfee.SatPerKWeight,
UNCOV
1432
        deliveryScript lnwire.DeliveryAddress) (chan interface{}, chan error) {
×
UNCOV
1433

×
UNCOV
1434
        // TODO(roasbeef) abstract out the close updates.
×
UNCOV
1435
        updateChan := make(chan interface{}, 2)
×
UNCOV
1436
        errChan := make(chan error, 1)
×
UNCOV
1437

×
UNCOV
1438
        command := &ChanClose{
×
UNCOV
1439
                CloseType:      closeType,
×
UNCOV
1440
                ChanPoint:      chanPoint,
×
UNCOV
1441
                Updates:        updateChan,
×
UNCOV
1442
                TargetFeePerKw: targetFeePerKw,
×
UNCOV
1443
                MaxFee:         maxFee,
×
UNCOV
1444
                DeliveryScript: deliveryScript,
×
UNCOV
1445
                Err:            errChan,
×
UNCOV
1446
        }
×
UNCOV
1447

×
UNCOV
1448
        select {
×
UNCOV
1449
        case s.chanCloseRequests <- command:
×
UNCOV
1450
                return updateChan, errChan
×
1451

NEW
1452
        case <-s.gm.Done():
×
1453
                errChan <- ErrSwitchExiting
×
1454
                close(updateChan)
×
1455
                return updateChan, errChan
×
1456
        }
1457
}
1458

1459
// htlcForwarder is responsible for optimally forwarding (and possibly
1460
// fragmenting) incoming/outgoing HTLCs amongst all active interfaces and their
1461
// links. The duties of the forwarder are similar to that of a network switch,
1462
// in that it facilitates multi-hop payments by acting as a central messaging
1463
// bus. The switch communicates will active links to create, manage, and tear
1464
// down active onion routed payments. Each active channel is modeled as
1465
// networked device with metadata such as the available payment bandwidth, and
1466
// total link capacity.
1467
//
1468
// NOTE: This MUST be run as a goroutine.
1469
func (s *Switch) htlcForwarder() {
208✔
1470
        defer func() {
416✔
1471
                s.blockEpochStream.Cancel()
208✔
1472

208✔
1473
                // Remove all links once we've been signalled for shutdown.
208✔
1474
                var linksToStop []ChannelLink
208✔
1475
                s.indexMtx.Lock()
208✔
1476
                for _, link := range s.linkIndex {
500✔
1477
                        activeLink := s.removeLink(link.ChanID())
292✔
1478
                        if activeLink == nil {
292✔
1479
                                log.Errorf("unable to remove ChannelLink(%v) "+
×
1480
                                        "on stop", link.ChanID())
×
1481
                                continue
×
1482
                        }
1483
                        linksToStop = append(linksToStop, activeLink)
292✔
1484
                }
1485
                for _, link := range s.pendingLinkIndex {
209✔
1486
                        pendingLink := s.removeLink(link.ChanID())
1✔
1487
                        if pendingLink == nil {
1✔
1488
                                log.Errorf("unable to remove ChannelLink(%v) "+
×
1489
                                        "on stop", link.ChanID())
×
1490
                                continue
×
1491
                        }
1492
                        linksToStop = append(linksToStop, pendingLink)
1✔
1493
                }
1494
                s.indexMtx.Unlock()
208✔
1495

208✔
1496
                // Now that all pending and live links have been removed from
208✔
1497
                // the forwarding indexes, stop each one before shutting down.
208✔
1498
                // We'll shut them down in parallel to make exiting as fast as
208✔
1499
                // possible.
208✔
1500
                var wg sync.WaitGroup
208✔
1501
                for _, link := range linksToStop {
501✔
1502
                        wg.Add(1)
293✔
1503
                        // Here it is ok to start a goroutine directly bypassing
293✔
1504
                        // s.gm, because we want for them to complete here.
293✔
1505
                        go func(l ChannelLink) {
586✔
1506
                                defer wg.Done()
293✔
1507

293✔
1508
                                l.Stop()
293✔
1509
                        }(link)
293✔
1510
                }
1511
                wg.Wait()
208✔
1512

208✔
1513
                // Before we exit fully, we'll attempt to flush out any
208✔
1514
                // forwarding events that may still be lingering since the last
208✔
1515
                // batch flush.
208✔
1516
                if err := s.FlushForwardingEvents(); err != nil {
208✔
1517
                        log.Errorf("unable to flush forwarding events: %v", err)
×
1518
                }
×
1519
        }()
1520

1521
        // TODO(roasbeef): cleared vs settled distinction
1522
        var (
208✔
1523
                totalNumUpdates uint64
208✔
1524
                totalSatSent    btcutil.Amount
208✔
1525
                totalSatRecv    btcutil.Amount
208✔
1526
        )
208✔
1527
        s.cfg.LogEventTicker.Resume()
208✔
1528
        defer s.cfg.LogEventTicker.Stop()
208✔
1529

208✔
1530
        // Every 15 seconds, we'll flush out the forwarding events that
208✔
1531
        // occurred during that period.
208✔
1532
        s.cfg.FwdEventTicker.Resume()
208✔
1533
        defer s.cfg.FwdEventTicker.Stop()
208✔
1534

208✔
1535
        defer s.cfg.AckEventTicker.Stop()
208✔
1536

208✔
1537
out:
208✔
1538
        for {
1,041✔
1539

833✔
1540
                // If the set of pending settle/fail entries is non-zero,
833✔
1541
                // reinstate the ack ticker so we can batch ack them.
833✔
1542
                if len(s.pendingSettleFails) > 0 {
1,210✔
1543
                        s.cfg.AckEventTicker.Resume()
377✔
1544
                }
377✔
1545

1546
                select {
833✔
UNCOV
1547
                case blockEpoch, ok := <-s.blockEpochStream.Epochs:
×
UNCOV
1548
                        if !ok {
×
1549
                                break out
×
1550
                        }
1551

UNCOV
1552
                        atomic.StoreUint32(&s.bestHeight, uint32(blockEpoch.Height))
×
1553

1554
                // A local close request has arrived, we'll forward this to the
1555
                // relevant link (if it exists) so the channel can be
1556
                // cooperatively closed (if possible).
UNCOV
1557
                case req := <-s.chanCloseRequests:
×
UNCOV
1558
                        chanID := lnwire.NewChanIDFromOutPoint(*req.ChanPoint)
×
UNCOV
1559

×
UNCOV
1560
                        s.indexMtx.RLock()
×
UNCOV
1561
                        link, ok := s.linkIndex[chanID]
×
UNCOV
1562
                        if !ok {
×
UNCOV
1563
                                s.indexMtx.RUnlock()
×
UNCOV
1564

×
UNCOV
1565
                                req.Err <- fmt.Errorf("no peer for channel with "+
×
UNCOV
1566
                                        "chan_id=%x", chanID[:])
×
UNCOV
1567
                                continue
×
1568
                        }
UNCOV
1569
                        s.indexMtx.RUnlock()
×
UNCOV
1570

×
UNCOV
1571
                        peerPub := link.PeerPubKey()
×
UNCOV
1572
                        log.Debugf("Requesting local channel close: peer=%v, "+
×
UNCOV
1573
                                "chan_id=%x", link.PeerPubKey(), chanID[:])
×
UNCOV
1574

×
UNCOV
1575
                        go s.cfg.LocalChannelClose(peerPub[:], req)
×
1576

1577
                case resolutionMsg := <-s.resolutionMsgs:
1✔
1578
                        // We'll persist the resolution message to the Switch's
1✔
1579
                        // resolution store.
1✔
1580
                        resMsg := resolutionMsg.ResolutionMsg
1✔
1581
                        err := s.resMsgStore.addResolutionMsg(&resMsg)
1✔
1582
                        if err != nil {
1✔
1583
                                // This will only fail if there is a database
×
1584
                                // error or a serialization error. Sending the
×
1585
                                // error prevents the contractcourt from being
×
1586
                                // in a state where it believes the send was
×
1587
                                // successful, when it wasn't.
×
1588
                                log.Errorf("unable to add resolution msg: %v",
×
1589
                                        err)
×
1590
                                resolutionMsg.errChan <- err
×
1591
                                continue
×
1592
                        }
1593

1594
                        // At this point, the resolution message has been
1595
                        // persisted. It is safe to signal success by sending
1596
                        // a nil error since the Switch will re-deliver the
1597
                        // resolution message on restart.
1598
                        resolutionMsg.errChan <- nil
1✔
1599

1✔
1600
                        // Create a htlc packet for this resolution. We do
1✔
1601
                        // not have some of the information that we'll need
1✔
1602
                        // for blinded error handling here , so we'll rely on
1✔
1603
                        // our forwarding logic to fill it in later.
1✔
1604
                        pkt := &htlcPacket{
1✔
1605
                                outgoingChanID: resolutionMsg.SourceChan,
1✔
1606
                                outgoingHTLCID: resolutionMsg.HtlcIndex,
1✔
1607
                                isResolution:   true,
1✔
1608
                        }
1✔
1609

1✔
1610
                        // Resolution messages will either be cancelling
1✔
1611
                        // backwards an existing HTLC, or settling a previously
1✔
1612
                        // outgoing HTLC. Based on this, we'll map the message
1✔
1613
                        // to the proper htlcPacket.
1✔
1614
                        if resolutionMsg.Failure != nil {
1✔
UNCOV
1615
                                pkt.htlc = &lnwire.UpdateFailHTLC{}
×
1616
                        } else {
1✔
1617
                                pkt.htlc = &lnwire.UpdateFulfillHTLC{
1✔
1618
                                        PaymentPreimage: *resolutionMsg.PreImage,
1✔
1619
                                }
1✔
1620
                        }
1✔
1621

1622
                        log.Infof("Received outside contract resolution, "+
1✔
1623
                                "mapping to: %v", spew.Sdump(pkt))
1✔
1624

1✔
1625
                        // We don't check the error, as the only failure we can
1✔
1626
                        // encounter is due to the circuit already being
1✔
1627
                        // closed. This is fine, as processing this message is
1✔
1628
                        // meant to be idempotent.
1✔
1629
                        err = s.handlePacketForward(pkt)
1✔
1630
                        if err != nil {
1✔
UNCOV
1631
                                log.Errorf("Unable to forward resolution msg: %v", err)
×
UNCOV
1632
                        }
×
1633

1634
                // A new packet has arrived for forwarding, we'll interpret the
1635
                // packet concretely, then either forward it along, or
1636
                // interpret a return packet to a locally initialized one.
1637
                case cmd := <-s.htlcPlex:
618✔
1638
                        cmd.err <- s.handlePacketForward(cmd.pkt)
618✔
1639

1640
                // When this time ticks, then it indicates that we should
1641
                // collect all the forwarding events since the last internal,
1642
                // and write them out to our log.
1643
                case <-s.cfg.FwdEventTicker.Ticks():
2✔
1644
                        // The error of Go is ignored: if it is shutting down,
2✔
1645
                        // the loop will terminate on the next iteration, in
2✔
1646
                        // s.gm.Done case.
2✔
1647
                        _ = s.gm.Go(background, func(ctx context.Context) {
4✔
1648
                                err := s.FlushForwardingEvents()
2✔
1649
                                if err != nil {
2✔
1650
                                        log.Errorf("Unable to flush "+
×
1651
                                                "forwarding events: %v", err)
×
1652
                                }
×
1653
                        })
1654

1655
                // The log ticker has fired, so we'll calculate some forwarding
1656
                // stats for the last 10 seconds to display within the logs to
1657
                // users.
1658
                case <-s.cfg.LogEventTicker.Ticks():
4✔
1659
                        // First, we'll collate the current running tally of
4✔
1660
                        // our forwarding stats.
4✔
1661
                        prevSatSent := totalSatSent
4✔
1662
                        prevSatRecv := totalSatRecv
4✔
1663
                        prevNumUpdates := totalNumUpdates
4✔
1664

4✔
1665
                        var (
4✔
1666
                                newNumUpdates uint64
4✔
1667
                                newSatSent    btcutil.Amount
4✔
1668
                                newSatRecv    btcutil.Amount
4✔
1669
                        )
4✔
1670

4✔
1671
                        // Next, we'll run through all the registered links and
4✔
1672
                        // compute their up-to-date forwarding stats.
4✔
1673
                        s.indexMtx.RLock()
4✔
1674
                        for _, link := range s.linkIndex {
10✔
1675
                                // TODO(roasbeef): when links first registered
6✔
1676
                                // stats printed.
6✔
1677
                                updates, sent, recv := link.Stats()
6✔
1678
                                newNumUpdates += updates
6✔
1679
                                newSatSent += sent.ToSatoshis()
6✔
1680
                                newSatRecv += recv.ToSatoshis()
6✔
1681
                        }
6✔
1682
                        s.indexMtx.RUnlock()
4✔
1683

4✔
1684
                        var (
4✔
1685
                                diffNumUpdates uint64
4✔
1686
                                diffSatSent    btcutil.Amount
4✔
1687
                                diffSatRecv    btcutil.Amount
4✔
1688
                        )
4✔
1689

4✔
1690
                        // If this is the first time we're computing these
4✔
1691
                        // stats, then the diff is just the new value. We do
4✔
1692
                        // this in order to avoid integer underflow issues.
4✔
1693
                        if prevNumUpdates == 0 {
8✔
1694
                                diffNumUpdates = newNumUpdates
4✔
1695
                                diffSatSent = newSatSent
4✔
1696
                                diffSatRecv = newSatRecv
4✔
1697
                        } else {
4✔
UNCOV
1698
                                diffNumUpdates = newNumUpdates - prevNumUpdates
×
UNCOV
1699
                                diffSatSent = newSatSent - prevSatSent
×
UNCOV
1700
                                diffSatRecv = newSatRecv - prevSatRecv
×
UNCOV
1701
                        }
×
1702

1703
                        // If the diff of num updates is zero, then we haven't
1704
                        // forwarded anything in the last 10 seconds, so we can
1705
                        // skip this update.
1706
                        if diffNumUpdates == 0 {
6✔
1707
                                continue
2✔
1708
                        }
1709

1710
                        // If the diff of num updates is negative, then some
1711
                        // links may have been unregistered from the switch, so
1712
                        // we'll update our stats to only include our registered
1713
                        // links.
1714
                        if int64(diffNumUpdates) < 0 {
2✔
UNCOV
1715
                                totalNumUpdates = newNumUpdates
×
UNCOV
1716
                                totalSatSent = newSatSent
×
UNCOV
1717
                                totalSatRecv = newSatRecv
×
UNCOV
1718
                                continue
×
1719
                        }
1720

1721
                        // Otherwise, we'll log this diff, then accumulate the
1722
                        // new stats into the running total.
1723
                        log.Debugf("Sent %d satoshis and received %d satoshis "+
2✔
1724
                                "in the last 10 seconds (%f tx/sec)",
2✔
1725
                                diffSatSent, diffSatRecv,
2✔
1726
                                float64(diffNumUpdates)/10)
2✔
1727

2✔
1728
                        totalNumUpdates += diffNumUpdates
2✔
1729
                        totalSatSent += diffSatSent
2✔
1730
                        totalSatRecv += diffSatRecv
2✔
1731

1732
                // The ack ticker has fired so if we have any settle/fail entries
1733
                // for a forwarding package to ack, we will do so here in a batch
1734
                // db call.
UNCOV
1735
                case <-s.cfg.AckEventTicker.Ticks():
×
UNCOV
1736
                        // If the current set is empty, pause the ticker.
×
UNCOV
1737
                        if len(s.pendingSettleFails) == 0 {
×
UNCOV
1738
                                s.cfg.AckEventTicker.Pause()
×
UNCOV
1739
                                continue
×
1740
                        }
1741

1742
                        // Batch ack the settle/fail entries.
UNCOV
1743
                        if err := s.ackSettleFail(s.pendingSettleFails...); err != nil {
×
1744
                                log.Errorf("Unable to ack batch of settle/fails: %v", err)
×
1745
                                continue
×
1746
                        }
1747

UNCOV
1748
                        log.Tracef("Acked %d settle fails: %v",
×
UNCOV
1749
                                len(s.pendingSettleFails),
×
UNCOV
1750
                                lnutils.SpewLogClosure(s.pendingSettleFails))
×
UNCOV
1751

×
UNCOV
1752
                        // Reset the pendingSettleFails buffer while keeping acquired
×
UNCOV
1753
                        // memory.
×
UNCOV
1754
                        s.pendingSettleFails = s.pendingSettleFails[:0]
×
1755

1756
                case <-s.gm.Done():
208✔
1757
                        return
208✔
1758
                }
1759
        }
1760
}
1761

1762
// Start starts all helper goroutines required for the operation of the switch.
1763
func (s *Switch) Start() error {
208✔
1764
        if !atomic.CompareAndSwapInt32(&s.started, 0, 1) {
208✔
1765
                log.Warn("Htlc Switch already started")
×
NEW
1766

×
1767
                return errors.New("htlc switch already started")
×
1768
        }
×
1769

1770
        log.Infof("HTLC Switch starting")
208✔
1771

208✔
1772
        blockEpochStream, err := s.cfg.Notifier.RegisterBlockEpochNtfn(nil)
208✔
1773
        if err != nil {
208✔
1774
                return err
×
1775
        }
×
1776
        s.blockEpochStream = blockEpochStream
208✔
1777

208✔
1778
        ok := s.gm.Go(background, func(ctx context.Context) {
416✔
1779
                s.htlcForwarder()
208✔
1780
        })
208✔
1781
        if !ok {
208✔
NEW
1782
                // We are already stopping so we can ignore the error.
×
NEW
1783
                _ = s.Stop()
×
NEW
1784
                err = fmt.Errorf("unable to start htlc forwarder: %w",
×
NEW
1785
                        ErrSwitchExiting)
×
NEW
1786
                log.Errorf("%v", err)
×
NEW
1787

×
NEW
1788
                return err
×
NEW
1789
        }
×
1790

1791
        if err := s.reforwardResponses(); err != nil {
208✔
NEW
1792
                // We are already stopping so we can ignore the error.
×
NEW
1793
                _ = s.Stop()
×
1794
                log.Errorf("unable to reforward responses: %v", err)
×
NEW
1795

×
1796
                return err
×
1797
        }
×
1798

1799
        if err := s.reforwardResolutions(); err != nil {
208✔
1800
                // We are already stopping so we can ignore the error.
×
1801
                _ = s.Stop()
×
1802
                log.Errorf("unable to reforward resolutions: %v", err)
×
NEW
1803

×
1804
                return err
×
1805
        }
×
1806

1807
        return nil
208✔
1808
}
1809

1810
// reforwardResolutions fetches the set of resolution messages stored on-disk
1811
// and reforwards them if their circuits are still open. If the circuits have
1812
// been deleted, then we will delete the resolution message from the database.
1813
func (s *Switch) reforwardResolutions() error {
208✔
1814
        // Fetch all stored resolution messages, deleting the ones that are
208✔
1815
        // resolved.
208✔
1816
        resMsgs, err := s.resMsgStore.fetchAllResolutionMsg()
208✔
1817
        if err != nil {
208✔
1818
                return err
×
1819
        }
×
1820

1821
        switchPackets := make([]*htlcPacket, 0, len(resMsgs))
208✔
1822
        for _, resMsg := range resMsgs {
209✔
1823
                // If the open circuit no longer exists, then we can remove the
1✔
1824
                // message from the store.
1✔
1825
                outKey := CircuitKey{
1✔
1826
                        ChanID: resMsg.SourceChan,
1✔
1827
                        HtlcID: resMsg.HtlcIndex,
1✔
1828
                }
1✔
1829

1✔
1830
                if s.circuits.LookupOpenCircuit(outKey) == nil {
2✔
1831
                        // The open circuit doesn't exist.
1✔
1832
                        err := s.resMsgStore.deleteResolutionMsg(&outKey)
1✔
1833
                        if err != nil {
1✔
1834
                                return err
×
1835
                        }
×
1836

1837
                        continue
1✔
1838
                }
1839

1840
                // The circuit is still open, so we can assume that the link or
1841
                // switch (if we are the source) hasn't cleaned it up yet.
1842
                // We rely on our forwarding logic to fill in details that
1843
                // are not currently available to us.
UNCOV
1844
                resPkt := &htlcPacket{
×
UNCOV
1845
                        outgoingChanID: resMsg.SourceChan,
×
UNCOV
1846
                        outgoingHTLCID: resMsg.HtlcIndex,
×
UNCOV
1847
                        isResolution:   true,
×
UNCOV
1848
                }
×
UNCOV
1849

×
UNCOV
1850
                if resMsg.Failure != nil {
×
UNCOV
1851
                        resPkt.htlc = &lnwire.UpdateFailHTLC{}
×
UNCOV
1852
                } else {
×
1853
                        resPkt.htlc = &lnwire.UpdateFulfillHTLC{
×
1854
                                PaymentPreimage: *resMsg.PreImage,
×
1855
                        }
×
1856
                }
×
1857

UNCOV
1858
                switchPackets = append(switchPackets, resPkt)
×
1859
        }
1860

1861
        // We'll now dispatch the set of resolution messages to the proper
1862
        // destination. An error is only encountered here if the switch is
1863
        // shutting down.
1864
        if err := s.ForwardPackets(nil, switchPackets...); err != nil {
208✔
1865
                return err
×
1866
        }
×
1867

1868
        return nil
208✔
1869
}
1870

1871
// reforwardResponses for every known, non-pending channel, loads all associated
1872
// forwarding packages and reforwards any Settle or Fail HTLCs found. This is
1873
// used to resurrect the switch's mailboxes after a restart. This also runs for
1874
// waiting close channels since there may be settles or fails that need to be
1875
// reforwarded before they completely close.
1876
func (s *Switch) reforwardResponses() error {
208✔
1877
        openChannels, err := s.cfg.FetchAllChannels()
208✔
1878
        if err != nil {
208✔
1879
                return err
×
1880
        }
×
1881

1882
        for _, openChannel := range openChannels {
337✔
1883
                shortChanID := openChannel.ShortChanID()
129✔
1884

129✔
1885
                // Locally-initiated payments never need reforwarding.
129✔
1886
                if shortChanID == hop.Source {
129✔
UNCOV
1887
                        continue
×
1888
                }
1889

1890
                // If the channel is pending, it should have no forwarding
1891
                // packages, and nothing to reforward.
1892
                if openChannel.IsPending {
129✔
1893
                        continue
×
1894
                }
1895

1896
                // Channels in open or waiting-close may still have responses in
1897
                // their forwarding packages. We will continue to reattempt
1898
                // forwarding on startup until the channel is fully-closed.
1899
                //
1900
                // Load this channel's forwarding packages, and deliver them to
1901
                // the switch.
1902
                fwdPkgs, err := s.loadChannelFwdPkgs(shortChanID)
129✔
1903
                if err != nil {
129✔
1904
                        log.Errorf("unable to load forwarding "+
×
1905
                                "packages for %v: %v", shortChanID, err)
×
1906
                        return err
×
1907
                }
×
1908

1909
                s.reforwardSettleFails(fwdPkgs)
129✔
1910
        }
1911

1912
        return nil
208✔
1913
}
1914

1915
// loadChannelFwdPkgs loads all forwarding packages owned by the `source` short
1916
// channel identifier.
1917
func (s *Switch) loadChannelFwdPkgs(source lnwire.ShortChannelID) ([]*channeldb.FwdPkg, error) {
129✔
1918

129✔
1919
        var fwdPkgs []*channeldb.FwdPkg
129✔
1920
        if err := kvdb.View(s.cfg.DB, func(tx kvdb.RTx) error {
258✔
1921
                var err error
129✔
1922
                fwdPkgs, err = s.cfg.SwitchPackager.LoadChannelFwdPkgs(
129✔
1923
                        tx, source,
129✔
1924
                )
129✔
1925
                return err
129✔
1926
        }, func() {
258✔
1927
                fwdPkgs = nil
129✔
1928
        }); err != nil {
129✔
1929
                return nil, err
×
1930
        }
×
1931

1932
        return fwdPkgs, nil
129✔
1933
}
1934

1935
// reforwardSettleFails parses the Settle and Fail HTLCs from the list of
1936
// forwarding packages, and reforwards those that have not been acknowledged.
1937
// This is intended to occur on startup, in order to recover the switch's
1938
// mailboxes, and to ensure that responses can be propagated in case the
1939
// outgoing link never comes back online.
1940
//
1941
// NOTE: This should mimic the behavior processRemoteSettleFails.
1942
func (s *Switch) reforwardSettleFails(fwdPkgs []*channeldb.FwdPkg) {
129✔
1943
        for _, fwdPkg := range fwdPkgs {
130✔
1944
                switchPackets := make([]*htlcPacket, 0, len(fwdPkg.SettleFails))
1✔
1945
                for i, update := range fwdPkg.SettleFails {
1✔
UNCOV
1946
                        // Skip any settles or fails that have already been
×
UNCOV
1947
                        // acknowledged by the incoming link that originated the
×
UNCOV
1948
                        // forwarded Add.
×
UNCOV
1949
                        if fwdPkg.SettleFailFilter.Contains(uint16(i)) {
×
UNCOV
1950
                                continue
×
1951
                        }
1952

UNCOV
1953
                        switch msg := update.UpdateMsg.(type) {
×
1954
                        // A settle for an HTLC we previously forwarded HTLC has
1955
                        // been received. So we'll forward the HTLC to the
1956
                        // switch which will handle propagating the settle to
1957
                        // the prior hop.
UNCOV
1958
                        case *lnwire.UpdateFulfillHTLC:
×
UNCOV
1959
                                destRef := fwdPkg.DestRef(uint16(i))
×
UNCOV
1960
                                settlePacket := &htlcPacket{
×
UNCOV
1961
                                        outgoingChanID: fwdPkg.Source,
×
UNCOV
1962
                                        outgoingHTLCID: msg.ID,
×
UNCOV
1963
                                        destRef:        &destRef,
×
UNCOV
1964
                                        htlc:           msg,
×
UNCOV
1965
                                }
×
UNCOV
1966

×
UNCOV
1967
                                // Add the packet to the batch to be forwarded, and
×
UNCOV
1968
                                // notify the overflow queue that a spare spot has been
×
UNCOV
1969
                                // freed up within the commitment state.
×
UNCOV
1970
                                switchPackets = append(switchPackets, settlePacket)
×
1971

1972
                        // A failureCode message for a previously forwarded HTLC has been
1973
                        // received. As a result a new slot will be freed up in our
1974
                        // commitment state, so we'll forward this to the switch so the
1975
                        // backwards undo can continue.
1976
                        case *lnwire.UpdateFailHTLC:
×
1977
                                // Fetch the reason the HTLC was canceled so
×
1978
                                // we can continue to propagate it. This
×
1979
                                // failure originated from another node, so
×
1980
                                // the linkFailure field is not set on this
×
1981
                                // packet. We rely on the link to fill in
×
1982
                                // additional circuit information for us.
×
1983
                                failPacket := &htlcPacket{
×
1984
                                        outgoingChanID: fwdPkg.Source,
×
1985
                                        outgoingHTLCID: msg.ID,
×
1986
                                        destRef: &channeldb.SettleFailRef{
×
1987
                                                Source: fwdPkg.Source,
×
1988
                                                Height: fwdPkg.Height,
×
1989
                                                Index:  uint16(i),
×
1990
                                        },
×
1991
                                        htlc: msg,
×
1992
                                }
×
1993

×
1994
                                // Add the packet to the batch to be forwarded, and
×
1995
                                // notify the overflow queue that a spare spot has been
×
1996
                                // freed up within the commitment state.
×
1997
                                switchPackets = append(switchPackets, failPacket)
×
1998
                        }
1999
                }
2000

2001
                // Since this send isn't tied to a specific link, we pass a nil
2002
                // link quit channel, meaning the send will fail only if the
2003
                // switch receives a shutdown request.
2004
                if err := s.ForwardPackets(nil, switchPackets...); err != nil {
1✔
2005
                        log.Errorf("Unhandled error while reforwarding packets "+
×
2006
                                "settle/fail over htlcswitch: %v", err)
×
2007
                }
×
2008
        }
2009
}
2010

2011
// Stop gracefully stops all active helper goroutines, then waits until they've
2012
// exited.
2013
func (s *Switch) Stop() error {
440✔
2014
        if !atomic.CompareAndSwapInt32(&s.shutdown, 0, 1) {
570✔
2015
                log.Warn("Htlc Switch already stopped")
130✔
2016
                return errors.New("htlc switch already shutdown")
130✔
2017
        }
130✔
2018

2019
        log.Info("HTLC Switch shutting down...")
310✔
2020
        defer log.Debug("HTLC Switch shutdown complete")
310✔
2021

310✔
2022
        // Ask running goroutines to stop and wait for them.
310✔
2023
        s.gm.Stop()
310✔
2024

310✔
2025
        // Wait until all active goroutines have finished exiting before
310✔
2026
        // stopping the mailboxes, otherwise the mailbox map could still be
310✔
2027
        // accessed and modified.
310✔
2028
        s.mailOrchestrator.Stop()
310✔
2029

310✔
2030
        return nil
310✔
2031
}
2032

2033
// CreateAndAddLink will create a link and then add it to the internal maps
2034
// when given a ChannelLinkConfig and LightningChannel.
2035
func (s *Switch) CreateAndAddLink(linkCfg ChannelLinkConfig,
UNCOV
2036
        lnChan *lnwallet.LightningChannel) error {
×
UNCOV
2037

×
UNCOV
2038
        link := NewChannelLink(linkCfg, lnChan)
×
UNCOV
2039
        return s.AddLink(link)
×
UNCOV
2040
}
×
2041

2042
// AddLink is used to initiate the handling of the add link command. The
2043
// request will be propagated and handled in the main goroutine.
2044
func (s *Switch) AddLink(link ChannelLink) error {
336✔
2045
        s.indexMtx.Lock()
336✔
2046
        defer s.indexMtx.Unlock()
336✔
2047

336✔
2048
        chanID := link.ChanID()
336✔
2049

336✔
2050
        // First, ensure that this link is not already active in the switch.
336✔
2051
        _, err := s.getLink(chanID)
336✔
2052
        if err == nil {
337✔
2053
                return fmt.Errorf("unable to add ChannelLink(%v), already "+
1✔
2054
                        "active", chanID)
1✔
2055
        }
1✔
2056

2057
        // Get and attach the mailbox for this link, which buffers packets in
2058
        // case there packets that we tried to deliver while this link was
2059
        // offline.
2060
        shortChanID := link.ShortChanID()
335✔
2061
        mailbox := s.mailOrchestrator.GetOrCreateMailBox(chanID, shortChanID)
335✔
2062
        link.AttachMailBox(mailbox)
335✔
2063

335✔
2064
        // Attach the Switch's failAliasUpdate function to the link.
335✔
2065
        link.attachFailAliasUpdate(s.failAliasUpdate)
335✔
2066

335✔
2067
        if err := link.Start(); err != nil {
335✔
2068
                log.Errorf("AddLink failed to start link with chanID=%v: %v",
×
2069
                        chanID, err)
×
2070
                s.removeLink(chanID)
×
2071
                return err
×
2072
        }
×
2073

2074
        if shortChanID == hop.Source {
336✔
2075
                log.Infof("Adding pending link chan_id=%v, short_chan_id=%v",
1✔
2076
                        chanID, shortChanID)
1✔
2077

1✔
2078
                s.pendingLinkIndex[chanID] = link
1✔
2079
        } else {
335✔
2080
                log.Infof("Adding live link chan_id=%v, short_chan_id=%v",
334✔
2081
                        chanID, shortChanID)
334✔
2082

334✔
2083
                s.addLiveLink(link)
334✔
2084
                s.mailOrchestrator.BindLiveShortChanID(
334✔
2085
                        mailbox, chanID, shortChanID,
334✔
2086
                )
334✔
2087
        }
334✔
2088

2089
        return nil
335✔
2090
}
2091

2092
// addLiveLink adds a link to all associated forwarding index, this makes it a
2093
// candidate for forwarding HTLCs.
2094
func (s *Switch) addLiveLink(link ChannelLink) {
334✔
2095
        linkScid := link.ShortChanID()
334✔
2096

334✔
2097
        // We'll add the link to the linkIndex which lets us quickly
334✔
2098
        // look up a channel when we need to close or register it, and
334✔
2099
        // the forwarding index which'll be used when forwarding HTLC's
334✔
2100
        // in the multi-hop setting.
334✔
2101
        s.linkIndex[link.ChanID()] = link
334✔
2102
        s.forwardingIndex[linkScid] = link
334✔
2103

334✔
2104
        // Next we'll add the link to the interface index so we can
334✔
2105
        // quickly look up all the channels for a particular node.
334✔
2106
        peerPub := link.PeerPubKey()
334✔
2107
        if _, ok := s.interfaceIndex[peerPub]; !ok {
663✔
2108
                s.interfaceIndex[peerPub] = make(map[lnwire.ChannelID]ChannelLink)
329✔
2109
        }
329✔
2110
        s.interfaceIndex[peerPub][link.ChanID()] = link
334✔
2111

334✔
2112
        s.updateLinkAliases(link)
334✔
2113
}
2114

2115
// UpdateLinkAliases is the externally exposed wrapper for updating link
2116
// aliases. It acquires the indexMtx and calls the internal method.
UNCOV
2117
func (s *Switch) UpdateLinkAliases(link ChannelLink) {
×
UNCOV
2118
        s.indexMtx.Lock()
×
UNCOV
2119
        defer s.indexMtx.Unlock()
×
UNCOV
2120

×
UNCOV
2121
        s.updateLinkAliases(link)
×
UNCOV
2122
}
×
2123

2124
// updateLinkAliases updates the aliases for a given link. This will cause the
2125
// htlcswitch to consult the alias manager on the up to date values of its
2126
// alias maps.
2127
//
2128
// NOTE: this MUST be called with the indexMtx held.
2129
func (s *Switch) updateLinkAliases(link ChannelLink) {
334✔
2130
        linkScid := link.ShortChanID()
334✔
2131

334✔
2132
        aliases := link.getAliases()
334✔
2133
        if link.isZeroConf() {
353✔
2134
                if link.zeroConfConfirmed() {
34✔
2135
                        // Since the zero-conf channel has confirmed, we can
15✔
2136
                        // populate the aliasToReal mapping.
15✔
2137
                        confirmedScid := link.confirmedScid()
15✔
2138

15✔
2139
                        for _, alias := range aliases {
37✔
2140
                                s.aliasToReal[alias] = confirmedScid
22✔
2141
                        }
22✔
2142

2143
                        // Add the confirmed SCID as a key in the baseIndex.
2144
                        s.baseIndex[confirmedScid] = linkScid
15✔
2145
                }
2146

2147
                // Now we populate the baseIndex which will be used to fetch
2148
                // the link given any of the channel's alias SCIDs or the real
2149
                // SCID. The link's SCID is an alias, so we don't need to
2150
                // special-case it like the option-scid-alias feature-bit case
2151
                // further down.
2152
                for _, alias := range aliases {
46✔
2153
                        s.baseIndex[alias] = linkScid
27✔
2154
                }
27✔
2155
        } else if link.negotiatedAliasFeature() {
331✔
2156
                // First, we flush any alias mappings for this link's scid
16✔
2157
                // before we populate the map again, in order to get rid of old
16✔
2158
                // values that no longer exist.
16✔
2159
                for alias, real := range s.aliasToReal {
18✔
2160
                        if real == linkScid {
2✔
UNCOV
2161
                                delete(s.aliasToReal, alias)
×
UNCOV
2162
                        }
×
2163
                }
2164

2165
                for alias, real := range s.baseIndex {
19✔
2166
                        if real == linkScid {
3✔
UNCOV
2167
                                delete(s.baseIndex, alias)
×
UNCOV
2168
                        }
×
2169
                }
2170

2171
                // The link's SCID is the confirmed SCID for non-zero-conf
2172
                // option-scid-alias feature bit channels.
2173
                for _, alias := range aliases {
39✔
2174
                        s.aliasToReal[alias] = linkScid
23✔
2175
                        s.baseIndex[alias] = linkScid
23✔
2176
                }
23✔
2177

2178
                // Since the link's SCID is confirmed, it was not included in
2179
                // the baseIndex above as a key. Add it now.
2180
                s.baseIndex[linkScid] = linkScid
16✔
2181
        }
2182
}
2183

2184
// GetLink is used to initiate the handling of the get link command. The
2185
// request will be propagated/handled to/in the main goroutine.
2186
func (s *Switch) GetLink(chanID lnwire.ChannelID) (ChannelUpdateHandler,
2187
        error) {
3,209✔
2188

3,209✔
2189
        s.indexMtx.RLock()
3,209✔
2190
        defer s.indexMtx.RUnlock()
3,209✔
2191

3,209✔
2192
        return s.getLink(chanID)
3,209✔
2193
}
3,209✔
2194

2195
// getLink returns the link stored in either the pending index or the live
2196
// lindex.
2197
func (s *Switch) getLink(chanID lnwire.ChannelID) (ChannelLink, error) {
3,874✔
2198
        link, ok := s.linkIndex[chanID]
3,874✔
2199
        if !ok {
4,210✔
2200
                link, ok = s.pendingLinkIndex[chanID]
336✔
2201
                if !ok {
671✔
2202
                        return nil, ErrChannelLinkNotFound
335✔
2203
                }
335✔
2204
        }
2205

2206
        return link, nil
3,539✔
2207
}
2208

2209
// GetLinkByShortID attempts to return the link which possesses the target short
2210
// channel ID.
2211
func (s *Switch) GetLinkByShortID(chanID lnwire.ShortChannelID) (ChannelLink,
UNCOV
2212
        error) {
×
UNCOV
2213

×
UNCOV
2214
        s.indexMtx.RLock()
×
UNCOV
2215
        defer s.indexMtx.RUnlock()
×
UNCOV
2216

×
UNCOV
2217
        link, err := s.getLinkByShortID(chanID)
×
UNCOV
2218
        if err != nil {
×
UNCOV
2219
                // If we failed to find the link under the passed-in SCID, we
×
UNCOV
2220
                // consult the Switch's baseIndex map to see if the confirmed
×
UNCOV
2221
                // SCID was used for a zero-conf channel.
×
UNCOV
2222
                aliasID, ok := s.baseIndex[chanID]
×
UNCOV
2223
                if !ok {
×
UNCOV
2224
                        return nil, err
×
UNCOV
2225
                }
×
2226

2227
                // An alias was found, use it to lookup if a link exists.
UNCOV
2228
                return s.getLinkByShortID(aliasID)
×
2229
        }
2230

UNCOV
2231
        return link, nil
×
2232
}
2233

2234
// getLinkByShortID attempts to return the link which possesses the target
2235
// short channel ID.
2236
//
2237
// NOTE: This MUST be called with the indexMtx held.
2238
func (s *Switch) getLinkByShortID(chanID lnwire.ShortChannelID) (ChannelLink, error) {
477✔
2239
        link, ok := s.forwardingIndex[chanID]
477✔
2240
        if !ok {
478✔
2241
                return nil, ErrChannelLinkNotFound
1✔
2242
        }
1✔
2243

2244
        return link, nil
476✔
2245
}
2246

2247
// getLinkByMapping attempts to fetch the link via the htlcPacket's
2248
// outgoingChanID, possibly using a mapping. If it finds the link via mapping,
2249
// the outgoingChanID will be changed so that an error can be properly
2250
// attributed when looping over linkErrs in handlePacketForward.
2251
//
2252
// * If the outgoingChanID is an alias, we'll fetch the link regardless if it's
2253
// public or not.
2254
//
2255
// * If the outgoingChanID is a confirmed SCID, we'll need to do more checks.
2256
//   - If there is no entry found in baseIndex, fetch the link. This channel
2257
//     did not have the option-scid-alias feature negotiated (which includes
2258
//     zero-conf and option-scid-alias channel-types).
2259
//   - If there is an entry found, fetch the link from forwardingIndex and
2260
//     fail if this is a private link.
2261
//
2262
// NOTE: This MUST be called with the indexMtx read lock held.
2263
func (s *Switch) getLinkByMapping(pkt *htlcPacket) (ChannelLink, error) {
80✔
2264
        // Determine if this ShortChannelID is an alias or a confirmed SCID.
80✔
2265
        chanID := pkt.outgoingChanID
80✔
2266
        aliasID := s.cfg.IsAlias(chanID)
80✔
2267

80✔
2268
        // Set the originalOutgoingChanID so the proper channel_update can be
80✔
2269
        // sent back if the option-scid-alias feature bit was negotiated.
80✔
2270
        pkt.originalOutgoingChanID = chanID
80✔
2271

80✔
2272
        if aliasID {
95✔
2273
                // Since outgoingChanID is an alias, we'll fetch the link via
15✔
2274
                // baseIndex.
15✔
2275
                baseScid, ok := s.baseIndex[chanID]
15✔
2276
                if !ok {
15✔
2277
                        // No mapping exists, bail.
×
2278
                        return nil, ErrChannelLinkNotFound
×
2279
                }
×
2280

2281
                // A mapping exists, so use baseScid to find the link in the
2282
                // forwardingIndex.
2283
                link, ok := s.forwardingIndex[baseScid]
15✔
2284
                if !ok {
15✔
2285
                        // Link not found, bail.
×
2286
                        return nil, ErrChannelLinkNotFound
×
2287
                }
×
2288

2289
                // Change the packet's outgoingChanID field so that errors are
2290
                // properly attributed.
2291
                pkt.outgoingChanID = baseScid
15✔
2292

15✔
2293
                // Return the link without checking if it's private or not.
15✔
2294
                return link, nil
15✔
2295
        }
2296

2297
        // The outgoingChanID is a confirmed SCID. Attempt to fetch the base
2298
        // SCID from baseIndex.
2299
        baseScid, ok := s.baseIndex[chanID]
65✔
2300
        if !ok {
123✔
2301
                // outgoingChanID is not a key in base index meaning this
58✔
2302
                // channel did not have the option-scid-alias feature bit
58✔
2303
                // negotiated. We'll fetch the link and return it.
58✔
2304
                link, ok := s.forwardingIndex[chanID]
58✔
2305
                if !ok {
60✔
2306
                        // The link wasn't found, bail out.
2✔
2307
                        return nil, ErrChannelLinkNotFound
2✔
2308
                }
2✔
2309

2310
                return link, nil
56✔
2311
        }
2312

2313
        // Fetch the link whose internal SCID is baseScid.
2314
        link, ok := s.forwardingIndex[baseScid]
7✔
2315
        if !ok {
7✔
2316
                // Link wasn't found, bail out.
×
2317
                return nil, ErrChannelLinkNotFound
×
2318
        }
×
2319

2320
        // If the link is unadvertised, we fail since the real SCID was used to
2321
        // forward over it and this is a channel where the option-scid-alias
2322
        // feature bit was negotiated.
2323
        if link.IsUnadvertised() {
9✔
2324
                return nil, ErrChannelLinkNotFound
2✔
2325
        }
2✔
2326

2327
        // The link is public so the confirmed SCID can be used to forward over
2328
        // it. We'll also replace pkt's outgoingChanID field so errors can
2329
        // properly be attributed in the calling function.
2330
        pkt.outgoingChanID = baseScid
5✔
2331
        return link, nil
5✔
2332
}
2333

2334
// HasActiveLink returns true if the given channel ID has a link in the link
2335
// index AND the link is eligible to forward.
2336
func (s *Switch) HasActiveLink(chanID lnwire.ChannelID) bool {
2✔
2337
        s.indexMtx.RLock()
2✔
2338
        defer s.indexMtx.RUnlock()
2✔
2339

2✔
2340
        if link, ok := s.linkIndex[chanID]; ok {
4✔
2341
                return link.EligibleToForward()
2✔
2342
        }
2✔
2343

UNCOV
2344
        return false
×
2345
}
2346

2347
// RemoveLink purges the switch of any link associated with chanID. If a pending
2348
// or active link is not found, this method does nothing. Otherwise, the method
2349
// returns after the link has been completely shutdown.
2350
func (s *Switch) RemoveLink(chanID lnwire.ChannelID) {
18✔
2351
        s.indexMtx.Lock()
18✔
2352
        link, err := s.getLink(chanID)
18✔
2353
        if err != nil {
18✔
UNCOV
2354
                // If err is non-nil, this means that link is also nil. The
×
UNCOV
2355
                // link variable cannot be nil without err being non-nil.
×
UNCOV
2356
                s.indexMtx.Unlock()
×
UNCOV
2357
                log.Tracef("Unable to remove link for ChannelID(%v): %v",
×
UNCOV
2358
                        chanID, err)
×
UNCOV
2359
                return
×
UNCOV
2360
        }
×
2361

2362
        // Check if the link is already stopping and grab the stop chan if it
2363
        // is.
2364
        stopChan, ok := s.linkStopIndex[chanID]
18✔
2365
        if !ok {
36✔
2366
                // If the link is non-nil, it is not currently stopping, so
18✔
2367
                // we'll add a stop chan to the linkStopIndex.
18✔
2368
                stopChan = make(chan struct{})
18✔
2369
                s.linkStopIndex[chanID] = stopChan
18✔
2370
        }
18✔
2371
        s.indexMtx.Unlock()
18✔
2372

18✔
2373
        if ok {
18✔
2374
                // If the stop chan exists, we will wait for it to be closed.
×
2375
                // Once it is closed, we will exit.
×
2376
                select {
×
2377
                case <-stopChan:
×
2378
                        return
×
NEW
2379
                case <-s.gm.Done():
×
2380
                        return
×
2381
                }
2382
        }
2383

2384
        // Stop the link before removing it from the maps.
2385
        link.Stop()
18✔
2386

18✔
2387
        s.indexMtx.Lock()
18✔
2388
        _ = s.removeLink(chanID)
18✔
2389

18✔
2390
        // Close stopChan and remove this link from the linkStopIndex.
18✔
2391
        // Deleting from the index and removing from the link must be done
18✔
2392
        // in the same block while the mutex is held.
18✔
2393
        close(stopChan)
18✔
2394
        delete(s.linkStopIndex, chanID)
18✔
2395
        s.indexMtx.Unlock()
18✔
2396
}
2397

2398
// removeLink is used to remove and stop the channel link.
2399
//
2400
// NOTE: This MUST be called with the indexMtx held.
2401
func (s *Switch) removeLink(chanID lnwire.ChannelID) ChannelLink {
311✔
2402
        log.Infof("Removing channel link with ChannelID(%v)", chanID)
311✔
2403

311✔
2404
        link, err := s.getLink(chanID)
311✔
2405
        if err != nil {
311✔
2406
                return nil
×
2407
        }
×
2408

2409
        // Remove the channel from live link indexes.
2410
        delete(s.pendingLinkIndex, link.ChanID())
311✔
2411
        delete(s.linkIndex, link.ChanID())
311✔
2412
        delete(s.forwardingIndex, link.ShortChanID())
311✔
2413

311✔
2414
        // If the link has been added to the peer index, then we'll move to
311✔
2415
        // delete the entry within the index.
311✔
2416
        peerPub := link.PeerPubKey()
311✔
2417
        if peerIndex, ok := s.interfaceIndex[peerPub]; ok {
621✔
2418
                delete(peerIndex, link.ChanID())
310✔
2419

310✔
2420
                // If after deletion, there are no longer any links, then we'll
310✔
2421
                // remove the interface map all together.
310✔
2422
                if len(peerIndex) == 0 {
615✔
2423
                        delete(s.interfaceIndex, peerPub)
305✔
2424
                }
305✔
2425
        }
2426

2427
        return link
311✔
2428
}
2429

2430
// UpdateShortChanID locates the link with the passed-in chanID and updates the
2431
// underlying channel state. This is only used in zero-conf channels to allow
2432
// the confirmed SCID to be updated.
2433
func (s *Switch) UpdateShortChanID(chanID lnwire.ChannelID) error {
1✔
2434
        s.indexMtx.Lock()
1✔
2435
        defer s.indexMtx.Unlock()
1✔
2436

1✔
2437
        // Locate the target link in the link index. If no such link exists,
1✔
2438
        // then we will ignore the request.
1✔
2439
        link, ok := s.linkIndex[chanID]
1✔
2440
        if !ok {
1✔
2441
                return fmt.Errorf("link %v not found", chanID)
×
2442
        }
×
2443

2444
        // Try to update the link's underlying channel state, returning early
2445
        // if this update failed.
2446
        _, err := link.UpdateShortChanID()
1✔
2447
        if err != nil {
1✔
2448
                return err
×
2449
        }
×
2450

2451
        // Since the zero-conf channel is confirmed, we should populate the
2452
        // aliasToReal map and update the baseIndex.
2453
        aliases := link.getAliases()
1✔
2454

1✔
2455
        confirmedScid := link.confirmedScid()
1✔
2456

1✔
2457
        for _, alias := range aliases {
3✔
2458
                s.aliasToReal[alias] = confirmedScid
2✔
2459
        }
2✔
2460

2461
        s.baseIndex[confirmedScid] = link.ShortChanID()
1✔
2462

1✔
2463
        return nil
1✔
2464
}
2465

2466
// GetLinksByInterface fetches all the links connected to a particular node
2467
// identified by the serialized compressed form of its public key.
2468
func (s *Switch) GetLinksByInterface(hop [33]byte) ([]ChannelUpdateHandler,
UNCOV
2469
        error) {
×
UNCOV
2470

×
UNCOV
2471
        s.indexMtx.RLock()
×
UNCOV
2472
        defer s.indexMtx.RUnlock()
×
UNCOV
2473

×
UNCOV
2474
        var handlers []ChannelUpdateHandler
×
UNCOV
2475

×
UNCOV
2476
        links, err := s.getLinks(hop)
×
UNCOV
2477
        if err != nil {
×
UNCOV
2478
                return nil, err
×
UNCOV
2479
        }
×
2480

2481
        // Range over the returned []ChannelLink to convert them into
2482
        // []ChannelUpdateHandler.
UNCOV
2483
        for _, link := range links {
×
UNCOV
2484
                handlers = append(handlers, link)
×
UNCOV
2485
        }
×
2486

UNCOV
2487
        return handlers, nil
×
2488
}
2489

2490
// getLinks is function which returns the channel links of the peer by hop
2491
// destination id.
2492
//
2493
// NOTE: This MUST be called with the indexMtx held.
2494
func (s *Switch) getLinks(destination [33]byte) ([]ChannelLink, error) {
76✔
2495
        links, ok := s.interfaceIndex[destination]
76✔
2496
        if !ok {
76✔
UNCOV
2497
                return nil, ErrNoLinksFound
×
UNCOV
2498
        }
×
2499

2500
        channelLinks := make([]ChannelLink, 0, len(links))
76✔
2501
        for _, link := range links {
156✔
2502
                channelLinks = append(channelLinks, link)
80✔
2503
        }
80✔
2504

2505
        return channelLinks, nil
76✔
2506
}
2507

2508
// CircuitModifier returns a reference to subset of the interfaces provided by
2509
// the circuit map, to allow links to open and close circuits.
2510
func (s *Switch) CircuitModifier() CircuitModifier {
215✔
2511
        return s.circuits
215✔
2512
}
215✔
2513

2514
// CircuitLookup returns a reference to subset of the interfaces provided by the
2515
// circuit map, to allow looking up circuits.
UNCOV
2516
func (s *Switch) CircuitLookup() CircuitLookup {
×
UNCOV
2517
        return s.circuits
×
UNCOV
2518
}
×
2519

2520
// commitCircuits persistently adds a circuit to the switch's circuit map.
2521
func (s *Switch) commitCircuits(circuits ...*PaymentCircuit) (
2522
        *CircuitFwdActions, error) {
17✔
2523

17✔
2524
        return s.circuits.CommitCircuits(circuits...)
17✔
2525
}
17✔
2526

2527
// FlushForwardingEvents flushes out the set of pending forwarding events to
2528
// the persistent log. This will be used by the switch to periodically flush
2529
// out the set of forwarding events to disk. External callers can also use this
2530
// method to ensure all data is flushed to dis before querying the log.
2531
func (s *Switch) FlushForwardingEvents() error {
210✔
2532
        // First, we'll obtain a copy of the current set of pending forwarding
210✔
2533
        // events.
210✔
2534
        s.fwdEventMtx.Lock()
210✔
2535

210✔
2536
        // If we won't have any forwarding events, then we can exit early.
210✔
2537
        if len(s.pendingFwdingEvents) == 0 {
403✔
2538
                s.fwdEventMtx.Unlock()
193✔
2539
                return nil
193✔
2540
        }
193✔
2541

2542
        events := make([]channeldb.ForwardingEvent, len(s.pendingFwdingEvents))
17✔
2543
        copy(events[:], s.pendingFwdingEvents[:])
17✔
2544

17✔
2545
        // With the copy obtained, we can now clear out the header pointer of
17✔
2546
        // the current slice. This way, we can re-use the underlying storage
17✔
2547
        // allocated for the slice.
17✔
2548
        s.pendingFwdingEvents = s.pendingFwdingEvents[:0]
17✔
2549
        s.fwdEventMtx.Unlock()
17✔
2550

17✔
2551
        // Finally, we'll write out the copied events to the persistent
17✔
2552
        // forwarding log.
17✔
2553
        return s.cfg.FwdingLog.AddForwardingEvents(events)
17✔
2554
}
2555

2556
// BestHeight returns the best height known to the switch.
2557
func (s *Switch) BestHeight() uint32 {
447✔
2558
        return atomic.LoadUint32(&s.bestHeight)
447✔
2559
}
447✔
2560

2561
// dustExceedsFeeThreshold takes in a ChannelLink, HTLC amount, and a boolean
2562
// to determine whether the default fee threshold has been exceeded. This
2563
// heuristic takes into account the trimmed-to-dust mechanism. The sum of the
2564
// commitment's dust with the mailbox's dust with the amount is checked against
2565
// the fee exposure threshold. If incoming is true, then the amount is not
2566
// included in the sum as it was already included in the commitment's dust. A
2567
// boolean is returned telling the caller whether the HTLC should be failed
2568
// back.
2569
func (s *Switch) dustExceedsFeeThreshold(link ChannelLink,
2570
        amount lnwire.MilliSatoshi, incoming bool) bool {
532✔
2571

532✔
2572
        // Retrieve the link's current commitment feerate and dustClosure.
532✔
2573
        feeRate := link.getFeeRate()
532✔
2574
        isDust := link.getDustClosure()
532✔
2575

532✔
2576
        // Evaluate if the HTLC is dust on either sides' commitment.
532✔
2577
        isLocalDust := isDust(
532✔
2578
                feeRate, incoming, lntypes.Local, amount.ToSatoshis(),
532✔
2579
        )
532✔
2580
        isRemoteDust := isDust(
532✔
2581
                feeRate, incoming, lntypes.Remote, amount.ToSatoshis(),
532✔
2582
        )
532✔
2583

532✔
2584
        if !(isLocalDust || isRemoteDust) {
664✔
2585
                // If the HTLC is not dust on either commitment, it's fine to
132✔
2586
                // forward.
132✔
2587
                return false
132✔
2588
        }
132✔
2589

2590
        // Fetch the dust sums currently in the mailbox for this link.
2591
        cid := link.ChanID()
400✔
2592
        sid := link.ShortChanID()
400✔
2593
        mailbox := s.mailOrchestrator.GetOrCreateMailBox(cid, sid)
400✔
2594
        localMailDust, remoteMailDust := mailbox.DustPackets()
400✔
2595

400✔
2596
        // If the htlc is dust on the local commitment, we'll obtain the dust
400✔
2597
        // sum for it.
400✔
2598
        if isLocalDust {
800✔
2599
                localSum := link.getDustSum(
400✔
2600
                        lntypes.Local, fn.None[chainfee.SatPerKWeight](),
400✔
2601
                )
400✔
2602
                localSum += localMailDust
400✔
2603

400✔
2604
                // Optionally include the HTLC amount only for outgoing
400✔
2605
                // HTLCs.
400✔
2606
                if !incoming {
760✔
2607
                        localSum += amount
360✔
2608
                }
360✔
2609

2610
                // Finally check against the defined fee threshold.
2611
                if localSum > s.cfg.MaxFeeExposure {
402✔
2612
                        return true
2✔
2613
                }
2✔
2614
        }
2615

2616
        // Also check if the htlc is dust on the remote commitment, if we've
2617
        // reached this point.
2618
        if isRemoteDust {
796✔
2619
                remoteSum := link.getDustSum(
398✔
2620
                        lntypes.Remote, fn.None[chainfee.SatPerKWeight](),
398✔
2621
                )
398✔
2622
                remoteSum += remoteMailDust
398✔
2623

398✔
2624
                // Optionally include the HTLC amount only for outgoing
398✔
2625
                // HTLCs.
398✔
2626
                if !incoming {
756✔
2627
                        remoteSum += amount
358✔
2628
                }
358✔
2629

2630
                // Finally check against the defined fee threshold.
2631
                if remoteSum > s.cfg.MaxFeeExposure {
398✔
2632
                        return true
×
2633
                }
×
2634
        }
2635

2636
        // If we reached this point, this HTLC is fine to forward.
2637
        return false
398✔
2638
}
2639

2640
// failMailboxUpdate is passed to the mailbox orchestrator which in turn passes
2641
// it to individual mailboxes. It allows the mailboxes to construct a
2642
// FailureMessage when failing back HTLC's due to expiry and may include an
2643
// alias in the ShortChannelID field. The outgoingScid is the SCID originally
2644
// used in the onion. The mailboxScid is the SCID that the mailbox and link
2645
// use. The mailboxScid is only used in the non-alias case, so it is always
2646
// the confirmed SCID.
2647
func (s *Switch) failMailboxUpdate(outgoingScid,
2648
        mailboxScid lnwire.ShortChannelID) lnwire.FailureMessage {
11✔
2649

11✔
2650
        // Try to use the failAliasUpdate function in case this is a channel
11✔
2651
        // that uses aliases. If it returns nil, we'll fallback to the original
11✔
2652
        // pre-alias behavior.
11✔
2653
        update := s.failAliasUpdate(outgoingScid, false)
11✔
2654
        if update == nil {
16✔
2655
                // Execute the fallback behavior.
5✔
2656
                var err error
5✔
2657
                update, err = s.cfg.FetchLastChannelUpdate(mailboxScid)
5✔
2658
                if err != nil {
5✔
2659
                        return &lnwire.FailTemporaryNodeFailure{}
×
2660
                }
×
2661
        }
2662

2663
        return lnwire.NewTemporaryChannelFailure(update)
11✔
2664
}
2665

2666
// failAliasUpdate prepares a ChannelUpdate for a failed incoming or outgoing
2667
// HTLC on a channel where the option-scid-alias feature bit was negotiated. If
2668
// the associated channel is not one of these, this function will return nil
2669
// and the caller is expected to handle this properly. In this case, a return
2670
// to the original non-alias behavior is expected.
2671
func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID,
2672
        incoming bool) *lnwire.ChannelUpdate1 {
34✔
2673

34✔
2674
        // This function does not defer the unlocking because of the database
34✔
2675
        // lookups for ChannelUpdate.
34✔
2676
        s.indexMtx.RLock()
34✔
2677

34✔
2678
        if s.cfg.IsAlias(scid) {
45✔
2679
                // The alias SCID was used. In the incoming case this means
11✔
2680
                // the channel is zero-conf as the link sets the scid. In the
11✔
2681
                // outgoing case, the sender set the scid to use and may be
11✔
2682
                // either the alias or the confirmed one, if it exists.
11✔
2683
                realScid, ok := s.aliasToReal[scid]
11✔
2684
                if !ok {
11✔
2685
                        // The real, confirmed SCID does not exist yet. Find
×
2686
                        // the "base" SCID that the link uses via the
×
2687
                        // baseIndex. If we can't find it, return nil. This
×
2688
                        // means the channel is zero-conf.
×
2689
                        baseScid, ok := s.baseIndex[scid]
×
2690
                        s.indexMtx.RUnlock()
×
2691
                        if !ok {
×
2692
                                return nil
×
2693
                        }
×
2694

2695
                        update, err := s.cfg.FetchLastChannelUpdate(baseScid)
×
2696
                        if err != nil {
×
2697
                                return nil
×
2698
                        }
×
2699

2700
                        // Replace the baseScid with the passed-in alias.
2701
                        update.ShortChannelID = scid
×
2702
                        sig, err := s.cfg.SignAliasUpdate(update)
×
2703
                        if err != nil {
×
2704
                                return nil
×
2705
                        }
×
2706

2707
                        update.Signature, err = lnwire.NewSigFromSignature(sig)
×
2708
                        if err != nil {
×
2709
                                return nil
×
2710
                        }
×
2711

2712
                        return update
×
2713
                }
2714

2715
                s.indexMtx.RUnlock()
11✔
2716

11✔
2717
                // Fetch the SCID via the confirmed SCID and replace it with
11✔
2718
                // the alias.
11✔
2719
                update, err := s.cfg.FetchLastChannelUpdate(realScid)
11✔
2720
                if err != nil {
11✔
UNCOV
2721
                        return nil
×
UNCOV
2722
                }
×
2723

2724
                // In the incoming case, we want to ensure that we don't leak
2725
                // the UTXO in case the channel is private. In the outgoing
2726
                // case, since the alias was used, we do the same thing.
2727
                update.ShortChannelID = scid
11✔
2728
                sig, err := s.cfg.SignAliasUpdate(update)
11✔
2729
                if err != nil {
11✔
2730
                        return nil
×
2731
                }
×
2732

2733
                update.Signature, err = lnwire.NewSigFromSignature(sig)
11✔
2734
                if err != nil {
11✔
2735
                        return nil
×
2736
                }
×
2737

2738
                return update
11✔
2739
        }
2740

2741
        // If the confirmed SCID is not in baseIndex, this is not an
2742
        // option-scid-alias or zero-conf channel.
2743
        baseScid, ok := s.baseIndex[scid]
23✔
2744
        if !ok {
41✔
2745
                s.indexMtx.RUnlock()
18✔
2746
                return nil
18✔
2747
        }
18✔
2748

2749
        // Fetch the link so we can get an alias to use in the ShortChannelID
2750
        // of the ChannelUpdate.
2751
        link, ok := s.forwardingIndex[baseScid]
5✔
2752
        s.indexMtx.RUnlock()
5✔
2753
        if !ok {
5✔
2754
                // This should never happen, but if it does for some reason,
×
2755
                // fallback to the old behavior.
×
2756
                return nil
×
2757
        }
×
2758

2759
        aliases := link.getAliases()
5✔
2760
        if len(aliases) == 0 {
5✔
2761
                // This should never happen, but if it does, fallback.
×
2762
                return nil
×
2763
        }
×
2764

2765
        // Fetch the ChannelUpdate via the real, confirmed SCID.
2766
        update, err := s.cfg.FetchLastChannelUpdate(scid)
5✔
2767
        if err != nil {
5✔
2768
                return nil
×
2769
        }
×
2770

2771
        // The incoming case will replace the ShortChannelID in the retrieved
2772
        // ChannelUpdate with the alias to ensure no privacy leak occurs. This
2773
        // would happen if a private non-zero-conf option-scid-alias
2774
        // feature-bit channel leaked its UTXO here rather than supplying an
2775
        // alias. In the outgoing case, the confirmed SCID was actually used
2776
        // for forwarding in the onion, so no replacement is necessary as the
2777
        // sender knows the scid.
2778
        if incoming {
7✔
2779
                // We will replace and sign the update with the first alias.
2✔
2780
                // Since this happens on the incoming side, it's not actually
2✔
2781
                // possible to know what the sender used in the onion.
2✔
2782
                update.ShortChannelID = aliases[0]
2✔
2783
                sig, err := s.cfg.SignAliasUpdate(update)
2✔
2784
                if err != nil {
2✔
2785
                        return nil
×
2786
                }
×
2787

2788
                update.Signature, err = lnwire.NewSigFromSignature(sig)
2✔
2789
                if err != nil {
2✔
2790
                        return nil
×
2791
                }
×
2792
        }
2793

2794
        return update
5✔
2795
}
2796

2797
// AddAliasForLink instructs the Switch to update its in-memory maps to reflect
2798
// that a link has a new alias.
2799
func (s *Switch) AddAliasForLink(chanID lnwire.ChannelID,
2800
        alias lnwire.ShortChannelID) error {
×
2801

×
2802
        // Fetch the link so that we can update the underlying channel's set of
×
2803
        // aliases.
×
2804
        s.indexMtx.RLock()
×
2805
        link, err := s.getLink(chanID)
×
2806
        s.indexMtx.RUnlock()
×
2807
        if err != nil {
×
2808
                return err
×
2809
        }
×
2810

2811
        // If the link is a channel where the option-scid-alias feature bit was
2812
        // not negotiated, we'll return an error.
2813
        if !link.negotiatedAliasFeature() {
×
2814
                return fmt.Errorf("attempted to update non-alias channel")
×
2815
        }
×
2816

2817
        linkScid := link.ShortChanID()
×
2818

×
2819
        // We'll update the maps so the Switch includes this alias in its
×
2820
        // forwarding decisions.
×
2821
        if link.isZeroConf() {
×
2822
                if link.zeroConfConfirmed() {
×
2823
                        // If the channel has confirmed on-chain, we'll
×
2824
                        // add this alias to the aliasToReal map.
×
2825
                        confirmedScid := link.confirmedScid()
×
2826

×
2827
                        s.aliasToReal[alias] = confirmedScid
×
2828
                }
×
2829

2830
                // Add this alias to the baseIndex mapping.
2831
                s.baseIndex[alias] = linkScid
×
2832
        } else if link.negotiatedAliasFeature() {
×
2833
                // The channel is confirmed, so we'll populate the aliasToReal
×
2834
                // and baseIndex maps.
×
2835
                s.aliasToReal[alias] = linkScid
×
2836
                s.baseIndex[alias] = linkScid
×
2837
        }
×
2838

2839
        return nil
×
2840
}
2841

2842
// handlePacketAdd handles forwarding an Add packet.
2843
func (s *Switch) handlePacketAdd(packet *htlcPacket,
2844
        htlc *lnwire.UpdateAddHTLC) error {
82✔
2845

82✔
2846
        // Check if the node is set to reject all onward HTLCs and also make
82✔
2847
        // sure that HTLC is not from the source node.
82✔
2848
        if s.cfg.RejectHTLC {
83✔
2849
                failure := NewDetailedLinkError(
1✔
2850
                        &lnwire.FailChannelDisabled{},
1✔
2851
                        OutgoingFailureForwardsDisabled,
1✔
2852
                )
1✔
2853

1✔
2854
                return s.failAddPacket(packet, failure)
1✔
2855
        }
1✔
2856

2857
        // Before we attempt to find a non-strict forwarding path for this
2858
        // htlc, check whether the htlc is being routed over the same incoming
2859
        // and outgoing channel. If our node does not allow forwards of this
2860
        // nature, we fail the htlc early. This check is in place to disallow
2861
        // inefficiently routed htlcs from locking up our balance. With
2862
        // channels where the option-scid-alias feature was negotiated, we also
2863
        // have to be sure that the IDs aren't the same since one or both could
2864
        // be an alias.
2865
        linkErr := s.checkCircularForward(
81✔
2866
                packet.incomingChanID, packet.outgoingChanID,
81✔
2867
                s.cfg.AllowCircularRoute, htlc.PaymentHash,
81✔
2868
        )
81✔
2869
        if linkErr != nil {
82✔
2870
                return s.failAddPacket(packet, linkErr)
1✔
2871
        }
1✔
2872

2873
        s.indexMtx.RLock()
80✔
2874
        targetLink, err := s.getLinkByMapping(packet)
80✔
2875
        if err != nil {
84✔
2876
                s.indexMtx.RUnlock()
4✔
2877

4✔
2878
                log.Debugf("unable to find link with "+
4✔
2879
                        "destination %v", packet.outgoingChanID)
4✔
2880

4✔
2881
                // If packet was forwarded from another channel link than we
4✔
2882
                // should notify this link that some error occurred.
4✔
2883
                linkError := NewLinkError(
4✔
2884
                        &lnwire.FailUnknownNextPeer{},
4✔
2885
                )
4✔
2886

4✔
2887
                return s.failAddPacket(packet, linkError)
4✔
2888
        }
4✔
2889
        targetPeerKey := targetLink.PeerPubKey()
76✔
2890
        interfaceLinks, _ := s.getLinks(targetPeerKey)
76✔
2891
        s.indexMtx.RUnlock()
76✔
2892

76✔
2893
        // We'll keep track of any HTLC failures during the link selection
76✔
2894
        // process. This way we can return the error for precise link that the
76✔
2895
        // sender selected, while optimistically trying all links to utilize
76✔
2896
        // our available bandwidth.
76✔
2897
        linkErrs := make(map[lnwire.ShortChannelID]*LinkError)
76✔
2898

76✔
2899
        // Find all destination channel links with appropriate bandwidth.
76✔
2900
        var destinations []ChannelLink
76✔
2901
        for _, link := range interfaceLinks {
156✔
2902
                var failure *LinkError
80✔
2903

80✔
2904
                // We'll skip any links that aren't yet eligible for
80✔
2905
                // forwarding.
80✔
2906
                if !link.EligibleToForward() {
84✔
2907
                        failure = NewDetailedLinkError(
4✔
2908
                                &lnwire.FailUnknownNextPeer{},
4✔
2909
                                OutgoingFailureLinkNotEligible,
4✔
2910
                        )
4✔
2911
                } else {
80✔
2912
                        // We'll ensure that the HTLC satisfies the current
76✔
2913
                        // forwarding conditions of this target link.
76✔
2914
                        currentHeight := atomic.LoadUint32(&s.bestHeight)
76✔
2915
                        failure = link.CheckHtlcForward(
76✔
2916
                                htlc.PaymentHash, packet.incomingAmount,
76✔
2917
                                packet.amount, packet.incomingTimeout,
76✔
2918
                                packet.outgoingTimeout, packet.inboundFee,
76✔
2919
                                currentHeight, packet.originalOutgoingChanID,
76✔
2920
                                htlc.CustomRecords,
76✔
2921
                        )
76✔
2922
                }
76✔
2923

2924
                // If this link can forward the htlc, add it to the set of
2925
                // destinations.
2926
                if failure == nil {
140✔
2927
                        destinations = append(destinations, link)
60✔
2928
                        continue
60✔
2929
                }
2930

2931
                linkErrs[link.ShortChanID()] = failure
20✔
2932
        }
2933

2934
        // If we had a forwarding failure due to the HTLC not satisfying the
2935
        // current policy, then we'll send back an error, but ensure we send
2936
        // back the error sourced at the *target* link.
2937
        if len(destinations) == 0 {
92✔
2938
                // At this point, some or all of the links rejected the HTLC so
16✔
2939
                // we couldn't forward it. So we'll try to look up the error
16✔
2940
                // that came from the source.
16✔
2941
                linkErr, ok := linkErrs[packet.outgoingChanID]
16✔
2942
                if !ok {
16✔
2943
                        // If we can't find the error of the source, then we'll
×
2944
                        // return an unknown next peer, though this should
×
2945
                        // never happen.
×
2946
                        linkErr = NewLinkError(
×
2947
                                &lnwire.FailUnknownNextPeer{},
×
2948
                        )
×
2949
                        log.Warnf("unable to find err source for "+
×
2950
                                "outgoing_link=%v, errors=%v",
×
2951
                                packet.outgoingChanID,
×
2952
                                lnutils.SpewLogClosure(linkErrs))
×
2953
                }
×
2954

2955
                log.Tracef("incoming HTLC(%x) violated "+
16✔
2956
                        "target outgoing link (id=%v) policy: %v",
16✔
2957
                        htlc.PaymentHash[:], packet.outgoingChanID,
16✔
2958
                        linkErr)
16✔
2959

16✔
2960
                return s.failAddPacket(packet, linkErr)
16✔
2961
        }
2962

2963
        // Choose a random link out of the set of links that can forward this
2964
        // htlc. The reason for randomization is to evenly distribute the htlc
2965
        // load without making assumptions about what the best channel is.
2966
        //nolint:gosec
2967
        destination := destinations[rand.Intn(len(destinations))]
60✔
2968

60✔
2969
        // Retrieve the incoming link by its ShortChannelID. Note that the
60✔
2970
        // incomingChanID is never set to hop.Source here.
60✔
2971
        s.indexMtx.RLock()
60✔
2972
        incomingLink, err := s.getLinkByShortID(packet.incomingChanID)
60✔
2973
        s.indexMtx.RUnlock()
60✔
2974
        if err != nil {
60✔
2975
                // If we couldn't find the incoming link, we can't evaluate the
×
2976
                // incoming's exposure to dust, so we just fail the HTLC back.
×
2977
                linkErr := NewLinkError(
×
2978
                        &lnwire.FailTemporaryChannelFailure{},
×
2979
                )
×
2980

×
2981
                return s.failAddPacket(packet, linkErr)
×
2982
        }
×
2983

2984
        // Evaluate whether this HTLC would increase our fee exposure over the
2985
        // threshold on the incoming link. If it does, fail it backwards.
2986
        if s.dustExceedsFeeThreshold(
60✔
2987
                incomingLink, packet.incomingAmount, true,
60✔
2988
        ) {
60✔
2989
                // The incoming dust exceeds the threshold, so we fail the add
×
2990
                // back.
×
2991
                linkErr := NewLinkError(
×
2992
                        &lnwire.FailTemporaryChannelFailure{},
×
2993
                )
×
2994

×
2995
                return s.failAddPacket(packet, linkErr)
×
2996
        }
×
2997

2998
        // Also evaluate whether this HTLC would increase our fee exposure over
2999
        // the threshold on the destination link. If it does, fail it back.
3000
        if s.dustExceedsFeeThreshold(
60✔
3001
                destination, packet.amount, false,
60✔
3002
        ) {
61✔
3003
                // The outgoing dust exceeds the threshold, so we fail the add
1✔
3004
                // back.
1✔
3005
                linkErr := NewLinkError(
1✔
3006
                        &lnwire.FailTemporaryChannelFailure{},
1✔
3007
                )
1✔
3008

1✔
3009
                return s.failAddPacket(packet, linkErr)
1✔
3010
        }
1✔
3011

3012
        // Send the packet to the destination channel link which manages the
3013
        // channel.
3014
        packet.outgoingChanID = destination.ShortChanID()
59✔
3015

59✔
3016
        return destination.handleSwitchPacket(packet)
59✔
3017
}
3018

3019
// handlePacketSettle handles forwarding a settle packet.
3020
func (s *Switch) handlePacketSettle(packet *htlcPacket) error {
399✔
3021
        // If the source of this packet has not been set, use the circuit map
399✔
3022
        // to lookup the origin.
399✔
3023
        circuit, err := s.closeCircuit(packet)
399✔
3024
        if err != nil {
399✔
UNCOV
3025
                return err
×
UNCOV
3026
        }
×
3027

3028
        // closeCircuit returns a nil circuit when a settle packet returns an
3029
        // ErrUnknownCircuit error upon the inner call to CloseCircuit.
3030
        //
3031
        // NOTE: We can only get a nil circuit when it has already been deleted
3032
        // and when `UpdateFulfillHTLC` is received. After which `RevokeAndAck`
3033
        // is received, which invokes `processRemoteSettleFails` in its link.
3034
        if circuit == nil {
589✔
3035
                log.Debugf("Found nil circuit: packet=%v", spew.Sdump(packet))
190✔
3036
                return nil
190✔
3037
        }
190✔
3038

3039
        localHTLC := packet.incomingChanID == hop.Source
209✔
3040

209✔
3041
        // If this is a locally initiated HTLC, we need to handle the packet by
209✔
3042
        // storing the network result.
209✔
3043
        //
209✔
3044
        // A blank IncomingChanID in a circuit indicates that it is a pending
209✔
3045
        // user-initiated payment.
209✔
3046
        //
209✔
3047
        // NOTE: `closeCircuit` modifies the state of `packet`.
209✔
3048
        if localHTLC {
389✔
3049
                // TODO(yy): remove the goroutine and send back the error here.
180✔
3050
                ok := s.gm.Go(background, func(ctx context.Context) {
360✔
3051
                        s.handleLocalResponse(packet)
180✔
3052
                })
180✔
3053
                if !ok {
180✔
NEW
3054
                        return ErrSwitchExiting
×
NEW
3055
                }
×
3056

3057
                // If this is a locally initiated HTLC, there's no need to
3058
                // forward it so we exit.
3059
                return nil
180✔
3060
        }
3061

3062
        // If this is an HTLC settle, and it wasn't from a locally initiated
3063
        // HTLC, then we'll log a forwarding event so we can flush it to disk
3064
        // later.
3065
        if circuit.Outgoing != nil {
58✔
3066
                log.Infof("Forwarded HTLC(%x) of %v (fee: %v) "+
29✔
3067
                        "from IncomingChanID(%v) to OutgoingChanID(%v)",
29✔
3068
                        circuit.PaymentHash[:], circuit.OutgoingAmount,
29✔
3069
                        circuit.IncomingAmount-circuit.OutgoingAmount,
29✔
3070
                        circuit.Incoming.ChanID, circuit.Outgoing.ChanID)
29✔
3071

29✔
3072
                s.fwdEventMtx.Lock()
29✔
3073
                s.pendingFwdingEvents = append(
29✔
3074
                        s.pendingFwdingEvents,
29✔
3075
                        channeldb.ForwardingEvent{
29✔
3076
                                Timestamp:      time.Now(),
29✔
3077
                                IncomingChanID: circuit.Incoming.ChanID,
29✔
3078
                                OutgoingChanID: circuit.Outgoing.ChanID,
29✔
3079
                                AmtIn:          circuit.IncomingAmount,
29✔
3080
                                AmtOut:         circuit.OutgoingAmount,
29✔
3081
                        },
29✔
3082
                )
29✔
3083
                s.fwdEventMtx.Unlock()
29✔
3084
        }
29✔
3085

3086
        // Deliver this packet.
3087
        return s.mailOrchestrator.Deliver(packet.incomingChanID, packet)
29✔
3088
}
3089

3090
// handlePacketFail handles forwarding a fail packet.
3091
func (s *Switch) handlePacketFail(packet *htlcPacket,
3092
        htlc *lnwire.UpdateFailHTLC) error {
138✔
3093

138✔
3094
        // If the source of this packet has not been set, use the circuit map
138✔
3095
        // to lookup the origin.
138✔
3096
        circuit, err := s.closeCircuit(packet)
138✔
3097
        if err != nil {
138✔
UNCOV
3098
                return err
×
UNCOV
3099
        }
×
3100

3101
        // If this is a locally initiated HTLC, we need to handle the packet by
3102
        // storing the network result.
3103
        //
3104
        // A blank IncomingChanID in a circuit indicates that it is a pending
3105
        // user-initiated payment.
3106
        //
3107
        // NOTE: `closeCircuit` modifies the state of `packet`.
3108
        if packet.incomingChanID == hop.Source {
262✔
3109
                // TODO(yy): remove the goroutine and send back the error here.
124✔
3110
                ok := s.gm.Go(background, func(ctx context.Context) {
248✔
3111
                        s.handleLocalResponse(packet)
124✔
3112
                })
124✔
3113
                if !ok {
124✔
NEW
3114
                        return ErrSwitchExiting
×
NEW
3115
                }
×
3116

3117
                // If this is a locally initiated HTLC, there's no need to
3118
                // forward it so we exit.
3119
                return nil
124✔
3120
        }
3121

3122
        // Exit early if this hasSource is true. This flag is only set via
3123
        // mailbox's `FailAdd`. This method has two callsites,
3124
        // - the packet has timed out after `MailboxDeliveryTimeout`, defaults
3125
        //   to 1 min.
3126
        // - the HTLC fails the validation in `channel.AddHTLC`.
3127
        // In either case, the `Reason` field is populated. Thus there's no
3128
        // need to proceed and extract the failure reason below.
3129
        if packet.hasSource {
21✔
3130
                // Deliver this packet.
7✔
3131
                return s.mailOrchestrator.Deliver(packet.incomingChanID, packet)
7✔
3132
        }
7✔
3133

3134
        // HTLC resolutions and messages restored from disk don't have the
3135
        // obfuscator set from the original htlc add packet - set it here for
3136
        // use in blinded errors.
3137
        packet.obfuscator = circuit.ErrorEncrypter
7✔
3138

7✔
3139
        switch {
7✔
3140
        // No message to encrypt, locally sourced payment.
3141
        case circuit.ErrorEncrypter == nil:
×
3142
                // TODO(yy) further check this case as we shouldn't end up here
3143
                // as `isLocal` is already false.
3144

3145
        // If this is a resolution message, then we'll need to encrypt it as
3146
        // it's actually internally sourced.
UNCOV
3147
        case packet.isResolution:
×
UNCOV
3148
                var err error
×
UNCOV
3149
                // TODO(roasbeef): don't need to pass actually?
×
UNCOV
3150
                failure := &lnwire.FailPermanentChannelFailure{}
×
UNCOV
3151
                htlc.Reason, err = circuit.ErrorEncrypter.EncryptFirstHop(
×
UNCOV
3152
                        failure,
×
UNCOV
3153
                )
×
UNCOV
3154
                if err != nil {
×
3155
                        err = fmt.Errorf("unable to obfuscate error: %w", err)
×
3156
                        log.Error(err)
×
3157
                }
×
3158

3159
        // Alternatively, if the remote party sends us an
3160
        // UpdateFailMalformedHTLC, then we'll need to convert this into a
3161
        // proper well formatted onion error as there's no HMAC currently.
3162
        case packet.convertedError:
2✔
3163
                log.Infof("Converting malformed HTLC error for circuit for "+
2✔
3164
                        "Circuit(%x: (%s, %d) <-> (%s, %d))",
2✔
3165
                        packet.circuit.PaymentHash,
2✔
3166
                        packet.incomingChanID, packet.incomingHTLCID,
2✔
3167
                        packet.outgoingChanID, packet.outgoingHTLCID)
2✔
3168

2✔
3169
                htlc.Reason = circuit.ErrorEncrypter.EncryptMalformedError(
2✔
3170
                        htlc.Reason,
2✔
3171
                )
2✔
3172

3173
        default:
5✔
3174
                // Otherwise, it's a forwarded error, so we'll perform a
5✔
3175
                // wrapper encryption as normal.
5✔
3176
                htlc.Reason = circuit.ErrorEncrypter.IntermediateEncrypt(
5✔
3177
                        htlc.Reason,
5✔
3178
                )
5✔
3179
        }
3180

3181
        // Deliver this packet.
3182
        return s.mailOrchestrator.Deliver(packet.incomingChanID, packet)
7✔
3183
}
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