commando: add filtering support.

1. When we receive a commando command from a remote using the `filter`
   field, use it.
2. Add a `filter` parameter to `commando` to send it: this is usually
   more efficient than using filtering locally.

Of course, older remote nodes will ignore the filter, but that's
harmless.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Plugins: `commando` now supports `filter` as a parameter (for send and receive).
This commit is contained in:
Rusty Russell 2023-01-03 14:53:28 +10:30
parent 1250806060
commit 3f0c5b985b
3 changed files with 24 additions and 2 deletions

View file

@ -30,6 +30,11 @@
"rune": { "rune": {
"type": "string", "type": "string",
"description": "rune to authorize the command" "description": "rune to authorize the command"
},
"filter": {
"type": "object",
"additionalProperties": true,
"description": "filter to peer to apply to any successful result"
} }
} }
} }

View file

@ -382,7 +382,7 @@ static void try_command(struct node_id *peer,
const u8 *msg, size_t msglen) const u8 *msg, size_t msglen)
{ {
struct commando *incoming = tal(plugin, struct commando); struct commando *incoming = tal(plugin, struct commando);
const jsmntok_t *toks, *method, *params, *rune, *id; const jsmntok_t *toks, *method, *params, *rune, *id, *filter;
const char *buf = (const char *)msg, *failmsg; const char *buf = (const char *)msg, *failmsg;
struct out_req *req; struct out_req *req;
const char *cmdid_prefix; const char *cmdid_prefix;
@ -415,6 +415,7 @@ static void try_command(struct node_id *peer,
return; return;
} }
rune = json_get_member(buf, toks, "rune"); rune = json_get_member(buf, toks, "rune");
filter = json_get_member(buf, toks, "filter");
id = json_get_member(buf, toks, "id"); id = json_get_member(buf, toks, "id");
if (!id) { if (!id) {
if (!deprecated_apis) { if (!deprecated_apis) {
@ -476,6 +477,11 @@ static void try_command(struct node_id *peer,
json_object_start(req->js, "params"); json_object_start(req->js, "params");
json_object_end(req->js); json_object_end(req->js);
} }
if (filter) {
json_add_jsonstr(req->js, "filter",
json_tok_full(buf, filter),
json_tok_full_len(filter));
}
tal_free(toks); tal_free(toks);
send_outreq(plugin, req); send_outreq(plugin, req);
} }
@ -700,7 +706,7 @@ static struct command_result *json_commando(struct command *cmd,
{ {
struct node_id *peer; struct node_id *peer;
const char *method, *cparams; const char *method, *cparams;
const char *rune; const char *rune, *filter;
struct commando *ocmd; struct commando *ocmd;
struct outgoing *outgoing; struct outgoing *outgoing;
char *json; char *json;
@ -711,6 +717,7 @@ static struct command_result *json_commando(struct command *cmd,
p_req("method", param_string, &method), p_req("method", param_string, &method),
p_opt("params", param_string, &cparams), p_opt("params", param_string, &cparams),
p_opt("rune", param_string, &rune), p_opt("rune", param_string, &rune),
p_opt("filter", param_string, &filter),
NULL)) NULL))
return command_param_failed(); return command_param_failed();
@ -731,6 +738,8 @@ static struct command_result *json_commando(struct command *cmd,
ocmd->json_id, cparams ? cparams : "{}"); ocmd->json_id, cparams ? cparams : "{}");
if (rune) if (rune)
tal_append_fmt(&json, ",\"rune\":\"%s\"", rune); tal_append_fmt(&json, ",\"rune\":\"%s\"", rune);
if (filter)
tal_append_fmt(&json, ",\"filter\":%s", filter);
tal_append_fmt(&json, "}"); tal_append_fmt(&json, "}");
outgoing = tal(cmd, struct outgoing); outgoing = tal(cmd, struct outgoing);

View file

@ -2648,6 +2648,14 @@ def test_commando(node_factory, executor):
assert len(res['peers']) == 1 assert len(res['peers']) == 1
assert res['peers'][0]['id'] == l2.info['id'] assert res['peers'][0]['id'] == l2.info['id']
# Filter test
res = l2.rpc.call(method='commando',
payload={'peer_id': l1.info['id'],
'rune': rune,
'method': 'listpeers',
'filter': {'peers': [{'id': True}]}})
assert res == {'peers': [{'id': l2.info['id']}]}
with pytest.raises(RpcError, match='missing required parameter'): with pytest.raises(RpcError, match='missing required parameter'):
l2.rpc.call(method='commando', l2.rpc.call(method='commando',
payload={'peer_id': l1.info['id'], payload={'peer_id': l1.info['id'],