From a5a9460521bf9eb5face5105e35966324cbd0224 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 2 Jul 2021 09:41:35 +0930 Subject: [PATCH] listinvoices: support listing by local offer_id. Signed-off-by: Rusty Russell --- contrib/pyln-client/pyln/client/lightning.py | 7 +++--- doc/lightning-listinvoices.7 | 8 +++---- doc/lightning-listinvoices.7.md | 6 ++--- lightningd/invoice.c | 24 ++++++++++++++------ tests/test_invoices.py | 3 ++- tests/test_pay.py | 3 +++ 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index a2bcf4ad5764..e83c15e4ba8f 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -890,17 +890,18 @@ def listtransactions(self): """ return self.call("listtransactions") - def listinvoices(self, label=None, payment_hash=None, invstring=None): + def listinvoices(self, label=None, payment_hash=None, invstring=None, offer_id=None): """Query invoices - Show invoice matching {label} {payment_hash} or {invstring} (or - all, if no filters are present). + Show invoice matching {label}, {payment_hash}, {invstring} or {offer_id} + (or all, if no filters are present). """ payload = { "label": label, "payment_hash": payment_hash, "invstring": invstring, + "offer_id": offer_id, } return self.call("listinvoices", payload) diff --git a/doc/lightning-listinvoices.7 b/doc/lightning-listinvoices.7 index d77d5b792306..52020c2ebfe0 100644 --- a/doc/lightning-listinvoices.7 +++ b/doc/lightning-listinvoices.7 @@ -3,7 +3,7 @@ lightning-listinvoices - Command for querying invoice status .SH SYNOPSIS -\fBlistinvoices\fR [\fIlabel\fR] [\fIinvstring\fR] [\fIpayment_hash\fR] +\fBlistinvoices\fR [\fIlabel\fR] [\fIinvstring\fR] [\fIpayment_hash\fR] [\fIoffer_id\fR] .SH DESCRIPTION @@ -13,8 +13,8 @@ if it exists, or the status of all invoices if given no argument\. A specific invoice can be queried by providing either the \fBlabel\fR provided when creating the invoice, the \fBinvstring\fR string representing -the invoice, or the \fBpayment_hash\fR of the invoice\. Only one of the -query parameters can be used at once\. +the invoice, the \fBpayment_hash\fR of the invoice, or the local \fBoffer_id\fR +this invoice was issued for\. Only one of the query parameters can be used at once\. .SH RETURN VALUE @@ -69,4 +69,4 @@ Rusty Russell \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:39640db51e7edd166966ff0f68bc1448328016fa23b56cf2e6e93961e62f458a +\" SHA256STAMP:37d1f6f0b6160b9aa4944f730bec6b04469a9f9a293b59cf8f6663d37073da9c diff --git a/doc/lightning-listinvoices.7.md b/doc/lightning-listinvoices.7.md index 48cc73b9abb2..a6a6f0e680a4 100644 --- a/doc/lightning-listinvoices.7.md +++ b/doc/lightning-listinvoices.7.md @@ -4,7 +4,7 @@ lightning-listinvoices -- Command for querying invoice status SYNOPSIS -------- -**listinvoices** \[*label*\] \[*invstring*\] \[*payment_hash*\] +**listinvoices** \[*label*\] \[*invstring*\] \[*payment_hash*\] \[*offer_id*\] DESCRIPTION ----------- @@ -14,8 +14,8 @@ if it exists, or the status of all invoices if given no argument. A specific invoice can be queried by providing either the `label` provided when creating the invoice, the `invstring` string representing -the invoice, or the `payment_hash` of the invoice. Only one of the -query parameters can be used at once. +the invoice, the `payment_hash` of the invoice, or the local `offer_id` +this invoice was issued for. Only one of the query parameters can be used at once. RETURN VALUE ------------ diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 11f97fe8170a..67d335154d56 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -1277,7 +1277,8 @@ AUTODATA(json_command, &invoice_command); static void json_add_invoices(struct json_stream *response, struct wallet *wallet, const struct json_escape *label, - const struct sha256 *payment_hash) + const struct sha256 *payment_hash, + const struct sha256 *local_offer_id) { struct invoice_iterator it; const struct invoice_details *details; @@ -1307,6 +1308,13 @@ static void json_add_invoices(struct json_stream *response, while (wallet_invoice_iterate(wallet, &it)) { details = wallet_invoice_iterator_deref(response, wallet, &it); + /* FIXME: db can filter this better! */ + if (local_offer_id) { + if (!details->local_offer_id + || !sha256_eq(local_offer_id, + details->local_offer_id)) + continue; + } json_object_start(response, NULL); json_add_invoice(response, details); json_object_end(response); @@ -1323,21 +1331,23 @@ static struct command_result *json_listinvoices(struct command *cmd, struct json_stream *response; struct wallet *wallet = cmd->ld->wallet; const char *invstring; - struct sha256 *payment_hash; + struct sha256 *payment_hash, *offer_id; char *fail; if (!param(cmd, buffer, params, p_opt("label", param_label, &label), p_opt("invstring", param_string, &invstring), p_opt("payment_hash", param_sha256, &payment_hash), + p_opt("offer_id", param_sha256, &offer_id), NULL)) return command_param_failed(); - if ((label && invstring) || (label && payment_hash) || - (invstring && payment_hash)) { + /* Yeah, I wasn't sure about this style either. It's curt though! */ + if (!!label + !!invstring + !!payment_hash + !!offer_id > 1) { return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Can only specify one of" - " {label}, {invstring} or {payment_hash}"); + " {label}, {invstring}, {payment_hash}" + " or {offer_id}"); } /* Extract the payment_hash from the invoice. */ @@ -1363,7 +1373,7 @@ static struct command_result *json_listinvoices(struct command *cmd, response = json_stream_success(cmd); json_array_start(response, "invoices"); - json_add_invoices(response, wallet, label, payment_hash); + json_add_invoices(response, wallet, label, payment_hash, offer_id); json_array_end(response); return command_success(cmd, response); } @@ -1372,7 +1382,7 @@ static const struct json_command listinvoices_command = { "listinvoices", "payment", json_listinvoices, - "Show invoice matching {label}, {invstring} or {payment_hash} (or all, if " + "Show invoice matching {label}, {invstring}, {payment_hash} or {offerid} (or all, if " "no query parameter specified)" }; AUTODATA(json_command, &listinvoices_command); diff --git a/tests/test_invoices.py b/tests/test_invoices.py index 1d199d1d9ca9..59b8dc794dc8 100644 --- a/tests/test_invoices.py +++ b/tests/test_invoices.py @@ -702,7 +702,7 @@ def match(node, query, invoice): for q in queries: with pytest.raises( RpcError, - match=r'Can only specify one of {label}, {invstring} or {payment_hash}' + match=r'Can only specify one of {label}, {invstring}, {payment_hash} or {offer_id}' ): l1.rpc.listinvoices(**q) @@ -711,6 +711,7 @@ def match(node, query, invoice): {'label': 'doesnt exist'}, {'payment_hash': 'AA' * 32}, {'invstring': 'lnbcrt420p1p0lfrl6pp5w4zsagnfqu08s93rd44z93s8tt920hd9jec2yph969wluwkzrwpqdq8v3jhxccxqyjw5qcqp9sp52kw0kp75f6v2jusd8nsg2nfmdr82pqj0gf3jc8tqp7a2j48rzweq9qy9qsqtlu8eslmd4yxqrtrz75v8vmqrwknnk64sm79cj4asxhgndnj22r3g2a6axdvfdkhw966zw63cy3uzzn5hxad9ja8amqpp3wputl3ffcpallm2g'}, + {'offer_id': 'AA' * 32}, ] for q in queries: diff --git a/tests/test_pay.py b/tests/test_pay.py index 27403effe469..997a588de1ed 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -4009,6 +4009,9 @@ def test_fetchinvoice(node_factory, bitcoind): assert 'payer_note' not in only_one(l3.rpc.call('listinvoices', {'invstring': inv1['invoice']})['invoices']) assert only_one(l3.rpc.call('listinvoices', {'invstring': inv2['invoice']})['invoices'])['payer_note'] == 'Thanks for the fish!' + # BTW, test listinvoices-by-offer_id: + assert len(l3.rpc.listinvoices(offer_id=offer1['offer_id'])['invoices']) == 2 + # We can also set the amount explicitly, to tip. inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'msatoshi': 3}) assert l1.rpc.call('decode', [inv1['invoice']])['amount_msat'] == 3