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

lightningnetwork / lnd / 10307363221

08 Aug 2024 06:17PM UTC coverage: 58.738%. Remained the same
10307363221

push

github

web-flow
Merge pull request #8994 from ellemouton/rbMicroFixes

Rb micro fixes

8 of 19 new or added lines in 6 files covered. (42.11%)

65 existing lines in 9 files now uncovered.

126050 of 214596 relevant lines covered (58.74%)

28381.57 hits per line

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

0.0
/cmd/lncli/cmd_invoice.go
1
package main
2

3
import (
4
        "encoding/hex"
5
        "fmt"
6
        "strconv"
7

8
        "github.com/lightningnetwork/lnd/lnrpc"
9
        "github.com/urfave/cli"
10
)
11

12
var addInvoiceCommand = cli.Command{
13
        Name:     "addinvoice",
14
        Category: "Invoices",
15
        Usage:    "Add a new invoice.",
16
        Description: `
17
        Add a new invoice, expressing intent for a future payment.
18

19
        Invoices without an amount can be created by not supplying any
20
        parameters or providing an amount of 0. These invoices allow the payer
21
        to specify the amount of satoshis they wish to send.`,
22
        ArgsUsage: "value preimage",
23
        Flags: []cli.Flag{
24
                cli.StringFlag{
25
                        Name: "memo",
26
                        Usage: "a description of the payment to attach along " +
27
                                "with the invoice (default=\"\")",
28
                },
29
                cli.StringFlag{
30
                        Name: "preimage",
31
                        Usage: "the hex-encoded preimage (32 byte) which will " +
32
                                "allow settling an incoming HTLC payable to this " +
33
                                "preimage. If not set, a random preimage will be " +
34
                                "created.",
35
                },
36
                cli.Int64Flag{
37
                        Name:  "amt",
38
                        Usage: "the amt of satoshis in this invoice",
39
                },
40
                cli.Int64Flag{
41
                        Name:  "amt_msat",
42
                        Usage: "the amt of millisatoshis in this invoice",
43
                },
44
                cli.StringFlag{
45
                        Name: "description_hash",
46
                        Usage: "SHA-256 hash of the description of the payment. " +
47
                                "Used if the purpose of payment cannot naturally " +
48
                                "fit within the memo. If provided this will be " +
49
                                "used instead of the description(memo) field in " +
50
                                "the encoded invoice.",
51
                },
52
                cli.StringFlag{
53
                        Name: "fallback_addr",
54
                        Usage: "fallback on-chain address that can be used in " +
55
                                "case the lightning payment fails",
56
                },
57
                cli.Int64Flag{
58
                        Name: "expiry",
59
                        Usage: "the invoice's expiry time in seconds. If not " +
60
                                "specified, an expiry of " +
61
                                "86400 seconds (24 hours) is implied.",
62
                },
63
                cli.Uint64Flag{
64
                        Name: "cltv_expiry_delta",
65
                        Usage: "The minimum CLTV delta to use for the final " +
66
                                "hop. If this is set to 0, the default value " +
67
                                "is used. The default value for " +
68
                                "cltv_expiry_delta is configured by the " +
69
                                "'bitcoin.timelockdelta' option.",
70
                },
71
                cli.BoolFlag{
72
                        Name: "private",
73
                        Usage: "encode routing hints in the invoice with " +
74
                                "private channels in order to assist the " +
75
                                "payer in reaching you. If amt and amt_msat " +
76
                                "are zero, a large number of hints with " +
77
                                "these channels can be included, which " +
78
                                "might not be desirable.",
79
                },
80
                cli.BoolFlag{
81
                        Name: "amp",
82
                        Usage: "creates an AMP invoice. If true, preimage " +
83
                                "should not be set.",
84
                },
85
                cli.BoolFlag{
86
                        Name: "blind",
87
                        Usage: "creates an invoice that contains blinded " +
88
                                "paths. Note that invoices with blinded " +
89
                                "paths will be signed using a random " +
90
                                "ephemeral key so as not to reveal the real " +
91
                                "node ID of this node.",
92
                },
93
                cli.UintFlag{
94
                        Name: "min_real_blinded_hops",
95
                        Usage: "The minimum number of real hops to use in a " +
96
                                "blinded path. This option will only be used " +
97
                                "if `--blind` has also been set.",
98
                },
99
                cli.UintFlag{
100
                        Name: "num_blinded_hops",
101
                        Usage: "The number of hops to use for each " +
102
                                "blinded path included in the invoice. This " +
103
                                "option will only be used if `--blind` has " +
104
                                "also been set. Dummy hops will be used to " +
105
                                "pad paths shorter than this.",
106
                },
107
                cli.UintFlag{
108
                        Name: "max_blinded_paths",
109
                        Usage: "The maximum number of blinded paths to add " +
110
                                "to an invoice. This option will only be " +
111
                                "used if `--blind` has also been set.",
112
                },
113
                cli.StringSliceFlag{
114
                        Name: "blinded_path_omit_node",
115
                        Usage: "The pub key (in hex) of a node not to " +
116
                                "use on a blinded path. The flag may be " +
117
                                "specified multiple times.",
118
                },
119
        },
120
        Action: actionDecorator(addInvoice),
121
}
122

123
func addInvoice(ctx *cli.Context) error {
×
124
        var (
×
125
                preimage []byte
×
126
                descHash []byte
×
127
                amt      int64
×
128
                amtMsat  int64
×
129
                err      error
×
130
        )
×
131
        ctxc := getContext()
×
132
        client, cleanUp := getClient(ctx)
×
133
        defer cleanUp()
×
134

×
135
        args := ctx.Args()
×
136

×
137
        amt = ctx.Int64("amt")
×
138
        amtMsat = ctx.Int64("amt_msat")
×
139
        if !ctx.IsSet("amt") && !ctx.IsSet("amt_msat") && args.Present() {
×
140
                amt, err = strconv.ParseInt(args.First(), 10, 64)
×
141
                args = args.Tail()
×
142
                if err != nil {
×
143
                        return fmt.Errorf("unable to decode amt argument: %w",
×
144
                                err)
×
145
                }
×
146
        }
147

148
        switch {
×
149
        case ctx.IsSet("preimage"):
×
150
                preimage, err = hex.DecodeString(ctx.String("preimage"))
×
151
        case args.Present():
×
152
                preimage, err = hex.DecodeString(args.First())
×
153
        }
154

155
        if err != nil {
×
156
                return fmt.Errorf("unable to parse preimage: %w", err)
×
157
        }
×
158

159
        descHash, err = hex.DecodeString(ctx.String("description_hash"))
×
160
        if err != nil {
×
161
                return fmt.Errorf("unable to parse description_hash: %w", err)
×
162
        }
×
163

164
        if ctx.IsSet("private") && ctx.IsSet("blind") {
×
165
                return fmt.Errorf("cannot include both route hints and " +
×
166
                        "blinded paths in the same invoice")
×
167
        }
×
168

169
        blindedPathCfg, err := parseBlindedPathCfg(ctx)
×
170
        if err != nil {
×
171
                return fmt.Errorf("could not parse blinded path config: %w",
×
172
                        err)
×
173
        }
×
174

175
        invoice := &lnrpc.Invoice{
×
176
                Memo:              ctx.String("memo"),
×
177
                RPreimage:         preimage,
×
178
                Value:             amt,
×
179
                ValueMsat:         amtMsat,
×
180
                DescriptionHash:   descHash,
×
181
                FallbackAddr:      ctx.String("fallback_addr"),
×
182
                Expiry:            ctx.Int64("expiry"),
×
183
                CltvExpiry:        ctx.Uint64("cltv_expiry_delta"),
×
184
                Private:           ctx.Bool("private"),
×
185
                IsAmp:             ctx.Bool("amp"),
×
NEW
186
                IsBlinded:         ctx.Bool("blind"),
×
187
                BlindedPathConfig: blindedPathCfg,
×
188
        }
×
189

×
190
        resp, err := client.AddInvoice(ctxc, invoice)
×
191
        if err != nil {
×
192
                return err
×
193
        }
×
194

195
        printRespJSON(resp)
×
196

×
197
        return nil
×
198
}
199

200
func parseBlindedPathCfg(ctx *cli.Context) (*lnrpc.BlindedPathConfig, error) {
×
201
        if !ctx.Bool("blind") {
×
202
                if ctx.IsSet("min_real_blinded_hops") ||
×
203
                        ctx.IsSet("num_blinded_hops") ||
×
204
                        ctx.IsSet("max_blinded_paths") ||
×
205
                        ctx.IsSet("blinded_path_omit_node") {
×
206

×
207
                        return nil, fmt.Errorf("blinded path options are " +
×
208
                                "only used if the `--blind` options is set")
×
209
                }
×
210

211
                return nil, nil
×
212
        }
213

214
        var blindCfg lnrpc.BlindedPathConfig
×
215

×
216
        if ctx.IsSet("min_real_blinded_hops") {
×
217
                minNumRealHops := uint32(ctx.Uint("min_real_blinded_hops"))
×
218
                blindCfg.MinNumRealHops = &minNumRealHops
×
219
        }
×
220

221
        if ctx.IsSet("num_blinded_hops") {
×
222
                numHops := uint32(ctx.Uint("num_blinded_hops"))
×
223
                blindCfg.NumHops = &numHops
×
224
        }
×
225

226
        if ctx.IsSet("max_blinded_paths") {
×
227
                maxPaths := uint32(ctx.Uint("max_blinded_paths"))
×
228
                blindCfg.MaxNumPaths = &maxPaths
×
229
        }
×
230

231
        for _, pubKey := range ctx.StringSlice("blinded_path_omit_node") {
×
232
                pubKeyBytes, err := hex.DecodeString(pubKey)
×
233
                if err != nil {
×
234
                        return nil, err
×
235
                }
×
236

237
                blindCfg.NodeOmissionList = append(
×
238
                        blindCfg.NodeOmissionList, pubKeyBytes,
×
239
                )
×
240
        }
241

242
        return &blindCfg, nil
×
243
}
244

245
var lookupInvoiceCommand = cli.Command{
246
        Name:      "lookupinvoice",
247
        Category:  "Invoices",
248
        Usage:     "Lookup an existing invoice by its payment hash.",
249
        ArgsUsage: "rhash",
250
        Flags: []cli.Flag{
251
                cli.StringFlag{
252
                        Name: "rhash",
253
                        Usage: "the 32 byte payment hash of the invoice to query for, the hash " +
254
                                "should be a hex-encoded string",
255
                },
256
        },
257
        Action: actionDecorator(lookupInvoice),
258
}
259

260
func lookupInvoice(ctx *cli.Context) error {
×
261
        ctxc := getContext()
×
262
        client, cleanUp := getClient(ctx)
×
263
        defer cleanUp()
×
264

×
265
        var (
×
266
                rHash []byte
×
267
                err   error
×
268
        )
×
269

×
270
        switch {
×
271
        case ctx.IsSet("rhash"):
×
272
                rHash, err = hex.DecodeString(ctx.String("rhash"))
×
273
        case ctx.Args().Present():
×
274
                rHash, err = hex.DecodeString(ctx.Args().First())
×
275
        default:
×
276
                return fmt.Errorf("rhash argument missing")
×
277
        }
278

279
        if err != nil {
×
280
                return fmt.Errorf("unable to decode rhash argument: %w", err)
×
281
        }
×
282

283
        req := &lnrpc.PaymentHash{
×
284
                RHash: rHash,
×
285
        }
×
286

×
287
        invoice, err := client.LookupInvoice(ctxc, req)
×
288
        if err != nil {
×
289
                return err
×
290
        }
×
291

292
        printRespJSON(invoice)
×
293

×
294
        return nil
×
295
}
296

297
var listInvoicesCommand = cli.Command{
298
        Name:     "listinvoices",
299
        Category: "Invoices",
300
        Usage: "List all invoices currently stored within the database. Any " +
301
                "active debug invoices are ignored.",
302
        Description: `
303
        This command enables the retrieval of all invoices currently stored
304
        within the database. It has full support for paginationed responses,
305
        allowing users to query for specific invoices through their add_index.
306
        This can be done by using either the first_index_offset or
307
        last_index_offset fields included in the response as the index_offset of
308
        the next request. Backward pagination is enabled by default to receive
309
        current invoices first. If you wish to paginate forwards, set the 
310
        paginate-forwards flag.        If none of the parameters are specified, then 
311
        the last 100 invoices will be returned.
312

313
        For example: if you have 200 invoices, "lncli listinvoices" will return
314
        the last 100 created. If you wish to retrieve the previous 100, the
315
        first_offset_index of the response can be used as the index_offset of
316
        the next listinvoices request.`,
317
        Flags: []cli.Flag{
318
                cli.BoolFlag{
319
                        Name: "pending_only",
320
                        Usage: "toggles if all invoices should be returned, " +
321
                                "or only those that are currently unsettled",
322
                },
323
                cli.Uint64Flag{
324
                        Name: "index_offset",
325
                        Usage: "the index of an invoice that will be used as " +
326
                                "either the start or end of a query to " +
327
                                "determine which invoices should be returned " +
328
                                "in the response",
329
                },
330
                cli.Uint64Flag{
331
                        Name:  "max_invoices",
332
                        Usage: "the max number of invoices to return",
333
                },
334
                cli.BoolFlag{
335
                        Name: "paginate-forwards",
336
                        Usage: "if set, invoices succeeding the " +
337
                                "index_offset will be returned",
338
                },
339
                cli.Uint64Flag{
340
                        Name: "creation_date_start",
341
                        Usage: "timestamp in seconds, if set, filter " +
342
                                "invoices with creation date greater than or " +
343
                                "equal to it",
344
                },
345
                cli.Uint64Flag{
346
                        Name: "creation_date_end",
347
                        Usage: "timestamp in seconds, if set, filter " +
348
                                "invoices with creation date less than or " +
349
                                "equal to it",
350
                },
351
        },
352
        Action: actionDecorator(listInvoices),
353
}
354

355
func listInvoices(ctx *cli.Context) error {
×
356
        ctxc := getContext()
×
357
        client, cleanUp := getClient(ctx)
×
358
        defer cleanUp()
×
359

×
360
        req := &lnrpc.ListInvoiceRequest{
×
361
                PendingOnly:       ctx.Bool("pending_only"),
×
362
                IndexOffset:       ctx.Uint64("index_offset"),
×
363
                NumMaxInvoices:    ctx.Uint64("max_invoices"),
×
364
                Reversed:          !ctx.Bool("paginate-forwards"),
×
365
                CreationDateStart: ctx.Uint64("creation_date_start"),
×
366
                CreationDateEnd:   ctx.Uint64("creation_date_end"),
×
367
        }
×
368

×
369
        invoices, err := client.ListInvoices(ctxc, req)
×
370
        if err != nil {
×
371
                return err
×
372
        }
×
373

374
        printRespJSON(invoices)
×
375

×
376
        return nil
×
377
}
378

379
var decodePayReqCommand = cli.Command{
380
        Name:        "decodepayreq",
381
        Category:    "Invoices",
382
        Usage:       "Decode a payment request.",
383
        Description: "Decode the passed payment request revealing the destination, payment hash and value of the payment request",
384
        ArgsUsage:   "pay_req",
385
        Flags: []cli.Flag{
386
                cli.StringFlag{
387
                        Name:  "pay_req",
388
                        Usage: "the bech32 encoded payment request",
389
                },
390
        },
391
        Action: actionDecorator(decodePayReq),
392
}
393

394
func decodePayReq(ctx *cli.Context) error {
×
395
        ctxc := getContext()
×
396
        client, cleanUp := getClient(ctx)
×
397
        defer cleanUp()
×
398

×
399
        var payreq string
×
400

×
401
        switch {
×
402
        case ctx.IsSet("pay_req"):
×
403
                payreq = ctx.String("pay_req")
×
404
        case ctx.Args().Present():
×
405
                payreq = ctx.Args().First()
×
406
        default:
×
407
                return fmt.Errorf("pay_req argument missing")
×
408
        }
409

410
        resp, err := client.DecodePayReq(ctxc, &lnrpc.PayReqString{
×
411
                PayReq: stripPrefix(payreq),
×
412
        })
×
413
        if err != nil {
×
414
                return err
×
415
        }
×
416

417
        printRespJSON(resp)
×
418
        return nil
×
419
}
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

© 2026 Coveralls, Inc