lightningd: allow plugins to specify cancheck for us to pass check commands through.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Plugins: Can now opt in to handle `check` command on their commands, for more thorough checking.
This commit is contained in:
Rusty Russell
2024-04-04 14:06:12 +10:30
parent 16615f4ed5
commit 11ffbc305e
3 changed files with 62 additions and 4 deletions

View File

@@ -94,6 +94,7 @@ The `getmanifest` method is required for all plugins and will be called on start
11010
],
"nonnumericids": true,
"cancheck": true,
"dynamic": true
}
```
@@ -110,6 +111,8 @@ The `nonnumericids` indicates that the plugin can handle string JSON request `id
The `dynamic` indicates if the plugin can be managed after `lightningd` has been started using the [lightning-plugin](ref:lightning-plugin) JSON-RPC command. Critical plugins that should not be stopped should set it to false. Plugin `options` can be passed to dynamic plugins as argument to the `plugin` command .
If you can handle the `check` command on your commands, you should set `cancheck` to `true` and expect `lightningd` to pass through any user-requested `check` commands to you directly (without this, `check` currently always passes, which is not very useful!).
If a `disable` member exists, the plugin will be disabled and the contents of this member is the reason why. This allows plugins to disable themselves if they are not supported in this configuration.
The `featurebits` object allows the plugin to register featurebits that should be announced in a number of places in [the protocol](https://github.com/lightning/bolts/blob/master/09-features). They can be used to signal support for custom protocol extensions to direct peers, remote nodes and in invoices. Custom protocol extensions can be implemented for example using the `sendcustommsg` method and the `custommsg` hook, or the `sendonion` method and the `htlc_accepted` hook. The keys in the `featurebits` object are `node` for features that should be announced via the `node_announcement` to all nodes in the network, `init` for features that should be announced to direct peers during the connection setup, `channel` for features which should apply to `channel_announcement`, and `invoice` for features that should be announced to a potential sender of a payment in the invoice. The low range of featurebits is reserved for standardize features, so please pick random, high position bits for experiments. If you'd like to standardize your extension please reach out to the [specification repository][spec] to get a featurebit assigned.

View File

@@ -356,6 +356,7 @@ struct plugin *plugin_register(struct plugins *plugins, const char* path TAKES,
p->checksum = file_checksum(plugins->ld, p->cmd);
p->shortname = path_basename(p, p->cmd);
p->start_cmd = start_cmd;
p->can_check = false;
p->plugin_state = UNCONFIGURED;
p->js_arr = tal_arr(p, struct json_stream *, 0);
@@ -1299,6 +1300,46 @@ struct plugin *find_plugin_for_command(struct lightningd *ld,
return NULL;
}
static struct command_result *plugin_rpcmethod_check(struct command *cmd,
const char *buffer,
const jsmntok_t *toks,
const jsmntok_t *params)
{
const jsmntok_t *idtok;
struct plugin *plugin;
struct jsonrpc_request *req;
plugin = find_plugin_for_command(cmd->ld, cmd->json_cmd->name);
if (!plugin)
fatal("No plugin for %s ?", cmd->json_cmd->name);
assert(command_check_only(cmd));
if (!plugin->can_check) {
log_unusual(plugin->log, "Plugin does not support check command for %s (id %s)",
cmd->json_cmd->name, cmd->id);
return command_check_done(cmd);
}
/* Find id again (we've parsed them before, this should not fail!) */
idtok = json_get_member(buffer, toks, "id");
assert(idtok != NULL);
/* Send check command through, it says it can handle it! */
req = jsonrpc_request_start_raw(plugin, "check",
cmd->id, plugin->non_numeric_ids,
plugin->log,
plugin_notify_cb,
plugin_rpcmethod_cb, cmd);
json_stream_forward_change_id(req->stream, buffer, toks, idtok, req->id);
json_stream_double_cr(req->stream);
plugin_request_send(plugin, req);
req->stream = NULL;
return command_still_pending(cmd);
}
static struct command_result *plugin_rpcmethod_dispatch(struct command *cmd,
const char *buffer,
const jsmntok_t *toks,
@@ -1309,14 +1350,13 @@ static struct command_result *plugin_rpcmethod_dispatch(struct command *cmd,
struct jsonrpc_request *req;
bool cmd_ok;
/* FIXME: Pass through to plugins! */
if (command_check_only(cmd))
return command_check_done(cmd);
plugin = find_plugin_for_command(cmd->ld, cmd->json_cmd->name);
if (!plugin)
fatal("No plugin for %s ?", cmd->json_cmd->name);
/* This should go to plugin_rpcmethod_check! */
assert(!command_check_only(cmd));
/* Find ID again (We've parsed them before, this should not fail!) */
idtok = json_get_member(buffer, toks, "id");
assert(idtok != NULL);
@@ -1408,6 +1448,7 @@ static const char *plugin_rpcmethod_add(struct plugin *plugin,
cmd->dev_only = false;
cmd->dispatch = plugin_rpcmethod_dispatch;
cmd->check = plugin_rpcmethod_check;
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd, usage)) {
struct plugin *p =
find_plugin_for_command(plugin->plugins->ld, cmd->name);
@@ -1803,6 +1844,17 @@ static const char *plugin_parse_getmanifest_response(const char *buffer,
"v23.08", "v24.08");
}
tok = json_get_member(buffer, resulttok, "cancheck");
if (tok) {
if (!json_to_bool(buffer, tok, &plugin->can_check))
return tal_fmt(plugin,
"Invalid cancheck: %.*s",
json_tok_full_len(tok),
json_tok_full(buffer, tok));
} else {
plugin->can_check = false;
}
err = plugin_notifications_add(buffer, resulttok, plugin);
if (!err)
err = plugin_opts_add(plugin, buffer, resulttok);

View File

@@ -93,6 +93,9 @@ struct plugin {
/* Custom message types we want to allow incoming */
u16 *custom_msgs;
/* Can this handle check commands? */
bool can_check;
};
/**