diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index d67ff2a48d8..0929147c00e 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -87,8 +87,9 @@ func TestInvoiceWorkflow(t *testing.T) { spew.Sdump(fakeInvoice), spew.Sdump(dbInvoice)) } - // Settle the invoice, the versin retreived from the database should - // now have the settled bit toggle to true. + // Settle the invoice, the version retrieved from the database should + // now have the settled bit toggle to true and a non-default + // SettledDate if err := db.SettleInvoice(paymentHash); err != nil { t.Fatalf("unable to settle invoice: %v", err) } @@ -100,6 +101,10 @@ func TestInvoiceWorkflow(t *testing.T) { t.Fatalf("invoice should now be settled but isn't") } + if dbInvoice2.SettleDate.IsZero() { + t.Fatalf("invoice should have non-zero SettledDate but isn't") + } + // Attempt to insert generated above again, this should fail as // duplicates are rejected by the processing logic. if err := db.AddInvoice(fakeInvoice); err != ErrDuplicateInvoice { diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 99a9caec5ae..c94d1e9c28a 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -100,6 +100,9 @@ type Invoice struct { // CreationDate is the exact time the invoice was created. CreationDate time.Time + // SettleDate is the exact time the invoice was settled. + SettleDate time.Time + // Terms are the contractual payment terms of the invoice. Once // all the terms have been satisfied by the payer, then the invoice can // be considered fully fulfilled. @@ -330,10 +333,20 @@ func serializeInvoice(w io.Writer, i *Invoice) error { if err != nil { return err } + if err := wire.WriteVarBytes(w, 0, birthBytes); err != nil { return err } + settleBytes, err := i.SettleDate.MarshalBinary() + if err != nil { + return err + } + + if err := wire.WriteVarBytes(w, 0, settleBytes); err != nil { + return err + } + if _, err := w.Write(i.Terms.PaymentPreimage[:]); err != nil { return err } @@ -389,6 +402,14 @@ func deserializeInvoice(r io.Reader) (*Invoice, error) { return nil, err } + settledBytes, err := wire.ReadVarBytes(r, 0, 300, "settled") + if err != nil { + return nil, err + } + if err := invoice.SettleDate.UnmarshalBinary(settledBytes); err != nil { + return nil, err + } + if _, err := io.ReadFull(r, invoice.Terms.PaymentPreimage[:]); err != nil { return nil, err } @@ -412,13 +433,12 @@ func settleInvoice(invoices *bolt.Bucket, invoiceNum []byte) error { } invoice.Terms.Settled = true + invoice.SettleDate = time.Now() var buf bytes.Buffer if err := serializeInvoice(&buf, invoice); err != nil { return nil } - // TODO(roasbeef): add timestamp - return invoices.Put(invoiceNum[:], buf.Bytes()) } diff --git a/lnd_test.go b/lnd_test.go index 563ec40d7f7..72787a934ed 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -2262,10 +2262,14 @@ func testInvoiceSubscriptions(net *networkHarness, t *harnessTest) { } // The invoice update should exactly match the invoice created - // above, but should now be settled. + // above, but should now be settled and have SettleDate if !invoiceUpdate.Settled { t.Fatalf("invoice not settled but shoudl be") } + if invoiceUpdate.SettleDate == 0 { + t.Fatalf("invoice should have non zero settle date, but doesn't") + } + if !bytes.Equal(invoiceUpdate.RPreimage, invoice.RPreimage) { t.Fatalf("payment preimages don't match: expected %v, got %v", invoice.RPreimage, invoiceUpdate.RPreimage) diff --git a/rpcserver.go b/rpcserver.go index 7e243b58592..229f0c14b96 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2119,6 +2119,11 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) { fallbackAddr = decoded.FallbackAddr.String() } + settleDate := int64(0) + if !invoice.SettleDate.IsZero() { + settleDate = invoice.SettleDate.Unix() + } + // Expiry time will default to 3600 seconds if not specified // explicitly. expiry := int64(decoded.Expiry().Seconds()) @@ -2136,6 +2141,7 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) { RPreimage: preimage[:], Value: int64(satAmt), CreationDate: invoice.CreationDate.Unix(), + SettleDate: settleDate, Settled: invoice.Terms.Settled, PaymentRequest: paymentRequest, DescriptionHash: descHash,