From 19300de58fac880fb0ea3853eb63ea0668a21e3d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 30 Nov 2022 13:07:46 +1030 Subject: [PATCH] lightningd: correctly exit when an important-plugin fails to start. This was found by tests/test_plugin.py::test_important_plugin and was NOT a flake! Signed-off-by: Rusty Russell Changelog-None: only just committed --- lightningd/chaintopology.c | 1 + lightningd/lightningd.c | 6 ++++-- lightningd/plugin.c | 11 ++++++++--- lightningd/plugin.h | 5 ++++- lightningd/test/run-find_my_abspath.c | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 9e41c449c..b3f0fc75c 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -968,6 +968,7 @@ struct chain_topology *new_topology(struct lightningd *ld, struct log *log) topo->feerate_uninitialized = true; topo->root = NULL; topo->sync_waiters = tal(topo, struct list_head); + topo->extend_timer = NULL; topo->stopping = false; list_head_init(topo->sync_waiters); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 9533d4af7..5dfe18194 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -876,7 +876,7 @@ int main(int argc, char *argv[]) struct htlc_in_map *unconnected_htlcs_in; struct ext_key *bip32_base; int sigchld_rfd; - struct io_conn *sigchld_conn; + struct io_conn *sigchld_conn = NULL; int exit_code = 0; char **orig_argv; bool try_reexec; @@ -1104,7 +1104,8 @@ int main(int argc, char *argv[]) /*~ Now that the rpc path exists, we can start the plugins and they * can start talking to us. */ - plugins_config(ld->plugins); + if (!plugins_config(ld->plugins)) + goto stop; /*~ Process any HTLCs we were in the middle of when we exited, now * that plugins (who might want to know via htlc_accepted hook) are @@ -1201,6 +1202,7 @@ int main(int argc, char *argv[]) assert(io_loop_ret == ld); log_debug(ld->log, "io_loop_with_timers: %s", __func__); +stop: /* Stop *new* JSON RPC requests. */ jsonrpc_stop_listening(ld->jsonrpc); diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 38acdbfb5..8a883e220 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -1938,7 +1938,7 @@ plugin_config(struct plugin *plugin) plugin->plugin_state = AWAITING_INIT_RESPONSE; } -void plugins_config(struct plugins *plugins) +bool plugins_config(struct plugins *plugins) { struct plugin *p; list_for_each(&plugins->plugins, p, list) { @@ -1948,10 +1948,15 @@ void plugins_config(struct plugins *plugins) /* Wait for them to configure, before continuing: large * nodes can take a while to startup! */ - if (plugins->startup) - io_loop_with_timers(plugins->ld); + if (plugins->startup) { + /* This happens if an important plugin fails init, + * or if they call shutdown now. */ + if (io_loop_with_timers(plugins->ld) == plugins->ld) + return false; + } plugins->startup = false; + return true; } /** json_add_opt_plugins_array diff --git a/lightningd/plugin.h b/lightningd/plugin.h index 6f41e701b..cc6c5d5bd 100644 --- a/lightningd/plugin.h +++ b/lightningd/plugin.h @@ -265,8 +265,11 @@ struct command_result *plugin_register_all_complete(struct lightningd *ld, * and send them over to the plugin. This finalizes the initialization * of the plugins and signals that lightningd is now ready to process * incoming JSON-RPC calls and messages. + * + * It waits for plugins to be initialized, but returns false if we + * should exit (an important plugin failed, or we got a shutdown command). */ -void plugins_config(struct plugins *plugins); +bool plugins_config(struct plugins *plugins); /** * This populates the jsonrpc request with the plugin/lightningd specifications diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 85fd5fcf9..37547757f 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -168,7 +168,7 @@ struct chain_topology *new_topology(struct lightningd *ld UNNEEDED, struct log * void onchaind_replay_channels(struct lightningd *ld UNNEEDED) { fprintf(stderr, "onchaind_replay_channels called!\n"); abort(); } /* Generated stub for plugins_config */ -void plugins_config(struct plugins *plugins UNNEEDED) +bool plugins_config(struct plugins *plugins UNNEEDED) { fprintf(stderr, "plugins_config called!\n"); abort(); } /* Generated stub for plugins_init */ void plugins_init(struct plugins *plugins UNNEEDED)