-
Notifications
You must be signed in to change notification settings - Fork 906
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
Allow hook chaining for the htlc_accepted
hook
#3489
Allow hook chaining for the htlc_accepted
hook
#3489
Conversation
70e5355
to
7367597
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 7367597
Tested with hacky jitrebalance.py
+ noise.py
combo tests.
Unrelated Travis spurious failure (actually common on all PRs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think we might now be buggy if we remove a plugin while it's supposed to be answering a hook? Request used to be freed previously, what now?
There are several possible fixes for plugins being removed while we're calling hooks.
The most specific would be to re-search hook.plugins for the plugin we were just on, and call the next one (O(n^2) but n is tiny). But the plugin could have been freed (unless we fix the above). We could attach a u64 for each hook.plugins[] entry (assigned off some global counter), and look for the next u64 instead.
What I was planning for this was that invocation of a hook would create a new list of plugins currently registered on that hook. Each list element would have a pointer to the plugin and a pointer to the hook invocation; the list element would be |
...
Even with the current scheme, we could walk all plugin_hook_request (we'd need a list somewhere), and if we're about to remove the We still need to check that we don't crap ourselves if the plugin gets removed while a hook is pending, though. Let me try that... |
OK, testing answered my question. If a plugin is freed, the requests are abandoned. This mean an HTLC is stuck, which is kinda nasty, but OK for now. I've filed a separate issue #3496 to track that. So there's no issue for now with this PR, please cleanup and apply. |
Yes, I had noticed that as well, and was planning to address this in a separate PR (using I'll address the feedback asap and update the PR 👍 Thanks for the review @rustyrussell and @ZmnSCPxj |
e9ace4b
to
d0ae53b
Compare
Added You can see the changes between the version reviewed and the current version of the PR here |
Now having a failing assertion:
Edit: Nevermind, turns out I killed the wrong one of the two overlapping checks. Now it works :-) |
d0ae53b
to
6cd0d59
Compare
The newly introduced type is used to determine what the call semantics of the hook are. We have `single` corresponding to the old behavior, as well as `chain` which allows multiple plugins to register for the hook, and they are then called sequentially (if all plugins return `{"result": "continue"}`) or exit the chain if the hook event was handled.
Switch from having a single plugin to a list of plugins. If the hook is of type single we will enforce that constraint on the number of registered plugins when attempting to add.
We are about to call multiple plugins, and we'll have to pass the payload into each call. Sadly the serialized stream gets consumed during the call, so keep the unserialized payload around.
We will be using `plugin_hook_call_next` as part of the loop to traverse all plugins that registered the hook, so group initialization in the init function and move per-plugin logic into `plugin_hook_call_next`
This used to be necessary because we allocated the `plugin_hook_request` off of the plugin instance (only tal allocated object we could grab at that time. Now the plugin was replaced by a list, which itself is tal-allocated, making that workaround pointless, or even wrong once we have multiple plugins registering for that hook.
Make the `htlc_accepted` hook the first chained hook in our repertoire. The plugins are called one after the other in order until we have no more plugins or the HTLC was handled by one of the plugins. If no plugins handles the HTLC we continue to handle it internally like always. Handling in this case means the plugin returns either `{"result": "resolve", ...}` or `{"result": "fail", ...}`. Changelog-Changed: plugin: Multiple plugins can now register for the htlc_accepted hook.
Triple nesting seems a bit excessive, I can't even read the titles in the sidebar of http://lightning.readthedocs.org anymore :-)
Trivial rebase... |
6cd0d59
to
d8c2a05
Compare
This pull request creates the infrastructure for registering multiple plugins
for a given hook and showcases this new capability with the
htlc_accepted
hook. The
htlc_accepted
hook was chosen due to its relative simple semanticsand because it currently is the hook with the most plugins making.
Before you could only use a single plugin that registers the
htlc_accepted
hook at a time, which was severely limiting its uses. With this you can
finally run multiple at the same time.
The
htlc_accepted
hook returns one of the following three outcomes:{"result": "continue"}
: the plugin signals that it could not handle theHTLC internally, so the chain continues. If there are more plugins that
have registered for this hook they get called, otherwise we handle
internally.
{"result": "fail", ...}
: the plugin decided that the HTLC should berejected, with the given parameters. This exits the call chain and fails
the HTLC. If there are more plugins they will not get called.
{"result": "resolve", ...}
: similar to the previous case, the pluginknows the preimage and choses to resolve this HTLC. The call chain is
exited, and no further plugins are called.
Future steps
The following details are as of yet not addressed in this pull request, but I
plan to continue working on these in new PRs:
which the plugins should be called
htlc_accepted
toregister multiple times, and we will enable more as the need arises and the
semantics are clarified.
fanout
type that calls all hooks in parallel,and collected the results again. One potential candidate is the
db_write
hook whose results can be combined into all
continue
s or at least onefail
.Related issues
sendcustommsg
RPC call and acustommsg
plugin hook forexperimental protocol extensions (Add a
sendcustommsg
RPC call and acustommsg
plugin hook for experimental protocol extensions #3315)