Skip to content
Merged
70 changes: 48 additions & 22 deletions doc/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,8 @@ above for example subscribes to the two topics `connect` and
`disconnect`. The topics that are currently defined and the
corresponding payloads are listed below.

### Notification Types

#### `channel_opened`
### `channel_opened`

A notification for topic `channel_opened` is sent if a peer successfully funded a channel
with us. It contains the peer id, the funding amount (in millisatoshis), the funding
Expand All @@ -257,7 +256,7 @@ into a block.
}
```

#### `connect`
### `connect`

A notification for topic `connect` is sent every time a new connection
to a peer is established.
Expand All @@ -269,7 +268,7 @@ to a peer is established.
}
```

#### `disconnect`
### `disconnect`

A notification for topic `disconnect` is sent every time a connection
to a peer was lost.
Expand All @@ -280,7 +279,7 @@ to a peer was lost.
}
```

#### `invoice_payment`
### `invoice_payment`

A notification for topic `invoice_payment` is sent every time an invoie is paid.

Expand All @@ -294,7 +293,7 @@ A notification for topic `invoice_payment` is sent every time an invoie is paid.
}
```

#### `warning`
### `warning`

A notification for topic `warning` is sent every time a new `BROKEN`
/`UNUSUAL` level(in plugins, we use `error`/`warn`) log generated,
Expand Down Expand Up @@ -322,7 +321,7 @@ forms:
`jcon fd <error_fd_to_jsonrpc>:`, `plugin-manager`;
4. `log` is the context of the original log entry.

#### `forward_event`
### `forward_event`

A notification for topic `forward_event` is sent every time the status
of a forward payment is set. The json format is same as the API
Expand Down Expand Up @@ -405,7 +404,7 @@ or
only `settled` and `failed` case contain `resolved_time`;
- The `failcode` and `failreason` are defined in [BOLT 4][bolt4-failure-codes].

#### `sendpay_success`
### `sendpay_success`

A notification for topic `sendpay_success` is sent every time a sendpay
succeeds (with `complete` status). The json is the same as the return value of
Expand All @@ -432,7 +431,7 @@ returns the result of sendpay in specified time or timeout, but
`sendpay_success` will always return the result anytime when sendpay
successes if is was subscribed.

#### `sendpay_failure`
### `sendpay_failure`

A notification for topic `sendpay_failure` is sent every time a sendpay
completes with `failed` status. The JSON is same as the return value of
Expand Down Expand Up @@ -476,17 +475,40 @@ declares that it'd like to be consulted on what to do next for certain
events in the daemon. A hook can then decide how `lightningd` should
react to the given event.

The call semantics of the hooks, i.e., when and how hooks are called, depend
on the hook type. Most hooks are currently set to `single`-mode. In this mode
only a single plugin can register the hook, and that plugin will get called
for each event of that type. If a second plugin attempts to register the hook
it gets killed and a corresponding log entry will be added to the logs. In
`chain`-mode multiple plugins can register for the hook type and they are
called sequentially if a matching event is triggered. Each plugin can then
handle the event or defer by returning a `continue` result like the following:

```json
{
"result": "continue"
}
```

The remainder of the response is ignored and if there are any more plugins
that have registered the hook the next one gets called. If there are no more
plugins then the internal handling is resumed as if no hook had been
called. Any other result returned by a plugin is considered an exit from the
chain. Upon exit no more plugin hooks are called for the current event, and
the result is executed. Unless otherwise stated all hooks are `single`-mode.

Hooks and notifications are very similar, however there are a few
key differences:

- Notifications are asynchronous, i.e., `lightningd` will send the
notifications but not wait for the plugin to process them. Hooks on
the other hand are synchronous, `lightningd` cannot finish
processing the event until the plugin has returned.
- Any number of plugins can subscribe to a notification topic,
however only one plugin may register for any hook topic at any
point in time (we cannot disambiguate between multiple plugins
returning contradictory results from a hook callback).
- Any number of plugins can subscribe to a notification topic and get
notified in parallel, however only one plugin may register for
`single`-mode hook types, and in all cases only one plugin may return a
non-`continue` response. This avoids having multiple contradictory
responses.

Hooks are considered to be an advanced feature due to the fact that
`lightningd` relies on the plugin to tell it what to do next. Use them
Expand All @@ -497,9 +519,7 @@ As a convention, for all hooks, returning the object
`{ "result" : "continue" }` results in `lightningd` behaving exactly as if
no plugin is registered on the hook.

### Hook Types

#### `peer_connected`
### `peer_connected`

This hook is called whenever a peer has connected and successfully completed
the cryptographic handshake. The parameters have the following structure if there is a channel with the peer:
Expand Down Expand Up @@ -527,7 +547,7 @@ there's a member `error_message`, that member is sent to the peer
before disconnection.


#### `db_write`
### `db_write`

This hook is called whenever a change is about to be committed to the database.
It is currently extremely restricted:
Expand Down Expand Up @@ -600,7 +620,7 @@ to error without
committing to the database!
This is the expected way to halt and catch fire.

#### `invoice_payment`
### `invoice_payment`

This hook is called whenever a valid payment for an unpaid invoice has arrived.

Expand All @@ -622,7 +642,7 @@ nodes in [BOLT 4][bolt4-failure-codes], a `result` field with the string
`result` field with the string `continue` to accept the payment.


#### `openchannel`
### `openchannel`

This hook is called whenever a remote peer tries to fund a channel to us,
and it has passed basic sanity checks:
Expand Down Expand Up @@ -668,7 +688,7 @@ e.g.
Note that `close_to` must be a valid address for the current chain; an invalid address will cause the node to exit with an error.


#### `htlc_accepted`
### `htlc_accepted`

The `htlc_accepted` hook is called whenever an incoming HTLC is accepted, and
its result determines how `lightningd` should treat that HTLC.
Expand Down Expand Up @@ -769,8 +789,14 @@ processed before the HTLC was forwarded, failed, or resolved, then the plugin
may see the same HTLC again during startup. It is therefore paramount that the
plugin is idempotent if it talks to an external system.

The `htlc_accepted` hook is a chained hook, i.e., multiple plugins can
register it, and they will be called in the order they were registered in
until the first plugin return a result that is not `{"result": "continue"}`,
after which the event is considered to be handled. After the event has been
handled the remaining plugins will be skipped.


#### `rpc_command`
### `rpc_command`

The `rpc_command` hook allows a plugin to take over any RPC command. It sends
the received JSON-RPC request to the registered plugin,
Expand Down Expand Up @@ -837,7 +863,7 @@ Return a custom error to the request sender:
```


#### `custommsg`
### `custommsg`

The `custommsg` plugin hook is the receiving counterpart to the
[`dev-sendcustommsg`][sendcustommsg] RPC method and allows plugins to handle
Expand Down
1 change: 1 addition & 0 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ invoice_payment_hook_cb(struct invoice_payment_hook_payload *payload,
}

REGISTER_PLUGIN_HOOK(invoice_payment,
PLUGIN_HOOK_SINGLE,
invoice_payment_hook_cb,
struct invoice_payment_hook_payload *,
invoice_payment_serialize,
Expand Down
3 changes: 2 additions & 1 deletion lightningd/jsonrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,8 @@ rpc_command_hook_callback(struct rpc_command_hook_payload *p,
"Bad response to 'rpc_command' hook."));
}

REGISTER_PLUGIN_HOOK(rpc_command, rpc_command_hook_callback,
REGISTER_PLUGIN_HOOK(rpc_command, PLUGIN_HOOK_SINGLE,
rpc_command_hook_callback,
struct rpc_command_hook_payload *,
rpc_command_hook_serialize,
struct rpc_command_hook_payload *);
Expand Down
1 change: 1 addition & 0 deletions lightningd/opening_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ static void openchannel_hook_cb(struct openchannel_hook_payload *payload,
}

REGISTER_PLUGIN_HOOK(openchannel,
PLUGIN_HOOK_SINGLE,
openchannel_hook_cb,
struct openchannel_hook_payload *,
openchannel_hook_serialize,
Expand Down
8 changes: 5 additions & 3 deletions lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,8 @@ peer_connected_hook_cb(struct peer_connected_hook_payload *payload,
tal_free(payload);
}

REGISTER_PLUGIN_HOOK(peer_connected, peer_connected_hook_cb,
REGISTER_PLUGIN_HOOK(peer_connected, PLUGIN_HOOK_SINGLE,
peer_connected_hook_cb,
struct peer_connected_hook_payload *,
peer_connected_serialize,
struct peer_connected_hook_payload *);
Expand Down Expand Up @@ -2393,8 +2394,9 @@ static void custommsg_payload_serialize(struct custommsg_payload *payload,
json_add_node_id(stream, "peer_id", &payload->peer_id);
}

REGISTER_PLUGIN_HOOK(custommsg, custommsg_callback, struct custommsg_payload *,
custommsg_payload_serialize, struct custommsg_payload *);
REGISTER_PLUGIN_HOOK(custommsg, PLUGIN_HOOK_SINGLE, custommsg_callback,
struct custommsg_payload *, custommsg_payload_serialize,
struct custommsg_payload *);

void handle_custommsg_in(struct lightningd *ld, const struct node_id *peer_id,
const u8 *msg)
Expand Down
3 changes: 2 additions & 1 deletion lightningd/peer_htlcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,8 @@ htlc_accepted_hook_callback(struct htlc_accepted_hook_payload *request,
tal_free(request);
}

REGISTER_PLUGIN_HOOK(htlc_accepted, htlc_accepted_hook_callback,
REGISTER_PLUGIN_HOOK(htlc_accepted, PLUGIN_HOOK_CHAIN,
Comment thread
cdecker marked this conversation as resolved.
htlc_accepted_hook_callback,
struct htlc_accepted_hook_payload *,
htlc_accepted_hook_serialize,
struct htlc_accepted_hook_payload *);
Expand Down
Loading