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

lightningnetwork / lnd / 14779943269

01 May 2025 05:22PM UTC coverage: 69.041% (+0.009%) from 69.032%
14779943269

Pull #9752

github

web-flow
Merge 51b1059cc into b068d79df
Pull Request #9752: routerrpc: reject payment to invoice that don't have payment secret or blinded paths

5 of 6 new or added lines in 1 file covered. (83.33%)

241 existing lines in 16 files now uncovered.

133931 of 193989 relevant lines covered (69.04%)

22108.46 hits per line

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

77.87
/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/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
        "github.com/lightningnetwork/lnd/record"
25
        "github.com/lightningnetwork/lnd/routing"
26
        "github.com/lightningnetwork/lnd/routing/route"
27
        "github.com/lightningnetwork/lnd/subscribe"
28
        "github.com/lightningnetwork/lnd/zpay32"
29
        "google.golang.org/protobuf/proto"
30
)
31

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

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

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

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

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

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

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

69
        MissionControl MissionControl
70

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

7✔
168
        routeReq, err := r.parseQueryRoutesRequest(in)
7✔
169
        if err != nil {
8✔
170
                return nil, err
1✔
171
        }
1✔
172

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

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

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

6✔
193
        return routeResp, nil
6✔
194
}
195

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

202
        return route.NewVertexFromBytes(pubKeyBytes)
7✔
203
}
204

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

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

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

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

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

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

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

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

248
        return ignoredNodes, ignoredPairs, nil
6✔
249
}
250

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

397
                        if !in.UseMissionControl {
11✔
398
                                return 1
5✔
399
                        }
5✔
400

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

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

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

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

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

442
func parseBlindedPaymentPaths(in *lnrpc.QueryRoutesRequest) (
443
        *routing.BlindedPaymentPathSet, error) {
3✔
444

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

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

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

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

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

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

480
                paths[i] = blindedPmt
3✔
481
        }
482

483
        return routing.NewBlindedPaymentPathSet(paths)
3✔
484
}
485

486
func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
487
        *routing.BlindedPayment, error) {
3✔
488

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

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

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

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

514
func unmarshalBlindedPaymentPaths(rpcPath *lnrpc.BlindedPath) (
515
        *sphinx.BlindedPath, error) {
3✔
516

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

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

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

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

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

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

551
        return path, nil
3✔
552
}
553

554
func unmarshalBlindedHop(rpcHop *lnrpc.BlindedHop) (*sphinx.BlindedHopInfo,
555
        error) {
3✔
556

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

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

566
        return &sphinx.BlindedHopInfo{
3✔
567
                BlindedNodePub: pubkey,
3✔
568
                CipherText:     rpcHop.EncryptedData,
3✔
569
        }, nil
3✔
570
}
571

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

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

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

589
        return pair, nil
3✔
590
}
591

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

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

611
                resp.CustomChannelData = customData
3✔
612

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

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

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

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

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

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

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

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

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

688
        return resp, nil
6✔
689
}
690

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

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

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

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

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

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

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

739
        return hop, nil
3✔
740
}
741

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

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

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

776
        return UnmarshallHopWithPubkey(rpcHop, pubKeyBytes)
3✔
777
}
778

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

3✔
784
        prevNodePubKey := r.SelfNode
3✔
785

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

793
                hops[i] = routeHop
3✔
794

3✔
795
                prevNodePubKey = routeHop.PubKeyBytes
3✔
796
        }
797

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

808
        return route, nil
3✔
809
}
810

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

27✔
817
        payIntent := &routing.LightningPayment{}
27✔
818

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

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

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

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

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

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

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

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

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

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

895
        customRecords := record.CustomSet(rpcPayReq.DestCustomRecords)
20✔
896
        if err := customRecords.Validate(); err != nil {
21✔
897
                return nil, err
1✔
898
        }
1✔
899
        payIntent.DestCustomRecords = customRecords
19✔
900

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

913
        firstHopRecords := lnwire.CustomRecords(rpcPayReq.FirstHopCustomRecords)
18✔
914
        if err := firstHopRecords.Validate(); err != nil {
19✔
915
                return nil, err
1✔
916
        }
1✔
917
        payIntent.FirstHopCustomRecords = firstHopRecords
17✔
918

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

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

936
        payIntent.PayAttemptTimeout = time.Second *
17✔
937
                time.Duration(rpcPayReq.TimeoutSeconds)
17✔
938

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

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

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

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

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

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

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

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

988
                // An invoice must include either a payment address or
989
                // blinded paths.
990
                if payReq.PaymentAddr.IsNone() &&
4✔
991
                        len(payReq.BlindedPaymentPaths) == 0 {
5✔
992
                        return nil, errors.New("payment request must contain " +
1✔
993
                                "either a payment address or blinded paths")
1✔
994
                }
1✔
995

996
                // If the amount was not included in the invoice, then we let
997
                // the payer specify the amount of satoshis they wish to send.
998
                // We override the amount to pay with the amount provided from
999
                // the payment request.
1000
                if payReq.MilliSat == nil {
3✔
1001
                        if reqAmt == 0 {
×
1002
                                return nil, errors.New("amount must be " +
×
1003
                                        "specified when paying a zero amount " +
×
1004
                                        "invoice")
×
1005
                        }
×
1006

1007
                        payIntent.Amount = reqAmt
×
1008
                } else {
3✔
1009
                        if reqAmt != 0 {
3✔
1010
                                return nil, errors.New("amount must not be " +
×
1011
                                        "specified when paying a non-zero " +
×
NEW
1012
                                        "amount invoice")
×
1013
                        }
×
1014

1015
                        payIntent.Amount = *payReq.MilliSat
3✔
1016
                }
1017

1018
                if !payReq.Features.HasFeature(lnwire.MPPOptional) &&
3✔
1019
                        !payReq.Features.HasFeature(lnwire.AMPOptional) {
3✔
1020

×
1021
                        payIntent.MaxParts = 1
×
1022
                }
×
1023

1024
                payAddr := payReq.PaymentAddr
3✔
1025
                if payReq.Features.HasFeature(lnwire.AMPOptional) {
6✔
1026
                        // The opt-in AMP flag is required to pay an AMP
3✔
1027
                        // invoice.
3✔
1028
                        if !rpcPayReq.Amp {
3✔
1029
                                return nil, fmt.Errorf("the AMP flag (--amp " +
×
1030
                                        "or SendPaymentRequest.Amp) must be " +
×
1031
                                        "set to pay an AMP invoice")
×
1032
                        }
×
1033

1034
                        // Generate random SetID and root share.
1035
                        var setID [32]byte
3✔
1036
                        _, err = rand.Read(setID[:])
3✔
1037
                        if err != nil {
3✔
1038
                                return nil, err
×
1039
                        }
×
1040

1041
                        var rootShare [32]byte
3✔
1042
                        _, err = rand.Read(rootShare[:])
3✔
1043
                        if err != nil {
3✔
1044
                                return nil, err
×
1045
                        }
×
1046
                        err := payIntent.SetAMP(&routing.AMPOptions{
3✔
1047
                                SetID:     setID,
3✔
1048
                                RootShare: rootShare,
3✔
1049
                        })
3✔
1050
                        if err != nil {
3✔
1051
                                return nil, err
×
1052
                        }
×
1053

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

1074
                destKey := payReq.Destination.SerializeCompressed()
3✔
1075
                copy(payIntent.Target[:], destKey)
3✔
1076

3✔
1077
                payIntent.FinalCLTVDelta = uint16(payReq.MinFinalCLTVExpiry())
3✔
1078
                payIntent.RouteHints = append(
3✔
1079
                        payIntent.RouteHints, payReq.RouteHints...,
3✔
1080
                )
3✔
1081
                payIntent.DestFeatures = payReq.Features
3✔
1082
                payIntent.PaymentAddr = payAddr
3✔
1083
                payIntent.PaymentRequest = []byte(rpcPayReq.PaymentRequest)
3✔
1084
                payIntent.Metadata = payReq.Metadata
3✔
1085

3✔
1086
                if len(payReq.BlindedPaymentPaths) > 0 {
6✔
1087
                        pathSet, err := BuildBlindedPathSet(
3✔
1088
                                payReq.BlindedPaymentPaths,
3✔
1089
                        )
3✔
1090
                        if err != nil {
3✔
1091
                                return nil, err
×
1092
                        }
×
1093
                        payIntent.BlindedPathSet = pathSet
3✔
1094

3✔
1095
                        // Replace the target node with the target public key
3✔
1096
                        // of the blinded path set.
3✔
1097
                        copy(
3✔
1098
                                payIntent.Target[:],
3✔
1099
                                pathSet.TargetPubKey().SerializeCompressed(),
3✔
1100
                        )
3✔
1101

3✔
1102
                        pathFeatures := pathSet.Features()
3✔
1103
                        if !pathFeatures.IsEmpty() {
3✔
1104
                                payIntent.DestFeatures = pathFeatures.Clone()
×
1105
                        }
×
1106
                }
1107
        } else {
10✔
1108
                // Otherwise, If the payment request field was not specified
10✔
1109
                // (and a custom route wasn't specified), construct the payment
10✔
1110
                // from the other fields.
10✔
1111

10✔
1112
                // Payment destination.
10✔
1113
                target, err := route.NewVertexFromBytes(rpcPayReq.Dest)
10✔
1114
                if err != nil {
11✔
1115
                        return nil, err
1✔
1116
                }
1✔
1117
                payIntent.Target = target
9✔
1118

9✔
1119
                // Final payment CLTV delta.
9✔
1120
                if rpcPayReq.FinalCltvDelta != 0 {
13✔
1121
                        payIntent.FinalCLTVDelta =
4✔
1122
                                uint16(rpcPayReq.FinalCltvDelta)
4✔
1123
                } else {
12✔
1124
                        payIntent.FinalCLTVDelta = r.DefaultFinalCltvDelta
8✔
1125
                }
8✔
1126

1127
                // Amount.
1128
                if reqAmt == 0 {
10✔
1129
                        return nil, errors.New("amount must be specified")
1✔
1130
                }
1✔
1131

1132
                payIntent.Amount = reqAmt
8✔
1133

8✔
1134
                // Parse destination feature bits.
8✔
1135
                features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
8✔
1136
                if err != nil {
8✔
1137
                        return nil, err
×
1138
                }
×
1139

1140
                // Validate the features if any was specified.
1141
                if features != nil {
12✔
1142
                        err = feature.ValidateDeps(features)
4✔
1143
                        if err != nil {
4✔
1144
                                return nil, err
×
1145
                        }
×
1146
                }
1147

1148
                // If this is an AMP payment, we must generate the initial
1149
                // randomness.
1150
                if rpcPayReq.Amp {
12✔
1151
                        // If no destination features were specified, we set
4✔
1152
                        // those necessary for AMP payments.
4✔
1153
                        if features == nil {
7✔
1154
                                ampFeatures := []lnrpc.FeatureBit{
3✔
1155
                                        lnrpc.FeatureBit_TLV_ONION_OPT,
3✔
1156
                                        lnrpc.FeatureBit_PAYMENT_ADDR_OPT,
3✔
1157
                                        lnrpc.FeatureBit_AMP_OPT,
3✔
1158
                                }
3✔
1159

3✔
1160
                                features, err = UnmarshalFeatures(ampFeatures)
3✔
1161
                                if err != nil {
3✔
1162
                                        return nil, err
×
1163
                                }
×
1164
                        }
1165

1166
                        // First make sure the destination supports AMP.
1167
                        if !features.HasFeature(lnwire.AMPOptional) {
5✔
1168
                                return nil, fmt.Errorf("destination doesn't " +
1✔
1169
                                        "support AMP payments")
1✔
1170
                        }
1✔
1171

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

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

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

1210
                        err = payIntent.SetPaymentHash(paymentHash)
6✔
1211
                        if err != nil {
6✔
1212
                                return nil, err
×
1213
                        }
×
1214

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

×
1221
                                payIntent.PaymentAddr = fn.Some(payAddr)
×
1222
                        }
×
1223
                }
1224

1225
                payIntent.DestFeatures = features
6✔
1226
        }
1227

1228
        // Validate that the MPP parameters are compatible with the
1229
        // payment amount. In other words, the parameters are invalid if
1230
        // they do not permit sending the full payment amount.
1231
        if payIntent.MaxShardAmt != nil {
8✔
1232
                maxPossibleAmount := (*payIntent.MaxShardAmt) *
2✔
1233
                        lnwire.MilliSatoshi(payIntent.MaxParts)
2✔
1234

2✔
1235
                if payIntent.Amount > maxPossibleAmount {
3✔
1236
                        return nil, fmt.Errorf("payment amount %v exceeds "+
1✔
1237
                                "maximum possible amount %v with max_parts=%v "+
1✔
1238
                                "and max_shard_size_msat=%v", payIntent.Amount,
1✔
1239
                                maxPossibleAmount, payIntent.MaxParts,
1✔
1240
                                *payIntent.MaxShardAmt,
1✔
1241
                        )
1✔
1242
                }
1✔
1243
        }
1244

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

1254
        // Check for disallowed payments to self.
1255
        if !rpcPayReq.AllowSelfPayment && payIntent.Target == r.SelfNode {
6✔
1256
                return nil, errors.New("self-payments not allowed")
1✔
1257
        }
1✔
1258

1259
        return payIntent, nil
4✔
1260
}
1261

1262
// BuildBlindedPathSet marshals a set of zpay32.BlindedPaymentPath and uses
1263
// the result to build a new routing.BlindedPaymentPathSet.
1264
func BuildBlindedPathSet(paths []*zpay32.BlindedPaymentPath) (
1265
        *routing.BlindedPaymentPathSet, error) {
3✔
1266

3✔
1267
        marshalledPaths := make([]*routing.BlindedPayment, len(paths))
3✔
1268
        for i, path := range paths {
6✔
1269
                paymentPath := marshalBlindedPayment(path)
3✔
1270

3✔
1271
                err := paymentPath.Validate()
3✔
1272
                if err != nil {
3✔
1273
                        return nil, err
×
1274
                }
×
1275

1276
                marshalledPaths[i] = paymentPath
3✔
1277
        }
1278

1279
        return routing.NewBlindedPaymentPathSet(marshalledPaths)
3✔
1280
}
1281

1282
// marshalBlindedPayment marshals a zpay32.BLindedPaymentPath into a
1283
// routing.BlindedPayment.
1284
func marshalBlindedPayment(
1285
        path *zpay32.BlindedPaymentPath) *routing.BlindedPayment {
3✔
1286

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

1302
// unmarshallRouteHints unmarshalls a list of route hints.
1303
func unmarshallRouteHints(rpcRouteHints []*lnrpc.RouteHint) (
1304
        [][]zpay32.HopHint, error) {
21✔
1305

21✔
1306
        routeHints := make([][]zpay32.HopHint, 0, len(rpcRouteHints))
21✔
1307
        for _, rpcRouteHint := range rpcRouteHints {
28✔
1308
                routeHint := make(
7✔
1309
                        []zpay32.HopHint, 0, len(rpcRouteHint.HopHints),
7✔
1310
                )
7✔
1311
                for _, rpcHint := range rpcRouteHint.HopHints {
14✔
1312
                        hint, err := unmarshallHopHint(rpcHint)
7✔
1313
                        if err != nil {
7✔
1314
                                return nil, err
×
1315
                        }
×
1316

1317
                        routeHint = append(routeHint, hint)
7✔
1318
                }
1319
                routeHints = append(routeHints, routeHint)
7✔
1320
        }
1321

1322
        return routeHints, nil
21✔
1323
}
1324

1325
// unmarshallHopHint unmarshalls a single hop hint.
1326
func unmarshallHopHint(rpcHint *lnrpc.HopHint) (zpay32.HopHint, error) {
7✔
1327
        pubBytes, err := hex.DecodeString(rpcHint.NodeId)
7✔
1328
        if err != nil {
7✔
1329
                return zpay32.HopHint{}, err
×
1330
        }
×
1331

1332
        pubkey, err := btcec.ParsePubKey(pubBytes)
7✔
1333
        if err != nil {
7✔
1334
                return zpay32.HopHint{}, err
×
1335
        }
×
1336

1337
        return zpay32.HopHint{
7✔
1338
                NodeID:                    pubkey,
7✔
1339
                ChannelID:                 rpcHint.ChanId,
7✔
1340
                FeeBaseMSat:               rpcHint.FeeBaseMsat,
7✔
1341
                FeeProportionalMillionths: rpcHint.FeeProportionalMillionths,
7✔
1342
                CLTVExpiryDelta:           uint16(rpcHint.CltvExpiryDelta),
7✔
1343
        }, nil
7✔
1344
}
1345

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

1353
        return featureBits
3✔
1354
}
1355

1356
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
1357
// This method checks that feature bit pairs aren't assigned together, and
1358
// validates transitive dependencies.
1359
func UnmarshalFeatures(
1360
        rpcFeatures []lnrpc.FeatureBit) (*lnwire.FeatureVector, error) {
11✔
1361

11✔
1362
        // If no destination features are specified we'll return nil to signal
11✔
1363
        // that the router should try to use the graph as a fallback.
11✔
1364
        if rpcFeatures == nil {
18✔
1365
                return nil, nil
7✔
1366
        }
7✔
1367

1368
        raw := lnwire.NewRawFeatureVector()
7✔
1369
        for _, bit := range rpcFeatures {
13✔
1370
                err := raw.SafeSet(lnwire.FeatureBit(bit))
6✔
1371
                if err != nil {
6✔
1372
                        return nil, err
×
1373
                }
×
1374
        }
1375

1376
        return lnwire.NewFeatureVector(raw, lnwire.Features), nil
7✔
1377
}
1378

1379
// ValidatePayReqExpiry checks if the passed payment request has expired. In
1380
// the case it has expired, an error will be returned.
1381
func ValidatePayReqExpiry(payReq *zpay32.Invoice) error {
5✔
1382
        expiry := payReq.Expiry()
5✔
1383
        validUntil := payReq.Timestamp.Add(expiry)
5✔
1384
        if time.Now().After(validUntil) {
6✔
1385
                return fmt.Errorf("invoice expired. Valid until %v", validUntil)
1✔
1386
        }
1✔
1387

1388
        return nil
4✔
1389
}
1390

1391
// ValidateCLTVLimit returns a valid CLTV limit given a value and a maximum. If
1392
// the value exceeds the maximum, then an error is returned. If the value is 0,
1393
// then the maximum is used.
1394
func ValidateCLTVLimit(val, max uint32) (uint32, error) {
28✔
1395
        switch {
28✔
1396
        case val == 0:
26✔
1397
                return max, nil
26✔
1398
        case val > max:
1✔
1399
                return 0, fmt.Errorf("total time lock of %v exceeds max "+
1✔
1400
                        "allowed %v", val, max)
1✔
1401
        default:
1✔
1402
                return val, nil
1✔
1403
        }
1404
}
1405

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

1419
        reqTotal := reqMPP.TotalAmtMsat
8✔
1420
        reqAddr := reqMPP.PaymentAddr
8✔
1421

8✔
1422
        switch {
8✔
1423
        // No MPP fields were provided.
1424
        case reqTotal == 0 && len(reqAddr) == 0:
1✔
1425
                return nil, fmt.Errorf("missing total_msat and payment_addr")
1✔
1426

1427
        // Total is present, but payment address is missing.
1428
        case reqTotal > 0 && len(reqAddr) == 0:
1✔
1429
                return nil, fmt.Errorf("missing payment_addr")
1✔
1430

1431
        // Payment address is present, but total is missing.
1432
        case reqTotal == 0 && len(reqAddr) > 0:
1✔
1433
                return nil, fmt.Errorf("missing total_msat")
1✔
1434
        }
1435

1436
        addr, err := lntypes.MakeHash(reqAddr)
5✔
1437
        if err != nil {
6✔
1438
                return nil, fmt.Errorf("unable to parse "+
1✔
1439
                        "payment_addr: %v", err)
1✔
1440
        }
1✔
1441

1442
        total := lnwire.MilliSatoshi(reqTotal)
4✔
1443

4✔
1444
        return record.NewMPP(total, addr), nil
4✔
1445
}
1446

1447
func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
8✔
1448
        if reqAMP == nil {
12✔
1449
                return nil, nil
4✔
1450
        }
4✔
1451

1452
        reqRootShare := reqAMP.RootShare
7✔
1453
        reqSetID := reqAMP.SetId
7✔
1454

7✔
1455
        switch {
7✔
1456
        case len(reqRootShare) != 32:
2✔
1457
                return nil, errors.New("AMP root_share must be 32 bytes")
2✔
1458

1459
        case len(reqSetID) != 32:
1✔
1460
                return nil, errors.New("AMP set_id must be 32 bytes")
1✔
1461
        }
1462

1463
        var (
4✔
1464
                rootShare [32]byte
4✔
1465
                setID     [32]byte
4✔
1466
        )
4✔
1467
        copy(rootShare[:], reqRootShare)
4✔
1468
        copy(setID[:], reqSetID)
4✔
1469

4✔
1470
        return record.NewAMP(rootShare, setID, reqAMP.ChildIndex), nil
4✔
1471
}
1472

1473
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
1474
func (r *RouterBackend) MarshalHTLCAttempt(
1475
        htlc channeldb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
3✔
1476

3✔
1477
        route, err := r.MarshallRoute(&htlc.Route)
3✔
1478
        if err != nil {
3✔
1479
                return nil, err
×
1480
        }
×
1481

1482
        rpcAttempt := &lnrpc.HTLCAttempt{
3✔
1483
                AttemptId:     htlc.AttemptID,
3✔
1484
                AttemptTimeNs: MarshalTimeNano(htlc.AttemptTime),
3✔
1485
                Route:         route,
3✔
1486
        }
3✔
1487

3✔
1488
        switch {
3✔
1489
        case htlc.Settle != nil:
3✔
1490
                rpcAttempt.Status = lnrpc.HTLCAttempt_SUCCEEDED
3✔
1491
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
3✔
1492
                        htlc.Settle.SettleTime,
3✔
1493
                )
3✔
1494
                rpcAttempt.Preimage = htlc.Settle.Preimage[:]
3✔
1495

1496
        case htlc.Failure != nil:
3✔
1497
                rpcAttempt.Status = lnrpc.HTLCAttempt_FAILED
3✔
1498
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
3✔
1499
                        htlc.Failure.FailTime,
3✔
1500
                )
3✔
1501

3✔
1502
                var err error
3✔
1503
                rpcAttempt.Failure, err = marshallHtlcFailure(htlc.Failure)
3✔
1504
                if err != nil {
3✔
1505
                        return nil, err
×
1506
                }
×
1507
        default:
3✔
1508
                rpcAttempt.Status = lnrpc.HTLCAttempt_IN_FLIGHT
3✔
1509
        }
1510

1511
        return rpcAttempt, nil
3✔
1512
}
1513

1514
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
1515
// representation.
1516
func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
1517
        error) {
3✔
1518

3✔
1519
        rpcFailure := &lnrpc.Failure{
3✔
1520
                FailureSourceIndex: failure.FailureSourceIndex,
3✔
1521
        }
3✔
1522

3✔
1523
        switch failure.Reason {
3✔
1524
        case channeldb.HTLCFailUnknown:
×
1525
                rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1526

1527
        case channeldb.HTLCFailUnreadable:
×
1528
                rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1529

1530
        case channeldb.HTLCFailInternal:
×
1531
                rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
×
1532

1533
        case channeldb.HTLCFailMessage:
3✔
1534
                err := marshallWireError(failure.Message, rpcFailure)
3✔
1535
                if err != nil {
3✔
1536
                        return nil, err
×
1537
                }
×
1538

1539
        default:
×
1540
                return nil, errors.New("unknown htlc failure reason")
×
1541
        }
1542

1543
        return rpcFailure, nil
3✔
1544
}
1545

1546
// MarshalTimeNano converts a time.Time into its nanosecond representation. If
1547
// the time is zero, this method simply returns 0, since calling UnixNano() on a
1548
// zero-valued time is undefined.
1549
func MarshalTimeNano(t time.Time) int64 {
6✔
1550
        if t.IsZero() {
9✔
1551
                return 0
3✔
1552
        }
3✔
1553
        return t.UnixNano()
3✔
1554
}
1555

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

3✔
1565
        if sendError == htlcswitch.ErrUnreadableFailureMessage {
3✔
1566
                response.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1567
                return response, nil
×
1568
        }
×
1569

1570
        rtErr, ok := sendError.(htlcswitch.ClearTextError)
3✔
1571
        if !ok {
3✔
1572
                return nil, sendError
×
1573
        }
×
1574

1575
        err := marshallWireError(rtErr.WireMessage(), response)
3✔
1576
        if err != nil {
3✔
1577
                return nil, err
×
1578
        }
×
1579

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

1591
        return response, nil
3✔
1592
}
1593

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

3✔
1603
        switch onionErr := msg.(type) {
3✔
1604
        case *lnwire.FailIncorrectDetails:
3✔
1605
                response.Code = lnrpc.Failure_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS
3✔
1606
                response.Height = onionErr.Height()
3✔
1607

1608
        case *lnwire.FailIncorrectPaymentAmount:
×
1609
                response.Code = lnrpc.Failure_INCORRECT_PAYMENT_AMOUNT
×
1610

1611
        case *lnwire.FailFinalIncorrectCltvExpiry:
×
1612
                response.Code = lnrpc.Failure_FINAL_INCORRECT_CLTV_EXPIRY
×
1613
                response.CltvExpiry = onionErr.CltvExpiry
×
1614

1615
        case *lnwire.FailFinalIncorrectHtlcAmount:
×
1616
                response.Code = lnrpc.Failure_FINAL_INCORRECT_HTLC_AMOUNT
×
1617
                response.HtlcMsat = uint64(onionErr.IncomingHTLCAmount)
×
1618

1619
        case *lnwire.FailFinalExpiryTooSoon:
×
1620
                response.Code = lnrpc.Failure_FINAL_EXPIRY_TOO_SOON
×
1621

1622
        case *lnwire.FailInvalidRealm:
×
1623
                response.Code = lnrpc.Failure_INVALID_REALM
×
1624

1625
        case *lnwire.FailExpiryTooSoon:
×
1626
                response.Code = lnrpc.Failure_EXPIRY_TOO_SOON
×
1627
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1628

1629
        case *lnwire.FailExpiryTooFar:
×
1630
                response.Code = lnrpc.Failure_EXPIRY_TOO_FAR
×
1631

1632
        case *lnwire.FailInvalidOnionVersion:
3✔
1633
                response.Code = lnrpc.Failure_INVALID_ONION_VERSION
3✔
1634
                response.OnionSha_256 = onionErr.OnionSHA256[:]
3✔
1635

1636
        case *lnwire.FailInvalidOnionHmac:
×
1637
                response.Code = lnrpc.Failure_INVALID_ONION_HMAC
×
1638
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1639

1640
        case *lnwire.FailInvalidOnionKey:
×
1641
                response.Code = lnrpc.Failure_INVALID_ONION_KEY
×
1642
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1643

1644
        case *lnwire.FailAmountBelowMinimum:
×
1645
                response.Code = lnrpc.Failure_AMOUNT_BELOW_MINIMUM
×
1646
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1647
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1648

1649
        case *lnwire.FailFeeInsufficient:
3✔
1650
                response.Code = lnrpc.Failure_FEE_INSUFFICIENT
3✔
1651
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
3✔
1652
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
3✔
1653

1654
        case *lnwire.FailIncorrectCltvExpiry:
×
1655
                response.Code = lnrpc.Failure_INCORRECT_CLTV_EXPIRY
×
1656
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1657
                response.CltvExpiry = onionErr.CltvExpiry
×
1658

1659
        case *lnwire.FailChannelDisabled:
3✔
1660
                response.Code = lnrpc.Failure_CHANNEL_DISABLED
3✔
1661
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
3✔
1662
                response.Flags = uint32(onionErr.Flags)
3✔
1663

1664
        case *lnwire.FailTemporaryChannelFailure:
3✔
1665
                response.Code = lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE
3✔
1666
                response.ChannelUpdate = marshallChannelUpdate(onionErr.Update)
3✔
1667

1668
        case *lnwire.FailRequiredNodeFeatureMissing:
×
1669
                response.Code = lnrpc.Failure_REQUIRED_NODE_FEATURE_MISSING
×
1670

1671
        case *lnwire.FailRequiredChannelFeatureMissing:
×
1672
                response.Code = lnrpc.Failure_REQUIRED_CHANNEL_FEATURE_MISSING
×
1673

1674
        case *lnwire.FailUnknownNextPeer:
3✔
1675
                response.Code = lnrpc.Failure_UNKNOWN_NEXT_PEER
3✔
1676

1677
        case *lnwire.FailTemporaryNodeFailure:
×
1678
                response.Code = lnrpc.Failure_TEMPORARY_NODE_FAILURE
×
1679

1680
        case *lnwire.FailPermanentNodeFailure:
×
1681
                response.Code = lnrpc.Failure_PERMANENT_NODE_FAILURE
×
1682

1683
        case *lnwire.FailPermanentChannelFailure:
3✔
1684
                response.Code = lnrpc.Failure_PERMANENT_CHANNEL_FAILURE
3✔
1685

1686
        case *lnwire.FailMPPTimeout:
×
1687
                response.Code = lnrpc.Failure_MPP_TIMEOUT
×
1688

1689
        case *lnwire.InvalidOnionPayload:
3✔
1690
                response.Code = lnrpc.Failure_INVALID_ONION_PAYLOAD
3✔
1691

1692
        case *lnwire.FailInvalidBlinding:
3✔
1693
                response.Code = lnrpc.Failure_INVALID_ONION_BLINDING
3✔
1694
                response.OnionSha_256 = onionErr.OnionSHA256[:]
3✔
1695

1696
        case nil:
×
1697
                response.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1698

1699
        default:
×
1700
                return fmt.Errorf("cannot marshall failure %T", onionErr)
×
1701
        }
1702

1703
        return nil
3✔
1704
}
1705

1706
// marshallChannelUpdate marshalls a channel update as received over the wire to
1707
// the router rpc format.
1708
func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
3✔
1709
        if update == nil {
3✔
1710
                return nil
×
1711
        }
×
1712

1713
        return &lnrpc.ChannelUpdate{
3✔
1714
                Signature:       update.Signature.RawBytes(),
3✔
1715
                ChainHash:       update.ChainHash[:],
3✔
1716
                ChanId:          update.ShortChannelID.ToUint64(),
3✔
1717
                Timestamp:       update.Timestamp,
3✔
1718
                MessageFlags:    uint32(update.MessageFlags),
3✔
1719
                ChannelFlags:    uint32(update.ChannelFlags),
3✔
1720
                TimeLockDelta:   uint32(update.TimeLockDelta),
3✔
1721
                HtlcMinimumMsat: uint64(update.HtlcMinimumMsat),
3✔
1722
                BaseFee:         update.BaseFee,
3✔
1723
                FeeRate:         update.FeeRate,
3✔
1724
                HtlcMaximumMsat: uint64(update.HtlcMaximumMsat),
3✔
1725
                ExtraOpaqueData: update.ExtraOpaqueData,
3✔
1726
        }
3✔
1727
}
1728

1729
// MarshallPayment marshall a payment to its rpc representation.
1730
func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
1731
        *lnrpc.Payment, error) {
6✔
1732

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

1747
        msatValue := int64(payment.Info.Value)
6✔
1748
        satValue := int64(payment.Info.Value.ToSatoshis())
6✔
1749

6✔
1750
        status, err := convertPaymentStatus(
6✔
1751
                payment.Status, r.UseStatusInitiated,
6✔
1752
        )
6✔
1753
        if err != nil {
6✔
1754
                return nil, err
×
1755
        }
×
1756

1757
        htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
6✔
1758
        for _, dbHTLC := range payment.HTLCs {
9✔
1759
                htlc, err := r.MarshalHTLCAttempt(dbHTLC)
3✔
1760
                if err != nil {
3✔
1761
                        return nil, err
×
1762
                }
×
1763

1764
                htlcs = append(htlcs, htlc)
3✔
1765
        }
1766

1767
        paymentID := payment.Info.PaymentIdentifier
6✔
1768
        creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
6✔
1769

6✔
1770
        failureReason, err := marshallPaymentFailureReason(
6✔
1771
                payment.FailureReason,
6✔
1772
        )
6✔
1773
        if err != nil {
6✔
1774
                return nil, err
×
1775
        }
×
1776

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

1798
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
1799
// by the RPC.
1800
func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
1801
        lnrpc.Payment_PaymentStatus, error) {
6✔
1802

6✔
1803
        switch dbStatus {
6✔
1804
        case channeldb.StatusInitiated:
3✔
1805
                // If the client understands the new status, return it.
3✔
1806
                if useInit {
6✔
1807
                        return lnrpc.Payment_INITIATED, nil
3✔
1808
                }
3✔
1809

1810
                // Otherwise remain the old behavior.
1811
                return lnrpc.Payment_IN_FLIGHT, nil
3✔
1812

1813
        case channeldb.StatusInFlight:
4✔
1814
                return lnrpc.Payment_IN_FLIGHT, nil
4✔
1815

1816
        case channeldb.StatusSucceeded:
5✔
1817
                return lnrpc.Payment_SUCCEEDED, nil
5✔
1818

1819
        case channeldb.StatusFailed:
3✔
1820
                return lnrpc.Payment_FAILED, nil
3✔
1821

1822
        default:
×
1823
                return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
×
1824
        }
1825
}
1826

1827
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
1828
// type.
1829
func marshallPaymentFailureReason(reason *channeldb.FailureReason) (
1830
        lnrpc.PaymentFailureReason, error) {
6✔
1831

6✔
1832
        if reason == nil {
12✔
1833
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, nil
6✔
1834
        }
6✔
1835

1836
        switch *reason {
3✔
1837
        case channeldb.FailureReasonTimeout:
×
1838
                return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
×
1839

1840
        case channeldb.FailureReasonNoRoute:
3✔
1841
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
3✔
1842

1843
        case channeldb.FailureReasonError:
3✔
1844
                return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
3✔
1845

1846
        case channeldb.FailureReasonPaymentDetails:
3✔
1847
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
3✔
1848

1849
        case channeldb.FailureReasonInsufficientBalance:
3✔
1850
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
3✔
1851

1852
        case channeldb.FailureReasonCanceled:
3✔
1853
                return lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, nil
3✔
1854
        }
1855

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