github.com/decred/dcrlnd@v0.7.6/zpay32/invoice.go (about) 1 package zpay32 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 8 "github.com/decred/dcrd/chaincfg/v3" 9 "github.com/decred/dcrd/dcrec/secp256k1/v4" 10 "github.com/decred/dcrd/txscript/v4/stdaddr" 11 12 "github.com/decred/dcrlnd/lnwire" 13 ) 14 15 const ( 16 // mAtPerDcr is the number of MilliAtoms in 1 DCR. 17 mAtPerDcr = 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 // fieldTypeN contains the pubkey of the target node. 51 fieldTypeN = 19 52 53 // fieldTypeH contains the hash of a description of the payment. 54 fieldTypeH = 23 55 56 // fieldTypeX contains the expiry in seconds of the invoice. 57 fieldTypeX = 6 58 59 // fieldTypeF contains a fallback on-chain address. 60 fieldTypeF = 9 61 62 // fieldTypeR contains extra routing information. 63 fieldTypeR = 3 64 65 // fieldTypeC contains an optional requested final CLTV delta. 66 fieldTypeC = 24 67 68 // fieldType9 contains one or more bytes for signaling features 69 // supported or required by the receiver. 70 fieldType9 = 5 71 72 // fieldTypeS contains a 32-byte payment address, which is a nonce 73 // included in the final hop's payload to prevent intermediaries from 74 // probing the recipient. 75 fieldTypeS = 16 76 77 // maxInvoiceLength is the maximum total length an invoice can have. 78 // This is chosen to be the maximum number of bytes that can fit into a 79 // single QR code: https://en.wikipedia.org/wiki/QR_code#Storage 80 maxInvoiceLength = 7089 81 82 // DefaultInvoiceExpiry is the default expiry duration from the creation 83 // timestamp if expiry is set to zero. 84 DefaultInvoiceExpiry = time.Hour 85 ) 86 87 var ( 88 // ErrInvoiceTooLarge is returned when an invoice exceeds 89 // maxInvoiceLength. 90 ErrInvoiceTooLarge = errors.New("invoice is too large") 91 92 // ErrInvalidFieldLength is returned when a tagged field was specified 93 // with a length larger than the left over bytes of the data field. 94 ErrInvalidFieldLength = errors.New("invalid field length") 95 96 // ErrBrokenTaggedField is returned when the last tagged field is 97 // incorrectly formatted and doesn't have enough bytes to be read. 98 ErrBrokenTaggedField = errors.New("last tagged field is broken") 99 ) 100 101 // decredHRPPrefixes are the prefixes that should be present on the HRP (human 102 // readable part) section of ln addresses for each decred network. 103 var decredHRPPrefixes = map[string]string{ 104 chaincfg.MainNetParams().Name: "dcr", 105 chaincfg.RegNetParams().Name: "rdcr", 106 chaincfg.SimNetParams().Name: "sdcr", 107 chaincfg.TestNet3Params().Name: "tdcr", 108 } 109 110 // MessageSigner is passed to the Encode method to provide a signature 111 // corresponding to the node's pubkey. 112 type MessageSigner struct { 113 // SignCompact signs the hash of the passed msg with the node's privkey. 114 // The returned signature should be 65 bytes, where the last 64 are the 115 // compact signature, and the first one is a header byte. This is the 116 // format returned by secp256k1.SignCompact. 117 SignCompact func(msg []byte) ([]byte, error) 118 } 119 120 // Invoice represents a decoded invoice, or to-be-encoded invoice. Some of the 121 // fields are optional, and will only be non-nil if the invoice this was parsed 122 // from contains that field. When encoding, only the non-nil fields will be 123 // added to the encoded invoice. 124 type Invoice struct { 125 // Net specifies what network this Lightning invoice is meant for. 126 Net *chaincfg.Params 127 128 // MilliAt specifies the amount of this invoice in MilliAtom. 129 // Optional. 130 MilliAt *lnwire.MilliAtom 131 132 // Timestamp specifies the time this invoice was created. 133 // Mandatory 134 Timestamp time.Time 135 136 // PaymentHash is the payment hash to be used for a payment to this 137 // invoice. 138 PaymentHash *[32]byte 139 140 // PaymentAddr is the payment address to be used by payments to prevent 141 // probing of the destination. 142 PaymentAddr *[32]byte 143 144 // Destination is the public key of the target node. This will always 145 // be set after decoding, and can optionally be set before encoding to 146 // include the pubkey as an 'n' field. If this is not set before 147 // encoding then the destination pubkey won't be added as an 'n' field, 148 // and the pubkey will be extracted from the signature during decoding. 149 Destination *secp256k1.PublicKey 150 151 // minFinalCLTVExpiry is the value that the creator of the invoice 152 // expects to be used for the CLTV expiry of the HTLC extended to it in 153 // the last hop. 154 // 155 // NOTE: This value is optional, and should be set to nil if the 156 // invoice creator doesn't have a strong requirement on the CLTV expiry 157 // of the final HTLC extended to it. 158 // 159 // This field is un-exported and can only be read by the 160 // MinFinalCLTVExpiry() method. By forcing callers to read via this 161 // method, we can easily enforce the default if not specified. 162 minFinalCLTVExpiry *uint64 163 164 // Description is a short description of the purpose of this invoice. 165 // Optional. Non-nil iff DescriptionHash is nil. 166 Description *string 167 168 // DescriptionHash is the SHA256 hash of a description of the purpose of 169 // this invoice. 170 // Optional. Non-nil iff Description is nil. 171 DescriptionHash *[32]byte 172 173 // expiry specifies the timespan this invoice will be valid. 174 // Optional. If not set, a default expiry of 60 min will be implied. 175 // 176 // This field is unexported and can be read by the Expiry() method. This 177 // method makes sure the default expiry time is returned in case the 178 // field is not set. 179 expiry *time.Duration 180 181 // FallbackAddr is an on-chain address that can be used for payment in 182 // case the Lightning payment fails. 183 // Optional. 184 FallbackAddr stdaddr.Address 185 186 // RouteHints represents one or more different route hints. Each route 187 // hint can be individually used to reach the destination. These usually 188 // represent private routes. 189 // 190 // NOTE: This is optional. 191 RouteHints [][]HopHint 192 193 // Features represents an optional field used to signal optional or 194 // required support for features by the receiver. 195 Features *lnwire.FeatureVector 196 } 197 198 // Amount is a functional option that allows callers of NewInvoice to set the 199 // amount in MilliAtoms that the Invoice should encode. 200 func Amount(milliAt lnwire.MilliAtom) func(*Invoice) { 201 return func(i *Invoice) { 202 i.MilliAt = &milliAt 203 } 204 } 205 206 // Destination is a functional option that allows callers of NewInvoice to 207 // explicitly set the pubkey of the Invoice's destination node. 208 func Destination(destination *secp256k1.PublicKey) func(*Invoice) { 209 return func(i *Invoice) { 210 i.Destination = destination 211 } 212 } 213 214 // Description is a functional option that allows callers of NewInvoice to set 215 // the payment description of the created Invoice. 216 // 217 // NOTE: Must be used if and only if DescriptionHash is not used. 218 func Description(description string) func(*Invoice) { 219 return func(i *Invoice) { 220 i.Description = &description 221 } 222 } 223 224 // CLTVExpiry is an optional value which allows the receiver of the payment to 225 // specify the delta between the current height and the HTLC extended to the 226 // receiver. 227 func CLTVExpiry(delta uint64) func(*Invoice) { 228 return func(i *Invoice) { 229 i.minFinalCLTVExpiry = &delta 230 } 231 } 232 233 // DescriptionHash is a functional option that allows callers of NewInvoice to 234 // set the payment description hash of the created Invoice. 235 // 236 // NOTE: Must be used if and only if Description is not used. 237 func DescriptionHash(descriptionHash [32]byte) func(*Invoice) { 238 return func(i *Invoice) { 239 i.DescriptionHash = &descriptionHash 240 } 241 } 242 243 // Expiry is a functional option that allows callers of NewInvoice to set the 244 // expiry of the created Invoice. If not set, a default expiry of 60 min will 245 // be implied. 246 func Expiry(expiry time.Duration) func(*Invoice) { 247 return func(i *Invoice) { 248 i.expiry = &expiry 249 } 250 } 251 252 // FallbackAddr is a functional option that allows callers of NewInvoice to set 253 // the Invoice's fallback on-chain address that can be used for payment in case 254 // the Lightning payment fails 255 func FallbackAddr(fallbackAddr stdaddr.Address) func(*Invoice) { 256 return func(i *Invoice) { 257 i.FallbackAddr = fallbackAddr 258 } 259 } 260 261 // RouteHint is a functional option that allows callers of NewInvoice to add 262 // one or more hop hints that represent a private route to the destination. 263 func RouteHint(routeHint []HopHint) func(*Invoice) { 264 return func(i *Invoice) { 265 i.RouteHints = append(i.RouteHints, routeHint) 266 } 267 } 268 269 // Features is a functional option that allows callers of NewInvoice to set the 270 // desired feature bits that are advertised on the invoice. If this option is 271 // not used, an empty feature vector will automatically be populated. 272 func Features(features *lnwire.FeatureVector) func(*Invoice) { 273 return func(i *Invoice) { 274 i.Features = features 275 } 276 } 277 278 // PaymentAddr is a functional option that allows callers of NewInvoice to set 279 // the desired payment address tht is advertised on the invoice. 280 func PaymentAddr(addr [32]byte) func(*Invoice) { 281 return func(i *Invoice) { 282 i.PaymentAddr = &addr 283 } 284 } 285 286 // NewInvoice creates a new Invoice object. The last parameter is a set of 287 // variadic arguments for setting optional fields of the invoice. 288 // 289 // NOTE: Either Description or DescriptionHash must be provided for the Invoice 290 // to be considered valid. 291 func NewInvoice(net *chaincfg.Params, paymentHash [32]byte, 292 timestamp time.Time, options ...func(*Invoice)) (*Invoice, error) { 293 294 invoice := &Invoice{ 295 Net: net, 296 PaymentHash: &paymentHash, 297 Timestamp: timestamp, 298 } 299 300 for _, option := range options { 301 option(invoice) 302 } 303 304 // If no features were set, we'll populate an empty feature vector. 305 if invoice.Features == nil { 306 invoice.Features = lnwire.NewFeatureVector( 307 nil, lnwire.Features, 308 ) 309 } 310 311 if err := validateInvoice(invoice); err != nil { 312 return nil, err 313 } 314 315 return invoice, nil 316 } 317 318 // Expiry returns the expiry time for this invoice. If expiry time is not set 319 // explicitly, the default 3600 second expiry will be returned. 320 func (invoice *Invoice) Expiry() time.Duration { 321 if invoice.expiry != nil { 322 return *invoice.expiry 323 } 324 325 // If no expiry is set for this invoice, default is 3600 seconds. 326 return DefaultInvoiceExpiry 327 } 328 329 // MinFinalCLTVExpiry returns the minimum final CLTV expiry delta as specified 330 // by the creator of the invoice. This value specifies the delta between the 331 // current height and the expiry height of the HTLC extended in the last hop. 332 func (invoice *Invoice) MinFinalCLTVExpiry() uint64 { 333 if invoice.minFinalCLTVExpiry != nil { 334 return *invoice.minFinalCLTVExpiry 335 } 336 337 return DefaultAssumedFinalCLTVDelta 338 } 339 340 // validateInvoice does a sanity check of the provided Invoice, making sure it 341 // has all the necessary fields set for it to be considered valid by BOLT-0011. 342 func validateInvoice(invoice *Invoice) error { 343 // The net must be set. 344 if invoice.Net == nil { 345 return fmt.Errorf("net params not set") 346 } 347 348 // The invoice must contain a payment hash. 349 if invoice.PaymentHash == nil { 350 return fmt.Errorf("no payment hash found") 351 } 352 353 // Either Description or DescriptionHash must be set, not both. 354 if invoice.Description != nil && invoice.DescriptionHash != nil { 355 return fmt.Errorf("both description and description hash set") 356 } 357 if invoice.Description == nil && invoice.DescriptionHash == nil { 358 return fmt.Errorf("neither description nor description hash set") 359 } 360 361 // Check that we support the field lengths. 362 if len(invoice.PaymentHash) != 32 { 363 return fmt.Errorf("unsupported payment hash length: %d", 364 len(invoice.PaymentHash)) 365 } 366 367 if invoice.DescriptionHash != nil && len(invoice.DescriptionHash) != 32 { 368 return fmt.Errorf("unsupported description hash length: %d", 369 len(invoice.DescriptionHash)) 370 } 371 372 if invoice.Destination != nil && 373 len(invoice.Destination.SerializeCompressed()) != 33 { 374 return fmt.Errorf("unsupported pubkey length: %d", 375 len(invoice.Destination.SerializeCompressed())) 376 } 377 378 // Ensure that all invoices have feature vectors. 379 if invoice.Features == nil { 380 return fmt.Errorf("missing feature vector") 381 } 382 383 return nil 384 }