Commit Graph

237 Commits

Author SHA1 Message Date
Rusty Russell a1e894a445 lightningd: treat JSON ids as direct tokens.
This avoids any confusion between primitive and string ids, and in
particular stops an issue with commando once it starts chaining ids,
that weird ids can be double-escaped and commando will not recognize
the response, leaving the client hanging.  It's the client's fault for
using a weird id, but it's still rude (and triggered by our tests!).

It also makes substituting the id in passthrough simpler, FTW.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-01-11 11:13:27 +10:30
Rusty Russell 19300de58f 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 <rusty@rustcorp.com.au>
Changelog-None: only just committed
2022-11-30 15:47:31 +01:00
Rusty Russell 626998efce lightningd: don't timeout plugins if init is slow!
This is a minimal fix: we wait until all plugins reply from init before
continuing.  Really large or busy nodes can have other things monopolize
lightningd, then the timer goes off and we blame the plugin (which has
responded, we just haven't read it yet!).

The real answer is to have some timeouts only advance when we're idle,
or have them low-priority so we only activate them when we're idle (this
doesn't apply to all timers: some are probably important!).  But
this is a minimal fix for -rc3.

Fixes: https://github.com/ElementsProject/lightning/issues/5736
Changelog-Fixed: plugins: on large/slow nodes we could blame plugins for failing to answer init in time, when we were just slow.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-11-27 14:58:42 +01:00
Rusty Russell d5ce5cbab3 lightningd: only use non-numeric JSON ids if plugin says we can.
We also remember whether the id is a string or not, for replacement in
JSON passthrough.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-11-21 11:23:54 +01:00
Rusty Russell 24651f57ad plugins: set non_numeric_ids flag based on getmanifest `nonnumericids` field.
And document support for it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Plugins: `getmanfest` response can contain `nonnumericids` to indicate support for modern string-based JSON request ids.
Changelog-Deprecated: Plugins: numeric JSON request ids: modern ones will be strings (see doc/lightningd-rpc.7.md!)
2022-11-21 11:23:54 +01:00
Rusty Russell 3380f559f9 memleak: simplify API.
Mainly renaming.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-19 11:34:42 +09:30
Rusty Russell eceb9f4328 lightningd: wire plugin command JSON id through to plugin commands.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-16 12:31:45 +09:30
Rusty Russell a9557d5194 lightningd: derive JSONRPC ids from incoming id (append /cln:<method>#NNN).
Usually the calls are spontanous, so it's just "cln:<method>#NNN", but
json_invoice() calls listincoming, and json_checkmessage calls
listnodes, so those become "cli:invoice-<pid>/cln:listincoming#NNN".

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-16 12:31:45 +09:30
Rusty Russell 8fcf880e0f lightningd: explicitly remember if JSON id was a string.
This lets us use 'cmd->id' as an unquoted string (for building
new ids!).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-16 12:31:45 +09:30
Rusty Russell ed3f700991 lightningd: use string as json req ids when we create them.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-16 12:31:45 +09:30
Rusty Russell 99f2019a24 lightningd: add jsonrpc_request_start_raw instead of NULL method.
Since we want to use methodname to create id, don't overload it
for a raw request.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-16 12:31:45 +09:30
Rusty Russell 375215a141 lightningd: more graceful shutdown.
Be more graceful in shutting down: this should fix the issue where
bookkeeper gets upset that its commands are rejected during shutdown,
and generally make things more graceful.

1. Stop any new RPC connections.
2. Stop any per-peer daemons (channeld, etc).
3. Shut down plugins.
4. Stop all existing RPC connections.
5. Stop global daemons.
6. Free up peer, chanen HTLC datastructures.
7. Close database.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: Plugins: RPC operations are now still available during shutdown.
2022-09-12 14:00:41 +02:00
Rusty Russell 29264e83fb lightningd: remove `use_proxy_always` parameter to plugin init.
Changelog-Removed: Plugins: plugin init `use_proxy_always` (deprecated v0.10.2)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-12 09:34:52 +09:30
Rusty Russell 733ce81bd4 plugins: require usage for plugin APIs.
Changelog-Removed: JSON-RPC: plugins must supply `usage` parameter (deprecated v0.7)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-12 09:34:52 +09:30
Rusty Russell 008a59b004 lightningd: ignore default if it's a literal 'null' JSON token.
I wondered how `tests/plugins/dblog.py` worked, since it is supposed to fail
unless the `dblog-file` arg is set:

```
@plugin.init()
def init(configuration, options, plugin):
    if not plugin.get_option('dblog-file'):
        raise RpcError("No dblog-file specified")
```

But it was set to "null".  That's because 'None' in python is turned into a literal
JSON "null", and we take that as the default value.

We also cleanup the popt->description double-assignment (a leftover
from when this was optional).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: plugins: setting the default value of a parameter to `null` is the same as not setting it (pyln plugins did this!).
2022-07-26 09:33:40 -07:00
Rusty Russell 401f1debc5 common: clean up json routine locations.
We have them split over common/param.c, common/json.c,
common/json_helpers.c, common/json_tok.c and common/json_stream.c.

Change that to:
* common/json_parse (all the json_to_xxx routines)
* common/json_parse_simple (simplest the json parsing routines, for cli too)
* common/json_stream (all the json_add_xxx routines)
* common/json_param (all the param and param_xxx routines)

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-07-15 12:24:00 -05:00
Vincenzo Palazzo b624c53051 plugin: add check on the type json object during the IO message handling 2022-07-14 12:49:23 -05:00
Simon Vrouwe cdf12d06ba lightningd: Make sure plugins don't register the same option "name"
The extra entry in opt_table would never be called, leaving plugins
clueless why options keep defaulting.

Note that option registration outside startup does nothing.
Instead, dynamic plugins can use `plugin start [second_parameter]` to pass options.
2022-07-10 21:09:41 -05:00
Simon Vrouwe 2fddfe3ffc lightningd: don't increment plugin state to NEEDS_INIT when error in getmanifest
Otherwise we hangs forever in startup when it was the last plugin, we would
miss destroy_plugin --> check_plugins_manifests --> io_break

e.g. when a plugin tries to register a bool option with a string as default value.
2022-07-10 21:09:41 -05:00
Simon Vrouwe 981fd2326a lightningd: convert plugin->cmd to absolute path, fail plugin early when non-existent
Otherwise different relative paths (e.g. /dir/plugin and /dir/../dir/plugin) to same plugin
executable would not be recognized as the same plugin
2022-07-10 21:09:41 -05:00
Rusty Russell 3f98cf3fce lightningd: track weird CI crash in test_important_plugin
Looks like we woke one of the startup io_loops early, and thus
we thought we'd finished connectd_activate and we hadn't.  This
caused us to use an uninitialized ld->announceable array, and
finally caused an assert fail in the main loop.

Make *every* loop assert that it was exited for the correct reason,
so if it happens again, we can maybe figure out what part of
the code to look at.

```
lightningd: lightningd/lightningd.c:1186: main: Assertion `io_loop_ret == ld' failed.
lightningd: FATAL SIGNAL 6 (version 4df66fa)
...
------------------------------- Valgrind errors --------------------------------
Valgrind error file: valgrind-errors.895509
==895509== Conditional jump or move depends on uninitialised value(s)
==895509==    at 0x22C58E: to_tal_hdr_or_null (tal.c:184)
==895509==    by 0x22D531: tal_bytelen (tal.c:637)
==895509==    by 0x1F10B6: towire_gossipd_init (gossipd_wiregen.c:100)
==895509==    by 0x13AC6E: gossip_init (gossip_control.c:254)
==895509==    by 0x1497EC: main (lightningd.c:1090)
==895509== 
```

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-06-27 17:21:35 +09:30
Rusty Russell e2f0ca9cbe lightningd: don't add null for unset plugin options.
In general, we don't like to use `null` in JSON: simply omit the
field.  I found this one because it broke our 'msat' parsing (made
stricter in followup) which doesn't allow `null`.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Deprecated: `listconfigs` `plugins` `options` which are not set are omitted, not `null`.
2022-06-21 06:52:35 +09:30
Rusty Russell 8b62e2584f connectd: remove enable-autotor-v2-mode option
Changelog-Removed: lightningd: removed `enable-autotor-v2-mode` option (deprecated v0.10.1)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-05-18 10:15:36 +09:30
Simon Vrouwe 426ff0abff lightningd: cleanup obsolete plugins->shutdown flag
After leaving the main event loop, the only path to destroy_plugin
goes via shutdown_plugins.
2021-12-14 09:33:10 +10:30
Simon Vrouwe f936fa926f plugins: simplify shutdown loop, simply close the db
The only thing that needs ld->wallet after this is destroy_invoices_waiter (off jsonrpc)
Could not find any other destructors (destroy_*) that need wallet or db access after this.
Any db access would now segfault.
2021-12-14 09:33:10 +10:30
Rusty Russell 484222b0a1 daemons: remove unused functions or make static.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-12-06 10:05:39 +10:30
Rusty Russell 4ffda340d3 check: make sure all files outside contrib/ include "config.h" first.
And turn "" includes into full-path (which makes it easier to put
config.h first, and finds some cases check-includes.sh missed
previously).

config.h sets _GNU_SOURCE which really needs to be done before any
'#includes': we mainly got away with it with glibc, but other platforms
like Alpine may have stricter requirements.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-12-06 10:05:39 +10:30
Simon Vrouwe 209614677a JSON RPC: In the shutdown loop, ignore plugin responses to JSON RPC requests 2021-11-30 13:34:44 +10:30
Simon Vrouwe 5f69674faa lightningd: shutdown plugins after subdaemons and assert no write access to db
because:
    - shutdown_subdaemons can trigger db write, comments in that function say so at least
    - resurrecting the main event loop with subdaemons still running is counter productive
      in shutting down activity (such as htlc's, hook_calls etc.)
    - custom behavior injected by plugins via hooks should be consistent, see test
      in previous commmit

    IDEA:

    in shutdown_plugins, when starting new io_loop:

    - A plugin that is still running can return a jsonrpc_request response, this triggers
      response_cb, which cannot be handled because subdaemons are gone -> so any response_cb should be blocked/aborted

    - jsonrpc is still there, so users (such as plugins) can make new jsonrpc_request's which
      cannot be handled because subdaemons are gone -> so new rpc_request should also be blocked

    - But we do want to send/receive notifications and log messages (handled in jsonrpc as jsonrpc_notification)
      as these do not trigger subdaemon calls or db_write's
      Log messages and notifications do not have "id" field, where jsonrpc_request *do* have an "id" field

    PLAN (hypothesis):
    - hack into plugin_read_json_one OR plugin_response_handle to filter-out json with
      an "id" field, this should
      block/abandon any jsonrpc_request responses (and new jsonrpc_requests for plugins?)

  Q. Can internal (so not via plugin) jsonrpc_requests called in the main io_loop return/revive in
     the shutdown io_loop?
  A. No. All code under lightningd/ returning command_still_pending depends on either a subdaemon, timer or
     plugin. In shutdown loop the subdaemons are dead, timer struct cleared and plugins will be taken
     care of (in next commits).

 fixup: we can only io_break the main io_loop once
2021-11-30 13:34:44 +10:30
Rusty Russell 65bb989cf1 pytest: don't checksum plugins on startup in VALGRIND developer mode.
This loads up 20MB of plugins temporarily; we seem to be getting OOM
killed under CI and I wonder if this is contributing.

Doesn't significantly reduce runtime here, but I have lots of memory.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-11-14 18:49:46 +01:00
Rusty Russell 7401b26824 cleanup: remove unneeded includes in C files.
Before:
 Ten builds, laptop -j5, no ccache:

```
real	0m36.686000-38.956000(38.608+/-0.65)s
user	2m32.864000-42.253000(40.7545+/-2.7)s
sys	0m16.618000-18.316000(17.8531+/-0.48)s
```

 Ten builds, laptop -j5, ccache (warm):

```
real	0m8.212000-8.577000(8.39989+/-0.13)s
user	0m12.731000-13.212000(12.9751+/-0.17)s
sys	0m3.697000-3.902000(3.83722+/-0.064)s
```

After:
 Ten builds, laptop -j5, no ccache: 8% faster

```
real	0m33.802000-35.773000(35.468+/-0.54)s
user	2m19.073000-27.754000(26.2542+/-2.3)s
sys	0m15.784000-17.173000(16.7165+/-0.37)s
```

 Ten builds, laptop -j5, ccache (warm): 1% faster

```
real	0m8.200000-8.485000(8.30138+/-0.097)s
user	0m12.485000-13.100000(12.7344+/-0.19)s
sys	0m3.702000-3.889000(3.78787+/-0.056)s
```

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-09-17 09:43:22 +09:30
Rusty Russell ea30c34d82 cleanup: remove unneeded includes in header files.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-09-17 09:43:22 +09:30
Rusty Russell 1d8aecb44f lightningd: call "shutdown" notification on plugins at shutdown.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Plugins: `shutdown` notification for clean exits.
2021-09-05 15:16:56 +02:00
Michael Schmoock 24ea498350 cleanup: rename use_proxy_always to always_use_proxy to match cfg
This renames all occurences of use_proxy_always to always_use_proxy
to keep it inline with config values. This was a bit confusing.

Only significant change is that the payload in the plugins init
requests also contained the old name. No plugin currently seems to make
use of this variable yet. The old name 'use_proxy_always' is added when
deprecated APIs is enabled.

Changelog-Deprecated: Plugins: Renames plugin init 'use_proxy_always' to 'always_use_proxy'
2021-08-23 14:43:40 +09:30
Michael Schmoock ec9693863d plugin: rescan restarts plugin on update
This adds a `u32 checksum` field to the plugin struct that is used
to identify if a plugin is outdated and needs to be restarted on `rescan`.

Note: Only affects non-important plugins.

Changelog-Added: Plugin: Restart plugin on `rescan` when binary was changed.
2021-07-15 13:26:05 -04:00
Rusty Russell bf74be3348 plugins: add `command` field to subcommand output.
Makes it possible to write a decent JSON schema, but means we need to carry
additional data, so we create a `struct plugin_command`.

We remove the unused struct dynamic_plugin, too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-06-25 09:49:33 +09:30
Rusty Russell 214fdcc9d7 plugin notifications: minor cleanups.
1. We don't need to check for NULL before tal_count(NULL).
2. Use of json_for_each_arr iterator is probably better.
3. Weird indent fixed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-05-14 10:24:05 +09:30
Christian Decker 98aa3c3da7 plugin: Make unannounced notification topics no longer fatal
Since plugins will start sending them soon, and they are likely to get
it wrong sometimes, be a bit more lenient, warn them in the logs
instead and then make sure it doesn't accidentally work anyway.
2021-05-03 11:20:15 +09:30
Christian Decker f08ae49134 plugin: Restrict plugin notifications only to announced topics
We want to have well-behaved notifications that are clearly announced
during the initialization, kill plugins that don't behave.
2021-05-03 11:20:15 +09:30
Christian Decker 62e3358a5b plugin: Wrap custom notifications in a dict with additional origin
This should allow us to differentiate the origin of the notification,
and further prevent plugins from spoofing native notifications.
2021-05-03 11:20:15 +09:30
Christian Decker cfb1107244 plugin: Remember the shortname for a plugin
We use it in a couple of places, so let's remember it for easier
access.
2021-05-03 11:20:15 +09:30
Christian Decker 2e27e4e443 plugin: Move list of notification topics to each plugin
We want to ensure that plugins register their topics before sending
any notification, so we need to remember which plugin registered which
topics.
2021-05-03 11:20:15 +09:30
Christian Decker c8c2c33952 plugin: Prevent plugins from registering native notification topics
They may already have subscribers, and they may crash if presented
with a malformed notification.
2021-05-03 11:20:15 +09:30
Christian Decker f716c55983 plugin: Implement custom notification dispatch for plugins
Changelog-Added: plugin: Plugins may now send custom notifications that other plugins can subscribe to.
2021-05-03 11:20:15 +09:30
Christian Decker 9d310366af plugin: Store the notification topics announced by the plugins 2021-05-03 11:20:15 +09:30
Christian Decker f77a0bcd8f plugin: Move the notification subscription check into a second phase
A plugin might subscribe to a notification topic that is only
registered by another plugin later, so push the check to that
consistency check phase where we do hook ordering as well.
2021-05-03 11:20:15 +09:30
Christian Decker 083b41f090 plugin: Add a list of notification topics registered by plugin
We will eventually start emitting and dispatching custom notifications
from plugins just like we dispatch internal notifications. In order to
get reasonable error messages we need to make sure that the topics
plugins are asking for were correctly registered. When doing this we
don't really care about whether the plugin that registered the
notification is still alive or not (it might have died, but
subscribers should stay up and running), so we keep a list of all
topics attached to the `struct plugins` which gathers global plugin
information.
2021-05-03 11:20:15 +09:30
Rusty Russell da4c2cab62 plugin: always send allow-deprecated-apis in getmanifest.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: plugins: we now always send `allow-deprecated-apis` in getmanifest.
2021-04-07 14:34:39 +09:30
Christian Decker 0bc8a47226 plugin: Add details about which plugin caused a clash in RPC methods 2021-03-10 12:03:10 -06:00
Rusty Russell 171af7742a plugin: log self-disable at debug level, other manifest fails at unusual.
This avoids spamming the logs.  We also remove the duplicate debug
logs on self-disable (plugin_kill logs it for us).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-03-01 12:16:42 +01:00