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

lightningnetwork / lnd / 14358372723

09 Apr 2025 01:26PM UTC coverage: 56.696% (-12.3%) from 69.037%
14358372723

Pull #9696

github

web-flow
Merge e2837e400 into 867d27d68
Pull Request #9696: Add `development_guidelines.md` for both human and machine

107055 of 188823 relevant lines covered (56.7%)

22721.56 hits per line

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

28.75
/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

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

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

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

56
        // FetchChannelEndpoints returns the pubkeys of both endpoints of the
57
        // given channel id.
58
        FetchChannelEndpoints func(chanID uint64) (route.Vertex,
59
                route.Vertex, error)
60

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

65
        MissionControl MissionControl
66

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

73
        // Tower is the ControlTower instance that is used to track pending
74
        // payments.
75
        Tower routing.ControlTower
76

77
        // MaxTotalTimelock is the maximum total time lock a route is allowed to
78
        // have.
79
        MaxTotalTimelock uint32
80

81
        // DefaultFinalCltvDelta is the default value used as final cltv delta
82
        // when an RPC caller doesn't specify a value.
83
        DefaultFinalCltvDelta uint16
84

85
        // SubscribeHtlcEvents returns a subscription client for the node's
86
        // htlc events.
87
        SubscribeHtlcEvents func() (*subscribe.Client, error)
88

89
        // InterceptableForwarder exposes the ability to intercept forward events
90
        // by letting the router register a ForwardInterceptor.
91
        InterceptableForwarder htlcswitch.InterceptableHtlcForwarder
92

93
        // SetChannelEnabled exposes the ability to manually enable a channel.
94
        SetChannelEnabled func(wire.OutPoint) error
95

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

99
        // SetChannelAuto exposes the ability to restore automatic channel state
100
        // management after manually setting channel status.
101
        SetChannelAuto func(wire.OutPoint) error
102

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

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

114
        // ShouldSetExpEndorsement returns a boolean indicating whether the
115
        // experimental endorsement bit should be set.
116
        ShouldSetExpEndorsement func() bool
117
}
118

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

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

130
        // GetHistorySnapshot takes a snapshot from the current mission control
131
        // state and actual probability estimates.
132
        GetHistorySnapshot() *routing.MissionControlSnapshot
133

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

139
        // GetPairHistorySnapshot returns the stored history for a given node
140
        // pair.
141
        GetPairHistorySnapshot(fromNode,
142
                toNode route.Vertex) routing.TimedPairResult
143

144
        // GetConfig gets mission control's current config.
145
        GetConfig() *routing.MissionControlConfig
146

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

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

4✔
164
        routeReq, err := r.parseQueryRoutesRequest(in)
4✔
165
        if err != nil {
5✔
166
                return nil, err
1✔
167
        }
1✔
168

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

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

184
        routeResp := &lnrpc.QueryRoutesResponse{
3✔
185
                Routes:      []*lnrpc.Route{rpcRoute},
3✔
186
                SuccessProb: successProb,
3✔
187
        }
3✔
188

3✔
189
        return routeResp, nil
3✔
190
}
191

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

198
        return route.NewVertexFromBytes(pubKeyBytes)
4✔
199
}
200

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

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

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

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

×
223
                        continue
×
224
                }
225
                ignoredPairs[pair] = struct{}{}
3✔
226
        }
227

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

235
                to, err := route.NewVertexFromBytes(ignorePair.To)
3✔
236
                if err != nil {
3✔
237
                        return nil, nil, err
×
238
                }
×
239

240
                pair := routing.NewDirectedNodePair(from, to)
3✔
241
                ignoredPairs[pair] = struct{}{}
3✔
242
        }
243

244
        return ignoredNodes, ignoredPairs, nil
3✔
245
}
246

247
func (r *RouterBackend) parseQueryRoutesRequest(in *lnrpc.QueryRoutesRequest) (
248
        *routing.RouteRequest, error) {
4✔
249

4✔
250
        // Parse the hex-encoded source public key into a full public key that
4✔
251
        // we can properly manipulate.
4✔
252

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

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

273
        // Unmarshall restrictions from request.
274
        feeLimit := lnrpc.CalculateFeeLimit(in.FeeLimit, amt)
4✔
275

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

283
        cltvLimit, err := ValidateCLTVLimit(in.CltvLimit, maxTotalTimelock)
4✔
284
        if err != nil {
4✔
285
                return nil, err
×
286
        }
×
287

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

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

4✔
302
                // destinationFeatures is the set of features for the
4✔
303
                // destination node.
4✔
304
                destinationFeatures *lnwire.FeatureVector
4✔
305
        )
4✔
306

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

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

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

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

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

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

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

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

3✔
370
        ignoredNodes, ignoredPairs, err := r.parseIgnored(in)
3✔
371
        if err != nil {
3✔
372
                return nil, err
×
373
        }
×
374

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

12✔
381
                        if _, ok := ignoredNodes[fromNode]; ok {
15✔
382
                                return 0
3✔
383
                        }
3✔
384

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

393
                        if !in.UseMissionControl {
5✔
394
                                return 1
2✔
395
                        }
2✔
396

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

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

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

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

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

438
func parseBlindedPaymentPaths(in *lnrpc.QueryRoutesRequest) (
439
        *routing.BlindedPaymentPathSet, error) {
×
440

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

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

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

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

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

472
                if err := blindedPmt.Validate(); err != nil {
×
473
                        return nil, fmt.Errorf("invalid blinded path: %w", err)
×
474
                }
×
475

476
                paths[i] = blindedPmt
×
477
        }
478

479
        return routing.NewBlindedPaymentPathSet(paths)
×
480
}
481

482
func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
483
        *routing.BlindedPayment, error) {
×
484

×
485
        if rpcPayment == nil {
×
486
                return nil, errors.New("nil blinded payment")
×
487
        }
×
488

489
        path, err := unmarshalBlindedPaymentPaths(rpcPayment.BlindedPath)
×
490
        if err != nil {
×
491
                return nil, err
×
492
        }
×
493

494
        features, err := UnmarshalFeatures(rpcPayment.Features)
×
495
        if err != nil {
×
496
                return nil, err
×
497
        }
×
498

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

510
func unmarshalBlindedPaymentPaths(rpcPath *lnrpc.BlindedPath) (
511
        *sphinx.BlindedPath, error) {
×
512

×
513
        if rpcPath == nil {
×
514
                return nil, errors.New("blinded path required when blinded " +
×
515
                        "route is provided")
×
516
        }
×
517

518
        introduction, err := btcec.ParsePubKey(rpcPath.IntroductionNode)
×
519
        if err != nil {
×
520
                return nil, err
×
521
        }
×
522

523
        blinding, err := btcec.ParsePubKey(rpcPath.BlindingPoint)
×
524
        if err != nil {
×
525
                return nil, err
×
526
        }
×
527

528
        if len(rpcPath.BlindedHops) < 1 {
×
529
                return nil, errors.New("at least 1 blinded hops required")
×
530
        }
×
531

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

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

547
        return path, nil
×
548
}
549

550
func unmarshalBlindedHop(rpcHop *lnrpc.BlindedHop) (*sphinx.BlindedHopInfo,
551
        error) {
×
552

×
553
        pubkey, err := btcec.ParsePubKey(rpcHop.BlindedNode)
×
554
        if err != nil {
×
555
                return nil, err
×
556
        }
×
557

558
        if len(rpcHop.EncryptedData) == 0 {
×
559
                return nil, errors.New("empty encrypted data not allowed")
×
560
        }
×
561

562
        return &sphinx.BlindedHopInfo{
×
563
                BlindedNodePub: pubkey,
×
564
                CipherText:     rpcHop.EncryptedData,
×
565
        }, nil
×
566
}
567

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

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

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

585
        return pair, nil
3✔
586
}
587

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

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

607
                resp.CustomChannelData = customData
×
608

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

619
        incomingAmt := route.TotalAmount
3✔
620
        for i, hop := range route.Hops {
6✔
621
                fee := route.HopFee(i)
3✔
622

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

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

×
639
                        mpp = &lnrpc.MPPRecord{
×
640
                                PaymentAddr:  addr[:],
×
641
                                TotalAmtMsat: int64(hop.MPP.TotalMsat()),
×
642
                        }
×
643
                }
×
644

645
                var amp *lnrpc.AMPRecord
3✔
646
                if hop.AMP != nil {
3✔
647
                        rootShare := hop.AMP.RootShare()
×
648
                        setID := hop.AMP.SetID()
×
649

×
650
                        amp = &lnrpc.AMPRecord{
×
651
                                RootShare:  rootShare[:],
×
652
                                SetId:      setID[:],
×
653
                                ChildIndex: hop.AMP.ChildIndex(),
×
654
                        }
×
655
                }
×
656

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

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

684
        return resp, nil
3✔
685
}
686

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

×
692
        customRecords := record.CustomSet(rpcHop.CustomRecords)
×
693
        if err := customRecords.Validate(); err != nil {
×
694
                return nil, err
×
695
        }
×
696

697
        mpp, err := UnmarshalMPP(rpcHop.MppRecord)
×
698
        if err != nil {
×
699
                return nil, err
×
700
        }
×
701

702
        amp, err := UnmarshalAMP(rpcHop.AmpRecord)
×
703
        if err != nil {
×
704
                return nil, err
×
705
        }
×
706

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

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

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

735
        return hop, nil
×
736
}
737

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

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

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

772
        return UnmarshallHopWithPubkey(rpcHop, pubKeyBytes)
×
773
}
774

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

×
780
        prevNodePubKey := r.SelfNode
×
781

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

789
                hops[i] = routeHop
×
790

×
791
                prevNodePubKey = routeHop.PubKeyBytes
×
792
        }
793

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

804
        return route, nil
×
805
}
806

807
// extractIntentFromSendRequest attempts to parse the SendRequest details
808
// required to dispatch a client from the information presented by an RPC
809
// client.
810
func (r *RouterBackend) extractIntentFromSendRequest(
811
        rpcPayReq *SendPaymentRequest) (*routing.LightningPayment, error) {
×
812

×
813
        payIntent := &routing.LightningPayment{}
×
814

×
815
        // Pass along time preference.
×
816
        if rpcPayReq.TimePref < -1 || rpcPayReq.TimePref > 1 {
×
817
                return nil, errors.New("time preference out of range")
×
818
        }
×
819
        payIntent.TimePref = rpcPayReq.TimePref
×
820

×
821
        // Pass along restrictions on the outgoing channels that may be used.
×
822
        payIntent.OutgoingChannelIDs = rpcPayReq.OutgoingChanIds
×
823

×
824
        // Add the deprecated single outgoing channel restriction if present.
×
825
        if rpcPayReq.OutgoingChanId != 0 {
×
826
                if payIntent.OutgoingChannelIDs != nil {
×
827
                        return nil, errors.New("outgoing_chan_id and " +
×
828
                                "outgoing_chan_ids are mutually exclusive")
×
829
                }
×
830

831
                payIntent.OutgoingChannelIDs = append(
×
832
                        payIntent.OutgoingChannelIDs, rpcPayReq.OutgoingChanId,
×
833
                )
×
834
        }
835

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

847
        // Take the CLTV limit from the request if set, otherwise use the max.
848
        cltvLimit, err := ValidateCLTVLimit(
×
849
                uint32(rpcPayReq.CltvLimit), r.MaxTotalTimelock,
×
850
        )
×
851
        if err != nil {
×
852
                return nil, err
×
853
        }
×
854
        payIntent.CltvLimit = cltvLimit
×
855

×
856
        // Attempt to parse the max parts value set by the user, if this value
×
857
        // isn't set, then we'll use the current default value for this
×
858
        // setting.
×
859
        maxParts := rpcPayReq.MaxParts
×
860
        if maxParts == 0 {
×
861
                maxParts = DefaultMaxParts
×
862
        }
×
863
        payIntent.MaxParts = maxParts
×
864

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

873
        // Take fee limit from request.
874
        payIntent.FeeLimit, err = lnrpc.UnmarshallAmt(
×
875
                rpcPayReq.FeeLimitSat, rpcPayReq.FeeLimitMsat,
×
876
        )
×
877
        if err != nil {
×
878
                return nil, err
×
879
        }
×
880

881
        customRecords := record.CustomSet(rpcPayReq.DestCustomRecords)
×
882
        if err := customRecords.Validate(); err != nil {
×
883
                return nil, err
×
884
        }
×
885
        payIntent.DestCustomRecords = customRecords
×
886

×
887
        // Keysend payments do not support MPP payments.
×
888
        //
×
889
        // NOTE: There is no need to validate the `MaxParts` value here because
×
890
        // it is set to 1 somewhere else in case it's a keysend payment.
×
891
        if customRecords.IsKeysend() {
×
892
                if payIntent.MaxShardAmt != nil {
×
893
                        return nil, errors.New("keysend payments cannot " +
×
894
                                "specify a max shard amount - MPP not " +
×
895
                                "supported with keysend payments")
×
896
                }
×
897
        }
898

899
        firstHopRecords := lnwire.CustomRecords(rpcPayReq.FirstHopCustomRecords)
×
900
        if err := firstHopRecords.Validate(); err != nil {
×
901
                return nil, err
×
902
        }
×
903
        payIntent.FirstHopCustomRecords = firstHopRecords
×
904

×
905
        // If the experimental endorsement signal is not already set, propagate
×
906
        // a zero value field if configured to set this signal.
×
907
        if r.ShouldSetExpEndorsement() {
×
908
                if payIntent.FirstHopCustomRecords == nil {
×
909
                        payIntent.FirstHopCustomRecords = make(
×
910
                                map[uint64][]byte,
×
911
                        )
×
912
                }
×
913

914
                t := uint64(lnwire.ExperimentalEndorsementType)
×
915
                if _, set := payIntent.FirstHopCustomRecords[t]; !set {
×
916
                        payIntent.FirstHopCustomRecords[t] = []byte{
×
917
                                lnwire.ExperimentalUnendorsed,
×
918
                        }
×
919
                }
×
920
        }
921

922
        payIntent.PayAttemptTimeout = time.Second *
×
923
                time.Duration(rpcPayReq.TimeoutSeconds)
×
924

×
925
        // Route hints.
×
926
        routeHints, err := unmarshallRouteHints(
×
927
                rpcPayReq.RouteHints,
×
928
        )
×
929
        if err != nil {
×
930
                return nil, err
×
931
        }
×
932
        payIntent.RouteHints = routeHints
×
933

×
934
        // Unmarshall either sat or msat amount from request.
×
935
        reqAmt, err := lnrpc.UnmarshallAmt(
×
936
                rpcPayReq.Amt, rpcPayReq.AmtMsat,
×
937
        )
×
938
        if err != nil {
×
939
                return nil, err
×
940
        }
×
941

942
        // If the payment request field isn't blank, then the details of the
943
        // invoice are encoded entirely within the encoded payReq.  So we'll
944
        // attempt to decode it, populating the payment accordingly.
945
        if rpcPayReq.PaymentRequest != "" {
×
946
                switch {
×
947

948
                case len(rpcPayReq.Dest) > 0:
×
949
                        return nil, errors.New("dest and payment_request " +
×
950
                                "cannot appear together")
×
951

952
                case len(rpcPayReq.PaymentHash) > 0:
×
953
                        return nil, errors.New("payment_hash and payment_request " +
×
954
                                "cannot appear together")
×
955

956
                case rpcPayReq.FinalCltvDelta != 0:
×
957
                        return nil, errors.New("final_cltv_delta and payment_request " +
×
958
                                "cannot appear together")
×
959
                }
960

961
                payReq, err := zpay32.Decode(
×
962
                        rpcPayReq.PaymentRequest, r.ActiveNetParams,
×
963
                )
×
964
                if err != nil {
×
965
                        return nil, err
×
966
                }
×
967

968
                // Next, we'll ensure that this payreq hasn't already expired.
969
                err = ValidatePayReqExpiry(payReq)
×
970
                if err != nil {
×
971
                        return nil, err
×
972
                }
×
973

974
                // If the amount was not included in the invoice, then we let
975
                // the payer specify the amount of satoshis they wish to send.
976
                // We override the amount to pay with the amount provided from
977
                // the payment request.
978
                if payReq.MilliSat == nil {
×
979
                        if reqAmt == 0 {
×
980
                                return nil, errors.New("amount must be " +
×
981
                                        "specified when paying a zero amount " +
×
982
                                        "invoice")
×
983
                        }
×
984

985
                        payIntent.Amount = reqAmt
×
986
                } else {
×
987
                        if reqAmt != 0 {
×
988
                                return nil, errors.New("amount must not be " +
×
989
                                        "specified when paying a non-zero " +
×
990
                                        " amount invoice")
×
991
                        }
×
992

993
                        payIntent.Amount = *payReq.MilliSat
×
994
                }
995

996
                if !payReq.Features.HasFeature(lnwire.MPPOptional) &&
×
997
                        !payReq.Features.HasFeature(lnwire.AMPOptional) {
×
998

×
999
                        payIntent.MaxParts = 1
×
1000
                }
×
1001

1002
                payAddr := payReq.PaymentAddr
×
1003
                if payReq.Features.HasFeature(lnwire.AMPOptional) {
×
1004
                        // The opt-in AMP flag is required to pay an AMP
×
1005
                        // invoice.
×
1006
                        if !rpcPayReq.Amp {
×
1007
                                return nil, fmt.Errorf("the AMP flag (--amp " +
×
1008
                                        "or SendPaymentRequest.Amp) must be " +
×
1009
                                        "set to pay an AMP invoice")
×
1010
                        }
×
1011

1012
                        // Generate random SetID and root share.
1013
                        var setID [32]byte
×
1014
                        _, err = rand.Read(setID[:])
×
1015
                        if err != nil {
×
1016
                                return nil, err
×
1017
                        }
×
1018

1019
                        var rootShare [32]byte
×
1020
                        _, err = rand.Read(rootShare[:])
×
1021
                        if err != nil {
×
1022
                                return nil, err
×
1023
                        }
×
1024
                        err := payIntent.SetAMP(&routing.AMPOptions{
×
1025
                                SetID:     setID,
×
1026
                                RootShare: rootShare,
×
1027
                        })
×
1028
                        if err != nil {
×
1029
                                return nil, err
×
1030
                        }
×
1031

1032
                        // For AMP invoices, we'll allow users to override the
1033
                        // included payment addr to allow the invoice to be
1034
                        // pseudo-reusable, e.g. the invoice parameters are
1035
                        // reused (amt, cltv, hop hints, etc) even though the
1036
                        // payments will share different payment hashes.
1037
                        //
1038
                        // NOTE: This will only work when the peer has
1039
                        // spontaneous AMP payments enabled.
1040
                        if len(rpcPayReq.PaymentAddr) > 0 {
×
1041
                                var addr [32]byte
×
1042
                                copy(addr[:], rpcPayReq.PaymentAddr)
×
1043
                                payAddr = fn.Some(addr)
×
1044
                        }
×
1045
                } else {
×
1046
                        err = payIntent.SetPaymentHash(*payReq.PaymentHash)
×
1047
                        if err != nil {
×
1048
                                return nil, err
×
1049
                        }
×
1050
                }
1051

1052
                destKey := payReq.Destination.SerializeCompressed()
×
1053
                copy(payIntent.Target[:], destKey)
×
1054

×
1055
                payIntent.FinalCLTVDelta = uint16(payReq.MinFinalCLTVExpiry())
×
1056
                payIntent.RouteHints = append(
×
1057
                        payIntent.RouteHints, payReq.RouteHints...,
×
1058
                )
×
1059
                payIntent.DestFeatures = payReq.Features
×
1060
                payIntent.PaymentAddr = payAddr
×
1061
                payIntent.PaymentRequest = []byte(rpcPayReq.PaymentRequest)
×
1062
                payIntent.Metadata = payReq.Metadata
×
1063

×
1064
                if len(payReq.BlindedPaymentPaths) > 0 {
×
1065
                        pathSet, err := BuildBlindedPathSet(
×
1066
                                payReq.BlindedPaymentPaths,
×
1067
                        )
×
1068
                        if err != nil {
×
1069
                                return nil, err
×
1070
                        }
×
1071
                        payIntent.BlindedPathSet = pathSet
×
1072

×
1073
                        // Replace the target node with the target public key
×
1074
                        // of the blinded path set.
×
1075
                        copy(
×
1076
                                payIntent.Target[:],
×
1077
                                pathSet.TargetPubKey().SerializeCompressed(),
×
1078
                        )
×
1079

×
1080
                        pathFeatures := pathSet.Features()
×
1081
                        if !pathFeatures.IsEmpty() {
×
1082
                                payIntent.DestFeatures = pathFeatures.Clone()
×
1083
                        }
×
1084
                }
1085
        } else {
×
1086
                // Otherwise, If the payment request field was not specified
×
1087
                // (and a custom route wasn't specified), construct the payment
×
1088
                // from the other fields.
×
1089

×
1090
                // Payment destination.
×
1091
                target, err := route.NewVertexFromBytes(rpcPayReq.Dest)
×
1092
                if err != nil {
×
1093
                        return nil, err
×
1094
                }
×
1095
                payIntent.Target = target
×
1096

×
1097
                // Final payment CLTV delta.
×
1098
                if rpcPayReq.FinalCltvDelta != 0 {
×
1099
                        payIntent.FinalCLTVDelta =
×
1100
                                uint16(rpcPayReq.FinalCltvDelta)
×
1101
                } else {
×
1102
                        payIntent.FinalCLTVDelta = r.DefaultFinalCltvDelta
×
1103
                }
×
1104

1105
                // Amount.
1106
                if reqAmt == 0 {
×
1107
                        return nil, errors.New("amount must be specified")
×
1108
                }
×
1109

1110
                payIntent.Amount = reqAmt
×
1111

×
1112
                // Parse destination feature bits.
×
1113
                features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
×
1114
                if err != nil {
×
1115
                        return nil, err
×
1116
                }
×
1117

1118
                // Validate the features if any was specified.
1119
                if features != nil {
×
1120
                        err = feature.ValidateDeps(features)
×
1121
                        if err != nil {
×
1122
                                return nil, err
×
1123
                        }
×
1124
                }
1125

1126
                // If this is an AMP payment, we must generate the initial
1127
                // randomness.
1128
                if rpcPayReq.Amp {
×
1129
                        // If no destination features were specified, we set
×
1130
                        // those necessary for AMP payments.
×
1131
                        if features == nil {
×
1132
                                ampFeatures := []lnrpc.FeatureBit{
×
1133
                                        lnrpc.FeatureBit_TLV_ONION_OPT,
×
1134
                                        lnrpc.FeatureBit_PAYMENT_ADDR_OPT,
×
1135
                                        lnrpc.FeatureBit_AMP_OPT,
×
1136
                                }
×
1137

×
1138
                                features, err = UnmarshalFeatures(ampFeatures)
×
1139
                                if err != nil {
×
1140
                                        return nil, err
×
1141
                                }
×
1142
                        }
1143

1144
                        // First make sure the destination supports AMP.
1145
                        if !features.HasFeature(lnwire.AMPOptional) {
×
1146
                                return nil, fmt.Errorf("destination doesn't " +
×
1147
                                        "support AMP payments")
×
1148
                        }
×
1149

1150
                        // If no payment address is set, generate a random one.
1151
                        var payAddr [32]byte
×
1152
                        if len(rpcPayReq.PaymentAddr) == 0 {
×
1153
                                _, err = rand.Read(payAddr[:])
×
1154
                                if err != nil {
×
1155
                                        return nil, err
×
1156
                                }
×
1157
                        } else {
×
1158
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1159
                        }
×
1160
                        payIntent.PaymentAddr = fn.Some(payAddr)
×
1161

×
1162
                        // Generate random SetID and root share.
×
1163
                        var setID [32]byte
×
1164
                        _, err = rand.Read(setID[:])
×
1165
                        if err != nil {
×
1166
                                return nil, err
×
1167
                        }
×
1168

1169
                        var rootShare [32]byte
×
1170
                        _, err = rand.Read(rootShare[:])
×
1171
                        if err != nil {
×
1172
                                return nil, err
×
1173
                        }
×
1174
                        err := payIntent.SetAMP(&routing.AMPOptions{
×
1175
                                SetID:     setID,
×
1176
                                RootShare: rootShare,
×
1177
                        })
×
1178
                        if err != nil {
×
1179
                                return nil, err
×
1180
                        }
×
1181
                } else {
×
1182
                        // Payment hash.
×
1183
                        paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
×
1184
                        if err != nil {
×
1185
                                return nil, err
×
1186
                        }
×
1187

1188
                        err = payIntent.SetPaymentHash(paymentHash)
×
1189
                        if err != nil {
×
1190
                                return nil, err
×
1191
                        }
×
1192

1193
                        // If the payment addresses is specified, then we'll
1194
                        // also populate that now as well.
1195
                        if len(rpcPayReq.PaymentAddr) != 0 {
×
1196
                                var payAddr [32]byte
×
1197
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1198

×
1199
                                payIntent.PaymentAddr = fn.Some(payAddr)
×
1200
                        }
×
1201
                }
1202

1203
                payIntent.DestFeatures = features
×
1204
        }
1205

1206
        // Do bounds checking with the block padding so the router isn't
1207
        // left with a zombie payment in case the user messes up.
1208
        err = routing.ValidateCLTVLimit(
×
1209
                payIntent.CltvLimit, payIntent.FinalCLTVDelta, true,
×
1210
        )
×
1211
        if err != nil {
×
1212
                return nil, err
×
1213
        }
×
1214

1215
        // Check for disallowed payments to self.
1216
        if !rpcPayReq.AllowSelfPayment && payIntent.Target == r.SelfNode {
×
1217
                return nil, errors.New("self-payments not allowed")
×
1218
        }
×
1219

1220
        return payIntent, nil
×
1221
}
1222

1223
// BuildBlindedPathSet marshals a set of zpay32.BlindedPaymentPath and uses
1224
// the result to build a new routing.BlindedPaymentPathSet.
1225
func BuildBlindedPathSet(paths []*zpay32.BlindedPaymentPath) (
1226
        *routing.BlindedPaymentPathSet, error) {
×
1227

×
1228
        marshalledPaths := make([]*routing.BlindedPayment, len(paths))
×
1229
        for i, path := range paths {
×
1230
                paymentPath := marshalBlindedPayment(path)
×
1231

×
1232
                err := paymentPath.Validate()
×
1233
                if err != nil {
×
1234
                        return nil, err
×
1235
                }
×
1236

1237
                marshalledPaths[i] = paymentPath
×
1238
        }
1239

1240
        return routing.NewBlindedPaymentPathSet(marshalledPaths)
×
1241
}
1242

1243
// marshalBlindedPayment marshals a zpay32.BLindedPaymentPath into a
1244
// routing.BlindedPayment.
1245
func marshalBlindedPayment(
1246
        path *zpay32.BlindedPaymentPath) *routing.BlindedPayment {
×
1247

×
1248
        return &routing.BlindedPayment{
×
1249
                BlindedPath: &sphinx.BlindedPath{
×
1250
                        IntroductionPoint: path.Hops[0].BlindedNodePub,
×
1251
                        BlindingPoint:     path.FirstEphemeralBlindingPoint,
×
1252
                        BlindedHops:       path.Hops,
×
1253
                },
×
1254
                BaseFee:             path.FeeBaseMsat,
×
1255
                ProportionalFeeRate: path.FeeRate,
×
1256
                CltvExpiryDelta:     path.CltvExpiryDelta,
×
1257
                HtlcMinimum:         path.HTLCMinMsat,
×
1258
                HtlcMaximum:         path.HTLCMaxMsat,
×
1259
                Features:            path.Features,
×
1260
        }
×
1261
}
×
1262

1263
// unmarshallRouteHints unmarshalls a list of route hints.
1264
func unmarshallRouteHints(rpcRouteHints []*lnrpc.RouteHint) (
1265
        [][]zpay32.HopHint, error) {
4✔
1266

4✔
1267
        routeHints := make([][]zpay32.HopHint, 0, len(rpcRouteHints))
4✔
1268
        for _, rpcRouteHint := range rpcRouteHints {
8✔
1269
                routeHint := make(
4✔
1270
                        []zpay32.HopHint, 0, len(rpcRouteHint.HopHints),
4✔
1271
                )
4✔
1272
                for _, rpcHint := range rpcRouteHint.HopHints {
8✔
1273
                        hint, err := unmarshallHopHint(rpcHint)
4✔
1274
                        if err != nil {
4✔
1275
                                return nil, err
×
1276
                        }
×
1277

1278
                        routeHint = append(routeHint, hint)
4✔
1279
                }
1280
                routeHints = append(routeHints, routeHint)
4✔
1281
        }
1282

1283
        return routeHints, nil
4✔
1284
}
1285

1286
// unmarshallHopHint unmarshalls a single hop hint.
1287
func unmarshallHopHint(rpcHint *lnrpc.HopHint) (zpay32.HopHint, error) {
4✔
1288
        pubBytes, err := hex.DecodeString(rpcHint.NodeId)
4✔
1289
        if err != nil {
4✔
1290
                return zpay32.HopHint{}, err
×
1291
        }
×
1292

1293
        pubkey, err := btcec.ParsePubKey(pubBytes)
4✔
1294
        if err != nil {
4✔
1295
                return zpay32.HopHint{}, err
×
1296
        }
×
1297

1298
        return zpay32.HopHint{
4✔
1299
                NodeID:                    pubkey,
4✔
1300
                ChannelID:                 rpcHint.ChanId,
4✔
1301
                FeeBaseMSat:               rpcHint.FeeBaseMsat,
4✔
1302
                FeeProportionalMillionths: rpcHint.FeeProportionalMillionths,
4✔
1303
                CLTVExpiryDelta:           uint16(rpcHint.CltvExpiryDelta),
4✔
1304
        }, nil
4✔
1305
}
1306

1307
// MarshalFeatures converts a feature vector into a list of uint32's.
1308
func MarshalFeatures(feats *lnwire.FeatureVector) []lnrpc.FeatureBit {
×
1309
        var featureBits []lnrpc.FeatureBit
×
1310
        for feature := range feats.Features() {
×
1311
                featureBits = append(featureBits, lnrpc.FeatureBit(feature))
×
1312
        }
×
1313

1314
        return featureBits
×
1315
}
1316

1317
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
1318
// This method checks that feature bit pairs aren't assigned together, and
1319
// validates transitive dependencies.
1320
func UnmarshalFeatures(
1321
        rpcFeatures []lnrpc.FeatureBit) (*lnwire.FeatureVector, error) {
3✔
1322

3✔
1323
        // If no destination features are specified we'll return nil to signal
3✔
1324
        // that the router should try to use the graph as a fallback.
3✔
1325
        if rpcFeatures == nil {
3✔
1326
                return nil, nil
×
1327
        }
×
1328

1329
        raw := lnwire.NewRawFeatureVector()
3✔
1330
        for _, bit := range rpcFeatures {
6✔
1331
                err := raw.SafeSet(lnwire.FeatureBit(bit))
3✔
1332
                if err != nil {
3✔
1333
                        return nil, err
×
1334
                }
×
1335
        }
1336

1337
        return lnwire.NewFeatureVector(raw, lnwire.Features), nil
3✔
1338
}
1339

1340
// ValidatePayReqExpiry checks if the passed payment request has expired. In
1341
// the case it has expired, an error will be returned.
1342
func ValidatePayReqExpiry(payReq *zpay32.Invoice) error {
×
1343
        expiry := payReq.Expiry()
×
1344
        validUntil := payReq.Timestamp.Add(expiry)
×
1345
        if time.Now().After(validUntil) {
×
1346
                return fmt.Errorf("invoice expired. Valid until %v", validUntil)
×
1347
        }
×
1348

1349
        return nil
×
1350
}
1351

1352
// ValidateCLTVLimit returns a valid CLTV limit given a value and a maximum. If
1353
// the value exceeds the maximum, then an error is returned. If the value is 0,
1354
// then the maximum is used.
1355
func ValidateCLTVLimit(val, max uint32) (uint32, error) {
4✔
1356
        switch {
4✔
1357
        case val == 0:
4✔
1358
                return max, nil
4✔
1359
        case val > max:
×
1360
                return 0, fmt.Errorf("total time lock of %v exceeds max "+
×
1361
                        "allowed %v", val, max)
×
1362
        default:
×
1363
                return val, nil
×
1364
        }
1365
}
1366

1367
// UnmarshalMPP accepts the mpp_total_amt_msat and mpp_payment_addr fields from
1368
// an RPC request and converts into an record.MPP object. An error is returned
1369
// if the payment address is not 0 or 32 bytes. If the total amount and payment
1370
// address are zero-value, the return value will be nil signaling there is no
1371
// MPP record to attach to this hop. Otherwise, a non-nil reocrd will be
1372
// contained combining the provided values.
1373
func UnmarshalMPP(reqMPP *lnrpc.MPPRecord) (*record.MPP, error) {
6✔
1374
        // If no MPP record was submitted, assume the user wants to send a
6✔
1375
        // regular payment.
6✔
1376
        if reqMPP == nil {
7✔
1377
                return nil, nil
1✔
1378
        }
1✔
1379

1380
        reqTotal := reqMPP.TotalAmtMsat
5✔
1381
        reqAddr := reqMPP.PaymentAddr
5✔
1382

5✔
1383
        switch {
5✔
1384
        // No MPP fields were provided.
1385
        case reqTotal == 0 && len(reqAddr) == 0:
1✔
1386
                return nil, fmt.Errorf("missing total_msat and payment_addr")
1✔
1387

1388
        // Total is present, but payment address is missing.
1389
        case reqTotal > 0 && len(reqAddr) == 0:
1✔
1390
                return nil, fmt.Errorf("missing payment_addr")
1✔
1391

1392
        // Payment address is present, but total is missing.
1393
        case reqTotal == 0 && len(reqAddr) > 0:
1✔
1394
                return nil, fmt.Errorf("missing total_msat")
1✔
1395
        }
1396

1397
        addr, err := lntypes.MakeHash(reqAddr)
2✔
1398
        if err != nil {
3✔
1399
                return nil, fmt.Errorf("unable to parse "+
1✔
1400
                        "payment_addr: %v", err)
1✔
1401
        }
1✔
1402

1403
        total := lnwire.MilliSatoshi(reqTotal)
1✔
1404

1✔
1405
        return record.NewMPP(total, addr), nil
1✔
1406
}
1407

1408
func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
5✔
1409
        if reqAMP == nil {
6✔
1410
                return nil, nil
1✔
1411
        }
1✔
1412

1413
        reqRootShare := reqAMP.RootShare
4✔
1414
        reqSetID := reqAMP.SetId
4✔
1415

4✔
1416
        switch {
4✔
1417
        case len(reqRootShare) != 32:
2✔
1418
                return nil, errors.New("AMP root_share must be 32 bytes")
2✔
1419

1420
        case len(reqSetID) != 32:
1✔
1421
                return nil, errors.New("AMP set_id must be 32 bytes")
1✔
1422
        }
1423

1424
        var (
1✔
1425
                rootShare [32]byte
1✔
1426
                setID     [32]byte
1✔
1427
        )
1✔
1428
        copy(rootShare[:], reqRootShare)
1✔
1429
        copy(setID[:], reqSetID)
1✔
1430

1✔
1431
        return record.NewAMP(rootShare, setID, reqAMP.ChildIndex), nil
1✔
1432
}
1433

1434
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
1435
func (r *RouterBackend) MarshalHTLCAttempt(
1436
        htlc channeldb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
×
1437

×
1438
        route, err := r.MarshallRoute(&htlc.Route)
×
1439
        if err != nil {
×
1440
                return nil, err
×
1441
        }
×
1442

1443
        rpcAttempt := &lnrpc.HTLCAttempt{
×
1444
                AttemptId:     htlc.AttemptID,
×
1445
                AttemptTimeNs: MarshalTimeNano(htlc.AttemptTime),
×
1446
                Route:         route,
×
1447
        }
×
1448

×
1449
        switch {
×
1450
        case htlc.Settle != nil:
×
1451
                rpcAttempt.Status = lnrpc.HTLCAttempt_SUCCEEDED
×
1452
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
×
1453
                        htlc.Settle.SettleTime,
×
1454
                )
×
1455
                rpcAttempt.Preimage = htlc.Settle.Preimage[:]
×
1456

1457
        case htlc.Failure != nil:
×
1458
                rpcAttempt.Status = lnrpc.HTLCAttempt_FAILED
×
1459
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
×
1460
                        htlc.Failure.FailTime,
×
1461
                )
×
1462

×
1463
                var err error
×
1464
                rpcAttempt.Failure, err = marshallHtlcFailure(htlc.Failure)
×
1465
                if err != nil {
×
1466
                        return nil, err
×
1467
                }
×
1468
        default:
×
1469
                rpcAttempt.Status = lnrpc.HTLCAttempt_IN_FLIGHT
×
1470
        }
1471

1472
        return rpcAttempt, nil
×
1473
}
1474

1475
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
1476
// representation.
1477
func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
1478
        error) {
×
1479

×
1480
        rpcFailure := &lnrpc.Failure{
×
1481
                FailureSourceIndex: failure.FailureSourceIndex,
×
1482
        }
×
1483

×
1484
        switch failure.Reason {
×
1485
        case channeldb.HTLCFailUnknown:
×
1486
                rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1487

1488
        case channeldb.HTLCFailUnreadable:
×
1489
                rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1490

1491
        case channeldb.HTLCFailInternal:
×
1492
                rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
×
1493

1494
        case channeldb.HTLCFailMessage:
×
1495
                err := marshallWireError(failure.Message, rpcFailure)
×
1496
                if err != nil {
×
1497
                        return nil, err
×
1498
                }
×
1499

1500
        default:
×
1501
                return nil, errors.New("unknown htlc failure reason")
×
1502
        }
1503

1504
        return rpcFailure, nil
×
1505
}
1506

1507
// MarshalTimeNano converts a time.Time into its nanosecond representation. If
1508
// the time is zero, this method simply returns 0, since calling UnixNano() on a
1509
// zero-valued time is undefined.
1510
func MarshalTimeNano(t time.Time) int64 {
3✔
1511
        if t.IsZero() {
6✔
1512
                return 0
3✔
1513
        }
3✔
1514
        return t.UnixNano()
×
1515
}
1516

1517
// marshallError marshall an error as received from the switch to rpc structs
1518
// suitable for returning to the caller of an rpc method.
1519
//
1520
// Because of difficulties with using protobuf oneof constructs in some
1521
// languages, the decision was made here to use a single message format for all
1522
// failure messages with some fields left empty depending on the failure type.
1523
func marshallError(sendError error) (*lnrpc.Failure, error) {
×
1524
        response := &lnrpc.Failure{}
×
1525

×
1526
        if sendError == htlcswitch.ErrUnreadableFailureMessage {
×
1527
                response.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1528
                return response, nil
×
1529
        }
×
1530

1531
        rtErr, ok := sendError.(htlcswitch.ClearTextError)
×
1532
        if !ok {
×
1533
                return nil, sendError
×
1534
        }
×
1535

1536
        err := marshallWireError(rtErr.WireMessage(), response)
×
1537
        if err != nil {
×
1538
                return nil, err
×
1539
        }
×
1540

1541
        // If the ClearTextError received is a ForwardingError, the error
1542
        // originated from a node along the route, not locally on our outgoing
1543
        // link. We set failureSourceIdx to the index of the node where the
1544
        // failure occurred. If the error is not a ForwardingError, the failure
1545
        // occurred at our node, so we leave the index as 0 to indicate that
1546
        // we failed locally.
1547
        fErr, ok := rtErr.(*htlcswitch.ForwardingError)
×
1548
        if ok {
×
1549
                response.FailureSourceIndex = uint32(fErr.FailureSourceIdx)
×
1550
        }
×
1551

1552
        return response, nil
×
1553
}
1554

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

×
1564
        switch onionErr := msg.(type) {
×
1565
        case *lnwire.FailIncorrectDetails:
×
1566
                response.Code = lnrpc.Failure_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS
×
1567
                response.Height = onionErr.Height()
×
1568

1569
        case *lnwire.FailIncorrectPaymentAmount:
×
1570
                response.Code = lnrpc.Failure_INCORRECT_PAYMENT_AMOUNT
×
1571

1572
        case *lnwire.FailFinalIncorrectCltvExpiry:
×
1573
                response.Code = lnrpc.Failure_FINAL_INCORRECT_CLTV_EXPIRY
×
1574
                response.CltvExpiry = onionErr.CltvExpiry
×
1575

1576
        case *lnwire.FailFinalIncorrectHtlcAmount:
×
1577
                response.Code = lnrpc.Failure_FINAL_INCORRECT_HTLC_AMOUNT
×
1578
                response.HtlcMsat = uint64(onionErr.IncomingHTLCAmount)
×
1579

1580
        case *lnwire.FailFinalExpiryTooSoon:
×
1581
                response.Code = lnrpc.Failure_FINAL_EXPIRY_TOO_SOON
×
1582

1583
        case *lnwire.FailInvalidRealm:
×
1584
                response.Code = lnrpc.Failure_INVALID_REALM
×
1585

1586
        case *lnwire.FailExpiryTooSoon:
×
1587
                response.Code = lnrpc.Failure_EXPIRY_TOO_SOON
×
1588
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1589

1590
        case *lnwire.FailExpiryTooFar:
×
1591
                response.Code = lnrpc.Failure_EXPIRY_TOO_FAR
×
1592

1593
        case *lnwire.FailInvalidOnionVersion:
×
1594
                response.Code = lnrpc.Failure_INVALID_ONION_VERSION
×
1595
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1596

1597
        case *lnwire.FailInvalidOnionHmac:
×
1598
                response.Code = lnrpc.Failure_INVALID_ONION_HMAC
×
1599
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1600

1601
        case *lnwire.FailInvalidOnionKey:
×
1602
                response.Code = lnrpc.Failure_INVALID_ONION_KEY
×
1603
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1604

1605
        case *lnwire.FailAmountBelowMinimum:
×
1606
                response.Code = lnrpc.Failure_AMOUNT_BELOW_MINIMUM
×
1607
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1608
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1609

1610
        case *lnwire.FailFeeInsufficient:
×
1611
                response.Code = lnrpc.Failure_FEE_INSUFFICIENT
×
1612
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1613
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1614

1615
        case *lnwire.FailIncorrectCltvExpiry:
×
1616
                response.Code = lnrpc.Failure_INCORRECT_CLTV_EXPIRY
×
1617
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1618
                response.CltvExpiry = onionErr.CltvExpiry
×
1619

1620
        case *lnwire.FailChannelDisabled:
×
1621
                response.Code = lnrpc.Failure_CHANNEL_DISABLED
×
1622
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1623
                response.Flags = uint32(onionErr.Flags)
×
1624

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

1629
        case *lnwire.FailRequiredNodeFeatureMissing:
×
1630
                response.Code = lnrpc.Failure_REQUIRED_NODE_FEATURE_MISSING
×
1631

1632
        case *lnwire.FailRequiredChannelFeatureMissing:
×
1633
                response.Code = lnrpc.Failure_REQUIRED_CHANNEL_FEATURE_MISSING
×
1634

1635
        case *lnwire.FailUnknownNextPeer:
×
1636
                response.Code = lnrpc.Failure_UNKNOWN_NEXT_PEER
×
1637

1638
        case *lnwire.FailTemporaryNodeFailure:
×
1639
                response.Code = lnrpc.Failure_TEMPORARY_NODE_FAILURE
×
1640

1641
        case *lnwire.FailPermanentNodeFailure:
×
1642
                response.Code = lnrpc.Failure_PERMANENT_NODE_FAILURE
×
1643

1644
        case *lnwire.FailPermanentChannelFailure:
×
1645
                response.Code = lnrpc.Failure_PERMANENT_CHANNEL_FAILURE
×
1646

1647
        case *lnwire.FailMPPTimeout:
×
1648
                response.Code = lnrpc.Failure_MPP_TIMEOUT
×
1649

1650
        case *lnwire.InvalidOnionPayload:
×
1651
                response.Code = lnrpc.Failure_INVALID_ONION_PAYLOAD
×
1652

1653
        case *lnwire.FailInvalidBlinding:
×
1654
                response.Code = lnrpc.Failure_INVALID_ONION_BLINDING
×
1655
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1656

1657
        case nil:
×
1658
                response.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1659

1660
        default:
×
1661
                return fmt.Errorf("cannot marshall failure %T", onionErr)
×
1662
        }
1663

1664
        return nil
×
1665
}
1666

1667
// marshallChannelUpdate marshalls a channel update as received over the wire to
1668
// the router rpc format.
1669
func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
×
1670
        if update == nil {
×
1671
                return nil
×
1672
        }
×
1673

1674
        return &lnrpc.ChannelUpdate{
×
1675
                Signature:       update.Signature.RawBytes(),
×
1676
                ChainHash:       update.ChainHash[:],
×
1677
                ChanId:          update.ShortChannelID.ToUint64(),
×
1678
                Timestamp:       update.Timestamp,
×
1679
                MessageFlags:    uint32(update.MessageFlags),
×
1680
                ChannelFlags:    uint32(update.ChannelFlags),
×
1681
                TimeLockDelta:   uint32(update.TimeLockDelta),
×
1682
                HtlcMinimumMsat: uint64(update.HtlcMinimumMsat),
×
1683
                BaseFee:         update.BaseFee,
×
1684
                FeeRate:         update.FeeRate,
×
1685
                HtlcMaximumMsat: uint64(update.HtlcMaximumMsat),
×
1686
                ExtraOpaqueData: update.ExtraOpaqueData,
×
1687
        }
×
1688
}
1689

1690
// MarshallPayment marshall a payment to its rpc representation.
1691
func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
1692
        *lnrpc.Payment, error) {
3✔
1693

3✔
1694
        // Fetch the payment's preimage and the total paid in fees.
3✔
1695
        var (
3✔
1696
                fee      lnwire.MilliSatoshi
3✔
1697
                preimage lntypes.Preimage
3✔
1698
        )
3✔
1699
        for _, htlc := range payment.HTLCs {
3✔
1700
                // If any of the htlcs have settled, extract a valid
×
1701
                // preimage.
×
1702
                if htlc.Settle != nil {
×
1703
                        preimage = htlc.Settle.Preimage
×
1704
                        fee += htlc.Route.TotalFees()
×
1705
                }
×
1706
        }
1707

1708
        msatValue := int64(payment.Info.Value)
3✔
1709
        satValue := int64(payment.Info.Value.ToSatoshis())
3✔
1710

3✔
1711
        status, err := convertPaymentStatus(
3✔
1712
                payment.Status, r.UseStatusInitiated,
3✔
1713
        )
3✔
1714
        if err != nil {
3✔
1715
                return nil, err
×
1716
        }
×
1717

1718
        htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
3✔
1719
        for _, dbHTLC := range payment.HTLCs {
3✔
1720
                htlc, err := r.MarshalHTLCAttempt(dbHTLC)
×
1721
                if err != nil {
×
1722
                        return nil, err
×
1723
                }
×
1724

1725
                htlcs = append(htlcs, htlc)
×
1726
        }
1727

1728
        paymentID := payment.Info.PaymentIdentifier
3✔
1729
        creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
3✔
1730

3✔
1731
        failureReason, err := marshallPaymentFailureReason(
3✔
1732
                payment.FailureReason,
3✔
1733
        )
3✔
1734
        if err != nil {
3✔
1735
                return nil, err
×
1736
        }
×
1737

1738
        return &lnrpc.Payment{
3✔
1739
                // TODO: set this to setID for AMP-payments?
3✔
1740
                PaymentHash:           hex.EncodeToString(paymentID[:]),
3✔
1741
                Value:                 satValue,
3✔
1742
                ValueMsat:             msatValue,
3✔
1743
                ValueSat:              satValue,
3✔
1744
                CreationDate:          payment.Info.CreationTime.Unix(),
3✔
1745
                CreationTimeNs:        creationTimeNS,
3✔
1746
                Fee:                   int64(fee.ToSatoshis()),
3✔
1747
                FeeSat:                int64(fee.ToSatoshis()),
3✔
1748
                FeeMsat:               int64(fee),
3✔
1749
                PaymentPreimage:       hex.EncodeToString(preimage[:]),
3✔
1750
                PaymentRequest:        string(payment.Info.PaymentRequest),
3✔
1751
                Status:                status,
3✔
1752
                Htlcs:                 htlcs,
3✔
1753
                PaymentIndex:          payment.SequenceNum,
3✔
1754
                FailureReason:         failureReason,
3✔
1755
                FirstHopCustomRecords: payment.Info.FirstHopCustomRecords,
3✔
1756
        }, nil
3✔
1757
}
1758

1759
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
1760
// by the RPC.
1761
func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
1762
        lnrpc.Payment_PaymentStatus, error) {
3✔
1763

3✔
1764
        switch dbStatus {
3✔
1765
        case channeldb.StatusInitiated:
×
1766
                // If the client understands the new status, return it.
×
1767
                if useInit {
×
1768
                        return lnrpc.Payment_INITIATED, nil
×
1769
                }
×
1770

1771
                // Otherwise remain the old behavior.
1772
                return lnrpc.Payment_IN_FLIGHT, nil
×
1773

1774
        case channeldb.StatusInFlight:
1✔
1775
                return lnrpc.Payment_IN_FLIGHT, nil
1✔
1776

1777
        case channeldb.StatusSucceeded:
2✔
1778
                return lnrpc.Payment_SUCCEEDED, nil
2✔
1779

1780
        case channeldb.StatusFailed:
×
1781
                return lnrpc.Payment_FAILED, nil
×
1782

1783
        default:
×
1784
                return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
×
1785
        }
1786
}
1787

1788
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
1789
// type.
1790
func marshallPaymentFailureReason(reason *channeldb.FailureReason) (
1791
        lnrpc.PaymentFailureReason, error) {
3✔
1792

3✔
1793
        if reason == nil {
6✔
1794
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, nil
3✔
1795
        }
3✔
1796

1797
        switch *reason {
×
1798
        case channeldb.FailureReasonTimeout:
×
1799
                return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
×
1800

1801
        case channeldb.FailureReasonNoRoute:
×
1802
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
×
1803

1804
        case channeldb.FailureReasonError:
×
1805
                return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
×
1806

1807
        case channeldb.FailureReasonPaymentDetails:
×
1808
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
×
1809

1810
        case channeldb.FailureReasonInsufficientBalance:
×
1811
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
×
1812

1813
        case channeldb.FailureReasonCanceled:
×
1814
                return lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, nil
×
1815
        }
1816

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