From 8dcfeeaef507ebe02c60e34022f614a65a18b050 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 26 Jun 2018 16:54:50 -0700 Subject: [PATCH] channeldb: explicitly store the FinalCltvDelta within the ContractTerm struct In this commit, we move to explicitly storing a bit more information within the invoice. Currently this information is already stored in the payment request, but by storing it at this level, callers that may not be in the state to fully decode a payment request can obtain this data. We avoid a database migration by appending this data to the end of an invoice. When decoding, we'll try to read out this extra information, and simply return what we have if it isn't found. --- channeldb/invoice_test.go | 3 +++ channeldb/invoices.go | 24 +++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) 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 }