diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 4dd58b918152..3e5f6f291187 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -875,14 +875,24 @@ static struct io_plan *plugin_write_json(struct io_conn *conn, /* This catches the case where their stdout closes (usually they're dead). */ static void plugin_conn_finish(struct io_conn *conn, struct plugin *plugin) { - struct db *db = plugin->plugins->ld->wallet->db; - db_begin_transaction(db); + struct db *db; + + /* If they die during startup (plugins_init) wallet is NULL + * (but there are also no plugin commands to kill, so nothing + * would ever try to access db */ + if (plugin->plugins->ld->wallet) { + db = plugin->plugins->ld->wallet->db; + db_begin_transaction(db); + } else + db = NULL; + /* This is expected at shutdown of course. */ plugin_kill(plugin, plugin->plugins->ld->state == LD_STATE_SHUTDOWN ? LOG_DBG : LOG_INFORM, "exited %s", state_desc(plugin)); - db_commit_transaction(db); + if (db) + db_commit_transaction(db); } struct io_plan *plugin_stdin_conn_init(struct io_conn *conn, diff --git a/tests/plugins/broken.py b/tests/plugins/broken.py index 4a88b9bfe665..1fa3c38bc904 100755 --- a/tests/plugins/broken.py +++ b/tests/plugins/broken.py @@ -2,18 +2,27 @@ """Simple plugin to test that lightningd doesnt crash if it starts a misbehaving plugin via RPC. """ - from pyln.client import Plugin -import an_unexistent_module_that_will_make_me_crash - -plugin = Plugin(dynamic=False) +import os +plugin = Plugin() +crash_at = os.environ.get("BROKEN_CRASH", "before_start") @plugin.init() def init(options, configuration, plugin): plugin.log("broken.py initializing {}".format(configuration)) - # We need to actually use the import to pass source checks.. - an_unexistent_module_that_will_make_me_crash.hello() + assert crash_at == "during_init" + plugin.does_not_exist() + + +@plugin.method("test_broken") +def test_broken(): + return {} + +if crash_at == "before_start": + assert False +elif crash_at == "during_getmanifest": + del plugin.methods['getmanifest'] plugin.run() diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 1c527741f983..9b8e3d3be58e 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -300,6 +300,18 @@ def test_plugin_command(node_factory): n.rpc.stop() +def test_plugin_fail_on_startup(node_factory): + for crash in ('during_init', 'before_start', 'during_getmanifest'): + os.environ['BROKEN_CRASH'] = crash + n = node_factory.get_node(options={'plugin': os.path.join(os.getcwd(), "tests/plugins/broken.py")}) + # This can happen before 'Server started with public key' msg + n.daemon.logsearch_start = 0 + n.daemon.wait_for_log('plugin-broken.py: Traceback') + + # Make sure they don't die *after* the message! + time.sleep(30) + + def test_plugin_disable(node_factory): """--disable-plugin works""" plugin_dir = os.path.join(os.getcwd(), 'contrib/plugins')