Skip to content

Commit

Permalink
plugins: make chained hooks have two different callbacks.
Browse files Browse the repository at this point in the history
One is called on every plugin return, and tells us whether to continue;
the other is only called if every plugin says ok.

This works for things like payload replacement, where we need to process
the results from each plugin, not just the final one!

We should probably turn everything into a chained callback next
release.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Apr 15, 2020
1 parent b94c7f1 commit c1ee2ab
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 138 deletions.
9 changes: 4 additions & 5 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,10 @@ invoice_payment_hook_cb(struct invoice_payment_hook_payload *payload STEALS,
htlc_set_fulfill(payload->set, &payload->preimage);
}

REGISTER_PLUGIN_HOOK(invoice_payment,
PLUGIN_HOOK_SINGLE,
invoice_payment_hook_cb,
invoice_payment_serialize,
struct invoice_payment_hook_payload *);
REGISTER_SINGLE_PLUGIN_HOOK(invoice_payment,
invoice_payment_hook_cb,
invoice_payment_serialize,
struct invoice_payment_hook_payload *);

const struct invoice_details *
invoice_check_payment(const tal_t *ctx,
Expand Down
8 changes: 4 additions & 4 deletions lightningd/jsonrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,10 +769,10 @@ rpc_command_hook_callback(struct rpc_command_hook_payload *p STEALS,
"Bad response to 'rpc_command' hook."));
}

REGISTER_PLUGIN_HOOK(rpc_command, PLUGIN_HOOK_SINGLE,
rpc_command_hook_callback,
rpc_command_hook_serialize,
struct rpc_command_hook_payload *);
REGISTER_SINGLE_PLUGIN_HOOK(rpc_command,
rpc_command_hook_callback,
rpc_command_hook_serialize,
struct rpc_command_hook_payload *);

static void call_rpc_command_hook(struct rpc_command_hook_payload *p)
{
Expand Down
8 changes: 3 additions & 5 deletions lightningd/onion_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,15 @@ onion_message_serialize(struct onion_message_hook_payload *payload,
}

static void
onion_message_hook_cb(struct onion_message_hook_payload *payload STEALS,
const char *buffer,
const jsmntok_t *toks)
onion_message_hook_cb(struct onion_message_hook_payload *payload STEALS)
{
/* The core infra checks the "result"; anything other than continue
/* plugin_hook_continue checks the "result"; anything other than continue
* just stops. */
tal_free(payload);
}

REGISTER_PLUGIN_HOOK(onion_message,
PLUGIN_HOOK_CHAIN,
plugin_hook_continue,
onion_message_hook_cb,
onion_message_serialize,
struct onion_message_hook_payload *);
Expand Down
9 changes: 4 additions & 5 deletions lightningd/opening_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -826,11 +826,10 @@ static void openchannel_hook_cb(struct openchannel_hook_payload *payload STEALS,
our_upfront_shutdown_script)));
}

REGISTER_PLUGIN_HOOK(openchannel,
PLUGIN_HOOK_SINGLE,
openchannel_hook_cb,
openchannel_hook_serialize,
struct openchannel_hook_payload *);
REGISTER_SINGLE_PLUGIN_HOOK(openchannel,
openchannel_hook_cb,
openchannel_hook_serialize,
struct openchannel_hook_payload *);

static void opening_got_offer(struct subd *openingd,
const u8 *msg,
Expand Down
16 changes: 8 additions & 8 deletions lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -972,10 +972,10 @@ peer_connected_hook_cb(struct peer_connected_hook_payload *payload STEALS,
tal_free(payload);
}

REGISTER_PLUGIN_HOOK(peer_connected, PLUGIN_HOOK_SINGLE,
peer_connected_hook_cb,
peer_connected_serialize,
struct peer_connected_hook_payload *);
REGISTER_SINGLE_PLUGIN_HOOK(peer_connected,
peer_connected_hook_cb,
peer_connected_serialize,
struct peer_connected_hook_payload *);

/* Connectd tells us a peer has connected: it never hands us duplicates, since
* it holds them until we say peer_died. */
Expand Down Expand Up @@ -2309,10 +2309,10 @@ static void custommsg_payload_serialize(struct custommsg_payload *payload,
json_add_node_id(stream, "peer_id", &payload->peer_id);
}

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

void handle_custommsg_in(struct lightningd *ld, const struct node_id *peer_id,
const u8 *msg)
Expand Down
119 changes: 45 additions & 74 deletions lightningd/peer_htlcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,14 +794,6 @@ struct htlc_accepted_hook_payload {
size_t failtlvpos;
};

/* The possible return value types that a plugin may return for the
* `htlc_accepted` hook. */
enum htlc_accepted_result {
htlc_accepted_continue,
htlc_accepted_fail,
htlc_accepted_resolve,
};

/* We only handle the simplest cases here */
static u8 *convert_failcode(const tal_t *ctx,
struct lightningd *ld,
Expand Down Expand Up @@ -834,22 +826,19 @@ static u8 *convert_failcode(const tal_t *ctx,
}

/**
* Parses the JSON-RPC response into a struct understood by the callback.
* Callback when a plugin answers to the htlc_accepted hook
*/
static enum htlc_accepted_result
htlc_accepted_hook_deserialize(const tal_t *ctx,
struct lightningd *ld,
const char *buffer, const jsmntok_t *toks,
/* If accepted */
struct preimage *payment_preimage,
/* If rejected (tallocated off ctx) */
const u8 **failmsg)
static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *request,
const char *buffer,
const jsmntok_t *toks)
{
struct htlc_in *hin = request->hin;
struct lightningd *ld = request->ld;
struct preimage payment_preimage;
const jsmntok_t *resulttok, *paykeytok;
enum htlc_accepted_result result;

if (!toks || !buffer)
return htlc_accepted_continue;
return true;

resulttok = json_get_member(buffer, toks, "result");

Expand All @@ -861,18 +850,18 @@ htlc_accepted_hook_deserialize(const tal_t *ctx,
}

if (json_tok_streq(buffer, resulttok, "continue")) {
return htlc_accepted_continue;
return true;
}

if (json_tok_streq(buffer, resulttok, "fail")) {
u8 *failmsg;
const jsmntok_t *failmsgtok, *failcodetok;

result = htlc_accepted_fail;
failmsgtok = json_get_member(buffer, toks, "failure_message");
if (failmsgtok) {
*failmsg = json_tok_bin_from_hex(ctx, buffer,
failmsgtok);
if (!*failmsg)
failmsg = json_tok_bin_from_hex(NULL, buffer,
failmsgtok);
if (!failmsg)
fatal("Bad failure_message for htlc_accepted"
" hook: %.*s",
failmsgtok->end - failmsgtok->start,
Expand All @@ -887,30 +876,29 @@ htlc_accepted_hook_deserialize(const tal_t *ctx,
failcodetok->end
- failcodetok->start,
buffer + failcodetok->start);
*failmsg = convert_failcode(ctx, ld, failcode);
failmsg = convert_failcode(NULL, ld, failcode);
} else
*failmsg = towire_temporary_node_failure(ctx);
failmsg = towire_temporary_node_failure(NULL);
local_fail_in_htlc(hin, take(failmsg));
return false;
} else if (json_tok_streq(buffer, resulttok, "resolve")) {
result = htlc_accepted_resolve;
paykeytok = json_get_member(buffer, toks, "payment_key");
if (!paykeytok)
fatal(
"Plugin did not specify a 'payment_key' in return "
"value to the htlc_accepted hook: %s",
json_strdup(tmpctx, buffer, resulttok));

if (!json_to_preimage(buffer, paykeytok,
payment_preimage))
if (!json_to_preimage(buffer, paykeytok, &payment_preimage))
fatal("Plugin specified an invalid 'payment_key': %s",
json_tok_full(buffer, resulttok));
fulfill_htlc(hin, &payment_preimage);
return false;
} else {
fatal("Plugin responded with an unknown result to the "
"htlc_accepted hook: %s",
json_strdup(tmpctx, buffer, resulttok));
}

/* cppcheck-suppress uninitvar - false positive on fatal() above */
return result;
}

static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,
Expand Down Expand Up @@ -975,57 +963,40 @@ static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,
* Callback when a plugin answers to the htlc_accepted hook
*/
static void
htlc_accepted_hook_callback(struct htlc_accepted_hook_payload *request STEALS,
const char *buffer, const jsmntok_t *toks)
htlc_accepted_hook_final(struct htlc_accepted_hook_payload *request STEALS)
{
struct route_step *rs = request->route_step;
struct htlc_in *hin = request->hin;
struct channel *channel = request->channel;
struct lightningd *ld = request->ld;
struct preimage payment_preimage;
enum htlc_accepted_result result;
const u8 *failmsg;
result = htlc_accepted_hook_deserialize(request, ld, buffer, toks, &payment_preimage, &failmsg);

switch (result) {
case htlc_accepted_continue:
/* *Now* we barf if it failed to decode */
if (!request->payload) {
log_debug(channel->log,
"Failing HTLC because of an invalid payload");
local_fail_in_htlc(hin,
take(towire_invalid_onion_payload(
NULL, request->failtlvtype,
request->failtlvpos)));
} else if (rs->nextcase == ONION_FORWARD) {
forward_htlc(hin, hin->cltv_expiry,
request->payload->amt_to_forward,
request->payload->outgoing_cltv,
request->payload->forward_channel,
serialize_onionpacket(tmpctx, rs->next),
request->next_blinding);
} else
handle_localpay(hin,
request->payload->amt_to_forward,
request->payload->outgoing_cltv,
*request->payload->total_msat,
request->payload->payment_secret);
break;
case htlc_accepted_fail:

/* *Now* we barf if it failed to decode */
if (!request->payload) {
log_debug(channel->log,
"Failing incoming HTLC as instructed by plugin hook");
local_fail_in_htlc(hin, take(failmsg));
break;
case htlc_accepted_resolve:
fulfill_htlc(hin, &payment_preimage);
break;
}
"Failing HTLC because of an invalid payload");
local_fail_in_htlc(hin,
take(towire_invalid_onion_payload(
NULL, request->failtlvtype,
request->failtlvpos)));
} else if (rs->nextcase == ONION_FORWARD) {
forward_htlc(hin, hin->cltv_expiry,
request->payload->amt_to_forward,
request->payload->outgoing_cltv,
request->payload->forward_channel,
serialize_onionpacket(tmpctx, rs->next),
request->next_blinding);
} else
handle_localpay(hin,
request->payload->amt_to_forward,
request->payload->outgoing_cltv,
*request->payload->total_msat,
request->payload->payment_secret);

tal_free(request);
}

REGISTER_PLUGIN_HOOK(htlc_accepted, PLUGIN_HOOK_CHAIN,
htlc_accepted_hook_callback,
REGISTER_PLUGIN_HOOK(htlc_accepted,
htlc_accepted_hook_deserialize,
htlc_accepted_hook_final,
htlc_accepted_hook_serialize,
struct htlc_accepted_hook_payload *);

Expand Down
Loading

0 comments on commit c1ee2ab

Please sign in to comment.