diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index 0a04e65b..edafc2e0 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -3,6 +3,7 @@ package channeldb import ( "crypto/rand" "crypto/sha256" + prand "math/rand" "reflect" "testing" "time" @@ -24,6 +25,7 @@ func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) { Terms: ContractTerm{ PaymentPreimage: pre, Value: value, + FinalCltvDelta: uint16(prand.Int31()), }, } i.Memo = []byte("memo") @@ -66,6 +68,7 @@ func TestInvoiceWorkflow(t *testing.T) { fakeInvoice.PaymentRequest = []byte("") copy(fakeInvoice.Terms.PaymentPreimage[:], rev[:]) fakeInvoice.Terms.Value = lnwire.NewMSatFromSatoshis(10000) + fakeInvoice.Terms.FinalCltvDelta = uint16(prand.Int31()) // Add the invoice to the database, this should succeed as there aren't // any existing invoices within the database with the same payment diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 8d2c585f..810f04f6 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -68,6 +68,13 @@ type ContractTerm struct { // Settled indicates if this particular contract term has been fully // settled by the payer. Settled bool + + // FinalCltvDelta is the lower bound of a delta from the current height + // that the HTLC that wishes to settle this invoice MUST carry. This + // allows the receiver to specify the time window that should be + // available for them to sweep the HTLC on-chain if that becomes + // necessary. + FinalCltvDelta uint16 } // Invoice is a payment invoice generated by a payee in order to request @@ -79,8 +86,7 @@ type ContractTerm struct { // invoices are never deleted from the database, instead a bit is toggled // denoting the invoice has been fully settled. Within the database, all // invoices must have a unique payment hash which is generated by taking the -// sha256 of the payment -// preimage. +// sha256 of the payment preimage. type Invoice struct { // Memo is an optional memo to be stored along side an invoice. The // memo may contain further details pertaining to the invoice itself, @@ -361,7 +367,7 @@ func serializeInvoice(w io.Writer, i *Invoice) error { return err } - return nil + return binary.Write(w, byteOrder, i.Terms.FinalCltvDelta) } func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (*Invoice, error) { @@ -423,6 +429,18 @@ func deserializeInvoice(r io.Reader) (*Invoice, error) { return nil, err } + // Before we return with the current invoice, we'll check to see if + // there's still enough space in the buffer to read out the final ctlv + // delta. We'll get an EOF error if there isn't any thing else + // lingering in the buffer. + err = binary.Read(r, byteOrder, &invoice.Terms.FinalCltvDelta) + if err != nil && err != io.EOF { + // If we got a non-eof error, then we know there's an actually + // issue. Otherwise, it may have been the case that this + // summary didn't have the set of optional fields. + return nil, err + } + return invoice, nil }