Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Libplugin improvements #7750

Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
10928b5
libplugin: tell compiler that plugin_err is like printf.
rustyrussell Nov 6, 2024
cf6a2f5
libplugin: add aux_command.
rustyrussell Nov 6, 2024
5fe7445
libplugin: always set the "id" field of a command.
rustyrussell Nov 6, 2024
b0c0c46
libplugin: enumerate the specific "struct command" types.
rustyrussell Nov 6, 2024
56184ac
libplugin: make timers have a "command" context.
rustyrussell Nov 6, 2024
9a441b6
commando: always use proper responses for commands.
rustyrussell Nov 6, 2024
6c563a9
funder: use auxilliary command instead of NULL command.
rustyrussell Nov 6, 2024
ddab665
libplugin: reindent.
rustyrussell Nov 6, 2024
dfad69d
libplugin-pay: always use a non-NULL `struct command`.
rustyrussell Nov 6, 2024
fea822e
libplugin-pay: fix command logging
rustyrussell Nov 6, 2024
1c12ead
libplugin: insist on always having a non-NULL command context.
rustyrussell Nov 6, 2024
e9c2c13
libplugin: check that command has/hasn't terminated when we get pendi…
rustyrussell Nov 6, 2024
cbf70de
libplugin: clean up API.
rustyrussell Nov 6, 2024
4884cf4
askrene: make sure we depend on libplugin.h
rustyrussell Nov 6, 2024
69654ee
libplugin: use NULL to imply "take prefix from cmd".
rustyrussell Nov 7, 2024
774b54a
libplugin: add method string to jsonrpc callbacks, implement generic …
rustyrussell Nov 7, 2024
59c864d
libplugin: call get_beglist async, in case they subscribe to the rpc_…
rustyrussell Nov 7, 2024
0b5f37d
lightningd: avoid false memleak positive with rpc_command_hook.
rustyrussell Nov 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lightningd/plugin.c
Original file line number Diff line number Diff line change
@@ -615,7 +615,7 @@ static void mark_plugin_destroyed(const struct plugin *unused,
static struct plugin_destroyed *
plugin_detect_destruction(const struct plugin *plugin)
{
struct plugin_destroyed *pd = tal(NULL, struct plugin_destroyed);
struct plugin_destroyed *pd = notleak(tal(NULL, struct plugin_destroyed));
pd->plugin = plugin;
tal_add_destructor2(plugin, mark_plugin_destroyed, pd);
return pd;
@@ -655,7 +655,7 @@ static void plugin_response_handle(struct plugin *plugin,


/* Request callback often frees request: if not, we do. */
ctx = tal(NULL, char);
ctx = tal(tmpctx, char);
tal_steal(ctx, request);
/* Don't keep track of this request; we will terminate it */
tal_del_destructor2(request, destroy_request, plugin);
3 changes: 2 additions & 1 deletion plugins/Makefile
Original file line number Diff line number Diff line change
@@ -128,7 +128,6 @@ endif

# This is non-python plugins (PY_PLUGINS need their whole directory!)
PLUGINS := $(C_PLUGINS)
PLUGIN_ALL_OBJS := $(PLUGIN_ALL_SRC:.c=.o)

ifneq ($(RUST),0)
# Builtin plugins must be in this plugins dir to work when we're executed
@@ -199,6 +198,8 @@ ALL_C_SOURCES += $(PLUGIN_ALL_SRC)
ALL_C_HEADERS += $(PLUGIN_ALL_HEADER)
ALL_PROGRAMS += $(C_PLUGINS)

PLUGIN_ALL_OBJS := $(PLUGIN_ALL_SRC:.c=.o)

# Make all plugins depend on all plugin headers, for simplicity.
$(PLUGIN_ALL_OBJS): $(PLUGIN_ALL_HEADER)

4 changes: 2 additions & 2 deletions plugins/askrene/Makefile
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ PLUGIN_ASKRENE_OBJS := $(PLUGIN_ASKRENE_SRC:.c=.o)

$(PLUGIN_ASKRENE_OBJS): $(PLUGIN_ASKRENE_HEADER)

ALL_C_SOURCES += $(PLUGIN_ASKRENE_SRC)
ALL_C_HEADERS += $(PLUGIN_ASKRENE_HEADER)
PLUGIN_ALL_SRC += $(PLUGIN_ASKRENE_SRC)
PLUGIN_ALL_HEADER += $(PLUGIN_ASKRENE_HEADER)

plugins/cln-askrene: $(PLUGIN_ASKRENE_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) bitcoin/chainparams.o common/gossmap.o common/sciddir_or_pubkey.o common/gossmods_listpeerchannels.o common/fp16.o common/dijkstra.o common/bolt12.o common/bolt12_merkle.o wire/bolt12_wiregen.o wire/onion_wiregen.o common/route.o
10 changes: 6 additions & 4 deletions plugins/askrene/askrene.c
Original file line number Diff line number Diff line change
@@ -719,6 +719,7 @@ static void add_localchan(struct gossmap_localmods *mods,

static struct command_result *
listpeerchannels_done(struct command *cmd,
const char *method UNUSED,
const char *buffer,
const jsmntok_t *toks,
struct getroutes_info *info)
@@ -759,11 +760,11 @@ static struct command_result *json_getroutes(struct command *cmd,
if (have_layer(info->layers, "auto.localchans")) {
struct out_req *req;

req = jsonrpc_request_start(cmd->plugin, cmd,
req = jsonrpc_request_start(cmd,
"listpeerchannels",
listpeerchannels_done,
forward_error, info);
return send_outreq(cmd->plugin, req);
return send_outreq(req);
} else
info->local_layer = NULL;

@@ -1152,9 +1153,10 @@ static void askrene_markmem(struct plugin *plugin, struct htable *memtable)
reserve_memleak_mark(askrene, memtable);
}

static const char *init(struct plugin *plugin,
static const char *init(struct command *init_cmd,
const char *buf UNUSED, const jsmntok_t *config UNUSED)
{
struct plugin *plugin = init_cmd->plugin;
struct askrene *askrene = tal(plugin, struct askrene);
askrene->plugin = plugin;
list_head_init(&askrene->layers);
@@ -1165,7 +1167,7 @@ static const char *init(struct plugin *plugin,
plugin_err(plugin, "Could not load gossmap %s: %s",
GOSSIP_STORE_FILENAME, strerror(errno));
askrene->capacities = get_capacities(askrene, askrene->plugin, askrene->gossmap);
rpc_scan(plugin, "getinfo", take(json_out_obj(NULL, NULL, NULL)),
rpc_scan(init_cmd, "getinfo", take(json_out_obj(NULL, NULL, NULL)),
"{id:%}", JSON_SCAN(json_to_node_id, &askrene->my_id));

plugin_set_data(plugin, askrene);
61 changes: 29 additions & 32 deletions plugins/autoclean.c
Original file line number Diff line number Diff line change
@@ -206,7 +206,7 @@ static const struct subsystem_ops *get_subsystem_ops(const struct per_subsystem
}

/* Mutual recursion */
static void do_clean_timer(void *unused);
static struct command_result *do_clean_timer(struct command *cmd, void *unused);
static struct command_result *do_clean(struct clean_info *cinfo);

static struct clean_info *new_clean_info(const tal_t *ctx,
@@ -259,15 +259,15 @@ static struct command_result *clean_finished(struct clean_info *cinfo)
plugin_log(plugin, LOG_DBG, "cleaned %zu from %s",
num_cleaned, subsystem_to_str(&sv));
*total_cleaned(&sv) += num_cleaned;
jsonrpc_set_datastore_string(plugin, cinfo->cmd,
jsonrpc_set_datastore_string(cinfo->cmd,
datastore_path(tmpctx, &sv, "num"),
tal_fmt(tmpctx, "%"PRIu64,
*total_cleaned(&sv)),
"create-or-replace", NULL, NULL, NULL);
} while (next_sv(&sv));

/* autoclean-once? */
if (cinfo->cmd) {
if (cinfo != timer_cinfo) {
struct json_stream *response = jsonrpc_stream_success(cinfo->cmd);

json_object_start(response, "autoclean");
@@ -287,9 +287,10 @@ static struct command_result *clean_finished(struct clean_info *cinfo)
return command_finished(cinfo->cmd, response);
} else { /* timer */
plugin_log(plugin, LOG_DBG, "setting next timer");
cleantimer = plugin_timer(plugin, time_from_sec(cycle_seconds),
cleantimer = global_timer(plugin,
time_from_sec(cycle_seconds),
do_clean_timer, NULL);
return timer_complete(plugin);
return timer_complete(cinfo->cmd);
}
}

@@ -304,6 +305,7 @@ static struct command_result *clean_finished_one(struct clean_info *cinfo)
}

static struct command_result *del_done(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct per_variant *variant)
@@ -313,6 +315,7 @@ static struct command_result *del_done(struct command *cmd,
}

static struct command_result *del_failed(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct per_variant *variant)
@@ -476,6 +479,7 @@ static void add_forward_del_fields(struct out_req *req,
}

static struct command_result *list_done(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct per_subsystem *subsystem)
@@ -508,17 +512,18 @@ static struct command_result *list_done(struct command *cmd,
}

subsystem->cinfo->cleanup_reqs_remaining++;
req = jsonrpc_request_start(plugin, NULL, ops->del_command,
req = jsonrpc_request_start(cmd, ops->del_command,
del_done, del_failed, variant);
ops->add_del_fields(req, buf, t);
send_outreq(plugin, req);
send_outreq(req);
}

subsystem->offset += max_entries_per_call;
return clean_finished_one(subsystem->cinfo);
}

static struct command_result *list_failed(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct per_subsystem *subsystem)
@@ -554,7 +559,7 @@ static struct command_result *do_clean(struct clean_info *cinfo)

filter = tal_fmt(tmpctx, "{\"%s\":[{%s}]}",
ops->arr_name, ops->list_filter);
req = jsonrpc_request_with_filter_start(plugin, NULL,
req = jsonrpc_request_with_filter_start(cinfo->cmd,
tal_fmt(tmpctx,
"list%s",
ops->system_name),
@@ -566,16 +571,17 @@ static struct command_result *do_clean(struct clean_info *cinfo)
json_add_string(req->js, "index", "created");
json_add_u64(req->js, "start", ps->offset);
json_add_u64(req->js, "limit", max_entries_per_call);
send_outreq(plugin, req);
send_outreq(req);
cinfo->cleanup_reqs_remaining++;
}

if (cinfo->cleanup_reqs_remaining)
return command_still_pending(NULL);
return command_still_pending(cinfo->cmd);
return clean_finished(cinfo);
}

static struct command_result *wait_done(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct per_subsystem *ps)
@@ -598,17 +604,6 @@ static struct command_result *wait_done(struct command *cmd,
return do_clean(ps->cinfo);
}

static struct command_result *wait_failed(struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct per_subsystem *subsystem)
{
plugin_err(plugin, "Failed wait '%s': '%.*s'",
get_subsystem_ops(subsystem)->system_name,
json_tok_full_len(result),
json_tok_full(buf, result));
}

static struct command_result *start_clean(struct clean_info *cinfo)
{
cinfo->cleanup_reqs_remaining = 0;
@@ -627,25 +622,26 @@ static struct command_result *start_clean(struct clean_info *cinfo)
}
ps->offset = 0;

req = jsonrpc_request_start(plugin, NULL,
req = jsonrpc_request_start(cinfo->cmd,
"wait",
wait_done, wait_failed, ps);
wait_done, plugin_broken_cb, ps);
json_add_string(req->js, "subsystem", ops->system_name);
json_add_string(req->js, "indexname", "created");
json_add_u64(req->js, "nextvalue", 0);
send_outreq(plugin, req);
send_outreq(req);
cinfo->cleanup_reqs_remaining++;
}

return command_still_pending(cinfo->cmd);
}

/* Needs a different signature than do_clean */
static void do_clean_timer(void *unused)
static struct command_result *do_clean_timer(struct command *cmd, void *unused)
{
assert(timer_cinfo->cleanup_reqs_remaining == 0);
cleantimer = NULL;
start_clean(timer_cinfo);
timer_cinfo->cmd = cmd;
return start_clean(timer_cinfo);
}

static struct command_result *param_subsystem(struct command *cmd,
@@ -740,29 +736,29 @@ static void memleak_mark_timer_cinfo(struct plugin *plugin,
memleak_scan_obj(memtable, timer_cinfo);
}

static const char *init(struct plugin *p,
static const char *init(struct command *init_cmd,
const char *buf UNUSED, const jsmntok_t *config UNUSED)
{
struct subsystem_and_variant sv;
plugin = p;
plugin = init_cmd->plugin;

/* Plugin owns global */
tal_steal(plugin, timer_cinfo);
plugin_set_memleak_handler(plugin, memleak_mark_timer_cinfo);

cleantimer = plugin_timer(p, time_from_sec(cycle_seconds), do_clean_timer, NULL);
cleantimer = global_timer(plugin, time_from_sec(cycle_seconds), do_clean_timer, NULL);

/* We don't care if this fails (it usually does, since entries
* don't exist! */
sv = first_sv();
do {
rpc_scan_datastore_str(tmpctx, plugin,
rpc_scan_datastore_str(tmpctx, init_cmd,
datastore_path(tmpctx, &sv, "num"),
JSON_SCAN(json_to_u64, total_cleaned(&sv)));
} while (next_sv(&sv));

/* Optimization FTW! */
rpc_enable_batching(p);
rpc_enable_batching(plugin);
return NULL;
}

@@ -777,7 +773,8 @@ static char *cycle_seconds_option(struct plugin *plugin, const char *arg,
/* If timer is not running right now, reset it to new cycle_seconds */
if (cleantimer) {
tal_free(cleantimer);
cleantimer = plugin_timer(plugin, time_from_sec(*cycle_seconds),
cleantimer = global_timer(plugin,
time_from_sec(*cycle_seconds),
do_clean_timer, NULL);
}
return NULL;
22 changes: 12 additions & 10 deletions plugins/bcli.c
Original file line number Diff line number Diff line change
@@ -199,15 +199,16 @@ static void destroy_bcli(struct bitcoin_cli *bcli)
list_del_from(&bitcoind->current, &bcli->list);
}

static void retry_bcli(void *cb_arg)
static struct command_result *retry_bcli(struct command *cmd,
struct bitcoin_cli *bcli)
{
struct bitcoin_cli *bcli = cb_arg;
list_del_from(&bitcoind->current, &bcli->list);
tal_del_destructor(bcli, destroy_bcli);

list_add_tail(&bitcoind->pending[bcli->prio], &bcli->list);
tal_free(bcli->output);
next_bcli(bcli->prio);
return timer_complete(cmd);
}

/* We allow 60 seconds of spurious errors, eg. reorg. */
@@ -238,7 +239,7 @@ static void bcli_failure(struct bitcoin_cli *bcli,
bitcoind->error_count++;

/* Retry in 1 second */
plugin_timer(bcli->cmd->plugin, time_from_sec(1), retry_bcli, bcli);
command_timer(bcli->cmd, time_from_sec(1), retry_bcli, bcli);
}

static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli)
@@ -1006,17 +1007,18 @@ static void parse_getnetworkinfo_result(struct plugin *p, const char *buf)
if (!result)
plugin_err(p, "Invalid response to '%s': '%s'. Can not "
"continue without proceeding to sanity checks.",
gather_args(bitcoind, "getnetworkinfo", NULL), buf);
args_string(tmpctx, gather_args(bitcoind, "getnetworkinfo", NULL)),
buf);

/* Check that we have a fully-featured `estimatesmartfee`. */
err = json_scan(tmpctx, buf, result, "{version:%,localrelay:%}",
JSON_SCAN(json_to_u32, &bitcoind->version),
JSON_SCAN(json_to_bool, &tx_relay));
if (err)
plugin_err(p, "%s. Got '%s'. Can not"
plugin_err(p, "%s. Got '%.*s'. Can not"
" continue without proceeding to sanity checks.",
err,
gather_args(bitcoind, "getnetworkinfo", NULL), buf);
json_tok_full_len(result), json_tok_full(buf, result));

if (bitcoind->version < min_version)
plugin_err(p, "Unsupported bitcoind version %"PRIu32", at least"
@@ -1098,19 +1100,19 @@ static void memleak_mark_bitcoind(struct plugin *p, struct htable *memtable)
memleak_scan_obj(memtable, bitcoind);
}

static const char *init(struct plugin *p, const char *buffer UNUSED,
static const char *init(struct command *init_cmd, const char *buffer UNUSED,
const jsmntok_t *config UNUSED)
{
wait_and_check_bitcoind(p);
wait_and_check_bitcoind(init_cmd->plugin);

/* Usually we fake up fees in regtest */
if (streq(chainparams->network_name, "regtest"))
bitcoind->fake_fees = !bitcoind->dev_no_fake_fees;
else
bitcoind->fake_fees = false;

plugin_set_memleak_handler(p, memleak_mark_bitcoind);
plugin_log(p, LOG_INFORM,
plugin_set_memleak_handler(init_cmd->plugin, memleak_mark_bitcoind);
plugin_log(init_cmd->plugin, LOG_INFORM,
"bitcoin-cli initialized and connected to bitcoind.");

return NULL;
Loading