mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
plugin: Parse response for htlc_accepted hook
Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
committed by
Rusty Russell
parent
bf53821f1a
commit
2b81e02a2e
@@ -38,7 +38,7 @@ def on_disconnect(plugin, id):
|
||||
def on_htlc_accepted(onion, htlc, plugin):
|
||||
plugin.log('on_htlc_accepted called')
|
||||
time.sleep(20)
|
||||
return None
|
||||
return {'result': 'continue'}
|
||||
|
||||
|
||||
plugin.add_option('greeting', 'Hello', 'The greeting I should use.')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/cast/cast.h>
|
||||
@@ -624,10 +625,22 @@ struct htlc_accepted_hook_payload {
|
||||
u8 *next_onion;
|
||||
};
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
/**
|
||||
* Response type from the plugin
|
||||
*/
|
||||
struct htlc_accepted_hook_response {
|
||||
enum htlc_accepted_result result;
|
||||
struct preimage payment_key;
|
||||
enum onion_type failure_code;
|
||||
u8 *channel_update;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -637,7 +650,64 @@ static struct htlc_accepted_hook_response *
|
||||
htlc_accepted_hook_deserialize(const tal_t *ctx, const char *buffer,
|
||||
const jsmntok_t *toks)
|
||||
{
|
||||
return NULL;
|
||||
struct htlc_accepted_hook_response *response;
|
||||
const jsmntok_t *resulttok, *failcodetok, *paykeytok, *chanupdtok;
|
||||
|
||||
if (!toks || !buffer)
|
||||
return NULL;
|
||||
|
||||
resulttok = json_get_member(buffer, toks, "result");
|
||||
|
||||
/* If the result is "continue" we can just return NULL since
|
||||
* this is the default behavior for this hook anyway */
|
||||
if (!resulttok) {
|
||||
fatal("Plugin return value does not contain 'result' key %s",
|
||||
json_strdup(tmpctx, buffer, toks));
|
||||
}
|
||||
|
||||
if (json_tok_streq(buffer, resulttok, "continue")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
response = tal(ctx, struct htlc_accepted_hook_response);
|
||||
if (json_tok_streq(buffer, resulttok, "fail")) {
|
||||
response->result = htlc_accepted_fail;
|
||||
failcodetok = json_get_member(buffer, toks, "failure_code");
|
||||
chanupdtok = json_get_member(buffer, toks, "channel_update");
|
||||
if (failcodetok && !json_to_number(buffer, failcodetok,
|
||||
&response->failure_code))
|
||||
fatal("Plugin provided a non-numeric failcode "
|
||||
"in response to an htlc_accepted hook");
|
||||
|
||||
if (!failcodetok)
|
||||
response->failure_code = WIRE_TEMPORARY_NODE_FAILURE;
|
||||
|
||||
if (chanupdtok)
|
||||
response->channel_update =
|
||||
json_tok_bin_from_hex(response, buffer, chanupdtok);
|
||||
else
|
||||
response->channel_update = NULL;
|
||||
|
||||
} else if (json_tok_streq(buffer, resulttok, "resolve")) {
|
||||
response->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,
|
||||
&response->payment_key))
|
||||
fatal("Plugin specified an invalid 'payment_key': %s",
|
||||
json_tok_full(buffer, resulttok));
|
||||
} else {
|
||||
fatal("Plugin responded with an unknown result to the "
|
||||
"htlc_accepted hook: %s",
|
||||
json_strdup(tmpctx, buffer, resulttok));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,
|
||||
@@ -679,29 +749,53 @@ htlc_accepted_hook_callback(struct htlc_accepted_hook_payload *request,
|
||||
struct channel *channel = request->channel;
|
||||
struct lightningd *ld = request->ld;
|
||||
u8 *req;
|
||||
enum htlc_accepted_result result;
|
||||
struct htlc_accepted_hook_response *response;
|
||||
response = htlc_accepted_hook_deserialize(request, buffer, toks);
|
||||
|
||||
/* TODO(cdecker) Assign to *response once we actually use it */
|
||||
htlc_accepted_hook_deserialize(request, buffer, toks);
|
||||
if (response)
|
||||
result = response->result;
|
||||
else
|
||||
result = htlc_accepted_continue;
|
||||
|
||||
if (rs->nextcase == ONION_FORWARD) {
|
||||
struct gossip_resolve *gr = tal(ld, struct gossip_resolve);
|
||||
switch (result) {
|
||||
case htlc_accepted_continue:
|
||||
if (rs->nextcase == ONION_FORWARD) {
|
||||
struct gossip_resolve *gr =
|
||||
tal(ld, struct gossip_resolve);
|
||||
|
||||
gr->next_onion = tal_steal(gr, request->next_onion);
|
||||
gr->next_channel = rs->hop_data.channel_id;
|
||||
gr->amt_to_forward = rs->hop_data.amt_forward;
|
||||
gr->outgoing_cltv_value = rs->hop_data.outgoing_cltv;
|
||||
gr->hin = hin;
|
||||
gr->next_onion = tal_steal(gr, request->next_onion);
|
||||
serialize_onionpacket(gr, rs->next);
|
||||
gr->next_channel = rs->hop_data.channel_id;
|
||||
gr->amt_to_forward = rs->hop_data.amt_forward;
|
||||
gr->outgoing_cltv_value = rs->hop_data.outgoing_cltv;
|
||||
gr->hin = hin;
|
||||
|
||||
req = towire_gossip_get_channel_peer(tmpctx,
|
||||
&gr->next_channel);
|
||||
log_debug(
|
||||
channel->log, "Asking gossip to resolve channel %s",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&gr->next_channel));
|
||||
subd_req(hin, ld->gossip, req, -1, 0,
|
||||
channel_resolve_reply, gr);
|
||||
} else
|
||||
handle_localpay(hin, hin->cltv_expiry,
|
||||
&hin->payment_hash,
|
||||
rs->hop_data.amt_forward,
|
||||
rs->hop_data.outgoing_cltv);
|
||||
|
||||
break;
|
||||
case htlc_accepted_fail:
|
||||
log_debug(channel->log,
|
||||
"Failing incoming HTLC as instructed by plugin hook");
|
||||
fail_in_htlc(hin, response->failure_code, NULL, NULL);
|
||||
break;
|
||||
case htlc_accepted_resolve:
|
||||
fulfill_htlc(hin, &response->payment_key);
|
||||
break;
|
||||
}
|
||||
|
||||
req = towire_gossip_get_channel_peer(tmpctx, &gr->next_channel);
|
||||
log_debug(channel->log, "Asking gossip to resolve channel %s",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&gr->next_channel));
|
||||
subd_req(hin, ld->gossip, req, -1, 0,
|
||||
channel_resolve_reply, gr);
|
||||
} else
|
||||
handle_localpay(hin, hin->cltv_expiry, &hin->payment_hash,
|
||||
rs->hop_data.amt_forward,
|
||||
rs->hop_data.outgoing_cltv);
|
||||
tal_free(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -299,9 +299,15 @@ void json_object_end(struct json_stream *js UNNEEDED)
|
||||
/* Generated stub for json_object_start */
|
||||
void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED)
|
||||
{ fprintf(stderr, "json_object_start called!\n"); abort(); }
|
||||
/* Generated stub for json_strdup */
|
||||
char *json_strdup(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
|
||||
{ fprintf(stderr, "json_strdup called!\n"); abort(); }
|
||||
/* Generated stub for json_stream_success */
|
||||
struct json_stream *json_stream_success(struct command *cmd UNNEEDED)
|
||||
{ fprintf(stderr, "json_stream_success called!\n"); abort(); }
|
||||
/* Generated stub for json_tok_bin_from_hex */
|
||||
u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
|
||||
{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); }
|
||||
/* Generated stub for json_tok_channel_id */
|
||||
bool json_tok_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
struct channel_id *cid UNNEEDED)
|
||||
@@ -319,6 +325,17 @@ bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
struct node_id *id UNNEEDED)
|
||||
{ fprintf(stderr, "json_to_node_id called!\n"); abort(); }
|
||||
/* Generated stub for json_to_number */
|
||||
bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
unsigned int *num UNNEEDED)
|
||||
{ fprintf(stderr, "json_to_number called!\n"); abort(); }
|
||||
/* Generated stub for json_to_preimage */
|
||||
bool json_to_preimage(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct preimage *preimage UNNEEDED)
|
||||
{ fprintf(stderr, "json_to_preimage called!\n"); abort(); }
|
||||
/* Generated stub for json_to_pubkey */
|
||||
bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
struct pubkey *pubkey UNNEEDED)
|
||||
{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); }
|
||||
/* Generated stub for json_to_short_channel_id */
|
||||
bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
struct short_channel_id *scid UNNEEDED,
|
||||
|
||||
Reference in New Issue
Block a user