delinvoice: allow desconly arg to only remove the description.

Means that field is now optional in JSON output.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: JSON-RPC: `delinvoice` has a new parameter `desconly` to remove description.
This commit is contained in:
Rusty Russell
2022-03-24 10:27:28 +10:30
parent ccaf04d268
commit aad4495f56
13 changed files with 110 additions and 36 deletions

View File

@@ -77,6 +77,7 @@ static const errcode_t INVOICE_WAIT_TIMED_OUT = 904;
static const errcode_t INVOICE_NOT_FOUND = 905; static const errcode_t INVOICE_NOT_FOUND = 905;
static const errcode_t INVOICE_STATUS_UNEXPECTED = 906; static const errcode_t INVOICE_STATUS_UNEXPECTED = 906;
static const errcode_t INVOICE_OFFER_INACTIVE = 907; static const errcode_t INVOICE_OFFER_INACTIVE = 907;
static const errcode_t INVOICE_NO_DESCRIPTION = 908;
/* Errors from HSM crypto operations. */ /* Errors from HSM crypto operations. */
static const errcode_t HSM_ECDH_FAILED = 800; static const errcode_t HSM_ECDH_FAILED = 800;

View File

@@ -566,13 +566,14 @@ class LightningRpc(UnixDomainSocketRpc):
} }
return self.call("delexpiredinvoice", payload) return self.call("delexpiredinvoice", payload)
def delinvoice(self, label, status): def delinvoice(self, label, status, desconly=None):
""" """
Delete unpaid invoice {label} with {status}. Delete unpaid invoice {label} with {status} (or, with {desconly} true, remove its description).
""" """
payload = { payload = {
"label": label, "label": label,
"status": status "status": status,
"desconly": desconly,
} }
return self.call("delinvoice", payload) return self.call("delinvoice", payload)

View File

@@ -1,20 +1,24 @@
lightning-delinvoice -- Command for removing an invoice lightning-delinvoice -- Command for removing an invoice (or just its description)
======================================================= =================================================================================
SYNOPSIS SYNOPSIS
-------- --------
**delinvoice** *label* *status* **delinvoice** *label* *status* [*desconly*]
DESCRIPTION DESCRIPTION
----------- -----------
The **delinvoice** RPC command removes an invoice with *status* as given The **delinvoice** RPC command removes an invoice with *status* as given
in **listinvoices**. in **listinvoices**, or with *desconly* set, removes its description.
The caller should be particularly aware of the error case caused by the The caller should be particularly aware of the error case caused by the
*status* changing just before this command is invoked! *status* changing just before this command is invoked!
If *desconly* is set, the invoice is not deleted, but has its
description removed (this can save space with very large descriptions,
as would be used with lightning-invoice(7) *deschashonly*.
RETURN VALUE RETURN VALUE
------------ ------------
@@ -55,6 +59,7 @@ The following errors may be reported:
*current_status* and *expected_status* fields. *current_status* and *expected_status* fields.
This is most likely due to the *status* of the invoice This is most likely due to the *status* of the invoice
changing just before this command is invoked. changing just before this command is invoked.
- 908: The invoice already has no description, and *desconly* was set.
AUTHOR AUTHOR
------ ------
@@ -73,4 +78,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning> Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:cd3b009a6ef0c220ca21c6d8e3a5716ca2080997016cf00a2e26defc03cfac73) [comment]: # ( SHA256STAMP:73d9097734e85d438de90844ab78bdd737e6df53620542887170c7564a86b90b)

View File

@@ -23,10 +23,10 @@ RETURN VALUE
[comment]: # (GENERATE-FROM-SCHEMA-START) [comment]: # (GENERATE-FROM-SCHEMA-START)
On success, an object containing **invoices** is returned. It is an array of objects, where each object contains: On success, an object containing **invoices** is returned. It is an array of objects, where each object contains:
- **label** (string): unique label supplied at invoice creation - **label** (string): unique label supplied at invoice creation
- **description** (string): description used in the invoice
- **payment_hash** (hex): the hash of the *payment_preimage* which will prove payment (always 64 characters) - **payment_hash** (hex): the hash of the *payment_preimage* which will prove payment (always 64 characters)
- **status** (string): Whether it's paid, unpaid or unpayable (one of "unpaid", "paid", "expired") - **status** (string): Whether it's paid, unpaid or unpayable (one of "unpaid", "paid", "expired")
- **expires_at** (u64): UNIX timestamp of when it will become / became unpayable - **expires_at** (u64): UNIX timestamp of when it will become / became unpayable
- **description** (string, optional): description used in the invoice
- **amount_msat** (msat, optional): the amount required to pay this invoice - **amount_msat** (msat, optional): the amount required to pay this invoice
- **bolt11** (string, optional): the BOLT11 string (always present unless *bolt12* is) - **bolt11** (string, optional): the BOLT11 string (always present unless *bolt12* is)
- **bolt12** (string, optional): the BOLT12 string (always present unless *bolt11* is) - **bolt12** (string, optional): the BOLT12 string (always present unless *bolt11* is)
@@ -56,4 +56,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning> Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:3dc5d5b8f7796d29e0d174d96e93915cbc7131b173a1547de022e021c55e8db6) [comment]: # ( SHA256STAMP:d1328ecc2a4e76ede8c9adc3a63d18ce36be305ddcee7cf717039f79642cfd41)

View File

@@ -13,7 +13,6 @@
"additionalProperties": true, "additionalProperties": true,
"required": [ "required": [
"label", "label",
"description",
"payment_hash", "payment_hash",
"status", "status",
"expires_at" "expires_at"

View File

@@ -1382,15 +1382,17 @@ static struct command_result *json_delinvoice(struct command *cmd,
const jsmntok_t *params) const jsmntok_t *params)
{ {
struct invoice i; struct invoice i;
const struct invoice_details *details; struct invoice_details *details;
struct json_stream *response; struct json_stream *response;
const char *status, *actual_status; const char *status, *actual_status;
struct json_escape *label; struct json_escape *label;
struct wallet *wallet = cmd->ld->wallet; struct wallet *wallet = cmd->ld->wallet;
bool *deldesc;
if (!param(cmd, buffer, params, if (!param(cmd, buffer, params,
p_req("label", param_label, &label), p_req("label", param_label, &label),
p_req("status", param_string, &status), p_req("status", param_string, &status),
p_opt_def("desconly", param_bool, &deldesc, false),
NULL)) NULL))
return command_param_failed(); return command_param_failed();
@@ -1415,12 +1417,27 @@ static struct command_result *json_delinvoice(struct command *cmd,
return command_failed(cmd, js); return command_failed(cmd, js);
} }
if (!wallet_invoice_delete(wallet, i)) { if (*deldesc) {
log_broken(cmd->ld->log, if (!details->description)
"Error attempting to remove invoice %"PRIu64, return command_fail(cmd, INVOICE_NO_DESCRIPTION,
i.id); "Invoice description already removed");
/* FIXME: allocate a generic DATABASE_ERROR code. */
return command_fail(cmd, LIGHTNINGD, "Database error"); if (!wallet_invoice_delete_description(wallet, i)) {
log_broken(cmd->ld->log,
"Error attempting to delete description of invoice %"PRIu64,
i.id);
/* FIXME: allocate a generic DATABASE_ERROR code. */
return command_fail(cmd, LIGHTNINGD, "Database error");
}
details->description = tal_free(details->description);
} else {
if (!wallet_invoice_delete(wallet, i)) {
log_broken(cmd->ld->log,
"Error attempting to remove invoice %"PRIu64,
i.id);
/* FIXME: allocate a generic DATABASE_ERROR code. */
return command_fail(cmd, LIGHTNINGD, "Database error");
}
} }
response = json_stream_success(cmd); response = json_stream_success(cmd);

View File

@@ -753,14 +753,18 @@ bool wallet_invoice_create(struct wallet *wallet UNNEEDED,
bool wallet_invoice_delete(struct wallet *wallet UNNEEDED, bool wallet_invoice_delete(struct wallet *wallet UNNEEDED,
struct invoice invoice UNNEEDED) struct invoice invoice UNNEEDED)
{ fprintf(stderr, "wallet_invoice_delete called!\n"); abort(); } { fprintf(stderr, "wallet_invoice_delete called!\n"); abort(); }
/* Generated stub for wallet_invoice_delete_description */
bool wallet_invoice_delete_description(struct wallet *wallet UNNEEDED,
struct invoice invoice UNNEEDED)
{ fprintf(stderr, "wallet_invoice_delete_description called!\n"); abort(); }
/* Generated stub for wallet_invoice_delete_expired */ /* Generated stub for wallet_invoice_delete_expired */
void wallet_invoice_delete_expired(struct wallet *wallet UNNEEDED, void wallet_invoice_delete_expired(struct wallet *wallet UNNEEDED,
u64 max_expiry_time UNNEEDED) u64 max_expiry_time UNNEEDED)
{ fprintf(stderr, "wallet_invoice_delete_expired called!\n"); abort(); } { fprintf(stderr, "wallet_invoice_delete_expired called!\n"); abort(); }
/* Generated stub for wallet_invoice_details */ /* Generated stub for wallet_invoice_details */
const struct invoice_details *wallet_invoice_details(const tal_t *ctx UNNEEDED, struct invoice_details *wallet_invoice_details(const tal_t *ctx UNNEEDED,
struct wallet *wallet UNNEEDED, struct wallet *wallet UNNEEDED,
struct invoice invoice UNNEEDED) struct invoice invoice UNNEEDED)
{ fprintf(stderr, "wallet_invoice_details called!\n"); abort(); } { fprintf(stderr, "wallet_invoice_details called!\n"); abort(); }
/* Generated stub for wallet_invoice_find_by_label */ /* Generated stub for wallet_invoice_find_by_label */
bool wallet_invoice_find_by_label(struct wallet *wallet UNNEEDED, bool wallet_invoice_find_by_label(struct wallet *wallet UNNEEDED,

View File

@@ -733,3 +733,10 @@ def test_invoice_deschash(node_factory, chainparams):
# Make sure we can pay it! # Make sure we can pay it!
l1.rpc.pay(inv['bolt11']) l1.rpc.pay(inv['bolt11'])
# Try removing description.
l2.rpc.delinvoice('label', "paid", desconly=True)
assert 'description' not in only_one(l2.rpc.listinvoices()['invoices'])
with pytest.raises(RpcError, match=r'description already removed'):
l2.rpc.delinvoice('label', "paid", desconly=True)

View File

@@ -421,6 +421,23 @@ bool invoices_delete(struct invoices *invoices, struct invoice invoice)
return true; return true;
} }
bool invoices_delete_description(struct invoices *invoices, struct invoice invoice)
{
struct db_stmt *stmt;
int changes;
stmt = db_prepare_v2(invoices->db, SQL("UPDATE invoices"
" SET description = NULL"
" WHERE ID = ?;"));
db_bind_u64(stmt, 0, invoice.id);
db_exec_prepared_v2(stmt);
changes = db_count_changes(stmt);
tal_free(stmt);
return changes == 1;
}
void invoices_delete_expired(struct invoices *invoices, void invoices_delete_expired(struct invoices *invoices,
u64 max_expiry_time) u64 max_expiry_time)
{ {
@@ -648,9 +665,9 @@ void invoices_waitone(const tal_t *ctx,
false, invoice.id, cb, cbarg); false, invoice.id, cb, cbarg);
} }
const struct invoice_details *invoices_get_details(const tal_t *ctx, struct invoice_details *invoices_get_details(const tal_t *ctx,
struct invoices *invoices, struct invoices *invoices,
struct invoice invoice) struct invoice invoice)
{ {
struct db_stmt *stmt; struct db_stmt *stmt;
bool res; bool res;

View File

@@ -108,6 +108,17 @@ bool invoices_find_unpaid(struct invoices *invoices,
bool invoices_delete(struct invoices *invoices, bool invoices_delete(struct invoices *invoices,
struct invoice invoice); struct invoice invoice);
/**
* invoices_delete_description - Remove description from an invoice
*
* @invoices - the invoice handler.
* @invoice - the invoice to remove description from.
*
* Return false on failure.
*/
bool invoices_delete_description(struct invoices *invoices,
struct invoice invoice);
/** /**
* invoices_delete_expired - Delete all expired invoices * invoices_delete_expired - Delete all expired invoices
* with expiration time less than or equal to the given. * with expiration time less than or equal to the given.
@@ -213,8 +224,8 @@ void invoices_waitone(const tal_t *ctx,
* @invoice - the invoice to get details on. * @invoice - the invoice to get details on.
* @return pointer to the invoice details allocated off of `ctx`. * @return pointer to the invoice details allocated off of `ctx`.
*/ */
const struct invoice_details *invoices_get_details(const tal_t *ctx, struct invoice_details *invoices_get_details(const tal_t *ctx,
struct invoices *invoices, struct invoices *invoices,
struct invoice invoice); struct invoice invoice);
#endif /* LIGHTNING_WALLET_INVOICES_H */ #endif /* LIGHTNING_WALLET_INVOICES_H */

View File

@@ -212,6 +212,10 @@ bool invoices_create(struct invoices *invoices UNNEEDED,
bool invoices_delete(struct invoices *invoices UNNEEDED, bool invoices_delete(struct invoices *invoices UNNEEDED,
struct invoice invoice UNNEEDED) struct invoice invoice UNNEEDED)
{ fprintf(stderr, "invoices_delete called!\n"); abort(); } { fprintf(stderr, "invoices_delete called!\n"); abort(); }
/* Generated stub for invoices_delete_description */
bool invoices_delete_description(struct invoices *invoices UNNEEDED,
struct invoice invoice UNNEEDED)
{ fprintf(stderr, "invoices_delete_description called!\n"); abort(); }
/* Generated stub for invoices_delete_expired */ /* Generated stub for invoices_delete_expired */
void invoices_delete_expired(struct invoices *invoices UNNEEDED, void invoices_delete_expired(struct invoices *invoices UNNEEDED,
u64 max_expiry_time UNNEEDED) u64 max_expiry_time UNNEEDED)
@@ -232,9 +236,9 @@ bool invoices_find_unpaid(struct invoices *invoices UNNEEDED,
const struct sha256 *rhash UNNEEDED) const struct sha256 *rhash UNNEEDED)
{ fprintf(stderr, "invoices_find_unpaid called!\n"); abort(); } { fprintf(stderr, "invoices_find_unpaid called!\n"); abort(); }
/* Generated stub for invoices_get_details */ /* Generated stub for invoices_get_details */
const struct invoice_details *invoices_get_details(const tal_t *ctx UNNEEDED, struct invoice_details *invoices_get_details(const tal_t *ctx UNNEEDED,
struct invoices *invoices UNNEEDED, struct invoices *invoices UNNEEDED,
struct invoice invoice UNNEEDED) struct invoice invoice UNNEEDED)
{ fprintf(stderr, "invoices_get_details called!\n"); abort(); } { fprintf(stderr, "invoices_get_details called!\n"); abort(); }
/* Generated stub for invoices_iterate */ /* Generated stub for invoices_iterate */
bool invoices_iterate(struct invoices *invoices UNNEEDED, bool invoices_iterate(struct invoices *invoices UNNEEDED,

View File

@@ -2850,6 +2850,11 @@ bool wallet_invoice_delete(struct wallet *wallet,
{ {
return invoices_delete(wallet->invoices, invoice); return invoices_delete(wallet->invoices, invoice);
} }
bool wallet_invoice_delete_description(struct wallet *wallet,
struct invoice invoice)
{
return invoices_delete_description(wallet->invoices, invoice);
}
void wallet_invoice_delete_expired(struct wallet *wallet, u64 e) void wallet_invoice_delete_expired(struct wallet *wallet, u64 e)
{ {
invoices_delete_expired(wallet->invoices, e); invoices_delete_expired(wallet->invoices, e);
@@ -2888,9 +2893,9 @@ void wallet_invoice_waitone(const tal_t *ctx,
invoices_waitone(ctx, wallet->invoices, invoice, cb, cbarg); invoices_waitone(ctx, wallet->invoices, invoice, cb, cbarg);
} }
const struct invoice_details *wallet_invoice_details(const tal_t *ctx, struct invoice_details *wallet_invoice_details(const tal_t *ctx,
struct wallet *wallet, struct wallet *wallet,
struct invoice invoice) struct invoice invoice)
{ {
return invoices_get_details(ctx, wallet->invoices, invoice); return invoices_get_details(ctx, wallet->invoices, invoice);
} }

View File

@@ -893,6 +893,9 @@ bool wallet_invoice_find_unpaid(struct wallet *wallet,
bool wallet_invoice_delete(struct wallet *wallet, bool wallet_invoice_delete(struct wallet *wallet,
struct invoice invoice); struct invoice invoice);
bool wallet_invoice_delete_description(struct wallet *wallet,
struct invoice invoice);
/** /**
* wallet_invoice_delete_expired - Delete all expired invoices * wallet_invoice_delete_expired - Delete all expired invoices
* with expiration time less than or equal to the given. * with expiration time less than or equal to the given.
@@ -999,9 +1002,9 @@ void wallet_invoice_waitone(const tal_t *ctx,
* @invoice - the invoice to get details on. * @invoice - the invoice to get details on.
* @return pointer to the invoice details allocated off of `ctx`. * @return pointer to the invoice details allocated off of `ctx`.
*/ */
const struct invoice_details *wallet_invoice_details(const tal_t *ctx, struct invoice_details *wallet_invoice_details(const tal_t *ctx,
struct wallet *wallet, struct wallet *wallet,
struct invoice invoice); struct invoice invoice);
/** /**
* wallet_htlc_stubs - Retrieve HTLC stubs for the given channel * wallet_htlc_stubs - Retrieve HTLC stubs for the given channel