github.com/decred/dcrlnd@v0.7.6/channeldb/migration12/invoices.go (about)

     1  package migration12
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  	"time"
     8  
     9  	"github.com/decred/dcrd/wire"
    10  	lnwire "github.com/decred/dcrlnd/channeldb/migration/lnwire21"
    11  	"github.com/decred/dcrlnd/lntypes"
    12  	"github.com/decred/dcrlnd/tlv"
    13  )
    14  
    15  const (
    16  	// MaxMemoSize is maximum size of the memo field within invoices stored
    17  	// in the database.
    18  	MaxMemoSize = 1024
    19  
    20  	// maxReceiptSize is the maximum size of the payment receipt stored
    21  	// within the database along side incoming/outgoing invoices.
    22  	maxReceiptSize = 1024
    23  
    24  	// MaxPaymentRequestSize is the max size of a payment request for
    25  	// this invoice.
    26  	// TODO(halseth): determine the max length payment request when field
    27  	// lengths are final.
    28  	MaxPaymentRequestSize = 4096
    29  
    30  	memoType        tlv.Type = 0
    31  	payReqType      tlv.Type = 1
    32  	createTimeType  tlv.Type = 2
    33  	settleTimeType  tlv.Type = 3
    34  	addIndexType    tlv.Type = 4
    35  	settleIndexType tlv.Type = 5
    36  	preimageType    tlv.Type = 6
    37  	valueType       tlv.Type = 7
    38  	cltvDeltaType   tlv.Type = 8
    39  	expiryType      tlv.Type = 9
    40  	paymentAddrType tlv.Type = 10
    41  	featuresType    tlv.Type = 11
    42  	invStateType    tlv.Type = 12
    43  	amtPaidType     tlv.Type = 13
    44  )
    45  
    46  var (
    47  	// invoiceBucket is the name of the bucket within the database that
    48  	// stores all data related to invoices no matter their final state.
    49  	// Within the invoice bucket, each invoice is keyed by its invoice ID
    50  	// which is a monotonically increasing uint32.
    51  	invoiceBucket = []byte("invoices")
    52  
    53  	// Big endian is the preferred byte order, due to cursor scans over
    54  	// integer keys iterating in order.
    55  	byteOrder = binary.BigEndian
    56  )
    57  
    58  // ContractState describes the state the invoice is in.
    59  type ContractState uint8
    60  
    61  // ContractTerm is a companion struct to the Invoice struct. This struct houses
    62  // the necessary conditions required before the invoice can be considered fully
    63  // settled by the payee.
    64  type ContractTerm struct {
    65  	// PaymentPreimage is the preimage which is to be revealed in the
    66  	// occasion that an HTLC paying to the hash of this preimage is
    67  	// extended.
    68  	PaymentPreimage lntypes.Preimage
    69  
    70  	// Value is the expected amount of milli-satoshis to be paid to an HTLC
    71  	// which can be satisfied by the above preimage.
    72  	Value lnwire.MilliAtom
    73  
    74  	// State describes the state the invoice is in.
    75  	State ContractState
    76  
    77  	// PaymentAddr is a randomly generated value include in the MPP record
    78  	// by the sender to prevent probing of the receiver.
    79  	PaymentAddr [32]byte
    80  
    81  	// Features is the feature vectors advertised on the payment request.
    82  	Features *lnwire.FeatureVector
    83  }
    84  
    85  // Invoice is a payment invoice generated by a payee in order to request
    86  // payment for some good or service. The inclusion of invoices within Lightning
    87  // creates a payment work flow for merchants very similar to that of the
    88  // existing financial system within PayPal, etc.  Invoices are added to the
    89  // database when a payment is requested, then can be settled manually once the
    90  // payment is received at the upper layer. For record keeping purposes,
    91  // invoices are never deleted from the database, instead a bit is toggled
    92  // denoting the invoice has been fully settled. Within the database, all
    93  // invoices must have a unique payment hash which is generated by taking the
    94  // sha256 of the payment preimage.
    95  type Invoice struct {
    96  	// Memo is an optional memo to be stored along side an invoice.  The
    97  	// memo may contain further details pertaining to the invoice itself,
    98  	// or any other message which fits within the size constraints.
    99  	Memo []byte
   100  
   101  	// PaymentRequest is an optional field where a payment request created
   102  	// for this invoice can be stored.
   103  	PaymentRequest []byte
   104  
   105  	// FinalCltvDelta is the minimum required number of blocks before htlc
   106  	// expiry when the invoice is accepted.
   107  	FinalCltvDelta int32
   108  
   109  	// Expiry defines how long after creation this invoice should expire.
   110  	Expiry time.Duration
   111  
   112  	// CreationDate is the exact time the invoice was created.
   113  	CreationDate time.Time
   114  
   115  	// SettleDate is the exact time the invoice was settled.
   116  	SettleDate time.Time
   117  
   118  	// Terms are the contractual payment terms of the invoice. Once all the
   119  	// terms have been satisfied by the payer, then the invoice can be
   120  	// considered fully fulfilled.
   121  	//
   122  	// TODO(roasbeef): later allow for multiple terms to fulfill the final
   123  	// invoice: payment fragmentation, etc.
   124  	Terms ContractTerm
   125  
   126  	// AddIndex is an auto-incrementing integer that acts as a
   127  	// monotonically increasing sequence number for all invoices created.
   128  	// Clients can then use this field as a "checkpoint" of sorts when
   129  	// implementing a streaming RPC to notify consumers of instances where
   130  	// an invoice has been added before they re-connected.
   131  	//
   132  	// NOTE: This index starts at 1.
   133  	AddIndex uint64
   134  
   135  	// SettleIndex is an auto-incrementing integer that acts as a
   136  	// monotonically increasing sequence number for all settled invoices.
   137  	// Clients can then use this field as a "checkpoint" of sorts when
   138  	// implementing a streaming RPC to notify consumers of instances where
   139  	// an invoice has been settled before they re-connected.
   140  	//
   141  	// NOTE: This index starts at 1.
   142  	SettleIndex uint64
   143  
   144  	// AmtPaid is the final amount that we ultimately accepted for pay for
   145  	// this invoice. We specify this value independently as it's possible
   146  	// that the invoice originally didn't specify an amount, or the sender
   147  	// overpaid.
   148  	AmtPaid lnwire.MilliAtom
   149  
   150  	// Htlcs records all htlcs that paid to this invoice. Some of these
   151  	// htlcs may have been marked as canceled.
   152  	Htlcs []byte
   153  }
   154  
   155  // LegacyDeserializeInvoice decodes an invoice from the passed io.Reader using
   156  // the pre-TLV serialization.
   157  func LegacyDeserializeInvoice(r io.Reader) (Invoice, error) {
   158  	var err error
   159  	invoice := Invoice{}
   160  
   161  	// TODO(roasbeef): use read full everywhere
   162  	invoice.Memo, err = wire.ReadVarBytes(r, 0, MaxMemoSize, "")
   163  	if err != nil {
   164  		return invoice, err
   165  	}
   166  	_, err = wire.ReadVarBytes(r, 0, maxReceiptSize, "")
   167  	if err != nil {
   168  		return invoice, err
   169  	}
   170  
   171  	invoice.PaymentRequest, err = wire.ReadVarBytes(r, 0, MaxPaymentRequestSize, "")
   172  	if err != nil {
   173  		return invoice, err
   174  	}
   175  
   176  	if err := binary.Read(r, byteOrder, &invoice.FinalCltvDelta); err != nil {
   177  		return invoice, err
   178  	}
   179  
   180  	var expiry int64
   181  	if err := binary.Read(r, byteOrder, &expiry); err != nil {
   182  		return invoice, err
   183  	}
   184  	invoice.Expiry = time.Duration(expiry)
   185  
   186  	birthBytes, err := wire.ReadVarBytes(r, 0, 300, "birth")
   187  	if err != nil {
   188  		return invoice, err
   189  	}
   190  	if err := invoice.CreationDate.UnmarshalBinary(birthBytes); err != nil {
   191  		return invoice, err
   192  	}
   193  
   194  	settledBytes, err := wire.ReadVarBytes(r, 0, 300, "settled")
   195  	if err != nil {
   196  		return invoice, err
   197  	}
   198  	if err := invoice.SettleDate.UnmarshalBinary(settledBytes); err != nil {
   199  		return invoice, err
   200  	}
   201  
   202  	if _, err := io.ReadFull(r, invoice.Terms.PaymentPreimage[:]); err != nil {
   203  		return invoice, err
   204  	}
   205  	var scratch [8]byte
   206  	if _, err := io.ReadFull(r, scratch[:]); err != nil {
   207  		return invoice, err
   208  	}
   209  	invoice.Terms.Value = lnwire.MilliAtom(byteOrder.Uint64(scratch[:]))
   210  
   211  	if err := binary.Read(r, byteOrder, &invoice.Terms.State); err != nil {
   212  		return invoice, err
   213  	}
   214  
   215  	if err := binary.Read(r, byteOrder, &invoice.AddIndex); err != nil {
   216  		return invoice, err
   217  	}
   218  	if err := binary.Read(r, byteOrder, &invoice.SettleIndex); err != nil {
   219  		return invoice, err
   220  	}
   221  	if err := binary.Read(r, byteOrder, &invoice.AmtPaid); err != nil {
   222  		return invoice, err
   223  	}
   224  
   225  	invoice.Htlcs, err = deserializeHtlcs(r)
   226  	if err != nil {
   227  		return Invoice{}, err
   228  	}
   229  
   230  	return invoice, nil
   231  }
   232  
   233  // deserializeHtlcs reads a list of invoice htlcs from a reader and returns it
   234  // as a flattened byte slice.
   235  func deserializeHtlcs(r io.Reader) ([]byte, error) {
   236  	var b bytes.Buffer
   237  	_, err := io.Copy(&b, r)
   238  	return b.Bytes(), err
   239  }
   240  
   241  // SerializeInvoice serializes an invoice to a writer.
   242  //
   243  // nolint: dupl
   244  func SerializeInvoice(w io.Writer, i *Invoice) error {
   245  	creationDateBytes, err := i.CreationDate.MarshalBinary()
   246  	if err != nil {
   247  		return err
   248  	}
   249  
   250  	settleDateBytes, err := i.SettleDate.MarshalBinary()
   251  	if err != nil {
   252  		return err
   253  	}
   254  
   255  	var fb bytes.Buffer
   256  	err = i.Terms.Features.EncodeBase256(&fb)
   257  	if err != nil {
   258  		return err
   259  	}
   260  	featureBytes := fb.Bytes()
   261  
   262  	preimage := [32]byte(i.Terms.PaymentPreimage)
   263  	value := uint64(i.Terms.Value)
   264  	cltvDelta := uint32(i.FinalCltvDelta)
   265  	expiry := uint64(i.Expiry)
   266  
   267  	amtPaid := uint64(i.AmtPaid)
   268  	state := uint8(i.Terms.State)
   269  
   270  	tlvStream, err := tlv.NewStream(
   271  		// Memo and payreq.
   272  		tlv.MakePrimitiveRecord(memoType, &i.Memo),
   273  		tlv.MakePrimitiveRecord(payReqType, &i.PaymentRequest),
   274  
   275  		// Add/settle metadata.
   276  		tlv.MakePrimitiveRecord(createTimeType, &creationDateBytes),
   277  		tlv.MakePrimitiveRecord(settleTimeType, &settleDateBytes),
   278  		tlv.MakePrimitiveRecord(addIndexType, &i.AddIndex),
   279  		tlv.MakePrimitiveRecord(settleIndexType, &i.SettleIndex),
   280  
   281  		// Terms.
   282  		tlv.MakePrimitiveRecord(preimageType, &preimage),
   283  		tlv.MakePrimitiveRecord(valueType, &value),
   284  		tlv.MakePrimitiveRecord(cltvDeltaType, &cltvDelta),
   285  		tlv.MakePrimitiveRecord(expiryType, &expiry),
   286  		tlv.MakePrimitiveRecord(paymentAddrType, &i.Terms.PaymentAddr),
   287  		tlv.MakePrimitiveRecord(featuresType, &featureBytes),
   288  
   289  		// Invoice state.
   290  		tlv.MakePrimitiveRecord(invStateType, &state),
   291  		tlv.MakePrimitiveRecord(amtPaidType, &amtPaid),
   292  	)
   293  	if err != nil {
   294  		return err
   295  	}
   296  
   297  	var b bytes.Buffer
   298  	if err = tlvStream.Encode(&b); err != nil {
   299  		return err
   300  	}
   301  
   302  	err = binary.Write(w, byteOrder, uint64(b.Len()))
   303  	if err != nil {
   304  		return err
   305  	}
   306  
   307  	if _, err = w.Write(b.Bytes()); err != nil {
   308  		return err
   309  	}
   310  
   311  	return serializeHtlcs(w, i.Htlcs)
   312  }
   313  
   314  // serializeHtlcs writes a serialized list of invoice htlcs into a writer.
   315  func serializeHtlcs(w io.Writer, htlcs []byte) error {
   316  	_, err := w.Write(htlcs)
   317  	return err
   318  }