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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 hits per line

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

69.57
/zpay32/invoice.go
1
package zpay32
2

3
import (
4
        "errors"
5
        "fmt"
6
        "time"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcutil"
10
        "github.com/btcsuite/btcd/chaincfg"
11
        "github.com/lightningnetwork/lnd/fn/v2"
12
        "github.com/lightningnetwork/lnd/lnwire"
13
)
14

15
const (
16
        // mSatPerBtc is the number of millisatoshis in 1 BTC.
17
        mSatPerBtc = 100000000000
18

19
        // signatureBase32Len is the number of 5-bit groups needed to encode
20
        // the 512 bit signature + 8 bit recovery ID.
21
        signatureBase32Len = 104
22

23
        // timestampBase32Len is the number of 5-bit groups needed to encode
24
        // the 35-bit timestamp.
25
        timestampBase32Len = 7
26

27
        // hashBase32Len is the number of 5-bit groups needed to encode a
28
        // 256-bit hash. Note that the last group will be padded with zeroes.
29
        hashBase32Len = 52
30

31
        // pubKeyBase32Len is the number of 5-bit groups needed to encode a
32
        // 33-byte compressed pubkey. Note that the last group will be padded
33
        // with zeroes.
34
        pubKeyBase32Len = 53
35

36
        // hopHintLen is the number of bytes needed to encode the hop hint of a
37
        // single private route.
38
        hopHintLen = 51
39

40
        // The following byte values correspond to the supported field types.
41
        // The field name is the character representing that 5-bit value in the
42
        // bech32 string.
43

44
        // fieldTypeP is the field containing the payment hash.
45
        fieldTypeP = 1
46

47
        // fieldTypeD contains a short description of the payment.
48
        fieldTypeD = 13
49

50
        // fieldTypeM contains the payment metadata.
51
        fieldTypeM = 27
52

53
        // fieldTypeN contains the pubkey of the target node.
54
        fieldTypeN = 19
55

56
        // fieldTypeH contains the hash of a description of the payment.
57
        fieldTypeH = 23
58

59
        // fieldTypeX contains the expiry in seconds of the invoice.
60
        fieldTypeX = 6
61

62
        // fieldTypeF contains a fallback on-chain address.
63
        fieldTypeF = 9
64

65
        // fieldTypeR contains extra routing information.
66
        fieldTypeR = 3
67

68
        // fieldTypeC contains an optional requested final CLTV delta.
69
        fieldTypeC = 24
70

71
        // fieldType9 contains one or more bytes for signaling features
72
        // supported or required by the receiver.
73
        fieldType9 = 5
74

75
        // fieldTypeS contains a 32-byte payment address, which is a nonce
76
        // included in the final hop's payload to prevent intermediaries from
77
        // probing the recipient.
78
        fieldTypeS = 16
79

80
        // fieldTypeB contains blinded payment path information. This field may
81
        // be repeated to include multiple blinded payment paths in the invoice.
82
        fieldTypeB = 20
83

84
        // maxInvoiceLength is the maximum total length an invoice can have.
85
        // This is chosen to be the maximum number of bytes that can fit into a
86
        // single QR code: https://en.wikipedia.org/wiki/QR_code#Storage
87
        maxInvoiceLength = 7089
88

89
        // DefaultInvoiceExpiry is the default expiry duration from the creation
90
        // timestamp if expiry is set to zero.
91
        DefaultInvoiceExpiry = time.Hour
92
)
93

94
var (
95
        // ErrInvoiceTooLarge is returned when an invoice exceeds
96
        // maxInvoiceLength.
97
        ErrInvoiceTooLarge = errors.New("invoice is too large")
98

99
        // ErrInvalidFieldLength is returned when a tagged field was specified
100
        // with a length larger than the left over bytes of the data field.
101
        ErrInvalidFieldLength = errors.New("invalid field length")
102

103
        // ErrBrokenTaggedField is returned when the last tagged field is
104
        // incorrectly formatted and doesn't have enough bytes to be read.
105
        ErrBrokenTaggedField = errors.New("last tagged field is broken")
106
)
107

108
// MessageSigner is passed to the Encode method to provide a signature
109
// corresponding to the node's pubkey.
110
type MessageSigner struct {
111
        // SignCompact signs the hash of the passed msg with the node's privkey.
112
        // The returned signature should be 65 bytes, where the last 64 are the
113
        // compact signature, and the first one is a header byte. This is the
114
        // format returned by ecdsa.SignCompact.
115
        SignCompact func(msg []byte) ([]byte, error)
116
}
117

118
// Invoice represents a decoded invoice, or to-be-encoded invoice. Some of the
119
// fields are optional, and will only be non-nil if the invoice this was parsed
120
// from contains that field. When encoding, only the non-nil fields will be
121
// added to the encoded invoice.
122
type Invoice struct {
123
        // Net specifies what network this Lightning invoice is meant for.
124
        Net *chaincfg.Params
125

126
        // MilliSat specifies the amount of this invoice in millisatoshi.
127
        // Optional.
128
        MilliSat *lnwire.MilliSatoshi
129

130
        // Timestamp specifies the time this invoice was created.
131
        // Mandatory
132
        Timestamp time.Time
133

134
        // PaymentHash is the payment hash to be used for a payment to this
135
        // invoice.
136
        PaymentHash *[32]byte
137

138
        // PaymentAddr is the payment address to be used by payments to prevent
139
        // probing of the destination.
140
        PaymentAddr fn.Option[[32]byte]
141

142
        // Destination is the public key of the target node. This will always
143
        // be set after decoding, and can optionally be set before encoding to
144
        // include the pubkey as an 'n' field. If this is not set before
145
        // encoding then the destination pubkey won't be added as an 'n' field,
146
        // and the pubkey will be extracted from the signature during decoding.
147
        Destination *btcec.PublicKey
148

149
        // minFinalCLTVExpiry is the value that the creator of the invoice
150
        // expects to be used for the CLTV expiry of the HTLC extended to it in
151
        // the last hop.
152
        //
153
        // NOTE: This value is optional, and should be set to nil if the
154
        // invoice creator doesn't have a strong requirement on the CLTV expiry
155
        // of the final HTLC extended to it.
156
        //
157
        // This field is un-exported and can only be read by the
158
        // MinFinalCLTVExpiry() method. By forcing callers to read via this
159
        // method, we can easily enforce the default if not specified.
160
        //
161
        // NOTE: this field is ignored in the case that the invoice contains
162
        // blinded paths since then the final minimum cltv expiry delta is
163
        // expected to be included in the route's accumulated CLTV delta value.
164
        minFinalCLTVExpiry *uint64
165

166
        // Description is a short description of the purpose of this invoice.
167
        // Optional. Non-nil iff DescriptionHash is nil.
168
        Description *string
169

170
        // DescriptionHash is the SHA256 hash of a description of the purpose of
171
        // this invoice.
172
        // Optional. Non-nil iff Description is nil.
173
        DescriptionHash *[32]byte
174

175
        // expiry specifies the timespan this invoice will be valid.
176
        // Optional. If not set, a default expiry of 60 min will be implied.
177
        //
178
        // This field is unexported and can be read by the Expiry() method. This
179
        // method makes sure the default expiry time is returned in case the
180
        // field is not set.
181
        expiry *time.Duration
182

183
        // FallbackAddr is an on-chain address that can be used for payment in
184
        // case the Lightning payment fails.
185
        // Optional.
186
        FallbackAddr btcutil.Address
187

188
        // RouteHints represents one or more different route hints. Each route
189
        // hint can be individually used to reach the destination. These usually
190
        // represent private routes.
191
        //
192
        // NOTE: This is optional and should not be set at the same time as
193
        // BlindedPaymentPaths.
194
        RouteHints [][]HopHint
195

196
        // BlindedPaymentPaths is a set of blinded payment paths that can be
197
        // used to find the payment receiver.
198
        //
199
        // NOTE: This is optional and should not be set at the same time as
200
        // RouteHints.
201
        BlindedPaymentPaths []*BlindedPaymentPath
202

203
        // Features represents an optional field used to signal optional or
204
        // required support for features by the receiver.
205
        Features *lnwire.FeatureVector
206

207
        // Metadata is additional data that is sent along with the payment to
208
        // the payee.
209
        Metadata []byte
210
}
211

212
// Amount is a functional option that allows callers of NewInvoice to set the
213
// amount in millisatoshis that the Invoice should encode.
214
func Amount(milliSat lnwire.MilliSatoshi) func(*Invoice) {
98✔
215
        return func(i *Invoice) {
196✔
216
                i.MilliSat = &milliSat
98✔
217
        }
98✔
218
}
219

220
// Destination is a functional option that allows callers of NewInvoice to
221
// explicitly set the pubkey of the Invoice's destination node.
222
func Destination(destination *btcec.PublicKey) func(*Invoice) {
7✔
223
        return func(i *Invoice) {
14✔
224
                i.Destination = destination
7✔
225
        }
7✔
226
}
227

228
// Description is a functional option that allows callers of NewInvoice to set
229
// the payment description of the created Invoice.
230
//
231
// NOTE: Must be used if and only if DescriptionHash is not used.
232
func Description(description string) func(*Invoice) {
103✔
233
        return func(i *Invoice) {
206✔
234
                i.Description = &description
103✔
235
        }
103✔
236
}
237

238
// CLTVExpiry is an optional value which allows the receiver of the payment to
239
// specify the delta between the current height and the HTLC extended to the
240
// receiver.
241
func CLTVExpiry(delta uint64) func(*Invoice) {
4✔
242
        return func(i *Invoice) {
8✔
243
                i.minFinalCLTVExpiry = &delta
4✔
244
        }
4✔
245
}
246

247
// DescriptionHash is a functional option that allows callers of NewInvoice to
248
// set the payment description hash of the created Invoice.
249
//
250
// NOTE: Must be used if and only if Description is not used.
251
func DescriptionHash(descriptionHash [32]byte) func(*Invoice) {
2✔
252
        return func(i *Invoice) {
4✔
253
                i.DescriptionHash = &descriptionHash
2✔
254
        }
2✔
255
}
256

257
// Expiry is a functional option that allows callers of NewInvoice to set the
258
// expiry of the created Invoice. If not set, a default expiry of 60 min will
259
// be implied.
260
func Expiry(expiry time.Duration) func(*Invoice) {
91✔
261
        return func(i *Invoice) {
182✔
262
                i.expiry = &expiry
91✔
263
        }
91✔
264
}
265

266
// FallbackAddr is a functional option that allows callers of NewInvoice to set
267
// the Invoice's fallback on-chain address that can be used for payment in case
268
// the Lightning payment fails
269
func FallbackAddr(fallbackAddr btcutil.Address) func(*Invoice) {
1✔
270
        return func(i *Invoice) {
2✔
271
                i.FallbackAddr = fallbackAddr
1✔
272
        }
1✔
273
}
274

275
// RouteHint is a functional option that allows callers of NewInvoice to add
276
// one or more hop hints that represent a private route to the destination.
277
func RouteHint(routeHint []HopHint) func(*Invoice) {
1✔
278
        return func(i *Invoice) {
2✔
279
                i.RouteHints = append(i.RouteHints, routeHint)
1✔
280
        }
1✔
281
}
282

283
// WithBlindedPaymentPath is a functional option that allows a caller of
284
// NewInvoice to attach a blinded payment path to the invoice. The option can
285
// be used multiple times to attach multiple paths.
286
func WithBlindedPaymentPath(p *BlindedPaymentPath) func(*Invoice) {
2✔
287
        return func(i *Invoice) {
4✔
288
                i.BlindedPaymentPaths = append(i.BlindedPaymentPaths, p)
2✔
289
        }
2✔
290
}
291

292
// Features is a functional option that allows callers of NewInvoice to set the
293
// desired feature bits that are advertised on the invoice. If this option is
294
// not used, an empty feature vector will automatically be populated.
UNCOV
295
func Features(features *lnwire.FeatureVector) func(*Invoice) {
×
UNCOV
296
        return func(i *Invoice) {
×
UNCOV
297
                i.Features = features
×
UNCOV
298
        }
×
299
}
300

301
// PaymentAddr is a functional option that allows callers of NewInvoice to set
302
// the desired payment address that is advertised on the invoice.
303
func PaymentAddr(addr [32]byte) func(*Invoice) {
90✔
304
        return func(i *Invoice) {
180✔
305
                i.PaymentAddr = fn.Some(addr)
90✔
306
        }
90✔
307
}
308

309
// Metadata is a functional option that allows callers of NewInvoice to set
310
// the desired payment Metadata that is advertised on the invoice.
311
func Metadata(metadata []byte) func(*Invoice) {
×
312
        return func(i *Invoice) {
×
313
                i.Metadata = metadata
×
314
        }
×
315
}
316

317
// NewInvoice creates a new Invoice object. The last parameter is a set of
318
// variadic arguments for setting optional fields of the invoice.
319
//
320
// NOTE: Either Description  or DescriptionHash must be provided for the Invoice
321
// to be considered valid.
322
func NewInvoice(net *chaincfg.Params, paymentHash [32]byte,
323
        timestamp time.Time, options ...func(*Invoice)) (*Invoice, error) {
104✔
324

104✔
325
        invoice := &Invoice{
104✔
326
                Net:         net,
104✔
327
                PaymentHash: &paymentHash,
104✔
328
                Timestamp:   timestamp,
104✔
329
        }
104✔
330

104✔
331
        for _, option := range options {
503✔
332
                option(invoice)
399✔
333
        }
399✔
334

335
        // If no features were set, we'll populate an empty feature vector.
336
        if invoice.Features == nil {
208✔
337
                invoice.Features = lnwire.NewFeatureVector(
104✔
338
                        nil, lnwire.Features,
104✔
339
                )
104✔
340
        }
104✔
341

342
        if err := validateInvoice(invoice); err != nil {
105✔
343
                return nil, err
1✔
344
        }
1✔
345

346
        return invoice, nil
103✔
347
}
348

349
// Expiry returns the expiry time for this invoice. If expiry time is not set
350
// explicitly, the default 3600 second expiry will be returned.
UNCOV
351
func (invoice *Invoice) Expiry() time.Duration {
×
UNCOV
352
        if invoice.expiry != nil {
×
UNCOV
353
                return *invoice.expiry
×
UNCOV
354
        }
×
355

356
        // If no expiry is set for this invoice, default is 3600 seconds.
357
        return DefaultInvoiceExpiry
×
358
}
359

360
// MinFinalCLTVExpiry returns the minimum final CLTV expiry delta as specified
361
// by the creator of the invoice. This value specifies the delta between the
362
// current height and the expiry height of the HTLC extended in the last hop.
UNCOV
363
func (invoice *Invoice) MinFinalCLTVExpiry() uint64 {
×
UNCOV
364
        if invoice.minFinalCLTVExpiry != nil {
×
UNCOV
365
                return *invoice.minFinalCLTVExpiry
×
UNCOV
366
        }
×
367

UNCOV
368
        return DefaultAssumedFinalCLTVDelta
×
369
}
370

371
// validateInvoice does a sanity check of the provided Invoice, making sure it
372
// has all the necessary fields set for it to be considered valid by BOLT-0011.
373
func validateInvoice(invoice *Invoice) error {
509✔
374
        // The net must be set.
509✔
375
        if invoice.Net == nil {
509✔
376
                return fmt.Errorf("net params not set")
×
377
        }
×
378

379
        // The invoice must contain a payment hash.
380
        if invoice.PaymentHash == nil {
572✔
381
                return fmt.Errorf("no payment hash found")
63✔
382
        }
63✔
383

384
        if len(invoice.RouteHints) != 0 &&
446✔
385
                len(invoice.BlindedPaymentPaths) != 0 {
446✔
386

×
387
                return fmt.Errorf("cannot have both route hints and blinded " +
×
388
                        "payment paths")
×
389
        }
×
390

391
        // Either Description or DescriptionHash must be set, not both.
392
        if invoice.Description != nil && invoice.DescriptionHash != nil {
450✔
393
                return fmt.Errorf("both description and description hash set")
4✔
394
        }
4✔
395
        if invoice.Description == nil && invoice.DescriptionHash == nil {
446✔
396
                return fmt.Errorf("neither description nor description hash set")
4✔
397
        }
4✔
398

399
        // Check that we support the field lengths.
400
        if len(invoice.PaymentHash) != 32 {
438✔
401
                return fmt.Errorf("unsupported payment hash length: %d",
×
402
                        len(invoice.PaymentHash))
×
403
        }
×
404

405
        if invoice.DescriptionHash != nil && len(invoice.DescriptionHash) != 32 {
438✔
406
                return fmt.Errorf("unsupported description hash length: %d",
×
407
                        len(invoice.DescriptionHash))
×
408
        }
×
409

410
        if invoice.Destination != nil &&
438✔
411
                len(invoice.Destination.SerializeCompressed()) != 33 {
438✔
412
                return fmt.Errorf("unsupported pubkey length: %d",
×
413
                        len(invoice.Destination.SerializeCompressed()))
×
414
        }
×
415

416
        // Ensure that all invoices have feature vectors.
417
        if invoice.Features == nil {
438✔
418
                return fmt.Errorf("missing feature vector")
×
419
        }
×
420

421
        return nil
438✔
422
}
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