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  }