From 93a92f4f2f46e439ec9ce6a7513748ae38895a4e Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Mon, 30 Mar 2020 12:24:43 +0200 Subject: [PATCH] plugin: Implement the ability to receive keysend payments This still uses the experimental TLV-type, but once the type is standardized we can add detection for the new type quite easily. Changelog-Added: pay: The `keysend` plugin implements the ability to receive spontaneous payments (keysend) --- plugins/Makefile | 2 +- plugins/keysend.c | 103 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/plugins/Makefile b/plugins/Makefile index 5ea6f91e0..fce5bfd3e 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -59,7 +59,7 @@ plugins/fundchannel: common/addr.o $(PLUGIN_FUNDCHANNEL_OBJS) $(PLUGIN_LIB_OBJS) plugins/bcli: bitcoin/chainparams.o $(PLUGIN_BCLI_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) -plugins/keysend: bitcoin/chainparams.o $(PLUGIN_KEYSEND_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) +plugins/keysend: bitcoin/chainparams.o wire/gen_onion_wire.o $(PLUGIN_KEYSEND_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(PLUGIN_PAY_OBJS) $(PLUGIN_AUTOCLEAN_OBJS) $(PLUGIN_FUNDCHANNEL_OBJS) $(PLUGIN_BCLI_OBJS) $(PLUGIN_LIB_OBJS): $(PLUGIN_LIB_HEADER) diff --git a/plugins/keysend.c b/plugins/keysend.c index 1299701f5..56b837133 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -1,5 +1,8 @@ #include #include +#include + +#define PREIMAGE_TLV_TYPE 5482373484 static void init(struct plugin *p, const char *buf UNUSED, const jsmntok_t *config UNUSED) @@ -9,10 +12,108 @@ static void init(struct plugin *p, const char *buf UNUSED, static const struct plugin_command commands[] = { }; +static struct command_result *htlc_accepted_continue(struct command *cmd) +{ + struct json_stream *response; + response = jsonrpc_stream_success(cmd); + json_add_string(response, "result", "continue"); + return command_finished(cmd, response); +} + +static struct command_result *htlc_accepted_resolve(struct command *cmd, + char *hexpreimage) +{ + struct json_stream *response; + response = jsonrpc_stream_success(cmd); + json_add_string(response, "result", "resolve"); + json_add_string(response, "payment_key", hexpreimage); + return command_finished(cmd, response); +} + +static struct command_result *htlc_accepted_call(struct command *cmd, const char *buf, + const jsmntok_t *params) +{ + const jsmntok_t *payloadt = json_delve(buf, params, ".onion.payload"); + const jsmntok_t *payment_hash_tok = json_delve(buf, params, ".htlc.payment_hash"); + const u8 *rawpayload; + size_t max; + struct tlv_tlv_payload *payload; + struct tlv_field *preimage_field = NULL; + char *hexpreimage, *hexpaymenthash; + struct sha256 payment_hash; + bigsize_t s; + + if (!payloadt) + return htlc_accepted_continue(cmd); + + rawpayload = json_tok_bin_from_hex(cmd, buf, payloadt); + max = tal_bytelen(rawpayload); + payload = tlv_tlv_payload_new(cmd); + + s = fromwire_varint(&rawpayload, &max); + if (s != max) { + return htlc_accepted_continue(cmd); + } + fromwire_tlv_payload(&rawpayload, &max, payload); + + /* Try looking for the field that contains the preimage */ + for (int i=0; ifields); i++) { + if (payload->fields[i].numtype == PREIMAGE_TLV_TYPE) { + preimage_field = &payload->fields[i]; + break; + } + } + + /* If we don't have a preimage field then this is not a keysend, let + * someone else take care of it. */ + if (preimage_field == NULL) + return htlc_accepted_continue(cmd); + + /* If the preimage is not 32 bytes long then we can't accept the + * payment. */ + if (preimage_field->length != 32) { + plugin_log(cmd->plugin, LOG_UNUSUAL, + "Sender specified a preimage that is %zu bytes long, " + "we expected 32 bytes. Ignoring this HTLC.", + preimage_field->length); + return htlc_accepted_continue(cmd); + } + + hexpreimage = tal_hex(cmd, preimage_field->value); + + /* If the preimage doesn't hash to the payment_hash we must continue, + * maybe someone else knows how to handle these. */ + sha256(&payment_hash, preimage_field->value, preimage_field->length); + hexpaymenthash = tal_hexstr(cmd, &payment_hash, sizeof(payment_hash)); + if (!json_tok_streq(buf, payment_hash_tok, hexpaymenthash)) { + plugin_log( + cmd->plugin, LOG_UNUSUAL, + "Preimage provided by the sender does not match the " + "payment_hash: SHA256(%s)=%s != %.*s. Ignoring keysend.", + hexpreimage, hexpaymenthash, + payment_hash_tok->end - payment_hash_tok->start, + buf + payment_hash_tok->start); + return htlc_accepted_continue(cmd); + } + + /* Finally we can resolve the payment with the preimage. */ + plugin_log(cmd->plugin, LOG_INFORM, + "Resolving incoming HTLC with preimage for payment_hash %s " + "provided in the onion payload.", + hexpaymenthash); + return htlc_accepted_resolve(cmd, hexpreimage); +} + +static const struct plugin_hook hooks[] = { + { + "htlc_accepted", + htlc_accepted_call + }, +}; int main(int argc, char *argv[]) { setup_locale(); plugin_main(argv, init, PLUGIN_RESTARTABLE, commands, ARRAY_SIZE(commands), - NULL, 0, NULL, 0, NULL); + NULL, 0, hooks, ARRAY_SIZE(hooks), NULL); }