From 3079afb024e9307a696046d0e936ff240a5f4c86 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 19 Sep 2022 10:22:58 +0930 Subject: [PATCH] lightningd: add `delforward` command. Changelog-Added: JSON-RPC: `delforward` command to delete listforwards entries. Signed-off-by: Rusty Russell --- common/jsonrpc_errors.h | 3 ++ doc/Makefile | 1 + doc/index.rst | 1 + doc/lightning-delforward.7.md | 53 ++++++++++++++++++++++++++ doc/schemas/delforward.request.json | 21 ++++++++++ doc/schemas/delforward.schema.json | 7 ++++ lightningd/peer_htlcs.c | 59 +++++++++++++++++++++++++++++ tests/test_misc.py | 11 ++++++ wallet/test/run-wallet.c | 5 +++ wallet/wallet.c | 23 +++++++++++ wallet/wallet.h | 9 +++++ 11 files changed, 193 insertions(+) create mode 100644 doc/lightning-delforward.7.md create mode 100644 doc/schemas/delforward.request.json create mode 100644 doc/schemas/delforward.schema.json diff --git a/common/jsonrpc_errors.h b/common/jsonrpc_errors.h index cb0f1a49c..ff678f417 100644 --- a/common/jsonrpc_errors.h +++ b/common/jsonrpc_errors.h @@ -104,6 +104,9 @@ enum jsonrpc_errcode { /* Errors from signmessage command */ SIGNMESSAGE_PUBKEY_NOT_FOUND = 1301, + /* Errors from delforward command */ + DELFORWARD_NOT_FOUND = 1401, + /* Errors from wait* commands */ WAIT_TIMEOUT = 2000, }; diff --git a/doc/Makefile b/doc/Makefile index 79a0b8622..6beb0d852 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -28,6 +28,7 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-decode.7 \ doc/lightning-deldatastore.7 \ doc/lightning-delexpiredinvoice.7 \ + doc/lightning-delforward.7 \ doc/lightning-delinvoice.7 \ doc/lightning-delpay.7 \ doc/lightning-disableoffer.7 \ diff --git a/doc/index.rst b/doc/index.rst index c7bd4bacc..80331e079 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -51,6 +51,7 @@ Core Lightning Documentation lightning-decodepay lightning-deldatastore lightning-delexpiredinvoice + lightning-delforward lightning-delinvoice lightning-delpay lightning-disableoffer diff --git a/doc/lightning-delforward.7.md b/doc/lightning-delforward.7.md new file mode 100644 index 000000000..5ae6ee51b --- /dev/null +++ b/doc/lightning-delforward.7.md @@ -0,0 +1,53 @@ +lightning-delforward -- Command for removing a forwarding entry +=============================================================== + +SYNOPSIS +-------- + +**delforward** *in_channel* *in_htlc_id* *status* + +DESCRIPTION +----------- + +The **delforward** RPC command removes a single forward from **listforwards**, +using the uniquely-identifying *in_channel* and *in_htlc_id* (and, as a sanity +check, the *status*) given by that command. + +This command is mainly used by the *autoclean* plugin (see lightningd-config(7)), +As these database entries are only kept for your own analysis, removing them +has no effect on the running of your node. + +You cannot delete forwards which have status *offered* (i.e. are +currently active). + +RETURN VALUE +------------ + +[comment]: # (GENERATE-FROM-SCHEMA-START) +On success, an empty object is returned. + +[comment]: # (GENERATE-FROM-SCHEMA-END) + +ERRORS +------ + +The following errors may be reported: + +- 1401: The forward specified does not exist. + +AUTHOR +------ + +Rusty Russell <> is mainly responsible. + +SEE ALSO +-------- + +lightning-autoclean(7) + +RESOURCES +--------- + +Main web site: + +[comment]: # ( SHA256STAMP:200de829c6635242cb2dd8ec0650c2fa8f5fcbf413f4a704884516df80492fcb) diff --git a/doc/schemas/delforward.request.json b/doc/schemas/delforward.request.json new file mode 100644 index 000000000..163c79909 --- /dev/null +++ b/doc/schemas/delforward.request.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [], + "properties": { + "in_channel": { + "type": "short_channel_id" + }, + "in_htlc_id": { + "type": "u64" + }, + "status": { + "type": "string", + "enum": [ + "settled", + "local_failed", + "failed" + ] + } + } +} diff --git a/doc/schemas/delforward.schema.json b/doc/schemas/delforward.schema.json new file mode 100644 index 000000000..65571ad4c --- /dev/null +++ b/doc/schemas/delforward.schema.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "required": [], + "properties": {} +} diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 7eadf672a..e1764bb27 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -2895,6 +2895,65 @@ static const struct json_command listforwards_command = { }; AUTODATA(json_command, &listforwards_command); +static struct command_result *param_forward_delstatus(struct command *cmd, + const char *name, + const char *buffer, + const jsmntok_t *tok, + enum forward_status **status) +{ + struct command_result *ret; + + ret = param_forward_status(cmd, name, buffer, tok, status); + if (ret) + return ret; + + switch (**status) { + case FORWARD_OFFERED: + return command_fail_badparam(cmd, name, buffer, tok, + "delforward status cannot be offered"); + case FORWARD_ANY: + return command_fail_badparam(cmd, name, buffer, tok, + "delforward status cannot be any"); + case FORWARD_SETTLED: + case FORWARD_FAILED: + case FORWARD_LOCAL_FAILED: + return NULL; + } + abort(); +} + +static struct command_result *json_delforward(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct short_channel_id *chan_in; + u64 *htlc_id; + enum forward_status *status; + + if (!param(cmd, buffer, params, + p_req("in_channel", param_short_channel_id, &chan_in), + p_req("in_htlc_id", param_u64, &htlc_id), + p_req("status", param_forward_delstatus, &status), + NULL)) + return command_param_failed(); + + if (!wallet_forward_delete(cmd->ld->wallet, + chan_in, *htlc_id, *status)) + return command_fail(cmd, DELFORWARD_NOT_FOUND, + "Could not find that forward"); + + return command_success(cmd, json_stream_success(cmd)); +} + +static const struct json_command delforward_command = { + "delforward", + "channels", + json_delforward, + "Delete a forwarded payment by [in_channel], [in_htlc_id] and [status]" +}; +AUTODATA(json_command, &delforward_command); + static struct command_result *param_channel(struct command *cmd, const char *name, const char *buffer, diff --git a/tests/test_misc.py b/tests/test_misc.py index 03f7605de..cb54b58d3 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2493,6 +2493,17 @@ def test_listforwards_and_listhtlcs(node_factory, bitcoind): # But forwards are not forgotten! assert l2.rpc.listforwards()['forwards'] == all_forwards + # Now try delforward! + with pytest.raises(RpcError, match="Could not find that forward") as exc_info: + l2.rpc.delforward(in_channel=c12, in_htlc_id=3, status='settled') + # static const errcode_t DELFORWARD_NOT_FOUND = 1401; + assert exc_info.value.error['code'] == 1401 + + l2.rpc.delforward(in_channel=c12, in_htlc_id=0, status='settled') + l2.rpc.delforward(in_channel=c12, in_htlc_id=1, status='settled') + l2.rpc.delforward(in_channel=c12, in_htlc_id=2, status='local_failed') + assert l2.rpc.listforwards() == {'forwards': []} + @pytest.mark.openchannel('v1') def test_version_reexec(node_factory, bitcoind): diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 5c2a71ed4..7157358ac 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -616,6 +616,11 @@ struct command_result *param_short_channel_id(struct command *cmd UNNEEDED, const jsmntok_t *tok UNNEEDED, struct short_channel_id **scid UNNEEDED) { fprintf(stderr, "param_short_channel_id called!\n"); abort(); } +/* Generated stub for param_u64 */ +struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name UNNEEDED, + const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + uint64_t **num UNNEEDED) +{ fprintf(stderr, "param_u64 called!\n"); abort(); } /* Generated stub for parse_onionpacket */ struct onionpacket *parse_onionpacket(const tal_t *ctx UNNEEDED, const u8 *src UNNEEDED, diff --git a/wallet/wallet.c b/wallet/wallet.c index 1674a7222..8458f42bc 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -4663,6 +4663,29 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w, return results; } +bool wallet_forward_delete(struct wallet *w, + const struct short_channel_id *chan_in, + u64 htlc_id, + enum forward_status state) +{ + struct db_stmt *stmt; + bool changed; + + stmt = db_prepare_v2(w->db, + SQL("DELETE FROM forwards" + " WHERE in_channel_scid = ?" + " AND in_htlc_id = ?" + " AND state = ?")); + db_bind_scid(stmt, 0, chan_in); + db_bind_u64(stmt, 1, htlc_id); + db_bind_int(stmt, 2, wallet_forward_status_in_db(state)); + db_exec_prepared_v2(stmt); + changed = db_count_changes(stmt) != 0; + tal_free(stmt); + + return changed; +} + struct wallet_transaction *wallet_transactions_get(struct wallet *w, const tal_t *ctx) { struct db_stmt *stmt; diff --git a/wallet/wallet.h b/wallet/wallet.h index 09b253148..d5315eb1e 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -1379,6 +1379,15 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w, const struct short_channel_id *chan_in, const struct short_channel_id *chan_out); +/** + * Delete a particular forward entry + * Returns false if not found + */ +bool wallet_forward_delete(struct wallet *w, + const struct short_channel_id *chan_in, + u64 htlc_id, + enum forward_status state); + /** * Load remote_ann_node_sig and remote_ann_bitcoin_sig *