From 6ecdc3f67226bbf348d41ab1548ca44c20ce5892 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Thu, 7 Nov 2019 19:06:43 +0100 Subject: [PATCH] json-rpc: Add `createonion` command similar to the `devtools/onion` tool This allows us to create an onion in the JSON-RPC that we can then later inject with the `sendonion` command that we're about to implement. --- lightningd/pay.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/lightningd/pay.c b/lightningd/pay.c index 6a08dbcd9..14d40ecf4 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -1103,3 +1104,99 @@ static const struct json_command listsendpays_command = { "Show sendpay, old and current, optionally limiting to {bolt11} or {payment_hash}." }; AUTODATA(json_command, &listsendpays_command); + +static struct command_result *json_createonion(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + const jsmntok_t *hopstok, *hop, *payloadtok, *typetok, *pubkeytok; + enum sphinx_payload_type type; + size_t i, hop_count = 0; + struct json_stream *response; + struct pubkey pubkey; + struct secret *session_key, *shared_secrets; + struct sphinx_path *sp; + u8 *assocdata, *payload, *serialized; + struct onionpacket *packet; + + if (!param(cmd, buffer, params, + p_req("hops", param_array, &hopstok), + p_req("assocdata", param_bin_from_hex, &assocdata), + p_opt("session_key", param_secret, &session_key), + NULL)) { + return command_param_failed(); + } + + if (session_key == NULL) + sp = sphinx_path_new(cmd, assocdata); + else + sp = sphinx_path_new_with_key(cmd, assocdata, session_key); + + json_for_each_arr(i, hop, hopstok) { + payloadtok = json_get_member(buffer, hop, "payload"); + typetok = json_get_member(buffer, hop, "type"); + pubkeytok = json_get_member(buffer, hop, "pubkey"); + + if (!pubkeytok) + return command_fail(cmd, JSONRPC2_INVALID_REQUEST, + "Hop %zu does not have a pubkey", i); + + if (!payloadtok) + return command_fail(cmd, JSONRPC2_INVALID_REQUEST, + "Hop %zu does not have a payload", i); + + payload = json_tok_bin_from_hex(cmd, buffer, payloadtok); + if (!json_to_pubkey(buffer, pubkeytok, &pubkey)) + return command_fail( + cmd, JSONRPC2_INVALID_PARAMS, + "'pubkey' should be a pubkey, not '%.*s'", + pubkeytok->end - pubkeytok->start, + buffer + pubkeytok->start); + + if (!payload) + return command_fail( + cmd, JSONRPC2_INVALID_PARAMS, + "'payload' should be a hex encoded binary, not '%.*s'", + pubkeytok->end - pubkeytok->start, + buffer + pubkeytok->start); + + if (!typetok || !json_tok_streq(buffer, typetok, "legacy")) { + type = SPHINX_RAW_PAYLOAD; + } else { + type = SPHINX_V0_PAYLOAD; + } + + sphinx_add_raw_hop(sp, &pubkey, type, payload); + hop_count++; + } + + if (hop_count == 0) + return command_fail(cmd, JSONRPC2_INVALID_REQUEST, + "Cannot create an onion without hops."); + + + packet = create_onionpacket(cmd, sp, &shared_secrets); + if (!packet) + return command_fail(cmd, LIGHTNINGD, + "Could not create onion packet"); + + serialized = serialize_onionpacket(cmd, packet); + + response = json_stream_success(cmd); + json_add_hex(response, "onion", serialized, tal_bytelen(serialized)); + json_array_start(response, "shared_secrets"); + for (size_t i=0; i