Skip to content

Commit

Permalink
listinvoices: support listing by local offer_id.
Browse files Browse the repository at this point in the history
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Jul 2, 2021
1 parent 40e8a20 commit a5a9460
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 18 deletions.
7 changes: 4 additions & 3 deletions contrib/pyln-client/pyln/client/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
8 changes: 4 additions & 4 deletions doc/lightning-listinvoices.7

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions doc/lightning-listinvoices.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----------
Expand All @@ -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
------------
Expand Down
24 changes: 17 additions & 7 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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. */
Expand All @@ -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);
}
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion tests/test_invoices.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a5a9460

Please sign in to comment.