From 234b9a3d971cf5619c3cde14165594c267304afb Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 16 Nov 2022 02:03:16 +0800 Subject: [PATCH] channeldb+lnd: rpc server filters invoices by date --- channeldb/invoice_test.go | 113 ++++++++++++++++++++++++++++++++++++++ channeldb/invoices.go | 32 ++++++++++- rpcserver.go | 21 +++++++ 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index 59faf329c..1ab459170 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -1090,6 +1090,9 @@ func TestQueryInvoices(t *testing.T) { for i := 1; i <= numInvoices; i++ { amt := lnwire.MilliSatoshi(i) invoice, err := randInvoice(amt) + invoice.CreationDate = invoice.CreationDate.Add( + time.Duration(i-1) * time.Second, + ) if err != nil { t.Fatalf("unable to create invoice: %v", err) } @@ -1337,6 +1340,116 @@ func TestQueryInvoices(t *testing.T) { }, expected: invoices, }, + // Fetch invoices <= 25 by creation date. + { + query: InvoiceQuery{ + NumMaxInvoices: numInvoices, + CreationDateEnd: time.Unix(25, 0), + }, + expected: invoices[:25], + }, + // Fetch invoices >= 26 creation date. + { + query: InvoiceQuery{ + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(26, 0), + }, + expected: invoices[25:], + }, + // Fetch pending invoices <= 25 by creation date. + { + query: InvoiceQuery{ + PendingOnly: true, + NumMaxInvoices: numInvoices, + CreationDateEnd: time.Unix(25, 0), + }, + expected: pendingInvoices[:13], + }, + // Fetch pending invoices >= 26 creation date. + { + query: InvoiceQuery{ + PendingOnly: true, + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(26, 0), + }, + expected: pendingInvoices[13:], + }, + // Fetch pending invoices with offset and end creation date. + { + query: InvoiceQuery{ + IndexOffset: 20, + NumMaxInvoices: numInvoices, + CreationDateEnd: time.Unix(30, 0), + }, + // Since we're skipping to invoice 20 and iterating + // to invoice 30, we'll expect those invoices. + expected: invoices[20:30], + }, + // Fetch pending invoices with offset and start creation date + // in reversed order. + { + query: InvoiceQuery{ + IndexOffset: 21, + Reversed: true, + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(11, 0), + }, + // Since we're skipping to invoice 20 and iterating + // backward to invoice 10, we'll expect those invoices. + expected: invoices[10:20], + }, + // Fetch invoices with start and end creation date. + { + query: InvoiceQuery{ + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(11, 0), + CreationDateEnd: time.Unix(20, 0), + }, + expected: invoices[10:20], + }, + // Fetch pending invoices with start and end creation date. + { + query: InvoiceQuery{ + PendingOnly: true, + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(11, 0), + CreationDateEnd: time.Unix(20, 0), + }, + expected: pendingInvoices[5:10], + }, + // Fetch invoices with start and end creation date in reverse + // order. + { + query: InvoiceQuery{ + Reversed: true, + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(11, 0), + CreationDateEnd: time.Unix(20, 0), + }, + expected: invoices[10:20], + }, + // Fetch pending invoices with start and end creation date in + // reverse order. + { + query: InvoiceQuery{ + PendingOnly: true, + Reversed: true, + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(11, 0), + CreationDateEnd: time.Unix(20, 0), + }, + expected: pendingInvoices[5:10], + }, + // Fetch invoices with a start date greater than end date + // should result in an empty slice. + { + query: InvoiceQuery{ + NumMaxInvoices: numInvoices, + CreationDateStart: time.Unix(20, 0), + CreationDateEnd: time.Unix(11, 0), + }, + expected: nil, + }, } for i, testCase := range testCases { diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 8f1a3ec0d..318011a4e 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -1279,6 +1279,14 @@ type InvoiceQuery struct { // Reversed, if set, indicates that the invoices returned should start // from the IndexOffset and go backwards. Reversed bool + + // CreationDateStart, if set, filters out all invoices with a creation + // date greater than or euqal to it. + CreationDateStart time.Time + + // CreationDateEnd, if set, filters out all invoices with a creation + // date less than or euqal to it. + CreationDateEnd time.Time } // InvoiceSlice is the response to a invoice query. It includes the original @@ -1309,7 +1317,11 @@ type InvoiceSlice struct { // QueryInvoices allows a caller to query the invoice database for invoices // within the specified add index range. func (d *DB) QueryInvoices(q InvoiceQuery) (InvoiceSlice, error) { - var resp InvoiceSlice + var ( + resp InvoiceSlice + startDateSet = !q.CreationDateStart.IsZero() + endDateSet = !q.CreationDateEnd.IsZero() + ) err := kvdb.View(d, func(tx kvdb.RTx) error { // If the bucket wasn't found, then there aren't any invoices @@ -1349,6 +1361,24 @@ func (d *DB) QueryInvoices(q InvoiceQuery) (InvoiceSlice, error) { return false, nil } + // Skip any invoices that were created before the + // specified time. + if startDateSet && invoice.CreationDate.Before( + q.CreationDateStart, + ) { + + return false, nil + } + + // Skip any invoices that were created after the + // specified time. + if endDateSet && invoice.CreationDate.After( + q.CreationDateEnd, + ) { + + return false, nil + } + // At this point, we've exhausted the offset, so we'll // begin collecting invoices found within the range. resp.Invoices = append(resp.Invoices, invoice) diff --git a/rpcserver.go b/rpcserver.go index 847e9564c..fb3bcc0c3 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -5516,6 +5516,16 @@ func (r *rpcServer) ListInvoices(ctx context.Context, req.NumMaxInvoices = 100 } + // If both dates are set, we check that the start date is less than the + // end date, otherwise we'll get an empty result. + if req.CreationDateStart != 0 && req.CreationDateEnd != 0 { + if req.CreationDateStart >= req.CreationDateEnd { + return nil, fmt.Errorf("start date(%v) must be before "+ + "end date(%v)", req.CreationDateStart, + req.CreationDateEnd) + } + } + // Next, we'll map the proto request into a format that is understood by // the database. q := channeldb.InvoiceQuery{ @@ -5524,6 +5534,17 @@ func (r *rpcServer) ListInvoices(ctx context.Context, PendingOnly: req.PendingOnly, Reversed: req.Reversed, } + + // Attach the start date if set. + if req.CreationDateStart != 0 { + q.CreationDateStart = time.Unix(int64(req.CreationDateStart), 0) + } + + // Attach the end date if set. + if req.CreationDateEnd != 0 { + q.CreationDateEnd = time.Unix(int64(req.CreationDateEnd), 0) + } + invoiceSlice, err := r.server.miscDB.QueryInvoices(q) if err != nil { return nil, fmt.Errorf("unable to query invoices: %v", err)