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

lightningnetwork / lnd / 14388908780

10 Apr 2025 07:39PM UTC coverage: 56.811% (-12.3%) from 69.08%
14388908780

Pull #9702

github

web-flow
Merge f006bbf4d into b732525a9
Pull Request #9702: multi: make payment address mandatory

28 of 42 new or added lines in 11 files covered. (66.67%)

23231 existing lines in 283 files now uncovered.

107286 of 188846 relevant lines covered (56.81%)

22749.28 hits per line

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

45.81
/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/channeldb"
18
        "github.com/lightningnetwork/lnd/feature"
19
        "github.com/lightningnetwork/lnd/htlcswitch"
20
        "github.com/lightningnetwork/lnd/lnrpc"
21
        "github.com/lightningnetwork/lnd/lntypes"
22
        "github.com/lightningnetwork/lnd/lnwire"
23
        "github.com/lightningnetwork/lnd/record"
24
        "github.com/lightningnetwork/lnd/routing"
25
        "github.com/lightningnetwork/lnd/routing/route"
26
        "github.com/lightningnetwork/lnd/subscribe"
27
        "github.com/lightningnetwork/lnd/zpay32"
28
        "google.golang.org/protobuf/proto"
29
)
30

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

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

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

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

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

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

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

68
        MissionControl MissionControl
69

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

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

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

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

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

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

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

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

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

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

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

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

122
// MissionControl defines the mission control dependencies of routerrpc.
123
type MissionControl interface {
124
        // GetProbability is expected to return the success probability of a
125
        // payment from fromNode to toNode.
126
        GetProbability(fromNode, toNode route.Vertex,
127
                amt lnwire.MilliSatoshi, capacity btcutil.Amount) float64
128

129
        // ResetHistory resets the history of MissionControl returning it to a
130
        // state as if no payment attempts have been made.
131
        ResetHistory() error
132

133
        // GetHistorySnapshot takes a snapshot from the current mission control
134
        // state and actual probability estimates.
135
        GetHistorySnapshot() *routing.MissionControlSnapshot
136

137
        // ImportHistory imports the mission control snapshot to our internal
138
        // state. This import will only be applied in-memory, and will not be
139
        // persisted across restarts.
140
        ImportHistory(snapshot *routing.MissionControlSnapshot, force bool) error
141

142
        // GetPairHistorySnapshot returns the stored history for a given node
143
        // pair.
144
        GetPairHistorySnapshot(fromNode,
145
                toNode route.Vertex) routing.TimedPairResult
146

147
        // GetConfig gets mission control's current config.
148
        GetConfig() *routing.MissionControlConfig
149

150
        // SetConfig sets mission control's config to the values provided, if
151
        // they are valid.
152
        SetConfig(cfg *routing.MissionControlConfig) error
153
}
154

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

4✔
167
        routeReq, err := r.parseQueryRoutesRequest(in)
4✔
168
        if err != nil {
5✔
169
                return nil, err
1✔
170
        }
1✔
171

172
        // Query the channel router for a possible path to the destination that
173
        // can carry `in.Amt` satoshis _including_ the total fee required on
174
        // the route
175
        route, successProb, err := r.FindRoute(routeReq)
3✔
176
        if err != nil {
3✔
177
                return nil, err
×
178
        }
×
179

180
        // For each valid route, we'll convert the result into the format
181
        // required by the RPC system.
182
        rpcRoute, err := r.MarshallRoute(route)
3✔
183
        if err != nil {
3✔
184
                return nil, err
×
185
        }
×
186

187
        routeResp := &lnrpc.QueryRoutesResponse{
3✔
188
                Routes:      []*lnrpc.Route{rpcRoute},
3✔
189
                SuccessProb: successProb,
3✔
190
        }
3✔
191

3✔
192
        return routeResp, nil
3✔
193
}
194

195
func parsePubKey(key string) (route.Vertex, error) {
4✔
196
        pubKeyBytes, err := hex.DecodeString(key)
4✔
197
        if err != nil {
4✔
198
                return route.Vertex{}, err
×
199
        }
×
200

201
        return route.NewVertexFromBytes(pubKeyBytes)
4✔
202
}
203

204
func (r *RouterBackend) parseIgnored(in *lnrpc.QueryRoutesRequest) (
205
        map[route.Vertex]struct{}, map[routing.DirectedNodePair]struct{},
206
        error) {
3✔
207

3✔
208
        ignoredNodes := make(map[route.Vertex]struct{})
3✔
209
        for _, ignorePubKey := range in.IgnoredNodes {
6✔
210
                ignoreVertex, err := route.NewVertexFromBytes(ignorePubKey)
3✔
211
                if err != nil {
3✔
212
                        return nil, nil, err
×
213
                }
×
214
                ignoredNodes[ignoreVertex] = struct{}{}
3✔
215
        }
216

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

3✔
219
        // Convert deprecated ignoredEdges to pairs.
3✔
220
        for _, ignoredEdge := range in.IgnoredEdges {
6✔
221
                pair, err := r.rpcEdgeToPair(ignoredEdge)
3✔
222
                if err != nil {
3✔
223
                        log.Warnf("Ignore channel %v skipped: %v",
×
224
                                ignoredEdge.ChannelId, err)
×
225

×
226
                        continue
×
227
                }
228
                ignoredPairs[pair] = struct{}{}
3✔
229
        }
230

231
        // Add ignored pairs to set.
232
        for _, ignorePair := range in.IgnoredPairs {
6✔
233
                from, err := route.NewVertexFromBytes(ignorePair.From)
3✔
234
                if err != nil {
3✔
235
                        return nil, nil, err
×
236
                }
×
237

238
                to, err := route.NewVertexFromBytes(ignorePair.To)
3✔
239
                if err != nil {
3✔
240
                        return nil, nil, err
×
241
                }
×
242

243
                pair := routing.NewDirectedNodePair(from, to)
3✔
244
                ignoredPairs[pair] = struct{}{}
3✔
245
        }
246

247
        return ignoredNodes, ignoredPairs, nil
3✔
248
}
249

250
func (r *RouterBackend) parseQueryRoutesRequest(in *lnrpc.QueryRoutesRequest) (
251
        *routing.RouteRequest, error) {
4✔
252

4✔
253
        // Parse the hex-encoded source public key into a full public key that
4✔
254
        // we can properly manipulate.
4✔
255

4✔
256
        var sourcePubKey route.Vertex
4✔
257
        if in.SourcePubKey != "" {
4✔
258
                var err error
×
259
                sourcePubKey, err = parsePubKey(in.SourcePubKey)
×
260
                if err != nil {
×
261
                        return nil, err
×
262
                }
×
263
        } else {
4✔
264
                // If no source is specified, use self.
4✔
265
                sourcePubKey = r.SelfNode
4✔
266
        }
4✔
267

268
        // Currently, within the bootstrap phase of the network, we limit the
269
        // largest payment size allotted to (2^32) - 1 mSAT or 4.29 million
270
        // satoshis.
271
        amt, err := lnrpc.UnmarshallAmt(in.Amt, in.AmtMsat)
4✔
272
        if err != nil {
4✔
273
                return nil, err
×
274
        }
×
275

276
        // Unmarshall restrictions from request.
277
        feeLimit := lnrpc.CalculateFeeLimit(in.FeeLimit, amt)
4✔
278

4✔
279
        // Since QueryRoutes allows having a different source other than
4✔
280
        // ourselves, we'll only apply our max time lock if we are the source.
4✔
281
        maxTotalTimelock := r.MaxTotalTimelock
4✔
282
        if sourcePubKey != r.SelfNode {
4✔
283
                maxTotalTimelock = math.MaxUint32
×
284
        }
×
285

286
        cltvLimit, err := ValidateCLTVLimit(in.CltvLimit, maxTotalTimelock)
4✔
287
        if err != nil {
4✔
288
                return nil, err
×
289
        }
×
290

291
        // If we have a blinded path set, we'll get a few of our fields from
292
        // inside of the path rather than the request's fields.
293
        var (
4✔
294
                targetPubKey   *route.Vertex
4✔
295
                routeHintEdges map[route.Vertex][]routing.AdditionalEdge
4✔
296
                blindedPathSet *routing.BlindedPaymentPathSet
4✔
297

4✔
298
                // finalCLTVDelta varies depending on whether we're sending to
4✔
299
                // a blinded route or an unblinded node. For blinded paths,
4✔
300
                // our final cltv is already baked into the path so we restrict
4✔
301
                // this value to zero on the API. Bolt11 invoices have a
4✔
302
                // default, so we'll fill that in for the non-blinded case.
4✔
303
                finalCLTVDelta uint16
4✔
304

4✔
305
                // destinationFeatures is the set of features for the
4✔
306
                // destination node.
4✔
307
                destinationFeatures *lnwire.FeatureVector
4✔
308
        )
4✔
309

4✔
310
        // Validate that the fields provided in the request are sane depending
4✔
311
        // on whether it is using a blinded path or not.
4✔
312
        if len(in.BlindedPaymentPaths) > 0 {
4✔
UNCOV
313
                blindedPathSet, err = parseBlindedPaymentPaths(in)
×
UNCOV
314
                if err != nil {
×
315
                        return nil, err
×
316
                }
×
317

UNCOV
318
                pathFeatures := blindedPathSet.Features()
×
UNCOV
319
                if pathFeatures != nil {
×
320
                        destinationFeatures = pathFeatures.Clone()
×
321
                }
×
322
        } else {
4✔
323
                // If we do not have a blinded path, a target pubkey must be
4✔
324
                // set.
4✔
325
                pk, err := parsePubKey(in.PubKey)
4✔
326
                if err != nil {
4✔
327
                        return nil, err
×
328
                }
×
329
                targetPubKey = &pk
4✔
330

4✔
331
                // Convert route hints to an edge map.
4✔
332
                routeHints, err := unmarshallRouteHints(in.RouteHints)
4✔
333
                if err != nil {
4✔
334
                        return nil, err
×
335
                }
×
336

337
                routeHintEdges, err = routing.RouteHintsToEdges(
4✔
338
                        routeHints, *targetPubKey,
4✔
339
                )
4✔
340
                if err != nil {
4✔
341
                        return nil, err
×
342
                }
×
343

344
                // Set a non-zero final CLTV delta for payments that are not
345
                // to blinded paths, as bolt11 has a default final cltv delta
346
                // value that is used in the absence of a value.
347
                finalCLTVDelta = r.DefaultFinalCltvDelta
4✔
348
                if in.FinalCltvDelta != 0 {
8✔
349
                        finalCLTVDelta = uint16(in.FinalCltvDelta)
4✔
350
                }
4✔
351

352
                // Do bounds checking without block padding so we don't give
353
                // routes that will leave the router in a zombie payment state.
354
                err = routing.ValidateCLTVLimit(
4✔
355
                        cltvLimit, finalCLTVDelta, false,
4✔
356
                )
4✔
357
                if err != nil {
5✔
358
                        return nil, err
1✔
359
                }
1✔
360

361
                // Parse destination feature bits.
362
                destinationFeatures, err = UnmarshalFeatures(in.DestFeatures)
3✔
363
                if err != nil {
3✔
364
                        return nil, err
×
365
                }
×
366
        }
367

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

3✔
373
        ignoredNodes, ignoredPairs, err := r.parseIgnored(in)
3✔
374
        if err != nil {
3✔
375
                return nil, err
×
376
        }
×
377

378
        restrictions := &routing.RestrictParams{
3✔
379
                FeeLimit: feeLimit,
3✔
380
                ProbabilitySource: func(fromNode, toNode route.Vertex,
3✔
381
                        amt lnwire.MilliSatoshi,
3✔
382
                        capacity btcutil.Amount) float64 {
15✔
383

12✔
384
                        if _, ok := ignoredNodes[fromNode]; ok {
15✔
385
                                return 0
3✔
386
                        }
3✔
387

388
                        pair := routing.DirectedNodePair{
9✔
389
                                From: fromNode,
9✔
390
                                To:   toNode,
9✔
391
                        }
9✔
392
                        if _, ok := ignoredPairs[pair]; ok {
15✔
393
                                return 0
6✔
394
                        }
6✔
395

396
                        if !in.UseMissionControl {
5✔
397
                                return 1
2✔
398
                        }
2✔
399

400
                        return r.MissionControl.GetProbability(
1✔
401
                                fromNode, toNode, amt, capacity,
1✔
402
                        )
1✔
403
                },
404
                DestCustomRecords:     record.CustomSet(in.DestCustomRecords),
405
                CltvLimit:             cltvLimit,
406
                DestFeatures:          destinationFeatures,
407
                BlindedPaymentPathSet: blindedPathSet,
408
        }
409

410
        // Pass along an outgoing channel restriction if specified.
411
        if in.OutgoingChanId != 0 {
6✔
412
                restrictions.OutgoingChannelIDs = []uint64{in.OutgoingChanId}
3✔
413
        }
3✔
414

415
        // Pass along a last hop restriction if specified.
416
        if len(in.LastHopPubkey) > 0 {
6✔
417
                lastHop, err := route.NewVertexFromBytes(
3✔
418
                        in.LastHopPubkey,
3✔
419
                )
3✔
420
                if err != nil {
3✔
421
                        return nil, err
×
422
                }
×
423
                restrictions.LastHop = &lastHop
3✔
424
        }
425

426
        // If we have any TLV records destined for the final hop, then we'll
427
        // attempt to decode them now into a form that the router can more
428
        // easily manipulate.
429
        customRecords := record.CustomSet(in.DestCustomRecords)
3✔
430
        if err := customRecords.Validate(); err != nil {
3✔
431
                return nil, err
×
432
        }
×
433

434
        return routing.NewRouteRequest(
3✔
435
                sourcePubKey, targetPubKey, amt, in.TimePref, restrictions,
3✔
436
                customRecords, routeHintEdges, blindedPathSet,
3✔
437
                finalCLTVDelta,
3✔
438
        )
3✔
439
}
440

441
func parseBlindedPaymentPaths(in *lnrpc.QueryRoutesRequest) (
UNCOV
442
        *routing.BlindedPaymentPathSet, error) {
×
UNCOV
443

×
UNCOV
444
        if len(in.PubKey) != 0 {
×
445
                return nil, fmt.Errorf("target pubkey: %x should not be set "+
×
446
                        "when blinded path is provided", in.PubKey)
×
447
        }
×
448

UNCOV
449
        if len(in.RouteHints) > 0 {
×
450
                return nil, errors.New("route hints and blinded path can't " +
×
451
                        "both be set")
×
452
        }
×
453

UNCOV
454
        if in.FinalCltvDelta != 0 {
×
455
                return nil, errors.New("final cltv delta should be " +
×
456
                        "zero for blinded paths")
×
457
        }
×
458

459
        // For blinded paths, we get one set of features for the relaying
460
        // intermediate nodes and the final destination. We don't allow the
461
        // destination feature bit field for regular payments to be set, as
462
        // this could lead to ambiguity.
UNCOV
463
        if len(in.DestFeatures) > 0 {
×
464
                return nil, errors.New("destination features should " +
×
465
                        "be populated in blinded path")
×
466
        }
×
467

UNCOV
468
        paths := make([]*routing.BlindedPayment, len(in.BlindedPaymentPaths))
×
UNCOV
469
        for i, paymentPath := range in.BlindedPaymentPaths {
×
UNCOV
470
                blindedPmt, err := unmarshalBlindedPayment(paymentPath)
×
UNCOV
471
                if err != nil {
×
472
                        return nil, fmt.Errorf("parse blinded payment: %w", err)
×
473
                }
×
474

UNCOV
475
                if err := blindedPmt.Validate(); err != nil {
×
476
                        return nil, fmt.Errorf("invalid blinded path: %w", err)
×
477
                }
×
478

UNCOV
479
                paths[i] = blindedPmt
×
480
        }
481

UNCOV
482
        return routing.NewBlindedPaymentPathSet(paths)
×
483
}
484

485
func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
UNCOV
486
        *routing.BlindedPayment, error) {
×
UNCOV
487

×
UNCOV
488
        if rpcPayment == nil {
×
489
                return nil, errors.New("nil blinded payment")
×
490
        }
×
491

UNCOV
492
        path, err := unmarshalBlindedPaymentPaths(rpcPayment.BlindedPath)
×
UNCOV
493
        if err != nil {
×
494
                return nil, err
×
495
        }
×
496

UNCOV
497
        features, err := UnmarshalFeatures(rpcPayment.Features)
×
UNCOV
498
        if err != nil {
×
499
                return nil, err
×
500
        }
×
501

UNCOV
502
        return &routing.BlindedPayment{
×
UNCOV
503
                BlindedPath:         path,
×
UNCOV
504
                CltvExpiryDelta:     uint16(rpcPayment.TotalCltvDelta),
×
UNCOV
505
                BaseFee:             uint32(rpcPayment.BaseFeeMsat),
×
UNCOV
506
                ProportionalFeeRate: rpcPayment.ProportionalFeeRate,
×
UNCOV
507
                HtlcMinimum:         rpcPayment.HtlcMinMsat,
×
UNCOV
508
                HtlcMaximum:         rpcPayment.HtlcMaxMsat,
×
UNCOV
509
                Features:            features,
×
UNCOV
510
        }, nil
×
511
}
512

513
func unmarshalBlindedPaymentPaths(rpcPath *lnrpc.BlindedPath) (
UNCOV
514
        *sphinx.BlindedPath, error) {
×
UNCOV
515

×
UNCOV
516
        if rpcPath == nil {
×
517
                return nil, errors.New("blinded path required when blinded " +
×
518
                        "route is provided")
×
519
        }
×
520

UNCOV
521
        introduction, err := btcec.ParsePubKey(rpcPath.IntroductionNode)
×
UNCOV
522
        if err != nil {
×
523
                return nil, err
×
524
        }
×
525

UNCOV
526
        blinding, err := btcec.ParsePubKey(rpcPath.BlindingPoint)
×
UNCOV
527
        if err != nil {
×
528
                return nil, err
×
529
        }
×
530

UNCOV
531
        if len(rpcPath.BlindedHops) < 1 {
×
532
                return nil, errors.New("at least 1 blinded hops required")
×
533
        }
×
534

UNCOV
535
        path := &sphinx.BlindedPath{
×
UNCOV
536
                IntroductionPoint: introduction,
×
UNCOV
537
                BlindingPoint:     blinding,
×
UNCOV
538
                BlindedHops: make(
×
UNCOV
539
                        []*sphinx.BlindedHopInfo, len(rpcPath.BlindedHops),
×
UNCOV
540
                ),
×
UNCOV
541
        }
×
UNCOV
542

×
UNCOV
543
        for i, hop := range rpcPath.BlindedHops {
×
UNCOV
544
                path.BlindedHops[i], err = unmarshalBlindedHop(hop)
×
UNCOV
545
                if err != nil {
×
546
                        return nil, err
×
547
                }
×
548
        }
549

UNCOV
550
        return path, nil
×
551
}
552

553
func unmarshalBlindedHop(rpcHop *lnrpc.BlindedHop) (*sphinx.BlindedHopInfo,
UNCOV
554
        error) {
×
UNCOV
555

×
UNCOV
556
        pubkey, err := btcec.ParsePubKey(rpcHop.BlindedNode)
×
UNCOV
557
        if err != nil {
×
558
                return nil, err
×
559
        }
×
560

UNCOV
561
        if len(rpcHop.EncryptedData) == 0 {
×
562
                return nil, errors.New("empty encrypted data not allowed")
×
563
        }
×
564

UNCOV
565
        return &sphinx.BlindedHopInfo{
×
UNCOV
566
                BlindedNodePub: pubkey,
×
UNCOV
567
                CipherText:     rpcHop.EncryptedData,
×
UNCOV
568
        }, nil
×
569
}
570

571
// rpcEdgeToPair looks up the provided channel and returns the channel endpoints
572
// as a directed pair.
573
func (r *RouterBackend) rpcEdgeToPair(e *lnrpc.EdgeLocator) (
574
        routing.DirectedNodePair, error) {
3✔
575

3✔
576
        a, b, err := r.FetchChannelEndpoints(e.ChannelId)
3✔
577
        if err != nil {
3✔
578
                return routing.DirectedNodePair{}, err
×
579
        }
×
580

581
        var pair routing.DirectedNodePair
3✔
582
        if e.DirectionReverse {
6✔
583
                pair.From, pair.To = b, a
3✔
584
        } else {
3✔
585
                pair.From, pair.To = a, b
×
586
        }
×
587

588
        return pair, nil
3✔
589
}
590

591
// MarshallRoute marshalls an internal route to an rpc route struct.
592
func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) {
3✔
593
        resp := &lnrpc.Route{
3✔
594
                TotalTimeLock:      route.TotalTimeLock,
3✔
595
                TotalFees:          int64(route.TotalFees().ToSatoshis()),
3✔
596
                TotalFeesMsat:      int64(route.TotalFees()),
3✔
597
                TotalAmt:           int64(route.TotalAmount.ToSatoshis()),
3✔
598
                TotalAmtMsat:       int64(route.TotalAmount),
3✔
599
                Hops:               make([]*lnrpc.Hop, len(route.Hops)),
3✔
600
                FirstHopAmountMsat: int64(route.FirstHopAmount.Val.Int()),
3✔
601
        }
3✔
602

3✔
603
        // Encode the route's custom channel data (if available).
3✔
604
        if len(route.FirstHopWireCustomRecords) > 0 {
3✔
UNCOV
605
                customData, err := route.FirstHopWireCustomRecords.Serialize()
×
UNCOV
606
                if err != nil {
×
607
                        return nil, err
×
608
                }
×
609

UNCOV
610
                resp.CustomChannelData = customData
×
UNCOV
611

×
UNCOV
612
                // Allow the aux data parser to parse the custom records into
×
UNCOV
613
                // a human-readable JSON (if available).
×
UNCOV
614
                if r.ParseCustomChannelData != nil {
×
UNCOV
615
                        err := r.ParseCustomChannelData(resp)
×
UNCOV
616
                        if err != nil {
×
617
                                return nil, err
×
618
                        }
×
619
                }
620
        }
621

622
        incomingAmt := route.TotalAmount
3✔
623
        for i, hop := range route.Hops {
6✔
624
                fee := route.HopFee(i)
3✔
625

3✔
626
                // Channel capacity is not a defining property of a route. For
3✔
627
                // backwards RPC compatibility, we retrieve it here from the
3✔
628
                // graph.
3✔
629
                chanCapacity, err := r.FetchChannelCapacity(hop.ChannelID)
3✔
630
                if err != nil {
3✔
UNCOV
631
                        // If capacity cannot be retrieved, this may be a
×
UNCOV
632
                        // not-yet-received or private channel. Then report
×
UNCOV
633
                        // amount that is sent through the channel as capacity.
×
UNCOV
634
                        chanCapacity = incomingAmt.ToSatoshis()
×
UNCOV
635
                }
×
636

637
                // Extract the MPP fields if present on this hop.
638
                var mpp *lnrpc.MPPRecord
3✔
639
                if hop.MPP != nil {
3✔
UNCOV
640
                        addr := hop.MPP.PaymentAddr()
×
UNCOV
641

×
UNCOV
642
                        mpp = &lnrpc.MPPRecord{
×
UNCOV
643
                                PaymentAddr:  addr[:],
×
UNCOV
644
                                TotalAmtMsat: int64(hop.MPP.TotalMsat()),
×
UNCOV
645
                        }
×
UNCOV
646
                }
×
647

648
                var amp *lnrpc.AMPRecord
3✔
649
                if hop.AMP != nil {
3✔
UNCOV
650
                        rootShare := hop.AMP.RootShare()
×
UNCOV
651
                        setID := hop.AMP.SetID()
×
UNCOV
652

×
UNCOV
653
                        amp = &lnrpc.AMPRecord{
×
UNCOV
654
                                RootShare:  rootShare[:],
×
UNCOV
655
                                SetId:      setID[:],
×
UNCOV
656
                                ChildIndex: hop.AMP.ChildIndex(),
×
UNCOV
657
                        }
×
UNCOV
658
                }
×
659

660
                resp.Hops[i] = &lnrpc.Hop{
3✔
661
                        ChanId:           hop.ChannelID,
3✔
662
                        ChanCapacity:     int64(chanCapacity),
3✔
663
                        AmtToForward:     int64(hop.AmtToForward.ToSatoshis()),
3✔
664
                        AmtToForwardMsat: int64(hop.AmtToForward),
3✔
665
                        Fee:              int64(fee.ToSatoshis()),
3✔
666
                        FeeMsat:          int64(fee),
3✔
667
                        Expiry:           uint32(hop.OutgoingTimeLock),
3✔
668
                        PubKey: hex.EncodeToString(
3✔
669
                                hop.PubKeyBytes[:],
3✔
670
                        ),
3✔
671
                        CustomRecords: hop.CustomRecords,
3✔
672
                        TlvPayload:    !hop.LegacyPayload,
3✔
673
                        MppRecord:     mpp,
3✔
674
                        AmpRecord:     amp,
3✔
675
                        Metadata:      hop.Metadata,
3✔
676
                        EncryptedData: hop.EncryptedData,
3✔
677
                        TotalAmtMsat:  uint64(hop.TotalAmtMsat),
3✔
678
                }
3✔
679

3✔
680
                if hop.BlindingPoint != nil {
3✔
UNCOV
681
                        blinding := hop.BlindingPoint.SerializeCompressed()
×
UNCOV
682
                        resp.Hops[i].BlindingPoint = blinding
×
UNCOV
683
                }
×
684
                incomingAmt = hop.AmtToForward
3✔
685
        }
686

687
        return resp, nil
3✔
688
}
689

690
// UnmarshallHopWithPubkey unmarshalls an rpc hop for which the pubkey has
691
// already been extracted.
692
func UnmarshallHopWithPubkey(rpcHop *lnrpc.Hop, pubkey route.Vertex) (*route.Hop,
UNCOV
693
        error) {
×
UNCOV
694

×
UNCOV
695
        customRecords := record.CustomSet(rpcHop.CustomRecords)
×
UNCOV
696
        if err := customRecords.Validate(); err != nil {
×
697
                return nil, err
×
698
        }
×
699

UNCOV
700
        mpp, err := UnmarshalMPP(rpcHop.MppRecord)
×
UNCOV
701
        if err != nil {
×
702
                return nil, err
×
703
        }
×
704

UNCOV
705
        amp, err := UnmarshalAMP(rpcHop.AmpRecord)
×
UNCOV
706
        if err != nil {
×
707
                return nil, err
×
708
        }
×
709

UNCOV
710
        hop := &route.Hop{
×
UNCOV
711
                OutgoingTimeLock: rpcHop.Expiry,
×
UNCOV
712
                AmtToForward:     lnwire.MilliSatoshi(rpcHop.AmtToForwardMsat),
×
UNCOV
713
                PubKeyBytes:      pubkey,
×
UNCOV
714
                ChannelID:        rpcHop.ChanId,
×
UNCOV
715
                CustomRecords:    customRecords,
×
UNCOV
716
                LegacyPayload:    false,
×
UNCOV
717
                MPP:              mpp,
×
UNCOV
718
                AMP:              amp,
×
UNCOV
719
                EncryptedData:    rpcHop.EncryptedData,
×
UNCOV
720
                TotalAmtMsat:     lnwire.MilliSatoshi(rpcHop.TotalAmtMsat),
×
UNCOV
721
        }
×
UNCOV
722

×
UNCOV
723
        haveBlindingPoint := len(rpcHop.BlindingPoint) != 0
×
UNCOV
724
        if haveBlindingPoint {
×
UNCOV
725
                hop.BlindingPoint, err = btcec.ParsePubKey(
×
UNCOV
726
                        rpcHop.BlindingPoint,
×
UNCOV
727
                )
×
UNCOV
728
                if err != nil {
×
729
                        return nil, fmt.Errorf("blinding point: %w", err)
×
730
                }
×
731
        }
732

UNCOV
733
        if haveBlindingPoint && len(rpcHop.EncryptedData) == 0 {
×
734
                return nil, errors.New("encrypted data should be present if " +
×
735
                        "blinding point is provided")
×
736
        }
×
737

UNCOV
738
        return hop, nil
×
739
}
740

741
// UnmarshallHop unmarshalls an rpc hop that may or may not contain a node
742
// pubkey.
743
func (r *RouterBackend) UnmarshallHop(rpcHop *lnrpc.Hop,
UNCOV
744
        prevNodePubKey [33]byte) (*route.Hop, error) {
×
UNCOV
745

×
UNCOV
746
        var pubKeyBytes [33]byte
×
UNCOV
747
        if rpcHop.PubKey != "" {
×
UNCOV
748
                // Unmarshall the provided hop pubkey.
×
UNCOV
749
                pubKey, err := hex.DecodeString(rpcHop.PubKey)
×
UNCOV
750
                if err != nil {
×
751
                        return nil, fmt.Errorf("cannot decode pubkey %s",
×
752
                                rpcHop.PubKey)
×
753
                }
×
UNCOV
754
                copy(pubKeyBytes[:], pubKey)
×
755
        } else {
×
756
                // If no pub key is given of the hop, the local channel graph
×
757
                // needs to be queried to complete the information necessary for
×
758
                // routing. Discard edge policies, because they may be nil.
×
759
                node1, node2, err := r.FetchChannelEndpoints(rpcHop.ChanId)
×
760
                if err != nil {
×
761
                        return nil, err
×
762
                }
×
763

764
                switch {
×
765
                case prevNodePubKey == node1:
×
766
                        pubKeyBytes = node2
×
767
                case prevNodePubKey == node2:
×
768
                        pubKeyBytes = node1
×
769
                default:
×
770
                        return nil, fmt.Errorf("channel edge does not match " +
×
771
                                "expected node")
×
772
                }
773
        }
774

UNCOV
775
        return UnmarshallHopWithPubkey(rpcHop, pubKeyBytes)
×
776
}
777

778
// UnmarshallRoute unmarshalls an rpc route. For hops that don't specify a
779
// pubkey, the channel graph is queried.
780
func (r *RouterBackend) UnmarshallRoute(rpcroute *lnrpc.Route) (
UNCOV
781
        *route.Route, error) {
×
UNCOV
782

×
UNCOV
783
        prevNodePubKey := r.SelfNode
×
UNCOV
784

×
UNCOV
785
        hops := make([]*route.Hop, len(rpcroute.Hops))
×
UNCOV
786
        for i, hop := range rpcroute.Hops {
×
UNCOV
787
                routeHop, err := r.UnmarshallHop(hop, prevNodePubKey)
×
UNCOV
788
                if err != nil {
×
789
                        return nil, err
×
790
                }
×
791

UNCOV
792
                hops[i] = routeHop
×
UNCOV
793

×
UNCOV
794
                prevNodePubKey = routeHop.PubKeyBytes
×
795
        }
796

UNCOV
797
        route, err := route.NewRouteFromHops(
×
UNCOV
798
                lnwire.MilliSatoshi(rpcroute.TotalAmtMsat),
×
UNCOV
799
                rpcroute.TotalTimeLock,
×
UNCOV
800
                r.SelfNode,
×
UNCOV
801
                hops,
×
UNCOV
802
        )
×
UNCOV
803
        if err != nil {
×
804
                return nil, err
×
805
        }
×
806

UNCOV
807
        return route, nil
×
808
}
809

810
// extractIntentFromSendRequest attempts to parse the SendRequest details
811
// required to dispatch a client from the information presented by an RPC
812
// client.
813
func (r *RouterBackend) extractIntentFromSendRequest(
814
        rpcPayReq *SendPaymentRequest) (*routing.LightningPayment, error) {
23✔
815

23✔
816
        payIntent := &routing.LightningPayment{}
23✔
817

23✔
818
        // Pass along time preference.
23✔
819
        if rpcPayReq.TimePref < -1 || rpcPayReq.TimePref > 1 {
24✔
820
                return nil, errors.New("time preference out of range")
1✔
821
        }
1✔
822
        payIntent.TimePref = rpcPayReq.TimePref
22✔
823

22✔
824
        // Pass along restrictions on the outgoing channels that may be used.
22✔
825
        payIntent.OutgoingChannelIDs = rpcPayReq.OutgoingChanIds
22✔
826

22✔
827
        // Add the deprecated single outgoing channel restriction if present.
22✔
828
        if rpcPayReq.OutgoingChanId != 0 {
23✔
829
                if payIntent.OutgoingChannelIDs != nil {
2✔
830
                        return nil, errors.New("outgoing_chan_id and " +
1✔
831
                                "outgoing_chan_ids are mutually exclusive")
1✔
832
                }
1✔
833

834
                payIntent.OutgoingChannelIDs = append(
×
835
                        payIntent.OutgoingChannelIDs, rpcPayReq.OutgoingChanId,
×
836
                )
×
837
        }
838

839
        // Pass along a last hop restriction if specified.
840
        if len(rpcPayReq.LastHopPubkey) > 0 {
22✔
841
                lastHop, err := route.NewVertexFromBytes(
1✔
842
                        rpcPayReq.LastHopPubkey,
1✔
843
                )
1✔
844
                if err != nil {
2✔
845
                        return nil, err
1✔
846
                }
1✔
847
                payIntent.LastHop = &lastHop
×
848
        }
849

850
        // Take the CLTV limit from the request if set, otherwise use the max.
851
        cltvLimit, err := ValidateCLTVLimit(
20✔
852
                uint32(rpcPayReq.CltvLimit), r.MaxTotalTimelock,
20✔
853
        )
20✔
854
        if err != nil {
21✔
855
                return nil, err
1✔
856
        }
1✔
857
        payIntent.CltvLimit = cltvLimit
19✔
858

19✔
859
        // Attempt to parse the max parts value set by the user, if this value
19✔
860
        // isn't set, then we'll use the current default value for this
19✔
861
        // setting.
19✔
862
        maxParts := rpcPayReq.MaxParts
19✔
863
        if maxParts == 0 {
35✔
864
                maxParts = DefaultMaxParts
16✔
865
        }
16✔
866
        payIntent.MaxParts = maxParts
19✔
867

19✔
868
        // If this payment had a max shard amount specified, then we'll apply
19✔
869
        // that now, which'll force us to always make payment splits smaller
19✔
870
        // than this.
19✔
871
        if rpcPayReq.MaxShardSizeMsat > 0 {
23✔
872
                shardAmtMsat := lnwire.MilliSatoshi(rpcPayReq.MaxShardSizeMsat)
4✔
873
                payIntent.MaxShardAmt = &shardAmtMsat
4✔
874

4✔
875
                // If the requested max_parts exceeds the allowed limit, then we
4✔
876
                // cannot send the payment amount.
4✔
877
                if payIntent.MaxParts > MaxPartsUpperLimit {
5✔
878
                        return nil, fmt.Errorf("requested max_parts (%v) "+
1✔
879
                                "exceeds the allowed upper limit of %v; cannot"+
1✔
880
                                " send payment amount with max_shard_size_msat"+
1✔
881
                                "=%v", payIntent.MaxParts, MaxPartsUpperLimit,
1✔
882
                                *payIntent.MaxShardAmt)
1✔
883
                }
1✔
884
        }
885

886
        // Take fee limit from request.
887
        payIntent.FeeLimit, err = lnrpc.UnmarshallAmt(
18✔
888
                rpcPayReq.FeeLimitSat, rpcPayReq.FeeLimitMsat,
18✔
889
        )
18✔
890
        if err != nil {
20✔
891
                return nil, err
2✔
892
        }
2✔
893

894
        customRecords := record.CustomSet(rpcPayReq.DestCustomRecords)
16✔
895
        if err := customRecords.Validate(); err != nil {
17✔
896
                return nil, err
1✔
897
        }
1✔
898
        payIntent.DestCustomRecords = customRecords
15✔
899

15✔
900
        // Keysend payments do not support MPP payments.
15✔
901
        //
15✔
902
        // NOTE: There is no need to validate the `MaxParts` value here because
15✔
903
        // it is set to 1 somewhere else in case it's a keysend payment.
15✔
904
        if customRecords.IsKeysend() {
16✔
905
                if payIntent.MaxShardAmt != nil {
2✔
906
                        return nil, errors.New("keysend payments cannot " +
1✔
907
                                "specify a max shard amount - MPP not " +
1✔
908
                                "supported with keysend payments")
1✔
909
                }
1✔
910
        }
911

912
        firstHopRecords := lnwire.CustomRecords(rpcPayReq.FirstHopCustomRecords)
14✔
913
        if err := firstHopRecords.Validate(); err != nil {
15✔
914
                return nil, err
1✔
915
        }
1✔
916
        payIntent.FirstHopCustomRecords = firstHopRecords
13✔
917

13✔
918
        // If the experimental endorsement signal is not already set, propagate
13✔
919
        // a zero value field if configured to set this signal.
13✔
920
        if r.ShouldSetExpEndorsement() {
14✔
921
                if payIntent.FirstHopCustomRecords == nil {
2✔
922
                        payIntent.FirstHopCustomRecords = make(
1✔
923
                                map[uint64][]byte,
1✔
924
                        )
1✔
925
                }
1✔
926

927
                t := uint64(lnwire.ExperimentalEndorsementType)
1✔
928
                if _, set := payIntent.FirstHopCustomRecords[t]; !set {
2✔
929
                        payIntent.FirstHopCustomRecords[t] = []byte{
1✔
930
                                lnwire.ExperimentalUnendorsed,
1✔
931
                        }
1✔
932
                }
1✔
933
        }
934

935
        payIntent.PayAttemptTimeout = time.Second *
13✔
936
                time.Duration(rpcPayReq.TimeoutSeconds)
13✔
937

13✔
938
        // Route hints.
13✔
939
        routeHints, err := unmarshallRouteHints(
13✔
940
                rpcPayReq.RouteHints,
13✔
941
        )
13✔
942
        if err != nil {
13✔
943
                return nil, err
×
944
        }
×
945
        payIntent.RouteHints = routeHints
13✔
946

13✔
947
        // Unmarshall either sat or msat amount from request.
13✔
948
        reqAmt, err := lnrpc.UnmarshallAmt(
13✔
949
                rpcPayReq.Amt, rpcPayReq.AmtMsat,
13✔
950
        )
13✔
951
        if err != nil {
14✔
952
                return nil, err
1✔
953
        }
1✔
954

955
        // If the payment request field isn't blank, then the details of the
956
        // invoice are encoded entirely within the encoded payReq.  So we'll
957
        // attempt to decode it, populating the payment accordingly.
958
        if rpcPayReq.PaymentRequest != "" {
17✔
959
                switch {
5✔
960

961
                case len(rpcPayReq.Dest) > 0:
1✔
962
                        return nil, errors.New("dest and payment_request " +
1✔
963
                                "cannot appear together")
1✔
964

965
                case len(rpcPayReq.PaymentHash) > 0:
1✔
966
                        return nil, errors.New("payment_hash and payment_request " +
1✔
967
                                "cannot appear together")
1✔
968

969
                case rpcPayReq.FinalCltvDelta != 0:
1✔
970
                        return nil, errors.New("final_cltv_delta and payment_request " +
1✔
971
                                "cannot appear together")
1✔
972
                }
973

974
                payReq, err := zpay32.Decode(
2✔
975
                        rpcPayReq.PaymentRequest, r.ActiveNetParams,
2✔
976
                )
2✔
977
                if err != nil {
3✔
978
                        return nil, err
1✔
979
                }
1✔
980

981
                // Next, we'll ensure that this payreq hasn't already expired.
982
                err = ValidatePayReqExpiry(payReq)
1✔
983
                if err != nil {
2✔
984
                        return nil, err
1✔
985
                }
1✔
986

987
                // If the amount was not included in the invoice, then we let
988
                // the payer specify the amount of satoshis they wish to send.
989
                // We override the amount to pay with the amount provided from
990
                // the payment request.
UNCOV
991
                if payReq.MilliSat == nil {
×
992
                        if reqAmt == 0 {
×
993
                                return nil, errors.New("amount must be " +
×
994
                                        "specified when paying a zero amount " +
×
995
                                        "invoice")
×
996
                        }
×
997

998
                        payIntent.Amount = reqAmt
×
UNCOV
999
                } else {
×
UNCOV
1000
                        if reqAmt != 0 {
×
1001
                                return nil, errors.New("amount must not be " +
×
1002
                                        "specified when paying a non-zero " +
×
1003
                                        " amount invoice")
×
1004
                        }
×
1005

UNCOV
1006
                        payIntent.Amount = *payReq.MilliSat
×
1007
                }
1008

UNCOV
1009
                if !payReq.Features.HasFeature(lnwire.MPPOptional) &&
×
UNCOV
1010
                        !payReq.Features.HasFeature(lnwire.AMPOptional) {
×
1011

×
1012
                        payIntent.MaxParts = 1
×
1013
                }
×
1014

UNCOV
1015
                payAddr := payReq.PaymentAddr
×
UNCOV
1016
                if payReq.Features.HasFeature(lnwire.AMPOptional) {
×
UNCOV
1017
                        // The opt-in AMP flag is required to pay an AMP
×
UNCOV
1018
                        // invoice.
×
UNCOV
1019
                        if !rpcPayReq.Amp {
×
1020
                                return nil, fmt.Errorf("the AMP flag (--amp " +
×
1021
                                        "or SendPaymentRequest.Amp) must be " +
×
1022
                                        "set to pay an AMP invoice")
×
1023
                        }
×
1024

1025
                        // Generate random SetID and root share.
UNCOV
1026
                        var setID [32]byte
×
UNCOV
1027
                        _, err = rand.Read(setID[:])
×
UNCOV
1028
                        if err != nil {
×
1029
                                return nil, err
×
1030
                        }
×
1031

UNCOV
1032
                        var rootShare [32]byte
×
UNCOV
1033
                        _, err = rand.Read(rootShare[:])
×
UNCOV
1034
                        if err != nil {
×
1035
                                return nil, err
×
1036
                        }
×
UNCOV
1037
                        err := payIntent.SetAMP(&routing.AMPOptions{
×
UNCOV
1038
                                SetID:     setID,
×
UNCOV
1039
                                RootShare: rootShare,
×
UNCOV
1040
                        })
×
UNCOV
1041
                        if err != nil {
×
NEW
1042
                                return nil, err
×
1043
                        }
×
1044

1045
                        // For AMP invoices, we'll allow users to override the
1046
                        // included payment addr to allow the invoice to be
1047
                        // pseudo-reusable, e.g. the invoice parameters are
1048
                        // reused (amt, cltv, hop hints, etc) even though the
1049
                        // payments will share different payment hashes.
1050
                        //
1051
                        // NOTE: This will only work when the peer has
1052
                        // spontaneous AMP payments enabled.
UNCOV
1053
                        if len(rpcPayReq.PaymentAddr) > 0 {
×
UNCOV
1054
                                var addr [32]byte
×
UNCOV
1055
                                copy(addr[:], rpcPayReq.PaymentAddr)
×
UNCOV
1056
                                payAddr = &addr
×
UNCOV
1057
                        }
×
UNCOV
1058
                } else {
×
UNCOV
1059
                        err = payIntent.SetPaymentHash(*payReq.PaymentHash)
×
UNCOV
1060
                        if err != nil {
×
1061
                                return nil, err
×
1062
                        }
×
1063
                }
1064

UNCOV
1065
                destKey := payReq.Destination.SerializeCompressed()
×
UNCOV
1066
                copy(payIntent.Target[:], destKey)
×
UNCOV
1067

×
UNCOV
1068
                payIntent.FinalCLTVDelta = uint16(payReq.MinFinalCLTVExpiry())
×
UNCOV
1069
                payIntent.RouteHints = append(
×
UNCOV
1070
                        payIntent.RouteHints, payReq.RouteHints...,
×
UNCOV
1071
                )
×
UNCOV
1072
                payIntent.DestFeatures = payReq.Features
×
UNCOV
1073
                payIntent.PaymentAddr = payAddr
×
UNCOV
1074
                payIntent.PaymentRequest = []byte(rpcPayReq.PaymentRequest)
×
UNCOV
1075
                payIntent.Metadata = payReq.Metadata
×
UNCOV
1076

×
UNCOV
1077
                if len(payReq.BlindedPaymentPaths) > 0 {
×
UNCOV
1078
                        pathSet, err := BuildBlindedPathSet(
×
UNCOV
1079
                                payReq.BlindedPaymentPaths,
×
UNCOV
1080
                        )
×
UNCOV
1081
                        if err != nil {
×
1082
                                return nil, err
×
1083
                        }
×
UNCOV
1084
                        payIntent.BlindedPathSet = pathSet
×
UNCOV
1085

×
UNCOV
1086
                        // Replace the target node with the target public key
×
UNCOV
1087
                        // of the blinded path set.
×
UNCOV
1088
                        copy(
×
UNCOV
1089
                                payIntent.Target[:],
×
UNCOV
1090
                                pathSet.TargetPubKey().SerializeCompressed(),
×
UNCOV
1091
                        )
×
UNCOV
1092

×
UNCOV
1093
                        pathFeatures := pathSet.Features()
×
UNCOV
1094
                        if !pathFeatures.IsEmpty() {
×
1095
                                payIntent.DestFeatures = pathFeatures.Clone()
×
1096
                        }
×
1097
                }
1098
        } else {
7✔
1099
                // Otherwise, If the payment request field was not specified
7✔
1100
                // (and a custom route wasn't specified), construct the payment
7✔
1101
                // from the other fields.
7✔
1102

7✔
1103
                // Payment destination.
7✔
1104
                target, err := route.NewVertexFromBytes(rpcPayReq.Dest)
7✔
1105
                if err != nil {
8✔
1106
                        return nil, err
1✔
1107
                }
1✔
1108
                payIntent.Target = target
6✔
1109

6✔
1110
                // Final payment CLTV delta.
6✔
1111
                if rpcPayReq.FinalCltvDelta != 0 {
7✔
1112
                        payIntent.FinalCLTVDelta =
1✔
1113
                                uint16(rpcPayReq.FinalCltvDelta)
1✔
1114
                } else {
6✔
1115
                        payIntent.FinalCLTVDelta = r.DefaultFinalCltvDelta
5✔
1116
                }
5✔
1117

1118
                // Amount.
1119
                if reqAmt == 0 {
7✔
1120
                        return nil, errors.New("amount must be specified")
1✔
1121
                }
1✔
1122

1123
                payIntent.Amount = reqAmt
5✔
1124

5✔
1125
                // Parse destination feature bits.
5✔
1126
                features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
5✔
1127
                if err != nil {
5✔
1128
                        return nil, err
×
1129
                }
×
1130

1131
                // Validate the features if any was specified.
1132
                if features != nil {
6✔
1133
                        err = feature.ValidateDeps(features)
1✔
1134
                        if err != nil {
1✔
1135
                                return nil, err
×
1136
                        }
×
1137
                }
1138

1139
                // If this is an AMP payment, we must generate the initial
1140
                // randomness.
1141
                if rpcPayReq.Amp {
6✔
1142
                        // If no destination features were specified, we set
1✔
1143
                        // those necessary for AMP payments.
1✔
1144
                        if features == nil {
1✔
UNCOV
1145
                                ampFeatures := []lnrpc.FeatureBit{
×
UNCOV
1146
                                        lnrpc.FeatureBit_TLV_ONION_OPT,
×
UNCOV
1147
                                        lnrpc.FeatureBit_PAYMENT_ADDR_OPT,
×
UNCOV
1148
                                        lnrpc.FeatureBit_AMP_OPT,
×
UNCOV
1149
                                }
×
UNCOV
1150

×
UNCOV
1151
                                features, err = UnmarshalFeatures(ampFeatures)
×
UNCOV
1152
                                if err != nil {
×
1153
                                        return nil, err
×
1154
                                }
×
1155
                        }
1156

1157
                        // First make sure the destination supports AMP.
1158
                        if !features.HasFeature(lnwire.AMPOptional) {
2✔
1159
                                return nil, fmt.Errorf("destination doesn't " +
1✔
1160
                                        "support AMP payments")
1✔
1161
                        }
1✔
1162

1163
                        // If no payment address is set, generate a random one.
UNCOV
1164
                        var payAddr [32]byte
×
UNCOV
1165
                        if len(rpcPayReq.PaymentAddr) == 0 {
×
UNCOV
1166
                                _, err = rand.Read(payAddr[:])
×
UNCOV
1167
                                if err != nil {
×
1168
                                        return nil, err
×
1169
                                }
×
1170
                        } else {
×
1171
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1172
                        }
×
UNCOV
1173
                        payIntent.PaymentAddr = &payAddr
×
UNCOV
1174

×
UNCOV
1175
                        // Generate random SetID and root share.
×
UNCOV
1176
                        var setID [32]byte
×
UNCOV
1177
                        _, err = rand.Read(setID[:])
×
UNCOV
1178
                        if err != nil {
×
1179
                                return nil, err
×
1180
                        }
×
1181

UNCOV
1182
                        var rootShare [32]byte
×
UNCOV
1183
                        _, err = rand.Read(rootShare[:])
×
UNCOV
1184
                        if err != nil {
×
1185
                                return nil, err
×
1186
                        }
×
UNCOV
1187
                        err := payIntent.SetAMP(&routing.AMPOptions{
×
UNCOV
1188
                                SetID:     setID,
×
UNCOV
1189
                                RootShare: rootShare,
×
UNCOV
1190
                        })
×
UNCOV
1191
                        if err != nil {
×
1192
                                return nil, err
×
1193
                        }
×
1194
                } else {
4✔
1195
                        // Payment hash.
4✔
1196
                        paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
4✔
1197
                        if err != nil {
5✔
1198
                                return nil, err
1✔
1199
                        }
1✔
1200

1201
                        err = payIntent.SetPaymentHash(paymentHash)
3✔
1202
                        if err != nil {
3✔
1203
                                return nil, err
×
1204
                        }
×
1205

1206
                        // If the payment addresses is specified, then we'll
1207
                        // also populate that now as well.
1208
                        if len(rpcPayReq.PaymentAddr) != 0 {
3✔
1209
                                var payAddr [32]byte
×
1210
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1211

×
1212
                                payIntent.PaymentAddr = &payAddr
×
1213
                        }
×
1214
                }
1215

1216
                payIntent.DestFeatures = features
3✔
1217
        }
1218

1219
        // Validate that the MPP parameters are compatible with the
1220
        // payment amount. In other words, the parameters are invalid if
1221
        // they do not permit sending the full payment amount.
1222
        if payIntent.MaxShardAmt != nil {
5✔
1223
                maxPossibleAmount := (*payIntent.MaxShardAmt) *
2✔
1224
                        lnwire.MilliSatoshi(payIntent.MaxParts)
2✔
1225

2✔
1226
                if payIntent.Amount > maxPossibleAmount {
3✔
1227
                        return nil, fmt.Errorf("payment amount %v exceeds "+
1✔
1228
                                "maximum possible amount %v with max_parts=%v "+
1✔
1229
                                "and max_shard_size_msat=%v", payIntent.Amount,
1✔
1230
                                maxPossibleAmount, payIntent.MaxParts,
1✔
1231
                                *payIntent.MaxShardAmt,
1✔
1232
                        )
1✔
1233
                }
1✔
1234
        }
1235

1236
        // Do bounds checking with the block padding so the router isn't
1237
        // left with a zombie payment in case the user messes up.
1238
        err = routing.ValidateCLTVLimit(
2✔
1239
                payIntent.CltvLimit, payIntent.FinalCLTVDelta, true,
2✔
1240
        )
2✔
1241
        if err != nil {
2✔
1242
                return nil, err
×
1243
        }
×
1244

1245
        // Check for disallowed payments to self.
1246
        if !rpcPayReq.AllowSelfPayment && payIntent.Target == r.SelfNode {
3✔
1247
                return nil, errors.New("self-payments not allowed")
1✔
1248
        }
1✔
1249

1250
        return payIntent, nil
1✔
1251
}
1252

1253
// BuildBlindedPathSet marshals a set of zpay32.BlindedPaymentPath and uses
1254
// the result to build a new routing.BlindedPaymentPathSet.
1255
func BuildBlindedPathSet(paths []*zpay32.BlindedPaymentPath) (
UNCOV
1256
        *routing.BlindedPaymentPathSet, error) {
×
UNCOV
1257

×
UNCOV
1258
        marshalledPaths := make([]*routing.BlindedPayment, len(paths))
×
UNCOV
1259
        for i, path := range paths {
×
UNCOV
1260
                paymentPath := marshalBlindedPayment(path)
×
UNCOV
1261

×
UNCOV
1262
                err := paymentPath.Validate()
×
UNCOV
1263
                if err != nil {
×
1264
                        return nil, err
×
1265
                }
×
1266

UNCOV
1267
                marshalledPaths[i] = paymentPath
×
1268
        }
1269

UNCOV
1270
        return routing.NewBlindedPaymentPathSet(marshalledPaths)
×
1271
}
1272

1273
// marshalBlindedPayment marshals a zpay32.BLindedPaymentPath into a
1274
// routing.BlindedPayment.
1275
func marshalBlindedPayment(
UNCOV
1276
        path *zpay32.BlindedPaymentPath) *routing.BlindedPayment {
×
UNCOV
1277

×
UNCOV
1278
        return &routing.BlindedPayment{
×
UNCOV
1279
                BlindedPath: &sphinx.BlindedPath{
×
UNCOV
1280
                        IntroductionPoint: path.Hops[0].BlindedNodePub,
×
UNCOV
1281
                        BlindingPoint:     path.FirstEphemeralBlindingPoint,
×
UNCOV
1282
                        BlindedHops:       path.Hops,
×
UNCOV
1283
                },
×
UNCOV
1284
                BaseFee:             path.FeeBaseMsat,
×
UNCOV
1285
                ProportionalFeeRate: path.FeeRate,
×
UNCOV
1286
                CltvExpiryDelta:     path.CltvExpiryDelta,
×
UNCOV
1287
                HtlcMinimum:         path.HTLCMinMsat,
×
UNCOV
1288
                HtlcMaximum:         path.HTLCMaxMsat,
×
UNCOV
1289
                Features:            path.Features,
×
UNCOV
1290
        }
×
UNCOV
1291
}
×
1292

1293
// unmarshallRouteHints unmarshalls a list of route hints.
1294
func unmarshallRouteHints(rpcRouteHints []*lnrpc.RouteHint) (
1295
        [][]zpay32.HopHint, error) {
17✔
1296

17✔
1297
        routeHints := make([][]zpay32.HopHint, 0, len(rpcRouteHints))
17✔
1298
        for _, rpcRouteHint := range rpcRouteHints {
21✔
1299
                routeHint := make(
4✔
1300
                        []zpay32.HopHint, 0, len(rpcRouteHint.HopHints),
4✔
1301
                )
4✔
1302
                for _, rpcHint := range rpcRouteHint.HopHints {
8✔
1303
                        hint, err := unmarshallHopHint(rpcHint)
4✔
1304
                        if err != nil {
4✔
1305
                                return nil, err
×
1306
                        }
×
1307

1308
                        routeHint = append(routeHint, hint)
4✔
1309
                }
1310
                routeHints = append(routeHints, routeHint)
4✔
1311
        }
1312

1313
        return routeHints, nil
17✔
1314
}
1315

1316
// unmarshallHopHint unmarshalls a single hop hint.
1317
func unmarshallHopHint(rpcHint *lnrpc.HopHint) (zpay32.HopHint, error) {
4✔
1318
        pubBytes, err := hex.DecodeString(rpcHint.NodeId)
4✔
1319
        if err != nil {
4✔
1320
                return zpay32.HopHint{}, err
×
1321
        }
×
1322

1323
        pubkey, err := btcec.ParsePubKey(pubBytes)
4✔
1324
        if err != nil {
4✔
1325
                return zpay32.HopHint{}, err
×
1326
        }
×
1327

1328
        return zpay32.HopHint{
4✔
1329
                NodeID:                    pubkey,
4✔
1330
                ChannelID:                 rpcHint.ChanId,
4✔
1331
                FeeBaseMSat:               rpcHint.FeeBaseMsat,
4✔
1332
                FeeProportionalMillionths: rpcHint.FeeProportionalMillionths,
4✔
1333
                CLTVExpiryDelta:           uint16(rpcHint.CltvExpiryDelta),
4✔
1334
        }, nil
4✔
1335
}
1336

1337
// MarshalFeatures converts a feature vector into a list of uint32's.
UNCOV
1338
func MarshalFeatures(feats *lnwire.FeatureVector) []lnrpc.FeatureBit {
×
UNCOV
1339
        var featureBits []lnrpc.FeatureBit
×
UNCOV
1340
        for feature := range feats.Features() {
×
UNCOV
1341
                featureBits = append(featureBits, lnrpc.FeatureBit(feature))
×
UNCOV
1342
        }
×
1343

UNCOV
1344
        return featureBits
×
1345
}
1346

1347
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
1348
// This method checks that feature bit pairs aren't assigned together, and
1349
// validates transitive dependencies.
1350
func UnmarshalFeatures(
1351
        rpcFeatures []lnrpc.FeatureBit) (*lnwire.FeatureVector, error) {
8✔
1352

8✔
1353
        // If no destination features are specified we'll return nil to signal
8✔
1354
        // that the router should try to use the graph as a fallback.
8✔
1355
        if rpcFeatures == nil {
12✔
1356
                return nil, nil
4✔
1357
        }
4✔
1358

1359
        raw := lnwire.NewRawFeatureVector()
4✔
1360
        for _, bit := range rpcFeatures {
7✔
1361
                err := raw.SafeSet(lnwire.FeatureBit(bit))
3✔
1362
                if err != nil {
3✔
1363
                        return nil, err
×
1364
                }
×
1365
        }
1366

1367
        return lnwire.NewFeatureVector(raw, lnwire.Features), nil
4✔
1368
}
1369

1370
// ValidatePayReqExpiry checks if the passed payment request has expired. In
1371
// the case it has expired, an error will be returned.
1372
func ValidatePayReqExpiry(payReq *zpay32.Invoice) error {
1✔
1373
        expiry := payReq.Expiry()
1✔
1374
        validUntil := payReq.Timestamp.Add(expiry)
1✔
1375
        if time.Now().After(validUntil) {
2✔
1376
                return fmt.Errorf("invoice expired. Valid until %v", validUntil)
1✔
1377
        }
1✔
1378

UNCOV
1379
        return nil
×
1380
}
1381

1382
// ValidateCLTVLimit returns a valid CLTV limit given a value and a maximum. If
1383
// the value exceeds the maximum, then an error is returned. If the value is 0,
1384
// then the maximum is used.
1385
func ValidateCLTVLimit(val, max uint32) (uint32, error) {
24✔
1386
        switch {
24✔
1387
        case val == 0:
23✔
1388
                return max, nil
23✔
1389
        case val > max:
1✔
1390
                return 0, fmt.Errorf("total time lock of %v exceeds max "+
1✔
1391
                        "allowed %v", val, max)
1✔
1392
        default:
×
1393
                return val, nil
×
1394
        }
1395
}
1396

1397
// UnmarshalMPP accepts the mpp_total_amt_msat and mpp_payment_addr fields from
1398
// an RPC request and converts into an record.MPP object. An error is returned
1399
// if the payment address is not 0 or 32 bytes. If the total amount and payment
1400
// address are zero-value, the return value will be nil signaling there is no
1401
// MPP record to attach to this hop. Otherwise, a non-nil reocrd will be
1402
// contained combining the provided values.
1403
func UnmarshalMPP(reqMPP *lnrpc.MPPRecord) (*record.MPP, error) {
6✔
1404
        // If no MPP record was submitted, assume the user wants to send a
6✔
1405
        // regular payment.
6✔
1406
        if reqMPP == nil {
7✔
1407
                return nil, nil
1✔
1408
        }
1✔
1409

1410
        reqTotal := reqMPP.TotalAmtMsat
5✔
1411
        reqAddr := reqMPP.PaymentAddr
5✔
1412

5✔
1413
        switch {
5✔
1414
        // No MPP fields were provided.
1415
        case reqTotal == 0 && len(reqAddr) == 0:
1✔
1416
                return nil, fmt.Errorf("missing total_msat and payment_addr")
1✔
1417

1418
        // Total is present, but payment address is missing.
1419
        case reqTotal > 0 && len(reqAddr) == 0:
1✔
1420
                return nil, fmt.Errorf("missing payment_addr")
1✔
1421

1422
        // Payment address is present, but total is missing.
1423
        case reqTotal == 0 && len(reqAddr) > 0:
1✔
1424
                return nil, fmt.Errorf("missing total_msat")
1✔
1425
        }
1426

1427
        addr, err := lntypes.MakeHash(reqAddr)
2✔
1428
        if err != nil {
3✔
1429
                return nil, fmt.Errorf("unable to parse "+
1✔
1430
                        "payment_addr: %v", err)
1✔
1431
        }
1✔
1432

1433
        total := lnwire.MilliSatoshi(reqTotal)
1✔
1434

1✔
1435
        return record.NewMPP(total, addr), nil
1✔
1436
}
1437

1438
func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
5✔
1439
        if reqAMP == nil {
6✔
1440
                return nil, nil
1✔
1441
        }
1✔
1442

1443
        reqRootShare := reqAMP.RootShare
4✔
1444
        reqSetID := reqAMP.SetId
4✔
1445

4✔
1446
        switch {
4✔
1447
        case len(reqRootShare) != 32:
2✔
1448
                return nil, errors.New("AMP root_share must be 32 bytes")
2✔
1449

1450
        case len(reqSetID) != 32:
1✔
1451
                return nil, errors.New("AMP set_id must be 32 bytes")
1✔
1452
        }
1453

1454
        var (
1✔
1455
                rootShare [32]byte
1✔
1456
                setID     [32]byte
1✔
1457
        )
1✔
1458
        copy(rootShare[:], reqRootShare)
1✔
1459
        copy(setID[:], reqSetID)
1✔
1460

1✔
1461
        return record.NewAMP(rootShare, setID, reqAMP.ChildIndex), nil
1✔
1462
}
1463

1464
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
1465
func (r *RouterBackend) MarshalHTLCAttempt(
UNCOV
1466
        htlc channeldb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
×
UNCOV
1467

×
UNCOV
1468
        route, err := r.MarshallRoute(&htlc.Route)
×
UNCOV
1469
        if err != nil {
×
1470
                return nil, err
×
1471
        }
×
1472

UNCOV
1473
        rpcAttempt := &lnrpc.HTLCAttempt{
×
UNCOV
1474
                AttemptId:     htlc.AttemptID,
×
UNCOV
1475
                AttemptTimeNs: MarshalTimeNano(htlc.AttemptTime),
×
UNCOV
1476
                Route:         route,
×
UNCOV
1477
        }
×
UNCOV
1478

×
UNCOV
1479
        switch {
×
UNCOV
1480
        case htlc.Settle != nil:
×
UNCOV
1481
                rpcAttempt.Status = lnrpc.HTLCAttempt_SUCCEEDED
×
UNCOV
1482
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
×
UNCOV
1483
                        htlc.Settle.SettleTime,
×
UNCOV
1484
                )
×
UNCOV
1485
                rpcAttempt.Preimage = htlc.Settle.Preimage[:]
×
1486

UNCOV
1487
        case htlc.Failure != nil:
×
UNCOV
1488
                rpcAttempt.Status = lnrpc.HTLCAttempt_FAILED
×
UNCOV
1489
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
×
UNCOV
1490
                        htlc.Failure.FailTime,
×
UNCOV
1491
                )
×
UNCOV
1492

×
UNCOV
1493
                var err error
×
UNCOV
1494
                rpcAttempt.Failure, err = marshallHtlcFailure(htlc.Failure)
×
UNCOV
1495
                if err != nil {
×
1496
                        return nil, err
×
1497
                }
×
UNCOV
1498
        default:
×
UNCOV
1499
                rpcAttempt.Status = lnrpc.HTLCAttempt_IN_FLIGHT
×
1500
        }
1501

UNCOV
1502
        return rpcAttempt, nil
×
1503
}
1504

1505
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
1506
// representation.
1507
func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
UNCOV
1508
        error) {
×
UNCOV
1509

×
UNCOV
1510
        rpcFailure := &lnrpc.Failure{
×
UNCOV
1511
                FailureSourceIndex: failure.FailureSourceIndex,
×
UNCOV
1512
        }
×
UNCOV
1513

×
UNCOV
1514
        switch failure.Reason {
×
1515
        case channeldb.HTLCFailUnknown:
×
1516
                rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1517

1518
        case channeldb.HTLCFailUnreadable:
×
1519
                rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1520

1521
        case channeldb.HTLCFailInternal:
×
1522
                rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
×
1523

UNCOV
1524
        case channeldb.HTLCFailMessage:
×
UNCOV
1525
                err := marshallWireError(failure.Message, rpcFailure)
×
UNCOV
1526
                if err != nil {
×
1527
                        return nil, err
×
1528
                }
×
1529

1530
        default:
×
1531
                return nil, errors.New("unknown htlc failure reason")
×
1532
        }
1533

UNCOV
1534
        return rpcFailure, nil
×
1535
}
1536

1537
// MarshalTimeNano converts a time.Time into its nanosecond representation. If
1538
// the time is zero, this method simply returns 0, since calling UnixNano() on a
1539
// zero-valued time is undefined.
1540
func MarshalTimeNano(t time.Time) int64 {
3✔
1541
        if t.IsZero() {
6✔
1542
                return 0
3✔
1543
        }
3✔
UNCOV
1544
        return t.UnixNano()
×
1545
}
1546

1547
// marshallError marshall an error as received from the switch to rpc structs
1548
// suitable for returning to the caller of an rpc method.
1549
//
1550
// Because of difficulties with using protobuf oneof constructs in some
1551
// languages, the decision was made here to use a single message format for all
1552
// failure messages with some fields left empty depending on the failure type.
UNCOV
1553
func marshallError(sendError error) (*lnrpc.Failure, error) {
×
UNCOV
1554
        response := &lnrpc.Failure{}
×
UNCOV
1555

×
UNCOV
1556
        if sendError == htlcswitch.ErrUnreadableFailureMessage {
×
1557
                response.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1558
                return response, nil
×
1559
        }
×
1560

UNCOV
1561
        rtErr, ok := sendError.(htlcswitch.ClearTextError)
×
UNCOV
1562
        if !ok {
×
1563
                return nil, sendError
×
1564
        }
×
1565

UNCOV
1566
        err := marshallWireError(rtErr.WireMessage(), response)
×
UNCOV
1567
        if err != nil {
×
1568
                return nil, err
×
1569
        }
×
1570

1571
        // If the ClearTextError received is a ForwardingError, the error
1572
        // originated from a node along the route, not locally on our outgoing
1573
        // link. We set failureSourceIdx to the index of the node where the
1574
        // failure occurred. If the error is not a ForwardingError, the failure
1575
        // occurred at our node, so we leave the index as 0 to indicate that
1576
        // we failed locally.
UNCOV
1577
        fErr, ok := rtErr.(*htlcswitch.ForwardingError)
×
UNCOV
1578
        if ok {
×
1579
                response.FailureSourceIndex = uint32(fErr.FailureSourceIdx)
×
1580
        }
×
1581

UNCOV
1582
        return response, nil
×
1583
}
1584

1585
// marshallError marshall an error as received from the switch to rpc structs
1586
// suitable for returning to the caller of an rpc method.
1587
//
1588
// Because of difficulties with using protobuf oneof constructs in some
1589
// languages, the decision was made here to use a single message format for all
1590
// failure messages with some fields left empty depending on the failure type.
1591
func marshallWireError(msg lnwire.FailureMessage,
UNCOV
1592
        response *lnrpc.Failure) error {
×
UNCOV
1593

×
UNCOV
1594
        switch onionErr := msg.(type) {
×
UNCOV
1595
        case *lnwire.FailIncorrectDetails:
×
UNCOV
1596
                response.Code = lnrpc.Failure_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS
×
UNCOV
1597
                response.Height = onionErr.Height()
×
1598

1599
        case *lnwire.FailIncorrectPaymentAmount:
×
1600
                response.Code = lnrpc.Failure_INCORRECT_PAYMENT_AMOUNT
×
1601

1602
        case *lnwire.FailFinalIncorrectCltvExpiry:
×
1603
                response.Code = lnrpc.Failure_FINAL_INCORRECT_CLTV_EXPIRY
×
1604
                response.CltvExpiry = onionErr.CltvExpiry
×
1605

1606
        case *lnwire.FailFinalIncorrectHtlcAmount:
×
1607
                response.Code = lnrpc.Failure_FINAL_INCORRECT_HTLC_AMOUNT
×
1608
                response.HtlcMsat = uint64(onionErr.IncomingHTLCAmount)
×
1609

1610
        case *lnwire.FailFinalExpiryTooSoon:
×
1611
                response.Code = lnrpc.Failure_FINAL_EXPIRY_TOO_SOON
×
1612

1613
        case *lnwire.FailInvalidRealm:
×
1614
                response.Code = lnrpc.Failure_INVALID_REALM
×
1615

1616
        case *lnwire.FailExpiryTooSoon:
×
1617
                response.Code = lnrpc.Failure_EXPIRY_TOO_SOON
×
1618
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1619

1620
        case *lnwire.FailExpiryTooFar:
×
1621
                response.Code = lnrpc.Failure_EXPIRY_TOO_FAR
×
1622

UNCOV
1623
        case *lnwire.FailInvalidOnionVersion:
×
UNCOV
1624
                response.Code = lnrpc.Failure_INVALID_ONION_VERSION
×
UNCOV
1625
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1626

1627
        case *lnwire.FailInvalidOnionHmac:
×
1628
                response.Code = lnrpc.Failure_INVALID_ONION_HMAC
×
1629
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1630

1631
        case *lnwire.FailInvalidOnionKey:
×
1632
                response.Code = lnrpc.Failure_INVALID_ONION_KEY
×
1633
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1634

1635
        case *lnwire.FailAmountBelowMinimum:
×
1636
                response.Code = lnrpc.Failure_AMOUNT_BELOW_MINIMUM
×
1637
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1638
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1639

UNCOV
1640
        case *lnwire.FailFeeInsufficient:
×
UNCOV
1641
                response.Code = lnrpc.Failure_FEE_INSUFFICIENT
×
UNCOV
1642
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
UNCOV
1643
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1644

1645
        case *lnwire.FailIncorrectCltvExpiry:
×
1646
                response.Code = lnrpc.Failure_INCORRECT_CLTV_EXPIRY
×
1647
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1648
                response.CltvExpiry = onionErr.CltvExpiry
×
1649

UNCOV
1650
        case *lnwire.FailChannelDisabled:
×
UNCOV
1651
                response.Code = lnrpc.Failure_CHANNEL_DISABLED
×
UNCOV
1652
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
UNCOV
1653
                response.Flags = uint32(onionErr.Flags)
×
1654

UNCOV
1655
        case *lnwire.FailTemporaryChannelFailure:
×
UNCOV
1656
                response.Code = lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE
×
UNCOV
1657
                response.ChannelUpdate = marshallChannelUpdate(onionErr.Update)
×
1658

1659
        case *lnwire.FailRequiredNodeFeatureMissing:
×
1660
                response.Code = lnrpc.Failure_REQUIRED_NODE_FEATURE_MISSING
×
1661

1662
        case *lnwire.FailRequiredChannelFeatureMissing:
×
1663
                response.Code = lnrpc.Failure_REQUIRED_CHANNEL_FEATURE_MISSING
×
1664

UNCOV
1665
        case *lnwire.FailUnknownNextPeer:
×
UNCOV
1666
                response.Code = lnrpc.Failure_UNKNOWN_NEXT_PEER
×
1667

1668
        case *lnwire.FailTemporaryNodeFailure:
×
1669
                response.Code = lnrpc.Failure_TEMPORARY_NODE_FAILURE
×
1670

1671
        case *lnwire.FailPermanentNodeFailure:
×
1672
                response.Code = lnrpc.Failure_PERMANENT_NODE_FAILURE
×
1673

UNCOV
1674
        case *lnwire.FailPermanentChannelFailure:
×
UNCOV
1675
                response.Code = lnrpc.Failure_PERMANENT_CHANNEL_FAILURE
×
1676

1677
        case *lnwire.FailMPPTimeout:
×
1678
                response.Code = lnrpc.Failure_MPP_TIMEOUT
×
1679

UNCOV
1680
        case *lnwire.InvalidOnionPayload:
×
UNCOV
1681
                response.Code = lnrpc.Failure_INVALID_ONION_PAYLOAD
×
1682

UNCOV
1683
        case *lnwire.FailInvalidBlinding:
×
UNCOV
1684
                response.Code = lnrpc.Failure_INVALID_ONION_BLINDING
×
UNCOV
1685
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1686

1687
        case nil:
×
1688
                response.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1689

1690
        default:
×
1691
                return fmt.Errorf("cannot marshall failure %T", onionErr)
×
1692
        }
1693

UNCOV
1694
        return nil
×
1695
}
1696

1697
// marshallChannelUpdate marshalls a channel update as received over the wire to
1698
// the router rpc format.
UNCOV
1699
func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
×
UNCOV
1700
        if update == nil {
×
1701
                return nil
×
1702
        }
×
1703

UNCOV
1704
        return &lnrpc.ChannelUpdate{
×
UNCOV
1705
                Signature:       update.Signature.RawBytes(),
×
UNCOV
1706
                ChainHash:       update.ChainHash[:],
×
UNCOV
1707
                ChanId:          update.ShortChannelID.ToUint64(),
×
UNCOV
1708
                Timestamp:       update.Timestamp,
×
UNCOV
1709
                MessageFlags:    uint32(update.MessageFlags),
×
UNCOV
1710
                ChannelFlags:    uint32(update.ChannelFlags),
×
UNCOV
1711
                TimeLockDelta:   uint32(update.TimeLockDelta),
×
UNCOV
1712
                HtlcMinimumMsat: uint64(update.HtlcMinimumMsat),
×
UNCOV
1713
                BaseFee:         update.BaseFee,
×
UNCOV
1714
                FeeRate:         update.FeeRate,
×
UNCOV
1715
                HtlcMaximumMsat: uint64(update.HtlcMaximumMsat),
×
UNCOV
1716
                ExtraOpaqueData: update.ExtraOpaqueData,
×
UNCOV
1717
        }
×
1718
}
1719

1720
// MarshallPayment marshall a payment to its rpc representation.
1721
func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
1722
        *lnrpc.Payment, error) {
3✔
1723

3✔
1724
        // Fetch the payment's preimage and the total paid in fees.
3✔
1725
        var (
3✔
1726
                fee      lnwire.MilliSatoshi
3✔
1727
                preimage lntypes.Preimage
3✔
1728
        )
3✔
1729
        for _, htlc := range payment.HTLCs {
3✔
UNCOV
1730
                // If any of the htlcs have settled, extract a valid
×
UNCOV
1731
                // preimage.
×
UNCOV
1732
                if htlc.Settle != nil {
×
UNCOV
1733
                        preimage = htlc.Settle.Preimage
×
UNCOV
1734
                        fee += htlc.Route.TotalFees()
×
UNCOV
1735
                }
×
1736
        }
1737

1738
        msatValue := int64(payment.Info.Value)
3✔
1739
        satValue := int64(payment.Info.Value.ToSatoshis())
3✔
1740

3✔
1741
        status, err := convertPaymentStatus(
3✔
1742
                payment.Status, r.UseStatusInitiated,
3✔
1743
        )
3✔
1744
        if err != nil {
3✔
1745
                return nil, err
×
1746
        }
×
1747

1748
        htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
3✔
1749
        for _, dbHTLC := range payment.HTLCs {
3✔
UNCOV
1750
                htlc, err := r.MarshalHTLCAttempt(dbHTLC)
×
UNCOV
1751
                if err != nil {
×
1752
                        return nil, err
×
1753
                }
×
1754

UNCOV
1755
                htlcs = append(htlcs, htlc)
×
1756
        }
1757

1758
        paymentID := payment.Info.PaymentIdentifier
3✔
1759
        creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
3✔
1760

3✔
1761
        failureReason, err := marshallPaymentFailureReason(
3✔
1762
                payment.FailureReason,
3✔
1763
        )
3✔
1764
        if err != nil {
3✔
1765
                return nil, err
×
1766
        }
×
1767

1768
        return &lnrpc.Payment{
3✔
1769
                // TODO: set this to setID for AMP-payments?
3✔
1770
                PaymentHash:           hex.EncodeToString(paymentID[:]),
3✔
1771
                Value:                 satValue,
3✔
1772
                ValueMsat:             msatValue,
3✔
1773
                ValueSat:              satValue,
3✔
1774
                CreationDate:          payment.Info.CreationTime.Unix(),
3✔
1775
                CreationTimeNs:        creationTimeNS,
3✔
1776
                Fee:                   int64(fee.ToSatoshis()),
3✔
1777
                FeeSat:                int64(fee.ToSatoshis()),
3✔
1778
                FeeMsat:               int64(fee),
3✔
1779
                PaymentPreimage:       hex.EncodeToString(preimage[:]),
3✔
1780
                PaymentRequest:        string(payment.Info.PaymentRequest),
3✔
1781
                Status:                status,
3✔
1782
                Htlcs:                 htlcs,
3✔
1783
                PaymentIndex:          payment.SequenceNum,
3✔
1784
                FailureReason:         failureReason,
3✔
1785
                FirstHopCustomRecords: payment.Info.FirstHopCustomRecords,
3✔
1786
        }, nil
3✔
1787
}
1788

1789
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
1790
// by the RPC.
1791
func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
1792
        lnrpc.Payment_PaymentStatus, error) {
3✔
1793

3✔
1794
        switch dbStatus {
3✔
UNCOV
1795
        case channeldb.StatusInitiated:
×
UNCOV
1796
                // If the client understands the new status, return it.
×
UNCOV
1797
                if useInit {
×
UNCOV
1798
                        return lnrpc.Payment_INITIATED, nil
×
UNCOV
1799
                }
×
1800

1801
                // Otherwise remain the old behavior.
UNCOV
1802
                return lnrpc.Payment_IN_FLIGHT, nil
×
1803

1804
        case channeldb.StatusInFlight:
1✔
1805
                return lnrpc.Payment_IN_FLIGHT, nil
1✔
1806

1807
        case channeldb.StatusSucceeded:
2✔
1808
                return lnrpc.Payment_SUCCEEDED, nil
2✔
1809

UNCOV
1810
        case channeldb.StatusFailed:
×
UNCOV
1811
                return lnrpc.Payment_FAILED, nil
×
1812

1813
        default:
×
1814
                return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
×
1815
        }
1816
}
1817

1818
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
1819
// type.
1820
func marshallPaymentFailureReason(reason *channeldb.FailureReason) (
1821
        lnrpc.PaymentFailureReason, error) {
3✔
1822

3✔
1823
        if reason == nil {
6✔
1824
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, nil
3✔
1825
        }
3✔
1826

UNCOV
1827
        switch *reason {
×
1828
        case channeldb.FailureReasonTimeout:
×
1829
                return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
×
1830

UNCOV
1831
        case channeldb.FailureReasonNoRoute:
×
UNCOV
1832
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
×
1833

UNCOV
1834
        case channeldb.FailureReasonError:
×
UNCOV
1835
                return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
×
1836

UNCOV
1837
        case channeldb.FailureReasonPaymentDetails:
×
UNCOV
1838
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
×
1839

UNCOV
1840
        case channeldb.FailureReasonInsufficientBalance:
×
UNCOV
1841
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
×
1842

UNCOV
1843
        case channeldb.FailureReasonCanceled:
×
UNCOV
1844
                return lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, nil
×
1845
        }
1846

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