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.
This commit is contained in:
Christian Decker 2019-11-07 19:06:43 +01:00
parent 714b57241b
commit 6ecdc3f672

View File

@ -3,6 +3,7 @@
#include <ccan/tal/str/str.h>
#include <common/bolt11.h>
#include <common/json_command.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
#include <common/param.h>
#include <common/timeout.h>
@ -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<hop_count; i++) {
json_add_secret(response, NULL, &shared_secrets[i]);
}
json_array_end(response);
return command_success(cmd, response);
}
static const struct json_command createonion_command = {
"createonion",
"payment",
json_createonion,
"Create an onion going through the provided nodes, each with its own payload"
};
AUTODATA(json_command, &createonion_command);