lightningd: add delforward command.

Changelog-Added: JSON-RPC: `delforward` command to delete listforwards entries.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-09-19 10:22:58 +09:30 committed by Christian Decker
parent 7420a7021f
commit 3079afb024
11 changed files with 193 additions and 0 deletions

View file

@ -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,
};

View file

@ -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 \

View file

@ -51,6 +51,7 @@ Core Lightning Documentation
lightning-decodepay <lightning-decodepay.7.md>
lightning-deldatastore <lightning-deldatastore.7.md>
lightning-delexpiredinvoice <lightning-delexpiredinvoice.7.md>
lightning-delforward <lightning-delforward.7.md>
lightning-delinvoice <lightning-delinvoice.7.md>
lightning-delpay <lightning-delpay.7.md>
lightning-disableoffer <lightning-disableoffer.7.md>

View file

@ -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 <<rusty@rustcorp.com.au>> is mainly responsible.
SEE ALSO
--------
lightning-autoclean(7)
RESOURCES
---------
Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:200de829c6635242cb2dd8ec0650c2fa8f5fcbf413f4a704884516df80492fcb)

View file

@ -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"
]
}
}
}

View file

@ -0,0 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"required": [],
"properties": {}
}

View file

@ -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,

View file

@ -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):

View file

@ -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,

View file

@ -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;

View file

@ -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
*