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

lightningnetwork / lnd / 17832014233

18 Sep 2025 02:30PM UTC coverage: 57.196% (-9.4%) from 66.637%
17832014233

Pull #10133

github

web-flow
Merge 3e12b2767 into b34fc964b
Pull Request #10133: Add `XFindBaseLocalChanAlias` RPC

20 of 34 new or added lines in 4 files covered. (58.82%)

28528 existing lines in 459 files now uncovered.

99371 of 173739 relevant lines covered (57.2%)

1.78 hits per line

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

68.05
/lnrpc/routerrpc/router_backend.go
1
package routerrpc
2

3
import (
4
        "context"
5
        "crypto/rand"
6
        "encoding/hex"
7
        "errors"
8
        "fmt"
9
        math "math"
10
        "time"
11

12
        "github.com/btcsuite/btcd/btcec/v2"
13
        "github.com/btcsuite/btcd/btcutil"
14
        "github.com/btcsuite/btcd/chaincfg"
15
        "github.com/btcsuite/btcd/wire"
16
        sphinx "github.com/lightningnetwork/lightning-onion"
17
        "github.com/lightningnetwork/lnd/clock"
18
        "github.com/lightningnetwork/lnd/feature"
19
        "github.com/lightningnetwork/lnd/fn/v2"
20
        "github.com/lightningnetwork/lnd/htlcswitch"
21
        "github.com/lightningnetwork/lnd/lnrpc"
22
        "github.com/lightningnetwork/lnd/lntypes"
23
        "github.com/lightningnetwork/lnd/lnwire"
24
        paymentsdb "github.com/lightningnetwork/lnd/payments/db"
25
        "github.com/lightningnetwork/lnd/record"
26
        "github.com/lightningnetwork/lnd/routing"
27
        "github.com/lightningnetwork/lnd/routing/route"
28
        "github.com/lightningnetwork/lnd/subscribe"
29
        "github.com/lightningnetwork/lnd/zpay32"
30
        "google.golang.org/protobuf/proto"
31
)
32

33
const (
34
        // DefaultMaxParts is the default number of splits we'll possibly use
35
        // for MPP when the user is attempting to send a payment.
36
        //
37
        // TODO(roasbeef): make this value dynamic based on expected number of
38
        // attempts for given amount.
39
        DefaultMaxParts = 16
40

41
        // MaxPartsUpperLimit defines the maximum allowable number of splits
42
        // for MPP/AMP when the user is attempting to send a payment.
43
        MaxPartsUpperLimit = 1000
44
)
45

46
// RouterBackend contains the backend implementation of the router rpc sub
47
// server calls.
48
type RouterBackend struct {
49
        // SelfNode is the vertex of the node sending the payment.
50
        SelfNode route.Vertex
51

52
        // FetchChannelCapacity is a closure that we'll use the fetch the total
53
        // capacity of a channel to populate in responses.
54
        FetchChannelCapacity func(chanID uint64) (btcutil.Amount, error)
55

56
        // FetchAmountPairCapacity determines the maximal channel capacity
57
        // between two nodes given a certain amount.
58
        FetchAmountPairCapacity func(nodeFrom, nodeTo route.Vertex,
59
                amount lnwire.MilliSatoshi) (btcutil.Amount, error)
60

61
        // FetchChannelEndpoints returns the pubkeys of both endpoints of the
62
        // given channel id.
63
        FetchChannelEndpoints func(chanID uint64) (route.Vertex,
64
                route.Vertex, error)
65

66
        // FindRoute is a closure that abstracts away how we locate/query for
67
        // routes.
68
        FindRoute func(*routing.RouteRequest) (*route.Route, float64, error)
69

70
        MissionControl MissionControl
71

72
        // ActiveNetParams are the network parameters of the primary network
73
        // that the route is operating on. This is necessary so we can ensure
74
        // that we receive payment requests that send to destinations on our
75
        // network.
76
        ActiveNetParams *chaincfg.Params
77

78
        // Tower is the ControlTower instance that is used to track pending
79
        // payments.
80
        Tower routing.ControlTower
81

82
        // MaxTotalTimelock is the maximum total time lock a route is allowed to
83
        // have.
84
        MaxTotalTimelock uint32
85

86
        // DefaultFinalCltvDelta is the default value used as final cltv delta
87
        // when an RPC caller doesn't specify a value.
88
        DefaultFinalCltvDelta uint16
89

90
        // SubscribeHtlcEvents returns a subscription client for the node's
91
        // htlc events.
92
        SubscribeHtlcEvents func() (*subscribe.Client, error)
93

94
        // InterceptableForwarder exposes the ability to intercept forward events
95
        // by letting the router register a ForwardInterceptor.
96
        InterceptableForwarder htlcswitch.InterceptableHtlcForwarder
97

98
        // SetChannelEnabled exposes the ability to manually enable a channel.
99
        SetChannelEnabled func(wire.OutPoint) error
100

101
        // SetChannelDisabled exposes the ability to manually disable a channel
102
        SetChannelDisabled func(wire.OutPoint) error
103

104
        // SetChannelAuto exposes the ability to restore automatic channel state
105
        // management after manually setting channel status.
106
        SetChannelAuto func(wire.OutPoint) error
107

108
        // UseStatusInitiated is a boolean that indicates whether the router
109
        // should use the new status code `Payment_INITIATED`.
110
        //
111
        // TODO(yy): remove this config after the new status code is fully
112
        // deployed to the network(v0.20.0).
113
        UseStatusInitiated bool
114

115
        // ParseCustomChannelData is a function that can be used to parse custom
116
        // channel data from the first hop of a route.
117
        ParseCustomChannelData func(message proto.Message) error
118

119
        // ShouldSetExpEndorsement returns a boolean indicating whether the
120
        // experimental endorsement bit should be set.
121
        ShouldSetExpEndorsement func() bool
122

123
        // Clock is the clock used to validate payment requests expiry.
124
        // It is useful for testing.
125
        Clock clock.Clock
126
}
127

128
// MissionControl defines the mission control dependencies of routerrpc.
129
type MissionControl interface {
130
        // GetProbability is expected to return the success probability of a
131
        // payment from fromNode to toNode.
132
        GetProbability(fromNode, toNode route.Vertex,
133
                amt lnwire.MilliSatoshi, capacity btcutil.Amount) float64
134

135
        // ResetHistory resets the history of MissionControl returning it to a
136
        // state as if no payment attempts have been made.
137
        ResetHistory() error
138

139
        // GetHistorySnapshot takes a snapshot from the current mission control
140
        // state and actual probability estimates.
141
        GetHistorySnapshot() *routing.MissionControlSnapshot
142

143
        // ImportHistory imports the mission control snapshot to our internal
144
        // state. This import will only be applied in-memory, and will not be
145
        // persisted across restarts.
146
        ImportHistory(snapshot *routing.MissionControlSnapshot, force bool) error
147

148
        // GetPairHistorySnapshot returns the stored history for a given node
149
        // pair.
150
        GetPairHistorySnapshot(fromNode,
151
                toNode route.Vertex) routing.TimedPairResult
152

153
        // GetConfig gets mission control's current config.
154
        GetConfig() *routing.MissionControlConfig
155

156
        // SetConfig sets mission control's config to the values provided, if
157
        // they are valid.
158
        SetConfig(cfg *routing.MissionControlConfig) error
159
}
160

161
// QueryRoutes attempts to query the daemons' Channel Router for a possible
162
// route to a target destination capable of carrying a specific amount of
163
// satoshis within the route's flow. The returned route contains the full
164
// details required to craft and send an HTLC, also including the necessary
165
// information that should be present within the Sphinx packet encapsulated
166
// within the HTLC.
167
//
168
// TODO(roasbeef): should return a slice of routes in reality * create separate
169
// PR to send based on well formatted route
170
func (r *RouterBackend) QueryRoutes(ctx context.Context,
171
        in *lnrpc.QueryRoutesRequest) (*lnrpc.QueryRoutesResponse, error) {
3✔
172

3✔
173
        routeReq, err := r.parseQueryRoutesRequest(in)
3✔
174
        if err != nil {
3✔
UNCOV
175
                return nil, err
×
UNCOV
176
        }
×
177

178
        // Query the channel router for a possible path to the destination that
179
        // can carry `in.Amt` satoshis _including_ the total fee required on
180
        // the route
181
        route, successProb, err := r.FindRoute(routeReq)
3✔
182
        if err != nil {
3✔
183
                return nil, err
×
184
        }
×
185

186
        // For each valid route, we'll convert the result into the format
187
        // required by the RPC system.
188
        rpcRoute, err := r.MarshallRoute(route)
3✔
189
        if err != nil {
3✔
190
                return nil, err
×
191
        }
×
192

193
        routeResp := &lnrpc.QueryRoutesResponse{
3✔
194
                Routes:      []*lnrpc.Route{rpcRoute},
3✔
195
                SuccessProb: successProb,
3✔
196
        }
3✔
197

3✔
198
        return routeResp, nil
3✔
199
}
200

201
func parsePubKey(key string) (route.Vertex, error) {
3✔
202
        pubKeyBytes, err := hex.DecodeString(key)
3✔
203
        if err != nil {
3✔
204
                return route.Vertex{}, err
×
205
        }
×
206

207
        return route.NewVertexFromBytes(pubKeyBytes)
3✔
208
}
209

210
func (r *RouterBackend) parseIgnored(in *lnrpc.QueryRoutesRequest) (
211
        map[route.Vertex]struct{}, map[routing.DirectedNodePair]struct{},
212
        error) {
3✔
213

3✔
214
        ignoredNodes := make(map[route.Vertex]struct{})
3✔
215
        for _, ignorePubKey := range in.IgnoredNodes {
3✔
UNCOV
216
                ignoreVertex, err := route.NewVertexFromBytes(ignorePubKey)
×
UNCOV
217
                if err != nil {
×
218
                        return nil, nil, err
×
219
                }
×
UNCOV
220
                ignoredNodes[ignoreVertex] = struct{}{}
×
221
        }
222

223
        ignoredPairs := make(map[routing.DirectedNodePair]struct{})
3✔
224

3✔
225
        // Convert deprecated ignoredEdges to pairs.
3✔
226
        for _, ignoredEdge := range in.IgnoredEdges {
3✔
UNCOV
227
                pair, err := r.rpcEdgeToPair(ignoredEdge)
×
UNCOV
228
                if err != nil {
×
229
                        log.Warnf("Ignore channel %v skipped: %v",
×
230
                                ignoredEdge.ChannelId, err)
×
231

×
232
                        continue
×
233
                }
UNCOV
234
                ignoredPairs[pair] = struct{}{}
×
235
        }
236

237
        // Add ignored pairs to set.
238
        for _, ignorePair := range in.IgnoredPairs {
3✔
UNCOV
239
                from, err := route.NewVertexFromBytes(ignorePair.From)
×
UNCOV
240
                if err != nil {
×
241
                        return nil, nil, err
×
242
                }
×
243

UNCOV
244
                to, err := route.NewVertexFromBytes(ignorePair.To)
×
UNCOV
245
                if err != nil {
×
246
                        return nil, nil, err
×
247
                }
×
248

UNCOV
249
                pair := routing.NewDirectedNodePair(from, to)
×
UNCOV
250
                ignoredPairs[pair] = struct{}{}
×
251
        }
252

253
        return ignoredNodes, ignoredPairs, nil
3✔
254
}
255

256
func (r *RouterBackend) parseQueryRoutesRequest(in *lnrpc.QueryRoutesRequest) (
257
        *routing.RouteRequest, error) {
3✔
258

3✔
259
        // Parse the hex-encoded source public key into a full public key that
3✔
260
        // we can properly manipulate.
3✔
261

3✔
262
        var sourcePubKey route.Vertex
3✔
263
        if in.SourcePubKey != "" {
3✔
264
                var err error
×
265
                sourcePubKey, err = parsePubKey(in.SourcePubKey)
×
266
                if err != nil {
×
267
                        return nil, err
×
268
                }
×
269
        } else {
3✔
270
                // If no source is specified, use self.
3✔
271
                sourcePubKey = r.SelfNode
3✔
272
        }
3✔
273

274
        // Currently, within the bootstrap phase of the network, we limit the
275
        // largest payment size allotted to (2^32) - 1 mSAT or 4.29 million
276
        // satoshis.
277
        amt, err := lnrpc.UnmarshallAmt(in.Amt, in.AmtMsat)
3✔
278
        if err != nil {
3✔
279
                return nil, err
×
280
        }
×
281

282
        // Unmarshall restrictions from request.
283
        feeLimit := lnrpc.CalculateFeeLimit(in.FeeLimit, amt)
3✔
284

3✔
285
        // Since QueryRoutes allows having a different source other than
3✔
286
        // ourselves, we'll only apply our max time lock if we are the source.
3✔
287
        maxTotalTimelock := r.MaxTotalTimelock
3✔
288
        if sourcePubKey != r.SelfNode {
3✔
289
                maxTotalTimelock = math.MaxUint32
×
290
        }
×
291

292
        cltvLimit, err := ValidateCLTVLimit(in.CltvLimit, maxTotalTimelock)
3✔
293
        if err != nil {
3✔
294
                return nil, err
×
295
        }
×
296

297
        // If we have a blinded path set, we'll get a few of our fields from
298
        // inside of the path rather than the request's fields.
299
        var (
3✔
300
                targetPubKey   *route.Vertex
3✔
301
                routeHintEdges map[route.Vertex][]routing.AdditionalEdge
3✔
302
                blindedPathSet *routing.BlindedPaymentPathSet
3✔
303

3✔
304
                // finalCLTVDelta varies depending on whether we're sending to
3✔
305
                // a blinded route or an unblinded node. For blinded paths,
3✔
306
                // our final cltv is already baked into the path so we restrict
3✔
307
                // this value to zero on the API. Bolt11 invoices have a
3✔
308
                // default, so we'll fill that in for the non-blinded case.
3✔
309
                finalCLTVDelta uint16
3✔
310

3✔
311
                // destinationFeatures is the set of features for the
3✔
312
                // destination node.
3✔
313
                destinationFeatures *lnwire.FeatureVector
3✔
314
        )
3✔
315

3✔
316
        // Validate that the fields provided in the request are sane depending
3✔
317
        // on whether it is using a blinded path or not.
3✔
318
        if len(in.BlindedPaymentPaths) > 0 {
6✔
319
                blindedPathSet, err = parseBlindedPaymentPaths(in)
3✔
320
                if err != nil {
3✔
321
                        return nil, err
×
322
                }
×
323

324
                pathFeatures := blindedPathSet.Features()
3✔
325
                if pathFeatures != nil {
3✔
326
                        destinationFeatures = pathFeatures.Clone()
×
327
                }
×
328
        } else {
3✔
329
                // If we do not have a blinded path, a target pubkey must be
3✔
330
                // set.
3✔
331
                pk, err := parsePubKey(in.PubKey)
3✔
332
                if err != nil {
3✔
333
                        return nil, err
×
334
                }
×
335
                targetPubKey = &pk
3✔
336

3✔
337
                // Convert route hints to an edge map.
3✔
338
                routeHints, err := unmarshallRouteHints(in.RouteHints)
3✔
339
                if err != nil {
3✔
340
                        return nil, err
×
341
                }
×
342

343
                routeHintEdges, err = routing.RouteHintsToEdges(
3✔
344
                        routeHints, *targetPubKey,
3✔
345
                )
3✔
346
                if err != nil {
3✔
347
                        return nil, err
×
348
                }
×
349

350
                // Set a non-zero final CLTV delta for payments that are not
351
                // to blinded paths, as bolt11 has a default final cltv delta
352
                // value that is used in the absence of a value.
353
                finalCLTVDelta = r.DefaultFinalCltvDelta
3✔
354
                if in.FinalCltvDelta != 0 {
6✔
355
                        finalCLTVDelta = uint16(in.FinalCltvDelta)
3✔
356
                }
3✔
357

358
                // Do bounds checking without block padding so we don't give
359
                // routes that will leave the router in a zombie payment state.
360
                err = routing.ValidateCLTVLimit(
3✔
361
                        cltvLimit, finalCLTVDelta, false,
3✔
362
                )
3✔
363
                if err != nil {
3✔
UNCOV
364
                        return nil, err
×
UNCOV
365
                }
×
366

367
                // Parse destination feature bits.
368
                destinationFeatures = UnmarshalFeatures(in.DestFeatures)
3✔
369
        }
370

371
        // We need to subtract the final delta before passing it into path
372
        // finding. The optimal path is independent of the final cltv delta and
373
        // the path finding algorithm is unaware of this value.
374
        cltvLimit -= uint32(finalCLTVDelta)
3✔
375

3✔
376
        ignoredNodes, ignoredPairs, err := r.parseIgnored(in)
3✔
377
        if err != nil {
3✔
378
                return nil, err
×
379
        }
×
380

381
        restrictions := &routing.RestrictParams{
3✔
382
                FeeLimit: feeLimit,
3✔
383
                ProbabilitySource: func(fromNode, toNode route.Vertex,
3✔
384
                        amt lnwire.MilliSatoshi,
3✔
385
                        capacity btcutil.Amount) float64 {
6✔
386

3✔
387
                        if _, ok := ignoredNodes[fromNode]; ok {
3✔
UNCOV
388
                                return 0
×
UNCOV
389
                        }
×
390

391
                        pair := routing.DirectedNodePair{
3✔
392
                                From: fromNode,
3✔
393
                                To:   toNode,
3✔
394
                        }
3✔
395
                        if _, ok := ignoredPairs[pair]; ok {
3✔
UNCOV
396
                                return 0
×
UNCOV
397
                        }
×
398

399
                        if !in.UseMissionControl {
6✔
400
                                return 1
3✔
401
                        }
3✔
402

UNCOV
403
                        return r.MissionControl.GetProbability(
×
UNCOV
404
                                fromNode, toNode, amt, capacity,
×
UNCOV
405
                        )
×
406
                },
407
                DestCustomRecords:     record.CustomSet(in.DestCustomRecords),
408
                CltvLimit:             cltvLimit,
409
                DestFeatures:          destinationFeatures,
410
                BlindedPaymentPathSet: blindedPathSet,
411
        }
412

413
        // We set the outgoing channel restrictions if the user provides a
414
        // list of channel ids. We also handle the case where the user
415
        // provides the deprecated `OutgoingChanId` field.
416
        switch {
3✔
UNCOV
417
        case len(in.OutgoingChanIds) > 0 && in.OutgoingChanId != 0:
×
UNCOV
418
                return nil, errors.New("outgoing_chan_id and " +
×
UNCOV
419
                        "outgoing_chan_ids cannot both be set")
×
420

UNCOV
421
        case len(in.OutgoingChanIds) > 0:
×
UNCOV
422
                restrictions.OutgoingChannelIDs = in.OutgoingChanIds
×
423

UNCOV
424
        case in.OutgoingChanId != 0:
×
UNCOV
425
                restrictions.OutgoingChannelIDs = []uint64{in.OutgoingChanId}
×
426
        }
427

428
        // Pass along a last hop restriction if specified.
429
        if len(in.LastHopPubkey) > 0 {
3✔
UNCOV
430
                lastHop, err := route.NewVertexFromBytes(
×
UNCOV
431
                        in.LastHopPubkey,
×
UNCOV
432
                )
×
UNCOV
433
                if err != nil {
×
434
                        return nil, err
×
435
                }
×
UNCOV
436
                restrictions.LastHop = &lastHop
×
437
        }
438

439
        // If we have any TLV records destined for the final hop, then we'll
440
        // attempt to decode them now into a form that the router can more
441
        // easily manipulate.
442
        customRecords := record.CustomSet(in.DestCustomRecords)
3✔
443
        if err := customRecords.Validate(); err != nil {
3✔
444
                return nil, err
×
445
        }
×
446

447
        return routing.NewRouteRequest(
3✔
448
                sourcePubKey, targetPubKey, amt, in.TimePref, restrictions,
3✔
449
                customRecords, routeHintEdges, blindedPathSet,
3✔
450
                finalCLTVDelta,
3✔
451
        )
3✔
452
}
453

454
func parseBlindedPaymentPaths(in *lnrpc.QueryRoutesRequest) (
455
        *routing.BlindedPaymentPathSet, error) {
3✔
456

3✔
457
        if len(in.PubKey) != 0 {
3✔
458
                return nil, fmt.Errorf("target pubkey: %x should not be set "+
×
459
                        "when blinded path is provided", in.PubKey)
×
460
        }
×
461

462
        if len(in.RouteHints) > 0 {
3✔
463
                return nil, errors.New("route hints and blinded path can't " +
×
464
                        "both be set")
×
465
        }
×
466

467
        if in.FinalCltvDelta != 0 {
3✔
468
                return nil, errors.New("final cltv delta should be " +
×
469
                        "zero for blinded paths")
×
470
        }
×
471

472
        // For blinded paths, we get one set of features for the relaying
473
        // intermediate nodes and the final destination. We don't allow the
474
        // destination feature bit field for regular payments to be set, as
475
        // this could lead to ambiguity.
476
        if len(in.DestFeatures) > 0 {
3✔
477
                return nil, errors.New("destination features should " +
×
478
                        "be populated in blinded path")
×
479
        }
×
480

481
        paths := make([]*routing.BlindedPayment, len(in.BlindedPaymentPaths))
3✔
482
        for i, paymentPath := range in.BlindedPaymentPaths {
6✔
483
                blindedPmt, err := unmarshalBlindedPayment(paymentPath)
3✔
484
                if err != nil {
3✔
485
                        return nil, fmt.Errorf("parse blinded payment: %w", err)
×
486
                }
×
487

488
                if err := blindedPmt.Validate(); err != nil {
3✔
489
                        return nil, fmt.Errorf("invalid blinded path: %w", err)
×
490
                }
×
491

492
                paths[i] = blindedPmt
3✔
493
        }
494

495
        return routing.NewBlindedPaymentPathSet(paths)
3✔
496
}
497

498
func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
499
        *routing.BlindedPayment, error) {
3✔
500

3✔
501
        if rpcPayment == nil {
3✔
502
                return nil, errors.New("nil blinded payment")
×
503
        }
×
504

505
        path, err := unmarshalBlindedPaymentPaths(rpcPayment.BlindedPath)
3✔
506
        if err != nil {
3✔
507
                return nil, err
×
508
        }
×
509

510
        features := UnmarshalFeatures(rpcPayment.Features)
3✔
511

3✔
512
        return &routing.BlindedPayment{
3✔
513
                BlindedPath:         path,
3✔
514
                CltvExpiryDelta:     uint16(rpcPayment.TotalCltvDelta),
3✔
515
                BaseFee:             uint32(rpcPayment.BaseFeeMsat),
3✔
516
                ProportionalFeeRate: rpcPayment.ProportionalFeeRate,
3✔
517
                HtlcMinimum:         rpcPayment.HtlcMinMsat,
3✔
518
                HtlcMaximum:         rpcPayment.HtlcMaxMsat,
3✔
519
                Features:            features,
3✔
520
        }, nil
3✔
521
}
522

523
func unmarshalBlindedPaymentPaths(rpcPath *lnrpc.BlindedPath) (
524
        *sphinx.BlindedPath, error) {
3✔
525

3✔
526
        if rpcPath == nil {
3✔
527
                return nil, errors.New("blinded path required when blinded " +
×
528
                        "route is provided")
×
529
        }
×
530

531
        introduction, err := btcec.ParsePubKey(rpcPath.IntroductionNode)
3✔
532
        if err != nil {
3✔
533
                return nil, err
×
534
        }
×
535

536
        blinding, err := btcec.ParsePubKey(rpcPath.BlindingPoint)
3✔
537
        if err != nil {
3✔
538
                return nil, err
×
539
        }
×
540

541
        if len(rpcPath.BlindedHops) < 1 {
3✔
542
                return nil, errors.New("at least 1 blinded hops required")
×
543
        }
×
544

545
        path := &sphinx.BlindedPath{
3✔
546
                IntroductionPoint: introduction,
3✔
547
                BlindingPoint:     blinding,
3✔
548
                BlindedHops: make(
3✔
549
                        []*sphinx.BlindedHopInfo, len(rpcPath.BlindedHops),
3✔
550
                ),
3✔
551
        }
3✔
552

3✔
553
        for i, hop := range rpcPath.BlindedHops {
6✔
554
                path.BlindedHops[i], err = unmarshalBlindedHop(hop)
3✔
555
                if err != nil {
3✔
556
                        return nil, err
×
557
                }
×
558
        }
559

560
        return path, nil
3✔
561
}
562

563
func unmarshalBlindedHop(rpcHop *lnrpc.BlindedHop) (*sphinx.BlindedHopInfo,
564
        error) {
3✔
565

3✔
566
        pubkey, err := btcec.ParsePubKey(rpcHop.BlindedNode)
3✔
567
        if err != nil {
3✔
568
                return nil, err
×
569
        }
×
570

571
        if len(rpcHop.EncryptedData) == 0 {
3✔
572
                return nil, errors.New("empty encrypted data not allowed")
×
573
        }
×
574

575
        return &sphinx.BlindedHopInfo{
3✔
576
                BlindedNodePub: pubkey,
3✔
577
                CipherText:     rpcHop.EncryptedData,
3✔
578
        }, nil
3✔
579
}
580

581
// rpcEdgeToPair looks up the provided channel and returns the channel endpoints
582
// as a directed pair.
583
func (r *RouterBackend) rpcEdgeToPair(e *lnrpc.EdgeLocator) (
UNCOV
584
        routing.DirectedNodePair, error) {
×
UNCOV
585

×
UNCOV
586
        a, b, err := r.FetchChannelEndpoints(e.ChannelId)
×
UNCOV
587
        if err != nil {
×
588
                return routing.DirectedNodePair{}, err
×
589
        }
×
590

UNCOV
591
        var pair routing.DirectedNodePair
×
UNCOV
592
        if e.DirectionReverse {
×
UNCOV
593
                pair.From, pair.To = b, a
×
UNCOV
594
        } else {
×
595
                pair.From, pair.To = a, b
×
596
        }
×
597

UNCOV
598
        return pair, nil
×
599
}
600

601
// MarshallRoute marshalls an internal route to an rpc route struct.
602
func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) {
3✔
603
        resp := &lnrpc.Route{
3✔
604
                TotalTimeLock:      route.TotalTimeLock,
3✔
605
                TotalFees:          int64(route.TotalFees().ToSatoshis()),
3✔
606
                TotalFeesMsat:      int64(route.TotalFees()),
3✔
607
                TotalAmt:           int64(route.TotalAmount.ToSatoshis()),
3✔
608
                TotalAmtMsat:       int64(route.TotalAmount),
3✔
609
                Hops:               make([]*lnrpc.Hop, len(route.Hops)),
3✔
610
                FirstHopAmountMsat: int64(route.FirstHopAmount.Val.Int()),
3✔
611
        }
3✔
612

3✔
613
        // Encode the route's custom channel data (if available).
3✔
614
        if len(route.FirstHopWireCustomRecords) > 0 {
6✔
615
                customData, err := route.FirstHopWireCustomRecords.Serialize()
3✔
616
                if err != nil {
3✔
617
                        return nil, err
×
618
                }
×
619

620
                resp.CustomChannelData = customData
3✔
621

3✔
622
                // Allow the aux data parser to parse the custom records into
3✔
623
                // a human-readable JSON (if available).
3✔
624
                if r.ParseCustomChannelData != nil {
6✔
625
                        err := r.ParseCustomChannelData(resp)
3✔
626
                        if err != nil {
3✔
627
                                return nil, err
×
628
                        }
×
629
                }
630
        }
631

632
        incomingAmt := route.TotalAmount
3✔
633
        for i, hop := range route.Hops {
6✔
634
                fee := route.HopFee(i)
3✔
635

3✔
636
                // Channel capacity is not a defining property of a route. For
3✔
637
                // backwards RPC compatibility, we retrieve it here from the
3✔
638
                // graph.
3✔
639
                chanCapacity, err := r.FetchChannelCapacity(hop.ChannelID)
3✔
640
                if err != nil {
6✔
641
                        // If capacity cannot be retrieved, this may be a
3✔
642
                        // not-yet-received or private channel. Then report
3✔
643
                        // amount that is sent through the channel as capacity.
3✔
644
                        chanCapacity = incomingAmt.ToSatoshis()
3✔
645
                }
3✔
646

647
                // Extract the MPP fields if present on this hop.
648
                var mpp *lnrpc.MPPRecord
3✔
649
                if hop.MPP != nil {
6✔
650
                        addr := hop.MPP.PaymentAddr()
3✔
651

3✔
652
                        mpp = &lnrpc.MPPRecord{
3✔
653
                                PaymentAddr:  addr[:],
3✔
654
                                TotalAmtMsat: int64(hop.MPP.TotalMsat()),
3✔
655
                        }
3✔
656
                }
3✔
657

658
                var amp *lnrpc.AMPRecord
3✔
659
                if hop.AMP != nil {
6✔
660
                        rootShare := hop.AMP.RootShare()
3✔
661
                        setID := hop.AMP.SetID()
3✔
662

3✔
663
                        amp = &lnrpc.AMPRecord{
3✔
664
                                RootShare:  rootShare[:],
3✔
665
                                SetId:      setID[:],
3✔
666
                                ChildIndex: hop.AMP.ChildIndex(),
3✔
667
                        }
3✔
668
                }
3✔
669

670
                resp.Hops[i] = &lnrpc.Hop{
3✔
671
                        ChanId:           hop.ChannelID,
3✔
672
                        ChanCapacity:     int64(chanCapacity),
3✔
673
                        AmtToForward:     int64(hop.AmtToForward.ToSatoshis()),
3✔
674
                        AmtToForwardMsat: int64(hop.AmtToForward),
3✔
675
                        Fee:              int64(fee.ToSatoshis()),
3✔
676
                        FeeMsat:          int64(fee),
3✔
677
                        Expiry:           uint32(hop.OutgoingTimeLock),
3✔
678
                        PubKey: hex.EncodeToString(
3✔
679
                                hop.PubKeyBytes[:],
3✔
680
                        ),
3✔
681
                        CustomRecords: hop.CustomRecords,
3✔
682
                        TlvPayload:    !hop.LegacyPayload,
3✔
683
                        MppRecord:     mpp,
3✔
684
                        AmpRecord:     amp,
3✔
685
                        Metadata:      hop.Metadata,
3✔
686
                        EncryptedData: hop.EncryptedData,
3✔
687
                        TotalAmtMsat:  uint64(hop.TotalAmtMsat),
3✔
688
                }
3✔
689

3✔
690
                if hop.BlindingPoint != nil {
6✔
691
                        blinding := hop.BlindingPoint.SerializeCompressed()
3✔
692
                        resp.Hops[i].BlindingPoint = blinding
3✔
693
                }
3✔
694
                incomingAmt = hop.AmtToForward
3✔
695
        }
696

697
        return resp, nil
3✔
698
}
699

700
// UnmarshallHopWithPubkey unmarshalls an rpc hop for which the pubkey has
701
// already been extracted.
702
func UnmarshallHopWithPubkey(rpcHop *lnrpc.Hop, pubkey route.Vertex) (*route.Hop,
703
        error) {
3✔
704

3✔
705
        customRecords := record.CustomSet(rpcHop.CustomRecords)
3✔
706
        if err := customRecords.Validate(); err != nil {
3✔
707
                return nil, err
×
708
        }
×
709

710
        mpp, err := UnmarshalMPP(rpcHop.MppRecord)
3✔
711
        if err != nil {
3✔
712
                return nil, err
×
713
        }
×
714

715
        amp, err := UnmarshalAMP(rpcHop.AmpRecord)
3✔
716
        if err != nil {
3✔
717
                return nil, err
×
718
        }
×
719

720
        hop := &route.Hop{
3✔
721
                OutgoingTimeLock: rpcHop.Expiry,
3✔
722
                AmtToForward:     lnwire.MilliSatoshi(rpcHop.AmtToForwardMsat),
3✔
723
                PubKeyBytes:      pubkey,
3✔
724
                ChannelID:        rpcHop.ChanId,
3✔
725
                CustomRecords:    customRecords,
3✔
726
                LegacyPayload:    false,
3✔
727
                MPP:              mpp,
3✔
728
                AMP:              amp,
3✔
729
                EncryptedData:    rpcHop.EncryptedData,
3✔
730
                TotalAmtMsat:     lnwire.MilliSatoshi(rpcHop.TotalAmtMsat),
3✔
731
        }
3✔
732

3✔
733
        haveBlindingPoint := len(rpcHop.BlindingPoint) != 0
3✔
734
        if haveBlindingPoint {
6✔
735
                hop.BlindingPoint, err = btcec.ParsePubKey(
3✔
736
                        rpcHop.BlindingPoint,
3✔
737
                )
3✔
738
                if err != nil {
3✔
739
                        return nil, fmt.Errorf("blinding point: %w", err)
×
740
                }
×
741
        }
742

743
        if haveBlindingPoint && len(rpcHop.EncryptedData) == 0 {
3✔
744
                return nil, errors.New("encrypted data should be present if " +
×
745
                        "blinding point is provided")
×
746
        }
×
747

748
        return hop, nil
3✔
749
}
750

751
// UnmarshallHop unmarshalls an rpc hop that may or may not contain a node
752
// pubkey.
753
func (r *RouterBackend) UnmarshallHop(rpcHop *lnrpc.Hop,
754
        prevNodePubKey [33]byte) (*route.Hop, error) {
3✔
755

3✔
756
        var pubKeyBytes [33]byte
3✔
757
        if rpcHop.PubKey != "" {
6✔
758
                // Unmarshall the provided hop pubkey.
3✔
759
                pubKey, err := hex.DecodeString(rpcHop.PubKey)
3✔
760
                if err != nil {
3✔
761
                        return nil, fmt.Errorf("cannot decode pubkey %s",
×
762
                                rpcHop.PubKey)
×
763
                }
×
764
                copy(pubKeyBytes[:], pubKey)
3✔
765
        } else {
×
766
                // If no pub key is given of the hop, the local channel graph
×
767
                // needs to be queried to complete the information necessary for
×
768
                // routing. Discard edge policies, because they may be nil.
×
769
                node1, node2, err := r.FetchChannelEndpoints(rpcHop.ChanId)
×
770
                if err != nil {
×
771
                        return nil, err
×
772
                }
×
773

774
                switch {
×
775
                case prevNodePubKey == node1:
×
776
                        pubKeyBytes = node2
×
777
                case prevNodePubKey == node2:
×
778
                        pubKeyBytes = node1
×
779
                default:
×
780
                        return nil, fmt.Errorf("channel edge does not match " +
×
781
                                "expected node")
×
782
                }
783
        }
784

785
        return UnmarshallHopWithPubkey(rpcHop, pubKeyBytes)
3✔
786
}
787

788
// UnmarshallRoute unmarshalls an rpc route. For hops that don't specify a
789
// pubkey, the channel graph is queried.
790
func (r *RouterBackend) UnmarshallRoute(rpcroute *lnrpc.Route) (
791
        *route.Route, error) {
3✔
792

3✔
793
        prevNodePubKey := r.SelfNode
3✔
794

3✔
795
        hops := make([]*route.Hop, len(rpcroute.Hops))
3✔
796
        for i, hop := range rpcroute.Hops {
6✔
797
                routeHop, err := r.UnmarshallHop(hop, prevNodePubKey)
3✔
798
                if err != nil {
3✔
799
                        return nil, err
×
800
                }
×
801

802
                hops[i] = routeHop
3✔
803

3✔
804
                prevNodePubKey = routeHop.PubKeyBytes
3✔
805
        }
806

807
        route, err := route.NewRouteFromHops(
3✔
808
                lnwire.MilliSatoshi(rpcroute.TotalAmtMsat),
3✔
809
                rpcroute.TotalTimeLock,
3✔
810
                r.SelfNode,
3✔
811
                hops,
3✔
812
        )
3✔
813
        if err != nil {
3✔
814
                return nil, err
×
815
        }
×
816

817
        return route, nil
3✔
818
}
819

820
// extractIntentFromSendRequest attempts to parse the SendRequest details
821
// required to dispatch a client from the information presented by an RPC
822
// client.
823
func (r *RouterBackend) extractIntentFromSendRequest(
824
        rpcPayReq *SendPaymentRequest) (*routing.LightningPayment, error) {
3✔
825

3✔
826
        payIntent := &routing.LightningPayment{}
3✔
827

3✔
828
        // Pass along time preference.
3✔
829
        if rpcPayReq.TimePref < -1 || rpcPayReq.TimePref > 1 {
3✔
UNCOV
830
                return nil, errors.New("time preference out of range")
×
UNCOV
831
        }
×
832
        payIntent.TimePref = rpcPayReq.TimePref
3✔
833

3✔
834
        // Pass along restrictions on the outgoing channels that may be used.
3✔
835
        payIntent.OutgoingChannelIDs = rpcPayReq.OutgoingChanIds
3✔
836

3✔
837
        // Add the deprecated single outgoing channel restriction if present.
3✔
838
        if rpcPayReq.OutgoingChanId != 0 {
3✔
UNCOV
839
                if payIntent.OutgoingChannelIDs != nil {
×
UNCOV
840
                        return nil, errors.New("outgoing_chan_id and " +
×
UNCOV
841
                                "outgoing_chan_ids are mutually exclusive")
×
UNCOV
842
                }
×
843

844
                payIntent.OutgoingChannelIDs = append(
×
845
                        payIntent.OutgoingChannelIDs, rpcPayReq.OutgoingChanId,
×
846
                )
×
847
        }
848

849
        // Pass along a last hop restriction if specified.
850
        if len(rpcPayReq.LastHopPubkey) > 0 {
3✔
UNCOV
851
                lastHop, err := route.NewVertexFromBytes(
×
UNCOV
852
                        rpcPayReq.LastHopPubkey,
×
UNCOV
853
                )
×
UNCOV
854
                if err != nil {
×
UNCOV
855
                        return nil, err
×
UNCOV
856
                }
×
857
                payIntent.LastHop = &lastHop
×
858
        }
859

860
        // Take the CLTV limit from the request if set, otherwise use the max.
861
        cltvLimit, err := ValidateCLTVLimit(
3✔
862
                uint32(rpcPayReq.CltvLimit), r.MaxTotalTimelock,
3✔
863
        )
3✔
864
        if err != nil {
3✔
UNCOV
865
                return nil, err
×
UNCOV
866
        }
×
867
        payIntent.CltvLimit = cltvLimit
3✔
868

3✔
869
        // Attempt to parse the max parts value set by the user, if this value
3✔
870
        // isn't set, then we'll use the current default value for this
3✔
871
        // setting.
3✔
872
        maxParts := rpcPayReq.MaxParts
3✔
873
        if maxParts == 0 {
6✔
874
                maxParts = DefaultMaxParts
3✔
875
        }
3✔
876
        payIntent.MaxParts = maxParts
3✔
877

3✔
878
        // If this payment had a max shard amount specified, then we'll apply
3✔
879
        // that now, which'll force us to always make payment splits smaller
3✔
880
        // than this.
3✔
881
        if rpcPayReq.MaxShardSizeMsat > 0 {
6✔
882
                shardAmtMsat := lnwire.MilliSatoshi(rpcPayReq.MaxShardSizeMsat)
3✔
883
                payIntent.MaxShardAmt = &shardAmtMsat
3✔
884

3✔
885
                // If the requested max_parts exceeds the allowed limit, then we
3✔
886
                // cannot send the payment amount.
3✔
887
                if payIntent.MaxParts > MaxPartsUpperLimit {
3✔
UNCOV
888
                        return nil, fmt.Errorf("requested max_parts (%v) "+
×
UNCOV
889
                                "exceeds the allowed upper limit of %v; cannot"+
×
UNCOV
890
                                " send payment amount with max_shard_size_msat"+
×
UNCOV
891
                                "=%v", payIntent.MaxParts, MaxPartsUpperLimit,
×
UNCOV
892
                                *payIntent.MaxShardAmt)
×
UNCOV
893
                }
×
894
        }
895

896
        // Take fee limit from request.
897
        payIntent.FeeLimit, err = lnrpc.UnmarshallAmt(
3✔
898
                rpcPayReq.FeeLimitSat, rpcPayReq.FeeLimitMsat,
3✔
899
        )
3✔
900
        if err != nil {
3✔
UNCOV
901
                return nil, err
×
UNCOV
902
        }
×
903

904
        customRecords := record.CustomSet(rpcPayReq.DestCustomRecords)
3✔
905
        if err := customRecords.Validate(); err != nil {
3✔
UNCOV
906
                return nil, err
×
UNCOV
907
        }
×
908
        payIntent.DestCustomRecords = customRecords
3✔
909

3✔
910
        // Keysend payments do not support MPP payments.
3✔
911
        //
3✔
912
        // NOTE: There is no need to validate the `MaxParts` value here because
3✔
913
        // it is set to 1 somewhere else in case it's a keysend payment.
3✔
914
        if customRecords.IsKeysend() {
6✔
915
                if payIntent.MaxShardAmt != nil {
6✔
916
                        return nil, errors.New("keysend payments cannot " +
3✔
917
                                "specify a max shard amount - MPP not " +
3✔
918
                                "supported with keysend payments")
3✔
919
                }
3✔
920
        }
921

922
        firstHopRecords := lnwire.CustomRecords(rpcPayReq.FirstHopCustomRecords)
3✔
923
        if err := firstHopRecords.Validate(); err != nil {
3✔
UNCOV
924
                return nil, err
×
UNCOV
925
        }
×
926
        payIntent.FirstHopCustomRecords = firstHopRecords
3✔
927

3✔
928
        // If the experimental endorsement signal is not already set, propagate
3✔
929
        // a zero value field if configured to set this signal.
3✔
930
        if r.ShouldSetExpEndorsement() {
6✔
931
                if payIntent.FirstHopCustomRecords == nil {
6✔
932
                        payIntent.FirstHopCustomRecords = make(
3✔
933
                                map[uint64][]byte,
3✔
934
                        )
3✔
935
                }
3✔
936

937
                t := uint64(lnwire.ExperimentalEndorsementType)
3✔
938
                if _, set := payIntent.FirstHopCustomRecords[t]; !set {
6✔
939
                        payIntent.FirstHopCustomRecords[t] = []byte{
3✔
940
                                lnwire.ExperimentalUnendorsed,
3✔
941
                        }
3✔
942
                }
3✔
943
        }
944

945
        payIntent.PayAttemptTimeout = time.Second *
3✔
946
                time.Duration(rpcPayReq.TimeoutSeconds)
3✔
947

3✔
948
        // Route hints.
3✔
949
        routeHints, err := unmarshallRouteHints(
3✔
950
                rpcPayReq.RouteHints,
3✔
951
        )
3✔
952
        if err != nil {
3✔
953
                return nil, err
×
954
        }
×
955
        payIntent.RouteHints = routeHints
3✔
956

3✔
957
        // Unmarshall either sat or msat amount from request.
3✔
958
        reqAmt, err := lnrpc.UnmarshallAmt(
3✔
959
                rpcPayReq.Amt, rpcPayReq.AmtMsat,
3✔
960
        )
3✔
961
        if err != nil {
3✔
UNCOV
962
                return nil, err
×
UNCOV
963
        }
×
964

965
        // If the payment request field isn't blank, then the details of the
966
        // invoice are encoded entirely within the encoded payReq.  So we'll
967
        // attempt to decode it, populating the payment accordingly.
968
        if rpcPayReq.PaymentRequest != "" {
6✔
969
                switch {
3✔
970

UNCOV
971
                case len(rpcPayReq.Dest) > 0:
×
UNCOV
972
                        return nil, errors.New("dest and payment_request " +
×
UNCOV
973
                                "cannot appear together")
×
974

UNCOV
975
                case len(rpcPayReq.PaymentHash) > 0:
×
UNCOV
976
                        return nil, errors.New("payment_hash and payment_request " +
×
UNCOV
977
                                "cannot appear together")
×
978

UNCOV
979
                case rpcPayReq.FinalCltvDelta != 0:
×
UNCOV
980
                        return nil, errors.New("final_cltv_delta and payment_request " +
×
UNCOV
981
                                "cannot appear together")
×
982
                }
983

984
                payReq, err := zpay32.Decode(
3✔
985
                        rpcPayReq.PaymentRequest, r.ActiveNetParams,
3✔
986
                )
3✔
987
                if err != nil {
3✔
UNCOV
988
                        return nil, err
×
UNCOV
989
                }
×
990

991
                // Next, we'll ensure that this payreq hasn't already expired.
992
                err = ValidatePayReqExpiry(r.Clock, payReq)
3✔
993
                if err != nil {
3✔
UNCOV
994
                        return nil, err
×
UNCOV
995
                }
×
996

997
                // An invoice must include either a payment address or
998
                // blinded paths.
999
                if payReq.PaymentAddr.IsNone() &&
3✔
1000
                        len(payReq.BlindedPaymentPaths) == 0 {
3✔
UNCOV
1001

×
UNCOV
1002
                        return nil, errors.New("payment request must contain " +
×
UNCOV
1003
                                "either a payment address or blinded paths")
×
UNCOV
1004
                }
×
1005

1006
                // If the amount was not included in the invoice, then we let
1007
                // the payer specify the amount of satoshis they wish to send.
1008
                // We override the amount to pay with the amount provided from
1009
                // the payment request.
1010
                if payReq.MilliSat == nil {
3✔
1011
                        if reqAmt == 0 {
×
1012
                                return nil, errors.New("amount must be " +
×
1013
                                        "specified when paying a zero amount " +
×
1014
                                        "invoice")
×
1015
                        }
×
1016

1017
                        payIntent.Amount = reqAmt
×
1018
                } else {
3✔
1019
                        if reqAmt != 0 {
3✔
1020
                                return nil, errors.New("amount must not be " +
×
1021
                                        "specified when paying a non-zero " +
×
1022
                                        "amount invoice")
×
1023
                        }
×
1024

1025
                        payIntent.Amount = *payReq.MilliSat
3✔
1026
                }
1027

1028
                if !payReq.Features.HasFeature(lnwire.MPPOptional) &&
3✔
1029
                        !payReq.Features.HasFeature(lnwire.AMPOptional) {
3✔
1030

×
1031
                        payIntent.MaxParts = 1
×
1032
                }
×
1033

1034
                payAddr := payReq.PaymentAddr
3✔
1035
                if payReq.Features.HasFeature(lnwire.AMPOptional) {
6✔
1036
                        // The opt-in AMP flag is required to pay an AMP
3✔
1037
                        // invoice.
3✔
1038
                        if !rpcPayReq.Amp {
3✔
1039
                                return nil, fmt.Errorf("the AMP flag (--amp " +
×
1040
                                        "or SendPaymentRequest.Amp) must be " +
×
1041
                                        "set to pay an AMP invoice")
×
1042
                        }
×
1043

1044
                        // Generate random SetID and root share.
1045
                        var setID [32]byte
3✔
1046
                        _, err = rand.Read(setID[:])
3✔
1047
                        if err != nil {
3✔
1048
                                return nil, err
×
1049
                        }
×
1050

1051
                        var rootShare [32]byte
3✔
1052
                        _, err = rand.Read(rootShare[:])
3✔
1053
                        if err != nil {
3✔
1054
                                return nil, err
×
1055
                        }
×
1056
                        err := payIntent.SetAMP(&routing.AMPOptions{
3✔
1057
                                SetID:     setID,
3✔
1058
                                RootShare: rootShare,
3✔
1059
                        })
3✔
1060
                        if err != nil {
3✔
1061
                                return nil, err
×
1062
                        }
×
1063

1064
                        // For AMP invoices, we'll allow users to override the
1065
                        // included payment addr to allow the invoice to be
1066
                        // pseudo-reusable, e.g. the invoice parameters are
1067
                        // reused (amt, cltv, hop hints, etc) even though the
1068
                        // payments will share different payment hashes.
1069
                        //
1070
                        // NOTE: This will only work when the peer has
1071
                        // spontaneous AMP payments enabled.
1072
                        if len(rpcPayReq.PaymentAddr) > 0 {
6✔
1073
                                var addr [32]byte
3✔
1074
                                copy(addr[:], rpcPayReq.PaymentAddr)
3✔
1075
                                payAddr = fn.Some(addr)
3✔
1076
                        }
3✔
1077
                } else {
3✔
1078
                        err = payIntent.SetPaymentHash(*payReq.PaymentHash)
3✔
1079
                        if err != nil {
3✔
1080
                                return nil, err
×
1081
                        }
×
1082
                }
1083

1084
                destKey := payReq.Destination.SerializeCompressed()
3✔
1085
                copy(payIntent.Target[:], destKey)
3✔
1086

3✔
1087
                payIntent.FinalCLTVDelta = uint16(payReq.MinFinalCLTVExpiry())
3✔
1088
                payIntent.RouteHints = append(
3✔
1089
                        payIntent.RouteHints, payReq.RouteHints...,
3✔
1090
                )
3✔
1091
                payIntent.DestFeatures = payReq.Features
3✔
1092
                payIntent.PaymentAddr = payAddr
3✔
1093
                payIntent.PaymentRequest = []byte(rpcPayReq.PaymentRequest)
3✔
1094
                payIntent.Metadata = payReq.Metadata
3✔
1095

3✔
1096
                if len(payReq.BlindedPaymentPaths) > 0 {
6✔
1097
                        pathSet, err := BuildBlindedPathSet(
3✔
1098
                                payReq.BlindedPaymentPaths,
3✔
1099
                        )
3✔
1100
                        if err != nil {
3✔
1101
                                return nil, err
×
1102
                        }
×
1103
                        payIntent.BlindedPathSet = pathSet
3✔
1104

3✔
1105
                        // Replace the target node with the target public key
3✔
1106
                        // of the blinded path set.
3✔
1107
                        copy(
3✔
1108
                                payIntent.Target[:],
3✔
1109
                                pathSet.TargetPubKey().SerializeCompressed(),
3✔
1110
                        )
3✔
1111

3✔
1112
                        pathFeatures := pathSet.Features()
3✔
1113
                        if !pathFeatures.IsEmpty() {
3✔
1114
                                payIntent.DestFeatures = pathFeatures.Clone()
×
1115
                        }
×
1116
                }
1117
        } else {
3✔
1118
                // Otherwise, If the payment request field was not specified
3✔
1119
                // (and a custom route wasn't specified), construct the payment
3✔
1120
                // from the other fields.
3✔
1121

3✔
1122
                // Payment destination.
3✔
1123
                target, err := route.NewVertexFromBytes(rpcPayReq.Dest)
3✔
1124
                if err != nil {
3✔
UNCOV
1125
                        return nil, err
×
UNCOV
1126
                }
×
1127
                payIntent.Target = target
3✔
1128

3✔
1129
                // Final payment CLTV delta.
3✔
1130
                if rpcPayReq.FinalCltvDelta != 0 {
6✔
1131
                        payIntent.FinalCLTVDelta =
3✔
1132
                                uint16(rpcPayReq.FinalCltvDelta)
3✔
1133
                } else {
6✔
1134
                        payIntent.FinalCLTVDelta = r.DefaultFinalCltvDelta
3✔
1135
                }
3✔
1136

1137
                // Amount.
1138
                if reqAmt == 0 {
3✔
UNCOV
1139
                        return nil, errors.New("amount must be specified")
×
UNCOV
1140
                }
×
1141

1142
                payIntent.Amount = reqAmt
3✔
1143

3✔
1144
                // Parse destination feature bits.
3✔
1145
                features := UnmarshalFeatures(rpcPayReq.DestFeatures)
3✔
1146

3✔
1147
                // Validate the features if any was specified.
3✔
1148
                if features != nil {
6✔
1149
                        err = feature.ValidateDeps(features)
3✔
1150
                        if err != nil {
3✔
1151
                                return nil, err
×
1152
                        }
×
1153
                }
1154

1155
                // If this is an AMP payment, we must generate the initial
1156
                // randomness.
1157
                if rpcPayReq.Amp {
6✔
1158
                        // If no destination features were specified, we set
3✔
1159
                        // those necessary for AMP payments.
3✔
1160
                        if features == nil {
6✔
1161
                                ampFeatures := []lnrpc.FeatureBit{
3✔
1162
                                        lnrpc.FeatureBit_TLV_ONION_OPT,
3✔
1163
                                        lnrpc.FeatureBit_PAYMENT_ADDR_OPT,
3✔
1164
                                        lnrpc.FeatureBit_AMP_OPT,
3✔
1165
                                }
3✔
1166

3✔
1167
                                features = UnmarshalFeatures(ampFeatures)
3✔
1168
                        }
3✔
1169

1170
                        // First make sure the destination supports AMP.
1171
                        if !features.HasFeature(lnwire.AMPOptional) {
3✔
UNCOV
1172
                                return nil, fmt.Errorf("destination doesn't " +
×
UNCOV
1173
                                        "support AMP payments")
×
UNCOV
1174
                        }
×
1175

1176
                        // If no payment address is set, generate a random one.
1177
                        var payAddr [32]byte
3✔
1178
                        if len(rpcPayReq.PaymentAddr) == 0 {
6✔
1179
                                _, err = rand.Read(payAddr[:])
3✔
1180
                                if err != nil {
3✔
1181
                                        return nil, err
×
1182
                                }
×
1183
                        } else {
×
1184
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1185
                        }
×
1186
                        payIntent.PaymentAddr = fn.Some(payAddr)
3✔
1187

3✔
1188
                        // Generate random SetID and root share.
3✔
1189
                        var setID [32]byte
3✔
1190
                        _, err = rand.Read(setID[:])
3✔
1191
                        if err != nil {
3✔
1192
                                return nil, err
×
1193
                        }
×
1194

1195
                        var rootShare [32]byte
3✔
1196
                        _, err = rand.Read(rootShare[:])
3✔
1197
                        if err != nil {
3✔
1198
                                return nil, err
×
1199
                        }
×
1200
                        err := payIntent.SetAMP(&routing.AMPOptions{
3✔
1201
                                SetID:     setID,
3✔
1202
                                RootShare: rootShare,
3✔
1203
                        })
3✔
1204
                        if err != nil {
3✔
1205
                                return nil, err
×
1206
                        }
×
1207
                } else {
3✔
1208
                        // Payment hash.
3✔
1209
                        paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
3✔
1210
                        if err != nil {
3✔
UNCOV
1211
                                return nil, err
×
UNCOV
1212
                        }
×
1213

1214
                        err = payIntent.SetPaymentHash(paymentHash)
3✔
1215
                        if err != nil {
3✔
1216
                                return nil, err
×
1217
                        }
×
1218

1219
                        // If the payment addresses is specified, then we'll
1220
                        // also populate that now as well.
1221
                        if len(rpcPayReq.PaymentAddr) != 0 {
3✔
1222
                                var payAddr [32]byte
×
1223
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1224

×
1225
                                payIntent.PaymentAddr = fn.Some(payAddr)
×
1226
                        }
×
1227
                }
1228

1229
                payIntent.DestFeatures = features
3✔
1230
        }
1231

1232
        // Validate that the MPP parameters are compatible with the
1233
        // payment amount. In other words, the parameters are invalid if
1234
        // they do not permit sending the full payment amount.
1235
        if payIntent.MaxShardAmt != nil {
3✔
UNCOV
1236
                maxPossibleAmount := (*payIntent.MaxShardAmt) *
×
UNCOV
1237
                        lnwire.MilliSatoshi(payIntent.MaxParts)
×
UNCOV
1238

×
UNCOV
1239
                if payIntent.Amount > maxPossibleAmount {
×
UNCOV
1240
                        return nil, fmt.Errorf("payment amount %v exceeds "+
×
UNCOV
1241
                                "maximum possible amount %v with max_parts=%v "+
×
UNCOV
1242
                                "and max_shard_size_msat=%v", payIntent.Amount,
×
UNCOV
1243
                                maxPossibleAmount, payIntent.MaxParts,
×
UNCOV
1244
                                *payIntent.MaxShardAmt,
×
UNCOV
1245
                        )
×
UNCOV
1246
                }
×
1247
        }
1248

1249
        // Do bounds checking with the block padding so the router isn't
1250
        // left with a zombie payment in case the user messes up.
1251
        err = routing.ValidateCLTVLimit(
3✔
1252
                payIntent.CltvLimit, payIntent.FinalCLTVDelta, true,
3✔
1253
        )
3✔
1254
        if err != nil {
3✔
1255
                return nil, err
×
1256
        }
×
1257

1258
        // Check for disallowed payments to self.
1259
        if !rpcPayReq.AllowSelfPayment && payIntent.Target == r.SelfNode {
3✔
UNCOV
1260
                return nil, errors.New("self-payments not allowed")
×
UNCOV
1261
        }
×
1262

1263
        return payIntent, nil
3✔
1264
}
1265

1266
// BuildBlindedPathSet marshals a set of zpay32.BlindedPaymentPath and uses
1267
// the result to build a new routing.BlindedPaymentPathSet.
1268
func BuildBlindedPathSet(paths []*zpay32.BlindedPaymentPath) (
1269
        *routing.BlindedPaymentPathSet, error) {
3✔
1270

3✔
1271
        marshalledPaths := make([]*routing.BlindedPayment, len(paths))
3✔
1272
        for i, path := range paths {
6✔
1273
                paymentPath := marshalBlindedPayment(path)
3✔
1274

3✔
1275
                err := paymentPath.Validate()
3✔
1276
                if err != nil {
3✔
1277
                        return nil, err
×
1278
                }
×
1279

1280
                marshalledPaths[i] = paymentPath
3✔
1281
        }
1282

1283
        return routing.NewBlindedPaymentPathSet(marshalledPaths)
3✔
1284
}
1285

1286
// marshalBlindedPayment marshals a zpay32.BLindedPaymentPath into a
1287
// routing.BlindedPayment.
1288
func marshalBlindedPayment(
1289
        path *zpay32.BlindedPaymentPath) *routing.BlindedPayment {
3✔
1290

3✔
1291
        return &routing.BlindedPayment{
3✔
1292
                BlindedPath: &sphinx.BlindedPath{
3✔
1293
                        IntroductionPoint: path.Hops[0].BlindedNodePub,
3✔
1294
                        BlindingPoint:     path.FirstEphemeralBlindingPoint,
3✔
1295
                        BlindedHops:       path.Hops,
3✔
1296
                },
3✔
1297
                BaseFee:             path.FeeBaseMsat,
3✔
1298
                ProportionalFeeRate: path.FeeRate,
3✔
1299
                CltvExpiryDelta:     path.CltvExpiryDelta,
3✔
1300
                HtlcMinimum:         path.HTLCMinMsat,
3✔
1301
                HtlcMaximum:         path.HTLCMaxMsat,
3✔
1302
                Features:            path.Features,
3✔
1303
        }
3✔
1304
}
3✔
1305

1306
// unmarshallRouteHints unmarshalls a list of route hints.
1307
func unmarshallRouteHints(rpcRouteHints []*lnrpc.RouteHint) (
1308
        [][]zpay32.HopHint, error) {
3✔
1309

3✔
1310
        routeHints := make([][]zpay32.HopHint, 0, len(rpcRouteHints))
3✔
1311
        for _, rpcRouteHint := range rpcRouteHints {
6✔
1312
                routeHint := make(
3✔
1313
                        []zpay32.HopHint, 0, len(rpcRouteHint.HopHints),
3✔
1314
                )
3✔
1315
                for _, rpcHint := range rpcRouteHint.HopHints {
6✔
1316
                        hint, err := unmarshallHopHint(rpcHint)
3✔
1317
                        if err != nil {
3✔
1318
                                return nil, err
×
1319
                        }
×
1320

1321
                        routeHint = append(routeHint, hint)
3✔
1322
                }
1323
                routeHints = append(routeHints, routeHint)
3✔
1324
        }
1325

1326
        return routeHints, nil
3✔
1327
}
1328

1329
// unmarshallHopHint unmarshalls a single hop hint.
1330
func unmarshallHopHint(rpcHint *lnrpc.HopHint) (zpay32.HopHint, error) {
3✔
1331
        pubBytes, err := hex.DecodeString(rpcHint.NodeId)
3✔
1332
        if err != nil {
3✔
1333
                return zpay32.HopHint{}, err
×
1334
        }
×
1335

1336
        pubkey, err := btcec.ParsePubKey(pubBytes)
3✔
1337
        if err != nil {
3✔
1338
                return zpay32.HopHint{}, err
×
1339
        }
×
1340

1341
        return zpay32.HopHint{
3✔
1342
                NodeID:                    pubkey,
3✔
1343
                ChannelID:                 rpcHint.ChanId,
3✔
1344
                FeeBaseMSat:               rpcHint.FeeBaseMsat,
3✔
1345
                FeeProportionalMillionths: rpcHint.FeeProportionalMillionths,
3✔
1346
                CLTVExpiryDelta:           uint16(rpcHint.CltvExpiryDelta),
3✔
1347
        }, nil
3✔
1348
}
1349

1350
// MarshalFeatures converts a feature vector into a list of uint32's.
1351
func MarshalFeatures(feats *lnwire.FeatureVector) []lnrpc.FeatureBit {
3✔
1352
        var featureBits []lnrpc.FeatureBit
3✔
1353
        for feature := range feats.Features() {
6✔
1354
                featureBits = append(featureBits, lnrpc.FeatureBit(feature))
3✔
1355
        }
3✔
1356

1357
        return featureBits
3✔
1358
}
1359

1360
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
1361
// This method checks that feature bit pairs aren't assigned together, and
1362
// validates transitive dependencies.
1363
func UnmarshalFeatures(rpcFeatures []lnrpc.FeatureBit) *lnwire.FeatureVector {
3✔
1364
        // If no destination features are specified we'll return nil to signal
3✔
1365
        // that the router should try to use the graph as a fallback.
3✔
1366
        if rpcFeatures == nil {
6✔
1367
                return nil
3✔
1368
        }
3✔
1369

1370
        raw := lnwire.NewRawFeatureVector()
3✔
1371
        for _, bit := range rpcFeatures {
6✔
1372
                // Even though the spec says that the writer of a feature vector
3✔
1373
                // should never set both the required and optional bits of a
3✔
1374
                // feature, it also says that if we receive a vector with both
3✔
1375
                // bits set, then we should just treat the feature as required.
3✔
1376
                // Therefore, we don't use SafeSet here when parsing a peer's
3✔
1377
                // feature bits and just set the feature no matter what so that
3✔
1378
                // if both are set then IsRequired returns true.
3✔
1379
                raw.Set(lnwire.FeatureBit(bit))
3✔
1380
        }
3✔
1381

1382
        return lnwire.NewFeatureVector(raw, lnwire.Features)
3✔
1383
}
1384

1385
// ValidatePayReqExpiry checks if the passed payment request has expired. In
1386
// the case it has expired, an error will be returned.
1387
func ValidatePayReqExpiry(clock clock.Clock, payReq *zpay32.Invoice) error {
3✔
1388
        expiry := payReq.Expiry()
3✔
1389
        validUntil := payReq.Timestamp.Add(expiry)
3✔
1390
        if clock.Now().After(validUntil) {
3✔
UNCOV
1391
                return fmt.Errorf("invoice expired. Valid until %v", validUntil)
×
UNCOV
1392
        }
×
1393

1394
        return nil
3✔
1395
}
1396

1397
// ValidateCLTVLimit returns a valid CLTV limit given a value and a maximum. If
1398
// the value exceeds the maximum, then an error is returned. If the value is 0,
1399
// then the maximum is used.
1400
func ValidateCLTVLimit(val, max uint32) (uint32, error) {
3✔
1401
        switch {
3✔
1402
        case val == 0:
3✔
1403
                return max, nil
3✔
UNCOV
1404
        case val > max:
×
UNCOV
1405
                return 0, fmt.Errorf("total time lock of %v exceeds max "+
×
UNCOV
1406
                        "allowed %v", val, max)
×
1407
        default:
×
1408
                return val, nil
×
1409
        }
1410
}
1411

1412
// UnmarshalMPP accepts the mpp_total_amt_msat and mpp_payment_addr fields from
1413
// an RPC request and converts into an record.MPP object. An error is returned
1414
// if the payment address is not 0 or 32 bytes. If the total amount and payment
1415
// address are zero-value, the return value will be nil signaling there is no
1416
// MPP record to attach to this hop. Otherwise, a non-nil reocrd will be
1417
// contained combining the provided values.
1418
func UnmarshalMPP(reqMPP *lnrpc.MPPRecord) (*record.MPP, error) {
3✔
1419
        // If no MPP record was submitted, assume the user wants to send a
3✔
1420
        // regular payment.
3✔
1421
        if reqMPP == nil {
6✔
1422
                return nil, nil
3✔
1423
        }
3✔
1424

1425
        reqTotal := reqMPP.TotalAmtMsat
3✔
1426
        reqAddr := reqMPP.PaymentAddr
3✔
1427

3✔
1428
        switch {
3✔
1429
        // No MPP fields were provided.
UNCOV
1430
        case reqTotal == 0 && len(reqAddr) == 0:
×
UNCOV
1431
                return nil, fmt.Errorf("missing total_msat and payment_addr")
×
1432

1433
        // Total is present, but payment address is missing.
UNCOV
1434
        case reqTotal > 0 && len(reqAddr) == 0:
×
UNCOV
1435
                return nil, fmt.Errorf("missing payment_addr")
×
1436

1437
        // Payment address is present, but total is missing.
UNCOV
1438
        case reqTotal == 0 && len(reqAddr) > 0:
×
UNCOV
1439
                return nil, fmt.Errorf("missing total_msat")
×
1440
        }
1441

1442
        addr, err := lntypes.MakeHash(reqAddr)
3✔
1443
        if err != nil {
3✔
UNCOV
1444
                return nil, fmt.Errorf("unable to parse "+
×
UNCOV
1445
                        "payment_addr: %v", err)
×
UNCOV
1446
        }
×
1447

1448
        total := lnwire.MilliSatoshi(reqTotal)
3✔
1449

3✔
1450
        return record.NewMPP(total, addr), nil
3✔
1451
}
1452

1453
func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
3✔
1454
        if reqAMP == nil {
6✔
1455
                return nil, nil
3✔
1456
        }
3✔
1457

1458
        reqRootShare := reqAMP.RootShare
3✔
1459
        reqSetID := reqAMP.SetId
3✔
1460

3✔
1461
        switch {
3✔
UNCOV
1462
        case len(reqRootShare) != 32:
×
UNCOV
1463
                return nil, errors.New("AMP root_share must be 32 bytes")
×
1464

UNCOV
1465
        case len(reqSetID) != 32:
×
UNCOV
1466
                return nil, errors.New("AMP set_id must be 32 bytes")
×
1467
        }
1468

1469
        var (
3✔
1470
                rootShare [32]byte
3✔
1471
                setID     [32]byte
3✔
1472
        )
3✔
1473
        copy(rootShare[:], reqRootShare)
3✔
1474
        copy(setID[:], reqSetID)
3✔
1475

3✔
1476
        return record.NewAMP(rootShare, setID, reqAMP.ChildIndex), nil
3✔
1477
}
1478

1479
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
1480
func (r *RouterBackend) MarshalHTLCAttempt(
1481
        htlc paymentsdb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
3✔
1482

3✔
1483
        route, err := r.MarshallRoute(&htlc.Route)
3✔
1484
        if err != nil {
3✔
1485
                return nil, err
×
1486
        }
×
1487

1488
        rpcAttempt := &lnrpc.HTLCAttempt{
3✔
1489
                AttemptId:     htlc.AttemptID,
3✔
1490
                AttemptTimeNs: MarshalTimeNano(htlc.AttemptTime),
3✔
1491
                Route:         route,
3✔
1492
        }
3✔
1493

3✔
1494
        switch {
3✔
1495
        case htlc.Settle != nil:
3✔
1496
                rpcAttempt.Status = lnrpc.HTLCAttempt_SUCCEEDED
3✔
1497
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
3✔
1498
                        htlc.Settle.SettleTime,
3✔
1499
                )
3✔
1500
                rpcAttempt.Preimage = htlc.Settle.Preimage[:]
3✔
1501

1502
        case htlc.Failure != nil:
3✔
1503
                rpcAttempt.Status = lnrpc.HTLCAttempt_FAILED
3✔
1504
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
3✔
1505
                        htlc.Failure.FailTime,
3✔
1506
                )
3✔
1507

3✔
1508
                var err error
3✔
1509
                rpcAttempt.Failure, err = marshallHtlcFailure(htlc.Failure)
3✔
1510
                if err != nil {
3✔
1511
                        return nil, err
×
1512
                }
×
1513
        default:
3✔
1514
                rpcAttempt.Status = lnrpc.HTLCAttempt_IN_FLIGHT
3✔
1515
        }
1516

1517
        return rpcAttempt, nil
3✔
1518
}
1519

1520
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
1521
// representation.
1522
func marshallHtlcFailure(failure *paymentsdb.HTLCFailInfo) (*lnrpc.Failure,
1523
        error) {
3✔
1524

3✔
1525
        rpcFailure := &lnrpc.Failure{
3✔
1526
                FailureSourceIndex: failure.FailureSourceIndex,
3✔
1527
        }
3✔
1528

3✔
1529
        switch failure.Reason {
3✔
1530
        case paymentsdb.HTLCFailUnknown:
×
1531
                rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1532

1533
        case paymentsdb.HTLCFailUnreadable:
×
1534
                rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1535

1536
        case paymentsdb.HTLCFailInternal:
×
1537
                rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
×
1538

1539
        case paymentsdb.HTLCFailMessage:
3✔
1540
                err := marshallWireError(failure.Message, rpcFailure)
3✔
1541
                if err != nil {
3✔
1542
                        return nil, err
×
1543
                }
×
1544

1545
        default:
×
1546
                return nil, errors.New("unknown htlc failure reason")
×
1547
        }
1548

1549
        return rpcFailure, nil
3✔
1550
}
1551

1552
// MarshalTimeNano converts a time.Time into its nanosecond representation. If
1553
// the time is zero, this method simply returns 0, since calling UnixNano() on a
1554
// zero-valued time is undefined.
1555
func MarshalTimeNano(t time.Time) int64 {
3✔
1556
        if t.IsZero() {
3✔
UNCOV
1557
                return 0
×
UNCOV
1558
        }
×
1559
        return t.UnixNano()
3✔
1560
}
1561

1562
// marshallError marshall an error as received from the switch to rpc structs
1563
// suitable for returning to the caller of an rpc method.
1564
//
1565
// Because of difficulties with using protobuf oneof constructs in some
1566
// languages, the decision was made here to use a single message format for all
1567
// failure messages with some fields left empty depending on the failure type.
1568
func marshallError(sendError error) (*lnrpc.Failure, error) {
3✔
1569
        response := &lnrpc.Failure{}
3✔
1570

3✔
1571
        if sendError == htlcswitch.ErrUnreadableFailureMessage {
3✔
1572
                response.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1573
                return response, nil
×
1574
        }
×
1575

1576
        rtErr, ok := sendError.(htlcswitch.ClearTextError)
3✔
1577
        if !ok {
3✔
1578
                return nil, sendError
×
1579
        }
×
1580

1581
        err := marshallWireError(rtErr.WireMessage(), response)
3✔
1582
        if err != nil {
3✔
1583
                return nil, err
×
1584
        }
×
1585

1586
        // If the ClearTextError received is a ForwardingError, the error
1587
        // originated from a node along the route, not locally on our outgoing
1588
        // link. We set failureSourceIdx to the index of the node where the
1589
        // failure occurred. If the error is not a ForwardingError, the failure
1590
        // occurred at our node, so we leave the index as 0 to indicate that
1591
        // we failed locally.
1592
        fErr, ok := rtErr.(*htlcswitch.ForwardingError)
3✔
1593
        if ok {
3✔
1594
                response.FailureSourceIndex = uint32(fErr.FailureSourceIdx)
×
1595
        }
×
1596

1597
        return response, nil
3✔
1598
}
1599

1600
// marshallError marshall an error as received from the switch to rpc structs
1601
// suitable for returning to the caller of an rpc method.
1602
//
1603
// Because of difficulties with using protobuf oneof constructs in some
1604
// languages, the decision was made here to use a single message format for all
1605
// failure messages with some fields left empty depending on the failure type.
1606
func marshallWireError(msg lnwire.FailureMessage,
1607
        response *lnrpc.Failure) error {
3✔
1608

3✔
1609
        switch onionErr := msg.(type) {
3✔
1610
        case *lnwire.FailIncorrectDetails:
3✔
1611
                response.Code = lnrpc.Failure_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS
3✔
1612
                response.Height = onionErr.Height()
3✔
1613

1614
        case *lnwire.FailIncorrectPaymentAmount:
×
1615
                response.Code = lnrpc.Failure_INCORRECT_PAYMENT_AMOUNT
×
1616

1617
        case *lnwire.FailFinalIncorrectCltvExpiry:
×
1618
                response.Code = lnrpc.Failure_FINAL_INCORRECT_CLTV_EXPIRY
×
1619
                response.CltvExpiry = onionErr.CltvExpiry
×
1620

1621
        case *lnwire.FailFinalIncorrectHtlcAmount:
×
1622
                response.Code = lnrpc.Failure_FINAL_INCORRECT_HTLC_AMOUNT
×
1623
                response.HtlcMsat = uint64(onionErr.IncomingHTLCAmount)
×
1624

1625
        case *lnwire.FailFinalExpiryTooSoon:
×
1626
                response.Code = lnrpc.Failure_FINAL_EXPIRY_TOO_SOON
×
1627

1628
        case *lnwire.FailInvalidRealm:
×
1629
                response.Code = lnrpc.Failure_INVALID_REALM
×
1630

1631
        case *lnwire.FailExpiryTooSoon:
×
1632
                response.Code = lnrpc.Failure_EXPIRY_TOO_SOON
×
1633
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1634

1635
        case *lnwire.FailExpiryTooFar:
×
1636
                response.Code = lnrpc.Failure_EXPIRY_TOO_FAR
×
1637

1638
        case *lnwire.FailInvalidOnionVersion:
3✔
1639
                response.Code = lnrpc.Failure_INVALID_ONION_VERSION
3✔
1640
                response.OnionSha_256 = onionErr.OnionSHA256[:]
3✔
1641

1642
        case *lnwire.FailInvalidOnionHmac:
×
1643
                response.Code = lnrpc.Failure_INVALID_ONION_HMAC
×
1644
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1645

1646
        case *lnwire.FailInvalidOnionKey:
×
1647
                response.Code = lnrpc.Failure_INVALID_ONION_KEY
×
1648
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1649

1650
        case *lnwire.FailAmountBelowMinimum:
×
1651
                response.Code = lnrpc.Failure_AMOUNT_BELOW_MINIMUM
×
1652
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1653
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1654

1655
        case *lnwire.FailFeeInsufficient:
3✔
1656
                response.Code = lnrpc.Failure_FEE_INSUFFICIENT
3✔
1657
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
3✔
1658
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
3✔
1659

1660
        case *lnwire.FailIncorrectCltvExpiry:
×
1661
                response.Code = lnrpc.Failure_INCORRECT_CLTV_EXPIRY
×
1662
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1663
                response.CltvExpiry = onionErr.CltvExpiry
×
1664

1665
        case *lnwire.FailChannelDisabled:
3✔
1666
                response.Code = lnrpc.Failure_CHANNEL_DISABLED
3✔
1667
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
3✔
1668
                response.Flags = uint32(onionErr.Flags)
3✔
1669

1670
        case *lnwire.FailTemporaryChannelFailure:
3✔
1671
                response.Code = lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE
3✔
1672
                response.ChannelUpdate = marshallChannelUpdate(onionErr.Update)
3✔
1673

1674
        case *lnwire.FailRequiredNodeFeatureMissing:
×
1675
                response.Code = lnrpc.Failure_REQUIRED_NODE_FEATURE_MISSING
×
1676

1677
        case *lnwire.FailRequiredChannelFeatureMissing:
×
1678
                response.Code = lnrpc.Failure_REQUIRED_CHANNEL_FEATURE_MISSING
×
1679

1680
        case *lnwire.FailUnknownNextPeer:
3✔
1681
                response.Code = lnrpc.Failure_UNKNOWN_NEXT_PEER
3✔
1682

1683
        case *lnwire.FailTemporaryNodeFailure:
×
1684
                response.Code = lnrpc.Failure_TEMPORARY_NODE_FAILURE
×
1685

1686
        case *lnwire.FailPermanentNodeFailure:
×
1687
                response.Code = lnrpc.Failure_PERMANENT_NODE_FAILURE
×
1688

1689
        case *lnwire.FailPermanentChannelFailure:
3✔
1690
                response.Code = lnrpc.Failure_PERMANENT_CHANNEL_FAILURE
3✔
1691

1692
        case *lnwire.FailMPPTimeout:
×
1693
                response.Code = lnrpc.Failure_MPP_TIMEOUT
×
1694

1695
        case *lnwire.InvalidOnionPayload:
3✔
1696
                response.Code = lnrpc.Failure_INVALID_ONION_PAYLOAD
3✔
1697

1698
        case *lnwire.FailInvalidBlinding:
3✔
1699
                response.Code = lnrpc.Failure_INVALID_ONION_BLINDING
3✔
1700
                response.OnionSha_256 = onionErr.OnionSHA256[:]
3✔
1701

1702
        case nil:
×
1703
                response.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1704

1705
        default:
×
1706
                return fmt.Errorf("cannot marshall failure %T", onionErr)
×
1707
        }
1708

1709
        return nil
3✔
1710
}
1711

1712
// marshallChannelUpdate marshalls a channel update as received over the wire to
1713
// the router rpc format.
1714
func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
3✔
1715
        if update == nil {
3✔
1716
                return nil
×
1717
        }
×
1718

1719
        return &lnrpc.ChannelUpdate{
3✔
1720
                Signature:       update.Signature.RawBytes(),
3✔
1721
                ChainHash:       update.ChainHash[:],
3✔
1722
                ChanId:          update.ShortChannelID.ToUint64(),
3✔
1723
                Timestamp:       update.Timestamp,
3✔
1724
                MessageFlags:    uint32(update.MessageFlags),
3✔
1725
                ChannelFlags:    uint32(update.ChannelFlags),
3✔
1726
                TimeLockDelta:   uint32(update.TimeLockDelta),
3✔
1727
                HtlcMinimumMsat: uint64(update.HtlcMinimumMsat),
3✔
1728
                BaseFee:         update.BaseFee,
3✔
1729
                FeeRate:         update.FeeRate,
3✔
1730
                HtlcMaximumMsat: uint64(update.HtlcMaximumMsat),
3✔
1731
                ExtraOpaqueData: update.ExtraOpaqueData,
3✔
1732
        }
3✔
1733
}
1734

1735
// MarshallPayment marshall a payment to its rpc representation.
1736
func (r *RouterBackend) MarshallPayment(payment *paymentsdb.MPPayment) (
1737
        *lnrpc.Payment, error) {
3✔
1738

3✔
1739
        // Fetch the payment's preimage and the total paid in fees.
3✔
1740
        var (
3✔
1741
                fee      lnwire.MilliSatoshi
3✔
1742
                preimage lntypes.Preimage
3✔
1743
        )
3✔
1744
        for _, htlc := range payment.HTLCs {
6✔
1745
                // If any of the htlcs have settled, extract a valid
3✔
1746
                // preimage.
3✔
1747
                if htlc.Settle != nil {
6✔
1748
                        preimage = htlc.Settle.Preimage
3✔
1749
                        fee += htlc.Route.TotalFees()
3✔
1750
                }
3✔
1751
        }
1752

1753
        msatValue := int64(payment.Info.Value)
3✔
1754
        satValue := int64(payment.Info.Value.ToSatoshis())
3✔
1755

3✔
1756
        status, err := convertPaymentStatus(
3✔
1757
                payment.Status, r.UseStatusInitiated,
3✔
1758
        )
3✔
1759
        if err != nil {
3✔
1760
                return nil, err
×
1761
        }
×
1762

1763
        htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
3✔
1764
        for _, dbHTLC := range payment.HTLCs {
6✔
1765
                htlc, err := r.MarshalHTLCAttempt(dbHTLC)
3✔
1766
                if err != nil {
3✔
1767
                        return nil, err
×
1768
                }
×
1769

1770
                htlcs = append(htlcs, htlc)
3✔
1771
        }
1772

1773
        paymentID := payment.Info.PaymentIdentifier
3✔
1774
        creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
3✔
1775

3✔
1776
        failureReason, err := marshallPaymentFailureReason(
3✔
1777
                payment.FailureReason,
3✔
1778
        )
3✔
1779
        if err != nil {
3✔
1780
                return nil, err
×
1781
        }
×
1782

1783
        return &lnrpc.Payment{
3✔
1784
                // TODO: set this to setID for AMP-payments?
3✔
1785
                PaymentHash:           hex.EncodeToString(paymentID[:]),
3✔
1786
                Value:                 satValue,
3✔
1787
                ValueMsat:             msatValue,
3✔
1788
                ValueSat:              satValue,
3✔
1789
                CreationDate:          payment.Info.CreationTime.Unix(),
3✔
1790
                CreationTimeNs:        creationTimeNS,
3✔
1791
                Fee:                   int64(fee.ToSatoshis()),
3✔
1792
                FeeSat:                int64(fee.ToSatoshis()),
3✔
1793
                FeeMsat:               int64(fee),
3✔
1794
                PaymentPreimage:       hex.EncodeToString(preimage[:]),
3✔
1795
                PaymentRequest:        string(payment.Info.PaymentRequest),
3✔
1796
                Status:                status,
3✔
1797
                Htlcs:                 htlcs,
3✔
1798
                PaymentIndex:          payment.SequenceNum,
3✔
1799
                FailureReason:         failureReason,
3✔
1800
                FirstHopCustomRecords: payment.Info.FirstHopCustomRecords,
3✔
1801
        }, nil
3✔
1802
}
1803

1804
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
1805
// by the RPC.
1806
func convertPaymentStatus(dbStatus paymentsdb.PaymentStatus, useInit bool) (
1807
        lnrpc.Payment_PaymentStatus, error) {
3✔
1808

3✔
1809
        switch dbStatus {
3✔
1810
        case paymentsdb.StatusInitiated:
3✔
1811
                // If the client understands the new status, return it.
3✔
1812
                if useInit {
6✔
1813
                        return lnrpc.Payment_INITIATED, nil
3✔
1814
                }
3✔
1815

1816
                // Otherwise remain the old behavior.
1817
                return lnrpc.Payment_IN_FLIGHT, nil
3✔
1818

1819
        case paymentsdb.StatusInFlight:
3✔
1820
                return lnrpc.Payment_IN_FLIGHT, nil
3✔
1821

1822
        case paymentsdb.StatusSucceeded:
3✔
1823
                return lnrpc.Payment_SUCCEEDED, nil
3✔
1824

1825
        case paymentsdb.StatusFailed:
3✔
1826
                return lnrpc.Payment_FAILED, nil
3✔
1827

1828
        default:
×
1829
                return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
×
1830
        }
1831
}
1832

1833
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
1834
// type.
1835
func marshallPaymentFailureReason(reason *paymentsdb.FailureReason) (
1836
        lnrpc.PaymentFailureReason, error) {
3✔
1837

3✔
1838
        if reason == nil {
6✔
1839
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, nil
3✔
1840
        }
3✔
1841

1842
        switch *reason {
3✔
1843
        case paymentsdb.FailureReasonTimeout:
×
1844
                return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
×
1845

1846
        case paymentsdb.FailureReasonNoRoute:
3✔
1847
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
3✔
1848

1849
        case paymentsdb.FailureReasonError:
3✔
1850
                return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
3✔
1851

1852
        case paymentsdb.FailureReasonPaymentDetails:
3✔
1853
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
3✔
1854

1855
        case paymentsdb.FailureReasonInsufficientBalance:
3✔
1856
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
3✔
1857

1858
        case paymentsdb.FailureReasonCanceled:
3✔
1859
                return lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, nil
3✔
1860
        }
1861

1862
        return 0, errors.New("unknown failure reason")
×
1863
}
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