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

lightningnetwork / lnd / 19924300449

04 Dec 2025 09:35AM UTC coverage: 53.479% (-1.9%) from 55.404%
19924300449

Pull #10419

github

web-flow
Merge f811805c6 into 20473482d
Pull Request #10419: [docs] Document use-native-sql=true for SQL migration step 2

110496 of 206616 relevant lines covered (53.48%)

21221.61 hits per line

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

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

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

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

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

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

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

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

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

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

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

71
        MissionControl MissionControl
72

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

6✔
174
        routeReq, err := r.parseQueryRoutesRequest(in)
6✔
175
        if err != nil {
8✔
176
                return nil, err
2✔
177
        }
2✔
178

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

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

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

4✔
199
        return routeResp, nil
4✔
200
}
201

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

208
        return route.NewVertexFromBytes(pubKeyBytes)
6✔
209
}
210

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

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

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

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

×
233
                        continue
×
234
                }
235
                ignoredPairs[pair] = struct{}{}
5✔
236
        }
237

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

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

250
                pair := routing.NewDirectedNodePair(from, to)
5✔
251
                ignoredPairs[pair] = struct{}{}
5✔
252
        }
253

254
        return ignoredNodes, ignoredPairs, nil
5✔
255
}
256

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

16✔
388
                        if _, ok := ignoredNodes[fromNode]; ok {
20✔
389
                                return 0
4✔
390
                        }
4✔
391

392
                        pair := routing.DirectedNodePair{
12✔
393
                                From: fromNode,
12✔
394
                                To:   toNode,
12✔
395
                        }
12✔
396
                        if _, ok := ignoredPairs[pair]; ok {
20✔
397
                                return 0
8✔
398
                        }
8✔
399

400
                        if !in.UseMissionControl {
7✔
401
                                return 1
3✔
402
                        }
3✔
403

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

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

422
        case len(in.OutgoingChanIds) > 0:
1✔
423
                restrictions.OutgoingChannelIDs = in.OutgoingChanIds
1✔
424

425
        case in.OutgoingChanId != 0:
3✔
426
                restrictions.OutgoingChannelIDs = []uint64{in.OutgoingChanId}
3✔
427
        }
428

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

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

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

455
func parseBlindedPaymentPaths(in *lnrpc.QueryRoutesRequest) (
456
        *routing.BlindedPaymentPathSet, error) {
×
457

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

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

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

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

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

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

493
                paths[i] = blindedPmt
×
494
        }
495

496
        return routing.NewBlindedPaymentPathSet(paths)
×
497
}
498

499
func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
500
        *routing.BlindedPayment, error) {
×
501

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

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

511
        features := UnmarshalFeatures(rpcPayment.Features)
×
512

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

524
func unmarshalBlindedPaymentPaths(rpcPath *lnrpc.BlindedPath) (
525
        *sphinx.BlindedPath, error) {
×
526

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

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

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

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

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

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

561
        return path, nil
×
562
}
563

564
func unmarshalBlindedHop(rpcHop *lnrpc.BlindedHop) (*sphinx.BlindedHopInfo,
565
        error) {
×
566

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

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

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

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

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

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

599
        return pair, nil
5✔
600
}
601

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

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

621
                resp.CustomChannelData = customData
×
622

×
623
                // Allow the aux data parser to parse the custom records into
×
624
                // a human-readable JSON (if available).
×
625
                if r.ParseCustomChannelData != nil {
×
626
                        // Store the original custom data to check if parsing
×
627
                        // changed it.
×
628
                        originalCustomData := make([]byte, len(customData))
×
629
                        copy(originalCustomData, customData)
×
630

×
631
                        err := r.ParseCustomChannelData(resp)
×
632
                        if err != nil {
×
633
                                return nil, err
×
634
                        }
×
635

636
                        // We make sure we only set this field if the parser
637
                        // changed the data otherwise we might mistakenly
638
                        // show other tlv custom wire data as custom channel
639
                        // data.
640
                        if bytes.Equal(
×
641
                                originalCustomData, resp.CustomChannelData,
×
642
                        ) {
×
643

×
644
                                resp.CustomChannelData = nil
×
645
                        }
×
646
                }
647
        }
648

649
        incomingAmt := route.TotalAmount
4✔
650
        for i, hop := range route.Hops {
8✔
651
                fee := route.HopFee(i)
4✔
652

4✔
653
                // Channel capacity is not a defining property of a route. For
4✔
654
                // backwards RPC compatibility, we retrieve it here from the
4✔
655
                // graph.
4✔
656
                chanCapacity, err := r.FetchChannelCapacity(hop.ChannelID)
4✔
657
                if err != nil {
4✔
658
                        // If capacity cannot be retrieved, this may be a
×
659
                        // not-yet-received or private channel. Then report
×
660
                        // amount that is sent through the channel as capacity.
×
661
                        chanCapacity = incomingAmt.ToSatoshis()
×
662
                }
×
663

664
                // Extract the MPP fields if present on this hop.
665
                var mpp *lnrpc.MPPRecord
4✔
666
                if hop.MPP != nil {
4✔
667
                        addr := hop.MPP.PaymentAddr()
×
668

×
669
                        mpp = &lnrpc.MPPRecord{
×
670
                                PaymentAddr:  addr[:],
×
671
                                TotalAmtMsat: int64(hop.MPP.TotalMsat()),
×
672
                        }
×
673
                }
×
674

675
                var amp *lnrpc.AMPRecord
4✔
676
                if hop.AMP != nil {
4✔
677
                        rootShare := hop.AMP.RootShare()
×
678
                        setID := hop.AMP.SetID()
×
679

×
680
                        amp = &lnrpc.AMPRecord{
×
681
                                RootShare:  rootShare[:],
×
682
                                SetId:      setID[:],
×
683
                                ChildIndex: hop.AMP.ChildIndex(),
×
684
                        }
×
685
                }
×
686

687
                resp.Hops[i] = &lnrpc.Hop{
4✔
688
                        ChanId:           hop.ChannelID,
4✔
689
                        ChanCapacity:     int64(chanCapacity),
4✔
690
                        AmtToForward:     int64(hop.AmtToForward.ToSatoshis()),
4✔
691
                        AmtToForwardMsat: int64(hop.AmtToForward),
4✔
692
                        Fee:              int64(fee.ToSatoshis()),
4✔
693
                        FeeMsat:          int64(fee),
4✔
694
                        Expiry:           uint32(hop.OutgoingTimeLock),
4✔
695
                        PubKey: hex.EncodeToString(
4✔
696
                                hop.PubKeyBytes[:],
4✔
697
                        ),
4✔
698
                        CustomRecords: hop.CustomRecords,
4✔
699
                        TlvPayload:    !hop.LegacyPayload,
4✔
700
                        MppRecord:     mpp,
4✔
701
                        AmpRecord:     amp,
4✔
702
                        Metadata:      hop.Metadata,
4✔
703
                        EncryptedData: hop.EncryptedData,
4✔
704
                        TotalAmtMsat:  uint64(hop.TotalAmtMsat),
4✔
705
                }
4✔
706

4✔
707
                if hop.BlindingPoint != nil {
4✔
708
                        blinding := hop.BlindingPoint.SerializeCompressed()
×
709
                        resp.Hops[i].BlindingPoint = blinding
×
710
                }
×
711
                incomingAmt = hop.AmtToForward
4✔
712
        }
713

714
        return resp, nil
4✔
715
}
716

717
// UnmarshallHopWithPubkey unmarshalls an rpc hop for which the pubkey has
718
// already been extracted.
719
func UnmarshallHopWithPubkey(rpcHop *lnrpc.Hop, pubkey route.Vertex) (*route.Hop,
720
        error) {
×
721

×
722
        customRecords := record.CustomSet(rpcHop.CustomRecords)
×
723
        if err := customRecords.Validate(); err != nil {
×
724
                return nil, err
×
725
        }
×
726

727
        mpp, err := UnmarshalMPP(rpcHop.MppRecord)
×
728
        if err != nil {
×
729
                return nil, err
×
730
        }
×
731

732
        amp, err := UnmarshalAMP(rpcHop.AmpRecord)
×
733
        if err != nil {
×
734
                return nil, err
×
735
        }
×
736

737
        hop := &route.Hop{
×
738
                OutgoingTimeLock: rpcHop.Expiry,
×
739
                AmtToForward:     lnwire.MilliSatoshi(rpcHop.AmtToForwardMsat),
×
740
                PubKeyBytes:      pubkey,
×
741
                ChannelID:        rpcHop.ChanId,
×
742
                CustomRecords:    customRecords,
×
743
                LegacyPayload:    false,
×
744
                MPP:              mpp,
×
745
                AMP:              amp,
×
746
                EncryptedData:    rpcHop.EncryptedData,
×
747
                TotalAmtMsat:     lnwire.MilliSatoshi(rpcHop.TotalAmtMsat),
×
748
        }
×
749

×
750
        haveBlindingPoint := len(rpcHop.BlindingPoint) != 0
×
751
        if haveBlindingPoint {
×
752
                hop.BlindingPoint, err = btcec.ParsePubKey(
×
753
                        rpcHop.BlindingPoint,
×
754
                )
×
755
                if err != nil {
×
756
                        return nil, fmt.Errorf("blinding point: %w", err)
×
757
                }
×
758
        }
759

760
        if haveBlindingPoint && len(rpcHop.EncryptedData) == 0 {
×
761
                return nil, errors.New("encrypted data should be present if " +
×
762
                        "blinding point is provided")
×
763
        }
×
764

765
        return hop, nil
×
766
}
767

768
// UnmarshallHop unmarshalls an rpc hop that may or may not contain a node
769
// pubkey.
770
func (r *RouterBackend) UnmarshallHop(rpcHop *lnrpc.Hop,
771
        prevNodePubKey [33]byte) (*route.Hop, error) {
×
772

×
773
        var pubKeyBytes [33]byte
×
774
        if rpcHop.PubKey != "" {
×
775
                // Unmarshall the provided hop pubkey.
×
776
                pubKey, err := hex.DecodeString(rpcHop.PubKey)
×
777
                if err != nil {
×
778
                        return nil, fmt.Errorf("cannot decode pubkey %s",
×
779
                                rpcHop.PubKey)
×
780
                }
×
781
                copy(pubKeyBytes[:], pubKey)
×
782
        } else {
×
783
                // If no pub key is given of the hop, the local channel graph
×
784
                // needs to be queried to complete the information necessary for
×
785
                // routing. Discard edge policies, because they may be nil.
×
786
                node1, node2, err := r.FetchChannelEndpoints(rpcHop.ChanId)
×
787
                if err != nil {
×
788
                        return nil, err
×
789
                }
×
790

791
                switch {
×
792
                case prevNodePubKey == node1:
×
793
                        pubKeyBytes = node2
×
794
                case prevNodePubKey == node2:
×
795
                        pubKeyBytes = node1
×
796
                default:
×
797
                        return nil, fmt.Errorf("channel edge does not match " +
×
798
                                "expected node")
×
799
                }
800
        }
801

802
        return UnmarshallHopWithPubkey(rpcHop, pubKeyBytes)
×
803
}
804

805
// UnmarshallRoute unmarshalls an rpc route. For hops that don't specify a
806
// pubkey, the channel graph is queried.
807
func (r *RouterBackend) UnmarshallRoute(rpcroute *lnrpc.Route) (
808
        *route.Route, error) {
×
809

×
810
        prevNodePubKey := r.SelfNode
×
811

×
812
        hops := make([]*route.Hop, len(rpcroute.Hops))
×
813
        for i, hop := range rpcroute.Hops {
×
814
                routeHop, err := r.UnmarshallHop(hop, prevNodePubKey)
×
815
                if err != nil {
×
816
                        return nil, err
×
817
                }
×
818

819
                hops[i] = routeHop
×
820

×
821
                prevNodePubKey = routeHop.PubKeyBytes
×
822
        }
823

824
        route, err := route.NewRouteFromHops(
×
825
                lnwire.MilliSatoshi(rpcroute.TotalAmtMsat),
×
826
                rpcroute.TotalTimeLock,
×
827
                r.SelfNode,
×
828
                hops,
×
829
        )
×
830
        if err != nil {
×
831
                return nil, err
×
832
        }
×
833

834
        return route, nil
×
835
}
836

837
// extractIntentFromSendRequest attempts to parse the SendRequest details
838
// required to dispatch a client from the information presented by an RPC
839
// client.
840
func (r *RouterBackend) extractIntentFromSendRequest(
841
        rpcPayReq *SendPaymentRequest) (*routing.LightningPayment, error) {
25✔
842

25✔
843
        payIntent := &routing.LightningPayment{}
25✔
844

25✔
845
        // Pass along time preference.
25✔
846
        if rpcPayReq.TimePref < -1 || rpcPayReq.TimePref > 1 {
26✔
847
                return nil, errors.New("time preference out of range")
1✔
848
        }
1✔
849
        payIntent.TimePref = rpcPayReq.TimePref
24✔
850

24✔
851
        // Pass along restrictions on the outgoing channels that may be used.
24✔
852
        payIntent.OutgoingChannelIDs = rpcPayReq.OutgoingChanIds
24✔
853

24✔
854
        // Add the deprecated single outgoing channel restriction if present.
24✔
855
        if rpcPayReq.OutgoingChanId != 0 {
25✔
856
                if payIntent.OutgoingChannelIDs != nil {
2✔
857
                        return nil, errors.New("outgoing_chan_id and " +
1✔
858
                                "outgoing_chan_ids are mutually exclusive")
1✔
859
                }
1✔
860

861
                payIntent.OutgoingChannelIDs = append(
×
862
                        payIntent.OutgoingChannelIDs, rpcPayReq.OutgoingChanId,
×
863
                )
×
864
        }
865

866
        // Pass along a last hop restriction if specified.
867
        if len(rpcPayReq.LastHopPubkey) > 0 {
24✔
868
                lastHop, err := route.NewVertexFromBytes(
1✔
869
                        rpcPayReq.LastHopPubkey,
1✔
870
                )
1✔
871
                if err != nil {
2✔
872
                        return nil, err
1✔
873
                }
1✔
874
                payIntent.LastHop = &lastHop
×
875
        }
876

877
        // Take the CLTV limit from the request if set, otherwise use the max.
878
        cltvLimit, err := ValidateCLTVLimit(
22✔
879
                uint32(rpcPayReq.CltvLimit), r.MaxTotalTimelock,
22✔
880
        )
22✔
881
        if err != nil {
23✔
882
                return nil, err
1✔
883
        }
1✔
884
        payIntent.CltvLimit = cltvLimit
21✔
885

21✔
886
        // Attempt to parse the max parts value set by the user, if this value
21✔
887
        // isn't set, then we'll use the current default value for this
21✔
888
        // setting.
21✔
889
        maxParts := rpcPayReq.MaxParts
21✔
890
        if maxParts == 0 {
38✔
891
                maxParts = DefaultMaxParts
17✔
892
        }
17✔
893
        payIntent.MaxParts = maxParts
21✔
894

21✔
895
        // If this payment had a max shard amount specified, then we'll apply
21✔
896
        // that now, which'll force us to always make payment splits smaller
21✔
897
        // than this.
21✔
898
        if rpcPayReq.MaxShardSizeMsat > 0 {
26✔
899
                shardAmtMsat := lnwire.MilliSatoshi(rpcPayReq.MaxShardSizeMsat)
5✔
900
                payIntent.MaxShardAmt = &shardAmtMsat
5✔
901

5✔
902
                // If the requested max_parts exceeds the allowed limit, then we
5✔
903
                // cannot send the payment amount.
5✔
904
                if payIntent.MaxParts > MaxPartsUpperLimit {
6✔
905
                        return nil, fmt.Errorf("requested max_parts (%v) "+
1✔
906
                                "exceeds the allowed upper limit of %v; cannot"+
1✔
907
                                " send payment amount with max_shard_size_msat"+
1✔
908
                                "=%v", payIntent.MaxParts, MaxPartsUpperLimit,
1✔
909
                                *payIntent.MaxShardAmt)
1✔
910
                }
1✔
911
        }
912

913
        // Take fee limit from request.
914
        payIntent.FeeLimit, err = lnrpc.UnmarshallAmt(
20✔
915
                rpcPayReq.FeeLimitSat, rpcPayReq.FeeLimitMsat,
20✔
916
        )
20✔
917
        if err != nil {
22✔
918
                return nil, err
2✔
919
        }
2✔
920

921
        customRecords := record.CustomSet(rpcPayReq.DestCustomRecords)
18✔
922
        if err := customRecords.Validate(); err != nil {
19✔
923
                return nil, err
1✔
924
        }
1✔
925
        payIntent.DestCustomRecords = customRecords
17✔
926

17✔
927
        // Keysend payments do not support MPP payments.
17✔
928
        //
17✔
929
        // NOTE: There is no need to validate the `MaxParts` value here because
17✔
930
        // it is set to 1 somewhere else in case it's a keysend payment.
17✔
931
        if customRecords.IsKeysend() {
18✔
932
                if payIntent.MaxShardAmt != nil {
2✔
933
                        return nil, errors.New("keysend payments cannot " +
1✔
934
                                "specify a max shard amount - MPP not " +
1✔
935
                                "supported with keysend payments")
1✔
936
                }
1✔
937
        }
938

939
        firstHopRecords := lnwire.CustomRecords(rpcPayReq.FirstHopCustomRecords)
16✔
940
        if err := firstHopRecords.Validate(); err != nil {
17✔
941
                return nil, err
1✔
942
        }
1✔
943
        payIntent.FirstHopCustomRecords = firstHopRecords
15✔
944

15✔
945
        // If the experimental endorsement signal is not already set, propagate
15✔
946
        // a zero value field if configured to set this signal.
15✔
947
        if r.ShouldSetExpEndorsement() {
16✔
948
                if payIntent.FirstHopCustomRecords == nil {
2✔
949
                        payIntent.FirstHopCustomRecords = make(
1✔
950
                                map[uint64][]byte,
1✔
951
                        )
1✔
952
                }
1✔
953

954
                t := uint64(lnwire.ExperimentalEndorsementType)
1✔
955
                if _, set := payIntent.FirstHopCustomRecords[t]; !set {
2✔
956
                        payIntent.FirstHopCustomRecords[t] = []byte{
1✔
957
                                lnwire.ExperimentalUnendorsed,
1✔
958
                        }
1✔
959
                }
1✔
960
        }
961

962
        payIntent.PayAttemptTimeout = time.Second *
15✔
963
                time.Duration(rpcPayReq.TimeoutSeconds)
15✔
964

15✔
965
        // Route hints.
15✔
966
        routeHints, err := unmarshallRouteHints(
15✔
967
                rpcPayReq.RouteHints,
15✔
968
        )
15✔
969
        if err != nil {
15✔
970
                return nil, err
×
971
        }
×
972
        payIntent.RouteHints = routeHints
15✔
973

15✔
974
        // Unmarshall either sat or msat amount from request.
15✔
975
        reqAmt, err := lnrpc.UnmarshallAmt(
15✔
976
                rpcPayReq.Amt, rpcPayReq.AmtMsat,
15✔
977
        )
15✔
978
        if err != nil {
16✔
979
                return nil, err
1✔
980
        }
1✔
981

982
        // If the payment request field isn't blank, then the details of the
983
        // invoice are encoded entirely within the encoded payReq.  So we'll
984
        // attempt to decode it, populating the payment accordingly.
985
        if rpcPayReq.PaymentRequest != "" {
20✔
986
                switch {
6✔
987

988
                case len(rpcPayReq.Dest) > 0:
1✔
989
                        return nil, errors.New("dest and payment_request " +
1✔
990
                                "cannot appear together")
1✔
991

992
                case len(rpcPayReq.PaymentHash) > 0:
1✔
993
                        return nil, errors.New("payment_hash and payment_request " +
1✔
994
                                "cannot appear together")
1✔
995

996
                case rpcPayReq.FinalCltvDelta != 0:
1✔
997
                        return nil, errors.New("final_cltv_delta and payment_request " +
1✔
998
                                "cannot appear together")
1✔
999
                }
1000

1001
                payReq, err := zpay32.Decode(
3✔
1002
                        rpcPayReq.PaymentRequest, r.ActiveNetParams,
3✔
1003
                )
3✔
1004
                if err != nil {
4✔
1005
                        return nil, err
1✔
1006
                }
1✔
1007

1008
                // Next, we'll ensure that this payreq hasn't already expired.
1009
                err = ValidatePayReqExpiry(r.Clock, payReq)
2✔
1010
                if err != nil {
3✔
1011
                        return nil, err
1✔
1012
                }
1✔
1013

1014
                // An invoice must include either a payment address or
1015
                // blinded paths.
1016
                if payReq.PaymentAddr.IsNone() &&
1✔
1017
                        len(payReq.BlindedPaymentPaths) == 0 {
2✔
1018

1✔
1019
                        return nil, errors.New("payment request must contain " +
1✔
1020
                                "either a payment address or blinded paths")
1✔
1021
                }
1✔
1022

1023
                // If the amount was not included in the invoice, then we let
1024
                // the payer specify the amount of satoshis they wish to send.
1025
                // We override the amount to pay with the amount provided from
1026
                // the payment request.
1027
                if payReq.MilliSat == nil {
×
1028
                        if reqAmt == 0 {
×
1029
                                return nil, errors.New("amount must be " +
×
1030
                                        "specified when paying a zero amount " +
×
1031
                                        "invoice")
×
1032
                        }
×
1033

1034
                        payIntent.Amount = reqAmt
×
1035
                } else {
×
1036
                        if reqAmt != 0 {
×
1037
                                return nil, errors.New("amount must not be " +
×
1038
                                        "specified when paying a non-zero " +
×
1039
                                        "amount invoice")
×
1040
                        }
×
1041

1042
                        payIntent.Amount = *payReq.MilliSat
×
1043
                }
1044

1045
                if !payReq.Features.HasFeature(lnwire.MPPOptional) &&
×
1046
                        !payReq.Features.HasFeature(lnwire.AMPOptional) {
×
1047

×
1048
                        payIntent.MaxParts = 1
×
1049
                }
×
1050

1051
                payAddr := payReq.PaymentAddr
×
1052
                if payReq.Features.HasFeature(lnwire.AMPOptional) {
×
1053
                        // The opt-in AMP flag is required to pay an AMP
×
1054
                        // invoice.
×
1055
                        if !rpcPayReq.Amp {
×
1056
                                return nil, fmt.Errorf("the AMP flag (--amp " +
×
1057
                                        "or SendPaymentRequest.Amp) must be " +
×
1058
                                        "set to pay an AMP invoice")
×
1059
                        }
×
1060

1061
                        // Generate random SetID and root share.
1062
                        var setID [32]byte
×
1063
                        _, err = rand.Read(setID[:])
×
1064
                        if err != nil {
×
1065
                                return nil, err
×
1066
                        }
×
1067

1068
                        var rootShare [32]byte
×
1069
                        _, err = rand.Read(rootShare[:])
×
1070
                        if err != nil {
×
1071
                                return nil, err
×
1072
                        }
×
1073
                        err := payIntent.SetAMP(&routing.AMPOptions{
×
1074
                                SetID:     setID,
×
1075
                                RootShare: rootShare,
×
1076
                        })
×
1077
                        if err != nil {
×
1078
                                return nil, err
×
1079
                        }
×
1080

1081
                        // For AMP invoices, we'll allow users to override the
1082
                        // included payment addr to allow the invoice to be
1083
                        // pseudo-reusable, e.g. the invoice parameters are
1084
                        // reused (amt, cltv, hop hints, etc) even though the
1085
                        // payments will share different payment hashes.
1086
                        //
1087
                        // NOTE: This will only work when the peer has
1088
                        // spontaneous AMP payments enabled.
1089
                        if len(rpcPayReq.PaymentAddr) > 0 {
×
1090
                                var addr [32]byte
×
1091
                                copy(addr[:], rpcPayReq.PaymentAddr)
×
1092
                                payAddr = fn.Some(addr)
×
1093
                        }
×
1094
                } else {
×
1095
                        err = payIntent.SetPaymentHash(*payReq.PaymentHash)
×
1096
                        if err != nil {
×
1097
                                return nil, err
×
1098
                        }
×
1099
                }
1100

1101
                destKey := payReq.Destination.SerializeCompressed()
×
1102
                copy(payIntent.Target[:], destKey)
×
1103

×
1104
                payIntent.FinalCLTVDelta = uint16(payReq.MinFinalCLTVExpiry())
×
1105
                payIntent.RouteHints = append(
×
1106
                        payIntent.RouteHints, payReq.RouteHints...,
×
1107
                )
×
1108
                payIntent.DestFeatures = payReq.Features
×
1109
                payIntent.PaymentAddr = payAddr
×
1110
                payIntent.PaymentRequest = []byte(rpcPayReq.PaymentRequest)
×
1111
                payIntent.Metadata = payReq.Metadata
×
1112

×
1113
                if len(payReq.BlindedPaymentPaths) > 0 {
×
1114
                        pathSet, err := BuildBlindedPathSet(
×
1115
                                payReq.BlindedPaymentPaths,
×
1116
                        )
×
1117
                        if err != nil {
×
1118
                                return nil, err
×
1119
                        }
×
1120
                        payIntent.BlindedPathSet = pathSet
×
1121

×
1122
                        // Replace the target node with the target public key
×
1123
                        // of the blinded path set.
×
1124
                        copy(
×
1125
                                payIntent.Target[:],
×
1126
                                pathSet.TargetPubKey().SerializeCompressed(),
×
1127
                        )
×
1128

×
1129
                        pathFeatures := pathSet.Features()
×
1130
                        if !pathFeatures.IsEmpty() {
×
1131
                                payIntent.DestFeatures = pathFeatures.Clone()
×
1132
                        }
×
1133
                }
1134
        } else {
8✔
1135
                // Otherwise, If the payment request field was not specified
8✔
1136
                // (and a custom route wasn't specified), construct the payment
8✔
1137
                // from the other fields.
8✔
1138

8✔
1139
                // Payment destination.
8✔
1140
                target, err := route.NewVertexFromBytes(rpcPayReq.Dest)
8✔
1141
                if err != nil {
9✔
1142
                        return nil, err
1✔
1143
                }
1✔
1144
                payIntent.Target = target
7✔
1145

7✔
1146
                // Final payment CLTV delta.
7✔
1147
                if rpcPayReq.FinalCltvDelta != 0 {
8✔
1148
                        payIntent.FinalCLTVDelta =
1✔
1149
                                uint16(rpcPayReq.FinalCltvDelta)
1✔
1150
                } else {
7✔
1151
                        payIntent.FinalCLTVDelta = r.DefaultFinalCltvDelta
6✔
1152
                }
6✔
1153

1154
                // Amount.
1155
                if reqAmt == 0 {
8✔
1156
                        return nil, errors.New("amount must be specified")
1✔
1157
                }
1✔
1158

1159
                payIntent.Amount = reqAmt
6✔
1160

6✔
1161
                // Parse destination feature bits.
6✔
1162
                features := UnmarshalFeatures(rpcPayReq.DestFeatures)
6✔
1163

6✔
1164
                // Validate the features if any was specified.
6✔
1165
                if features != nil {
8✔
1166
                        err = feature.ValidateDeps(features)
2✔
1167
                        if err != nil {
2✔
1168
                                return nil, err
×
1169
                        }
×
1170
                }
1171

1172
                // If this is an AMP payment, we must generate the initial
1173
                // randomness.
1174
                if rpcPayReq.Amp {
7✔
1175
                        // If no destination features were specified, we set
1✔
1176
                        // those necessary for AMP payments.
1✔
1177
                        if features == nil {
1✔
1178
                                ampFeatures := []lnrpc.FeatureBit{
×
1179
                                        lnrpc.FeatureBit_TLV_ONION_OPT,
×
1180
                                        lnrpc.FeatureBit_PAYMENT_ADDR_OPT,
×
1181
                                        lnrpc.FeatureBit_AMP_OPT,
×
1182
                                }
×
1183

×
1184
                                features = UnmarshalFeatures(ampFeatures)
×
1185
                        }
×
1186

1187
                        // First make sure the destination supports AMP.
1188
                        if !features.HasFeature(lnwire.AMPOptional) {
2✔
1189
                                return nil, fmt.Errorf("destination doesn't " +
1✔
1190
                                        "support AMP payments")
1✔
1191
                        }
1✔
1192

1193
                        // If no payment address is set, generate a random one.
1194
                        var payAddr [32]byte
×
1195
                        if len(rpcPayReq.PaymentAddr) == 0 {
×
1196
                                _, err = rand.Read(payAddr[:])
×
1197
                                if err != nil {
×
1198
                                        return nil, err
×
1199
                                }
×
1200
                        } else {
×
1201
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1202
                        }
×
1203
                        payIntent.PaymentAddr = fn.Some(payAddr)
×
1204

×
1205
                        // Generate random SetID and root share.
×
1206
                        var setID [32]byte
×
1207
                        _, err = rand.Read(setID[:])
×
1208
                        if err != nil {
×
1209
                                return nil, err
×
1210
                        }
×
1211

1212
                        var rootShare [32]byte
×
1213
                        _, err = rand.Read(rootShare[:])
×
1214
                        if err != nil {
×
1215
                                return nil, err
×
1216
                        }
×
1217
                        err := payIntent.SetAMP(&routing.AMPOptions{
×
1218
                                SetID:     setID,
×
1219
                                RootShare: rootShare,
×
1220
                        })
×
1221
                        if err != nil {
×
1222
                                return nil, err
×
1223
                        }
×
1224
                } else {
5✔
1225
                        // Payment hash.
5✔
1226
                        paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
5✔
1227
                        if err != nil {
6✔
1228
                                return nil, err
1✔
1229
                        }
1✔
1230

1231
                        err = payIntent.SetPaymentHash(paymentHash)
4✔
1232
                        if err != nil {
4✔
1233
                                return nil, err
×
1234
                        }
×
1235

1236
                        // If the payment addresses is specified, then we'll
1237
                        // also populate that now as well.
1238
                        if len(rpcPayReq.PaymentAddr) != 0 {
4✔
1239
                                var payAddr [32]byte
×
1240
                                copy(payAddr[:], rpcPayReq.PaymentAddr)
×
1241

×
1242
                                payIntent.PaymentAddr = fn.Some(payAddr)
×
1243
                        }
×
1244
                }
1245

1246
                payIntent.DestFeatures = features
4✔
1247
        }
1248

1249
        // Validate that the MPP parameters are compatible with the
1250
        // payment amount. In other words, the parameters are invalid if
1251
        // they do not permit sending the full payment amount.
1252
        if payIntent.MaxShardAmt != nil {
7✔
1253
                maxPossibleAmount := (*payIntent.MaxShardAmt) *
3✔
1254
                        lnwire.MilliSatoshi(payIntent.MaxParts)
3✔
1255

3✔
1256
                if payIntent.Amount > maxPossibleAmount {
4✔
1257
                        return nil, fmt.Errorf("payment amount %v exceeds "+
1✔
1258
                                "maximum possible amount %v with max_parts=%v "+
1✔
1259
                                "and max_shard_size_msat=%v", payIntent.Amount,
1✔
1260
                                maxPossibleAmount, payIntent.MaxParts,
1✔
1261
                                *payIntent.MaxShardAmt,
1✔
1262
                        )
1✔
1263
                }
1✔
1264
        }
1265

1266
        // Do bounds checking with the block padding so the router isn't
1267
        // left with a zombie payment in case the user messes up.
1268
        err = routing.ValidateCLTVLimit(
3✔
1269
                payIntent.CltvLimit, payIntent.FinalCLTVDelta, true,
3✔
1270
        )
3✔
1271
        if err != nil {
3✔
1272
                return nil, err
×
1273
        }
×
1274

1275
        // Check for disallowed payments to self.
1276
        if !rpcPayReq.AllowSelfPayment && payIntent.Target == r.SelfNode {
4✔
1277
                return nil, errors.New("self-payments not allowed")
1✔
1278
        }
1✔
1279

1280
        return payIntent, nil
2✔
1281
}
1282

1283
// BuildBlindedPathSet marshals a set of zpay32.BlindedPaymentPath and uses
1284
// the result to build a new routing.BlindedPaymentPathSet.
1285
func BuildBlindedPathSet(paths []*zpay32.BlindedPaymentPath) (
1286
        *routing.BlindedPaymentPathSet, error) {
×
1287

×
1288
        marshalledPaths := make([]*routing.BlindedPayment, len(paths))
×
1289
        for i, path := range paths {
×
1290
                paymentPath := marshalBlindedPayment(path)
×
1291

×
1292
                err := paymentPath.Validate()
×
1293
                if err != nil {
×
1294
                        return nil, err
×
1295
                }
×
1296

1297
                marshalledPaths[i] = paymentPath
×
1298
        }
1299

1300
        return routing.NewBlindedPaymentPathSet(marshalledPaths)
×
1301
}
1302

1303
// marshalBlindedPayment marshals a zpay32.BLindedPaymentPath into a
1304
// routing.BlindedPayment.
1305
func marshalBlindedPayment(
1306
        path *zpay32.BlindedPaymentPath) *routing.BlindedPayment {
×
1307

×
1308
        return &routing.BlindedPayment{
×
1309
                BlindedPath: &sphinx.BlindedPath{
×
1310
                        IntroductionPoint: path.Hops[0].BlindedNodePub,
×
1311
                        BlindingPoint:     path.FirstEphemeralBlindingPoint,
×
1312
                        BlindedHops:       path.Hops,
×
1313
                },
×
1314
                BaseFee:             path.FeeBaseMsat,
×
1315
                ProportionalFeeRate: path.FeeRate,
×
1316
                CltvExpiryDelta:     path.CltvExpiryDelta,
×
1317
                HtlcMinimum:         path.HTLCMinMsat,
×
1318
                HtlcMaximum:         path.HTLCMaxMsat,
×
1319
                Features:            path.Features,
×
1320
        }
×
1321
}
×
1322

1323
// unmarshallRouteHints unmarshalls a list of route hints.
1324
func unmarshallRouteHints(rpcRouteHints []*lnrpc.RouteHint) (
1325
        [][]zpay32.HopHint, error) {
21✔
1326

21✔
1327
        routeHints := make([][]zpay32.HopHint, 0, len(rpcRouteHints))
21✔
1328
        for _, rpcRouteHint := range rpcRouteHints {
27✔
1329
                routeHint := make(
6✔
1330
                        []zpay32.HopHint, 0, len(rpcRouteHint.HopHints),
6✔
1331
                )
6✔
1332
                for _, rpcHint := range rpcRouteHint.HopHints {
12✔
1333
                        hint, err := unmarshallHopHint(rpcHint)
6✔
1334
                        if err != nil {
6✔
1335
                                return nil, err
×
1336
                        }
×
1337

1338
                        routeHint = append(routeHint, hint)
6✔
1339
                }
1340
                routeHints = append(routeHints, routeHint)
6✔
1341
        }
1342

1343
        return routeHints, nil
21✔
1344
}
1345

1346
// unmarshallHopHint unmarshalls a single hop hint.
1347
func unmarshallHopHint(rpcHint *lnrpc.HopHint) (zpay32.HopHint, error) {
6✔
1348
        pubBytes, err := hex.DecodeString(rpcHint.NodeId)
6✔
1349
        if err != nil {
6✔
1350
                return zpay32.HopHint{}, err
×
1351
        }
×
1352

1353
        pubkey, err := btcec.ParsePubKey(pubBytes)
6✔
1354
        if err != nil {
6✔
1355
                return zpay32.HopHint{}, err
×
1356
        }
×
1357

1358
        return zpay32.HopHint{
6✔
1359
                NodeID:                    pubkey,
6✔
1360
                ChannelID:                 rpcHint.ChanId,
6✔
1361
                FeeBaseMSat:               rpcHint.FeeBaseMsat,
6✔
1362
                FeeProportionalMillionths: rpcHint.FeeProportionalMillionths,
6✔
1363
                CLTVExpiryDelta:           uint16(rpcHint.CltvExpiryDelta),
6✔
1364
        }, nil
6✔
1365
}
1366

1367
// MarshalFeatures converts a feature vector into a list of uint32's.
1368
func MarshalFeatures(feats *lnwire.FeatureVector) []lnrpc.FeatureBit {
×
1369
        var featureBits []lnrpc.FeatureBit
×
1370
        for feature := range feats.Features() {
×
1371
                featureBits = append(featureBits, lnrpc.FeatureBit(feature))
×
1372
        }
×
1373

1374
        return featureBits
×
1375
}
1376

1377
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
1378
// This method checks that feature bit pairs aren't assigned together, and
1379
// validates transitive dependencies.
1380
func UnmarshalFeatures(rpcFeatures []lnrpc.FeatureBit) *lnwire.FeatureVector {
11✔
1381
        // If no destination features are specified we'll return nil to signal
11✔
1382
        // that the router should try to use the graph as a fallback.
11✔
1383
        if rpcFeatures == nil {
15✔
1384
                return nil
4✔
1385
        }
4✔
1386

1387
        raw := lnwire.NewRawFeatureVector()
7✔
1388
        for _, bit := range rpcFeatures {
14✔
1389
                // Even though the spec says that the writer of a feature vector
7✔
1390
                // should never set both the required and optional bits of a
7✔
1391
                // feature, it also says that if we receive a vector with both
7✔
1392
                // bits set, then we should just treat the feature as required.
7✔
1393
                // Therefore, we don't use SafeSet here when parsing a peer's
7✔
1394
                // feature bits and just set the feature no matter what so that
7✔
1395
                // if both are set then IsRequired returns true.
7✔
1396
                raw.Set(lnwire.FeatureBit(bit))
7✔
1397
        }
7✔
1398

1399
        return lnwire.NewFeatureVector(raw, lnwire.Features)
7✔
1400
}
1401

1402
// ValidatePayReqExpiry checks if the passed payment request has expired. In
1403
// the case it has expired, an error will be returned.
1404
func ValidatePayReqExpiry(clock clock.Clock, payReq *zpay32.Invoice) error {
2✔
1405
        expiry := payReq.Expiry()
2✔
1406
        validUntil := payReq.Timestamp.Add(expiry)
2✔
1407
        if clock.Now().After(validUntil) {
3✔
1408
                return fmt.Errorf("invoice expired. Valid until %v", validUntil)
1✔
1409
        }
1✔
1410

1411
        return nil
1✔
1412
}
1413

1414
// ValidateCLTVLimit returns a valid CLTV limit given a value and a maximum. If
1415
// the value exceeds the maximum, then an error is returned. If the value is 0,
1416
// then the maximum is used.
1417
func ValidateCLTVLimit(val, max uint32) (uint32, error) {
28✔
1418
        switch {
28✔
1419
        case val == 0:
27✔
1420
                return max, nil
27✔
1421
        case val > max:
1✔
1422
                return 0, fmt.Errorf("total time lock of %v exceeds max "+
1✔
1423
                        "allowed %v", val, max)
1✔
1424
        default:
×
1425
                return val, nil
×
1426
        }
1427
}
1428

1429
// UnmarshalMPP accepts the mpp_total_amt_msat and mpp_payment_addr fields from
1430
// an RPC request and converts into an record.MPP object. An error is returned
1431
// if the payment address is not 0 or 32 bytes. If the total amount and payment
1432
// address are zero-value, the return value will be nil signaling there is no
1433
// MPP record to attach to this hop. Otherwise, a non-nil reocrd will be
1434
// contained combining the provided values.
1435
func UnmarshalMPP(reqMPP *lnrpc.MPPRecord) (*record.MPP, error) {
6✔
1436
        // If no MPP record was submitted, assume the user wants to send a
6✔
1437
        // regular payment.
6✔
1438
        if reqMPP == nil {
7✔
1439
                return nil, nil
1✔
1440
        }
1✔
1441

1442
        reqTotal := reqMPP.TotalAmtMsat
5✔
1443
        reqAddr := reqMPP.PaymentAddr
5✔
1444

5✔
1445
        switch {
5✔
1446
        // No MPP fields were provided.
1447
        case reqTotal == 0 && len(reqAddr) == 0:
1✔
1448
                return nil, fmt.Errorf("missing total_msat and payment_addr")
1✔
1449

1450
        // Total is present, but payment address is missing.
1451
        case reqTotal > 0 && len(reqAddr) == 0:
1✔
1452
                return nil, fmt.Errorf("missing payment_addr")
1✔
1453

1454
        // Payment address is present, but total is missing.
1455
        case reqTotal == 0 && len(reqAddr) > 0:
1✔
1456
                return nil, fmt.Errorf("missing total_msat")
1✔
1457
        }
1458

1459
        addr, err := lntypes.MakeHash(reqAddr)
2✔
1460
        if err != nil {
3✔
1461
                return nil, fmt.Errorf("unable to parse "+
1✔
1462
                        "payment_addr: %v", err)
1✔
1463
        }
1✔
1464

1465
        total := lnwire.MilliSatoshi(reqTotal)
1✔
1466

1✔
1467
        return record.NewMPP(total, addr), nil
1✔
1468
}
1469

1470
func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
5✔
1471
        if reqAMP == nil {
6✔
1472
                return nil, nil
1✔
1473
        }
1✔
1474

1475
        reqRootShare := reqAMP.RootShare
4✔
1476
        reqSetID := reqAMP.SetId
4✔
1477

4✔
1478
        switch {
4✔
1479
        case len(reqRootShare) != 32:
2✔
1480
                return nil, errors.New("AMP root_share must be 32 bytes")
2✔
1481

1482
        case len(reqSetID) != 32:
1✔
1483
                return nil, errors.New("AMP set_id must be 32 bytes")
1✔
1484
        }
1485

1486
        var (
1✔
1487
                rootShare [32]byte
1✔
1488
                setID     [32]byte
1✔
1489
        )
1✔
1490
        copy(rootShare[:], reqRootShare)
1✔
1491
        copy(setID[:], reqSetID)
1✔
1492

1✔
1493
        return record.NewAMP(rootShare, setID, reqAMP.ChildIndex), nil
1✔
1494
}
1495

1496
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
1497
func (r *RouterBackend) MarshalHTLCAttempt(
1498
        htlc paymentsdb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
×
1499

×
1500
        route, err := r.MarshallRoute(&htlc.Route)
×
1501
        if err != nil {
×
1502
                return nil, err
×
1503
        }
×
1504

1505
        rpcAttempt := &lnrpc.HTLCAttempt{
×
1506
                AttemptId:     htlc.AttemptID,
×
1507
                AttemptTimeNs: MarshalTimeNano(htlc.AttemptTime),
×
1508
                Route:         route,
×
1509
        }
×
1510

×
1511
        switch {
×
1512
        case htlc.Settle != nil:
×
1513
                rpcAttempt.Status = lnrpc.HTLCAttempt_SUCCEEDED
×
1514
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
×
1515
                        htlc.Settle.SettleTime,
×
1516
                )
×
1517
                rpcAttempt.Preimage = htlc.Settle.Preimage[:]
×
1518

1519
        case htlc.Failure != nil:
×
1520
                rpcAttempt.Status = lnrpc.HTLCAttempt_FAILED
×
1521
                rpcAttempt.ResolveTimeNs = MarshalTimeNano(
×
1522
                        htlc.Failure.FailTime,
×
1523
                )
×
1524

×
1525
                var err error
×
1526
                rpcAttempt.Failure, err = marshallHtlcFailure(htlc.Failure)
×
1527
                if err != nil {
×
1528
                        return nil, err
×
1529
                }
×
1530
        default:
×
1531
                rpcAttempt.Status = lnrpc.HTLCAttempt_IN_FLIGHT
×
1532
        }
1533

1534
        return rpcAttempt, nil
×
1535
}
1536

1537
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
1538
// representation.
1539
func marshallHtlcFailure(failure *paymentsdb.HTLCFailInfo) (*lnrpc.Failure,
1540
        error) {
×
1541

×
1542
        rpcFailure := &lnrpc.Failure{
×
1543
                FailureSourceIndex: failure.FailureSourceIndex,
×
1544
        }
×
1545

×
1546
        switch failure.Reason {
×
1547
        case paymentsdb.HTLCFailUnknown:
×
1548
                rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1549

1550
        case paymentsdb.HTLCFailUnreadable:
×
1551
                rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1552

1553
        case paymentsdb.HTLCFailInternal:
×
1554
                rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
×
1555

1556
        case paymentsdb.HTLCFailMessage:
×
1557
                err := marshallWireError(failure.Message, rpcFailure)
×
1558
                if err != nil {
×
1559
                        return nil, err
×
1560
                }
×
1561

1562
        default:
×
1563
                return nil, errors.New("unknown htlc failure reason")
×
1564
        }
1565

1566
        return rpcFailure, nil
×
1567
}
1568

1569
// MarshalTimeNano converts a time.Time into its nanosecond representation. If
1570
// the time is zero, this method simply returns 0, since calling UnixNano() on a
1571
// zero-valued time is undefined.
1572
func MarshalTimeNano(t time.Time) int64 {
3✔
1573
        if t.IsZero() {
6✔
1574
                return 0
3✔
1575
        }
3✔
1576
        return t.UnixNano()
×
1577
}
1578

1579
// marshallError marshall an error as received from the switch to rpc structs
1580
// suitable for returning to the caller of an rpc method.
1581
//
1582
// Because of difficulties with using protobuf oneof constructs in some
1583
// languages, the decision was made here to use a single message format for all
1584
// failure messages with some fields left empty depending on the failure type.
1585
func marshallError(sendError error) (*lnrpc.Failure, error) {
×
1586
        response := &lnrpc.Failure{}
×
1587

×
1588
        if sendError == htlcswitch.ErrUnreadableFailureMessage {
×
1589
                response.Code = lnrpc.Failure_UNREADABLE_FAILURE
×
1590
                return response, nil
×
1591
        }
×
1592

1593
        rtErr, ok := sendError.(htlcswitch.ClearTextError)
×
1594
        if !ok {
×
1595
                return nil, sendError
×
1596
        }
×
1597

1598
        err := marshallWireError(rtErr.WireMessage(), response)
×
1599
        if err != nil {
×
1600
                return nil, err
×
1601
        }
×
1602

1603
        // If the ClearTextError received is a ForwardingError, the error
1604
        // originated from a node along the route, not locally on our outgoing
1605
        // link. We set failureSourceIdx to the index of the node where the
1606
        // failure occurred. If the error is not a ForwardingError, the failure
1607
        // occurred at our node, so we leave the index as 0 to indicate that
1608
        // we failed locally.
1609
        fErr, ok := rtErr.(*htlcswitch.ForwardingError)
×
1610
        if ok {
×
1611
                response.FailureSourceIndex = uint32(fErr.FailureSourceIdx)
×
1612
        }
×
1613

1614
        return response, nil
×
1615
}
1616

1617
// marshallError marshall an error as received from the switch to rpc structs
1618
// suitable for returning to the caller of an rpc method.
1619
//
1620
// Because of difficulties with using protobuf oneof constructs in some
1621
// languages, the decision was made here to use a single message format for all
1622
// failure messages with some fields left empty depending on the failure type.
1623
func marshallWireError(msg lnwire.FailureMessage,
1624
        response *lnrpc.Failure) error {
×
1625

×
1626
        switch onionErr := msg.(type) {
×
1627
        case *lnwire.FailIncorrectDetails:
×
1628
                response.Code = lnrpc.Failure_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS
×
1629
                response.Height = onionErr.Height()
×
1630

1631
        case *lnwire.FailIncorrectPaymentAmount:
×
1632
                response.Code = lnrpc.Failure_INCORRECT_PAYMENT_AMOUNT
×
1633

1634
        case *lnwire.FailFinalIncorrectCltvExpiry:
×
1635
                response.Code = lnrpc.Failure_FINAL_INCORRECT_CLTV_EXPIRY
×
1636
                response.CltvExpiry = onionErr.CltvExpiry
×
1637

1638
        case *lnwire.FailFinalIncorrectHtlcAmount:
×
1639
                response.Code = lnrpc.Failure_FINAL_INCORRECT_HTLC_AMOUNT
×
1640
                response.HtlcMsat = uint64(onionErr.IncomingHTLCAmount)
×
1641

1642
        case *lnwire.FailFinalExpiryTooSoon:
×
1643
                response.Code = lnrpc.Failure_FINAL_EXPIRY_TOO_SOON
×
1644

1645
        case *lnwire.FailInvalidRealm:
×
1646
                response.Code = lnrpc.Failure_INVALID_REALM
×
1647

1648
        case *lnwire.FailExpiryTooSoon:
×
1649
                response.Code = lnrpc.Failure_EXPIRY_TOO_SOON
×
1650
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1651

1652
        case *lnwire.FailExpiryTooFar:
×
1653
                response.Code = lnrpc.Failure_EXPIRY_TOO_FAR
×
1654

1655
        case *lnwire.FailInvalidOnionVersion:
×
1656
                response.Code = lnrpc.Failure_INVALID_ONION_VERSION
×
1657
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1658

1659
        case *lnwire.FailInvalidOnionHmac:
×
1660
                response.Code = lnrpc.Failure_INVALID_ONION_HMAC
×
1661
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1662

1663
        case *lnwire.FailInvalidOnionKey:
×
1664
                response.Code = lnrpc.Failure_INVALID_ONION_KEY
×
1665
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1666

1667
        case *lnwire.FailAmountBelowMinimum:
×
1668
                response.Code = lnrpc.Failure_AMOUNT_BELOW_MINIMUM
×
1669
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1670
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1671

1672
        case *lnwire.FailFeeInsufficient:
×
1673
                response.Code = lnrpc.Failure_FEE_INSUFFICIENT
×
1674
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1675
                response.HtlcMsat = uint64(onionErr.HtlcMsat)
×
1676

1677
        case *lnwire.FailIncorrectCltvExpiry:
×
1678
                response.Code = lnrpc.Failure_INCORRECT_CLTV_EXPIRY
×
1679
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1680
                response.CltvExpiry = onionErr.CltvExpiry
×
1681

1682
        case *lnwire.FailChannelDisabled:
×
1683
                response.Code = lnrpc.Failure_CHANNEL_DISABLED
×
1684
                response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update)
×
1685
                response.Flags = uint32(onionErr.Flags)
×
1686

1687
        case *lnwire.FailTemporaryChannelFailure:
×
1688
                response.Code = lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE
×
1689
                response.ChannelUpdate = marshallChannelUpdate(onionErr.Update)
×
1690

1691
        case *lnwire.FailRequiredNodeFeatureMissing:
×
1692
                response.Code = lnrpc.Failure_REQUIRED_NODE_FEATURE_MISSING
×
1693

1694
        case *lnwire.FailRequiredChannelFeatureMissing:
×
1695
                response.Code = lnrpc.Failure_REQUIRED_CHANNEL_FEATURE_MISSING
×
1696

1697
        case *lnwire.FailUnknownNextPeer:
×
1698
                response.Code = lnrpc.Failure_UNKNOWN_NEXT_PEER
×
1699

1700
        case *lnwire.FailTemporaryNodeFailure:
×
1701
                response.Code = lnrpc.Failure_TEMPORARY_NODE_FAILURE
×
1702

1703
        case *lnwire.FailPermanentNodeFailure:
×
1704
                response.Code = lnrpc.Failure_PERMANENT_NODE_FAILURE
×
1705

1706
        case *lnwire.FailPermanentChannelFailure:
×
1707
                response.Code = lnrpc.Failure_PERMANENT_CHANNEL_FAILURE
×
1708

1709
        case *lnwire.FailMPPTimeout:
×
1710
                response.Code = lnrpc.Failure_MPP_TIMEOUT
×
1711

1712
        case *lnwire.InvalidOnionPayload:
×
1713
                response.Code = lnrpc.Failure_INVALID_ONION_PAYLOAD
×
1714

1715
        case *lnwire.FailInvalidBlinding:
×
1716
                response.Code = lnrpc.Failure_INVALID_ONION_BLINDING
×
1717
                response.OnionSha_256 = onionErr.OnionSHA256[:]
×
1718

1719
        case nil:
×
1720
                response.Code = lnrpc.Failure_UNKNOWN_FAILURE
×
1721

1722
        default:
×
1723
                return fmt.Errorf("cannot marshall failure %T", onionErr)
×
1724
        }
1725

1726
        return nil
×
1727
}
1728

1729
// marshallChannelUpdate marshalls a channel update as received over the wire to
1730
// the router rpc format.
1731
func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
×
1732
        if update == nil {
×
1733
                return nil
×
1734
        }
×
1735

1736
        return &lnrpc.ChannelUpdate{
×
1737
                Signature:       update.Signature.RawBytes(),
×
1738
                ChainHash:       update.ChainHash[:],
×
1739
                ChanId:          update.ShortChannelID.ToUint64(),
×
1740
                Timestamp:       update.Timestamp,
×
1741
                MessageFlags:    uint32(update.MessageFlags),
×
1742
                ChannelFlags:    uint32(update.ChannelFlags),
×
1743
                TimeLockDelta:   uint32(update.TimeLockDelta),
×
1744
                HtlcMinimumMsat: uint64(update.HtlcMinimumMsat),
×
1745
                BaseFee:         update.BaseFee,
×
1746
                FeeRate:         update.FeeRate,
×
1747
                HtlcMaximumMsat: uint64(update.HtlcMaximumMsat),
×
1748
                ExtraOpaqueData: update.ExtraOpaqueData,
×
1749
        }
×
1750
}
1751

1752
// MarshallPayment marshall a payment to its rpc representation.
1753
func (r *RouterBackend) MarshallPayment(payment *paymentsdb.MPPayment) (
1754
        *lnrpc.Payment, error) {
3✔
1755

3✔
1756
        // Fetch the payment's preimage and the total paid in fees.
3✔
1757
        var (
3✔
1758
                fee      lnwire.MilliSatoshi
3✔
1759
                preimage lntypes.Preimage
3✔
1760
        )
3✔
1761
        for _, htlc := range payment.HTLCs {
3✔
1762
                // If any of the htlcs have settled, extract a valid
×
1763
                // preimage.
×
1764
                if htlc.Settle != nil {
×
1765
                        preimage = htlc.Settle.Preimage
×
1766
                        fee += htlc.Route.TotalFees()
×
1767
                }
×
1768
        }
1769

1770
        msatValue := int64(payment.Info.Value)
3✔
1771
        satValue := int64(payment.Info.Value.ToSatoshis())
3✔
1772

3✔
1773
        status, err := convertPaymentStatus(
3✔
1774
                payment.Status, r.UseStatusInitiated,
3✔
1775
        )
3✔
1776
        if err != nil {
3✔
1777
                return nil, err
×
1778
        }
×
1779

1780
        htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
3✔
1781
        for _, dbHTLC := range payment.HTLCs {
3✔
1782
                htlc, err := r.MarshalHTLCAttempt(dbHTLC)
×
1783
                if err != nil {
×
1784
                        return nil, err
×
1785
                }
×
1786

1787
                htlcs = append(htlcs, htlc)
×
1788
        }
1789

1790
        paymentID := payment.Info.PaymentIdentifier
3✔
1791
        creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
3✔
1792

3✔
1793
        failureReason, err := marshallPaymentFailureReason(
3✔
1794
                payment.FailureReason,
3✔
1795
        )
3✔
1796
        if err != nil {
3✔
1797
                return nil, err
×
1798
        }
×
1799

1800
        return &lnrpc.Payment{
3✔
1801
                // TODO: set this to setID for AMP-payments?
3✔
1802
                PaymentHash:           hex.EncodeToString(paymentID[:]),
3✔
1803
                Value:                 satValue,
3✔
1804
                ValueMsat:             msatValue,
3✔
1805
                ValueSat:              satValue,
3✔
1806
                CreationDate:          payment.Info.CreationTime.Unix(),
3✔
1807
                CreationTimeNs:        creationTimeNS,
3✔
1808
                Fee:                   int64(fee.ToSatoshis()),
3✔
1809
                FeeSat:                int64(fee.ToSatoshis()),
3✔
1810
                FeeMsat:               int64(fee),
3✔
1811
                PaymentPreimage:       hex.EncodeToString(preimage[:]),
3✔
1812
                PaymentRequest:        string(payment.Info.PaymentRequest),
3✔
1813
                Status:                status,
3✔
1814
                Htlcs:                 htlcs,
3✔
1815
                PaymentIndex:          payment.SequenceNum,
3✔
1816
                FailureReason:         failureReason,
3✔
1817
                FirstHopCustomRecords: payment.Info.FirstHopCustomRecords,
3✔
1818
        }, nil
3✔
1819
}
1820

1821
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
1822
// by the RPC.
1823
func convertPaymentStatus(dbStatus paymentsdb.PaymentStatus, useInit bool) (
1824
        lnrpc.Payment_PaymentStatus, error) {
3✔
1825

3✔
1826
        switch dbStatus {
3✔
1827
        case paymentsdb.StatusInitiated:
×
1828
                // If the client understands the new status, return it.
×
1829
                if useInit {
×
1830
                        return lnrpc.Payment_INITIATED, nil
×
1831
                }
×
1832

1833
                // Otherwise remain the old behavior.
1834
                return lnrpc.Payment_IN_FLIGHT, nil
×
1835

1836
        case paymentsdb.StatusInFlight:
1✔
1837
                return lnrpc.Payment_IN_FLIGHT, nil
1✔
1838

1839
        case paymentsdb.StatusSucceeded:
2✔
1840
                return lnrpc.Payment_SUCCEEDED, nil
2✔
1841

1842
        case paymentsdb.StatusFailed:
×
1843
                return lnrpc.Payment_FAILED, nil
×
1844

1845
        default:
×
1846
                return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
×
1847
        }
1848
}
1849

1850
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
1851
// type.
1852
func marshallPaymentFailureReason(reason *paymentsdb.FailureReason) (
1853
        lnrpc.PaymentFailureReason, error) {
3✔
1854

3✔
1855
        if reason == nil {
6✔
1856
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, nil
3✔
1857
        }
3✔
1858

1859
        switch *reason {
×
1860
        case paymentsdb.FailureReasonTimeout:
×
1861
                return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
×
1862

1863
        case paymentsdb.FailureReasonNoRoute:
×
1864
                return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
×
1865

1866
        case paymentsdb.FailureReasonError:
×
1867
                return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
×
1868

1869
        case paymentsdb.FailureReasonPaymentDetails:
×
1870
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
×
1871

1872
        case paymentsdb.FailureReasonInsufficientBalance:
×
1873
                return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
×
1874

1875
        case paymentsdb.FailureReasonCanceled:
×
1876
                return lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, nil
×
1877
        }
1878

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