fetchinvoice: include send in path, use pubkeys.

We had sent->path be a list of node_ids, but it makes more sense as
pubkeys so we can avoid conversion.  Also, I find it easier to think
about (especially creating backwards paths) if we include *ourselves*
as the first element in the path.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2021-09-21 14:53:45 +09:30
parent 37ddf2e829
commit 2112f4fd8e

View File

@ -20,7 +20,7 @@
#include <sodium.h>
static struct gossmap *global_gossmap;
static struct node_id local_id;
static struct pubkey local_id;
static bool disable_connect = false;
static LIST_HEAD(sent_list);
@ -33,8 +33,8 @@ struct sent {
struct command *cmd;
/* The offer we are trying to get an invoice/payment for. */
struct tlv_offer *offer;
/* Path to use. */
struct node_id *path;
/* Path to use (including self) */
struct pubkey *path;
/* The invreq we sent, OR the invoice we sent */
struct tlv_invoice_request *invreq;
@ -567,18 +567,21 @@ static void node_id_from_pubkey32(struct node_id *nid,
&node32_id->pubkey);
}
/* Create path to node which can carry onion messages; if it can't find
* one, returns NULL. Fills in nodeid_parity for 33rd nodeid byte. */
static struct node_id *path_to_node(const tal_t *ctx,
struct gossmap *gossmap,
const struct pubkey32 *node32_id,
enum nodeid_parity *parity)
/* Create path to node which can carry onion messages (including
* self); if it can't find one, returns NULL. Fills in nodeid_parity
* for 33rd nodeid byte. */
static struct pubkey *path_to_node(const tal_t *ctx,
struct plugin *plugin,
const struct pubkey32 *node32_id,
enum nodeid_parity *parity)
{
struct route_hop *r;
const struct dijkstra *dij;
const struct gossmap_node *src;
const struct gossmap_node *dst;
struct node_id *nodes, dstid;
struct node_id dstid, local_nodeid;
struct pubkey *nodes;
struct gossmap *gossmap = get_gossmap(plugin);
/* We try both parities. */
*parity = nodeid_parity_even;
@ -597,7 +600,8 @@ static struct node_id *path_to_node(const tal_t *ctx,
*parity = node_parity(gossmap, dst);
/* If we don't exist in gossip, routing can't happen. */
src = gossmap_find_node(gossmap, &local_id);
node_id_from_pubkey(&local_nodeid, &local_id);
src = gossmap_find_node(gossmap, &local_nodeid);
if (!src)
return NULL;
@ -608,9 +612,15 @@ static struct node_id *path_to_node(const tal_t *ctx,
if (!r)
return NULL;
nodes = tal_arr(ctx, struct node_id, tal_count(r));
for (size_t i = 0; i < tal_count(r); i++)
nodes[i] = r[i].node_id;
nodes = tal_arr(ctx, struct pubkey, tal_count(r) + 1);
nodes[0] = local_id;
for (size_t i = 0; i < tal_count(r); i++) {
if (!pubkey_from_node_id(&nodes[i+1], &r[i].node_id)) {
plugin_err(plugin, "Could not convert nodeid %s",
type_to_string(tmpctx, struct node_id,
&r[i].node_id));
}
}
return nodes;
}
@ -631,19 +641,14 @@ static struct command_result *send_message(struct command *cmd,
struct out_req *req;
/* FIXME: Maybe we should allow this? */
if (tal_bytelen(sent->path) == 0)
if (tal_count(sent->path) == 1)
return command_fail(cmd, PAY_ROUTE_NOT_FOUND,
"Refusing to talk to ourselves");
/* Reverse path is offset by one: we are the final node. */
backwards = tal_arr(tmpctx, struct pubkey, tal_count(sent->path));
for (size_t i = 0; i < tal_count(sent->path) - 1; i++) {
if (!pubkey_from_node_id(&backwards[tal_count(sent->path)-2-i],
&sent->path[i]))
abort();
}
if (!pubkey_from_node_id(&backwards[tal_count(sent->path)-1], &local_id))
abort();
/* Reverse path is offset by one. */
backwards = tal_arr(tmpctx, struct pubkey, tal_count(sent->path) - 1);
for (size_t i = 0; i < tal_count(backwards); i++)
backwards[tal_count(backwards)-1-i] = sent->path[i];
/* Ok, now make reply for onion_message */
path = make_blindedpath(tmpctx, backwards, &blinding,
@ -654,9 +659,9 @@ static struct command_result *send_message(struct command *cmd,
forward_error,
sent);
json_array_start(req->js, "hops");
for (size_t i = 0; i < tal_count(sent->path); i++) {
for (size_t i = 1; i < tal_count(sent->path); i++) {
json_object_start(req->js, NULL);
json_add_node_id(req->js, "id", &sent->path[i]);
json_add_pubkey(req->js, "id", &sent->path[i]);
if (i == tal_count(sent->path) - 1)
json_add_hex_talarr(req->js, msgfield, msgval);
json_object_end(req->js);
@ -757,7 +762,17 @@ static struct command_result *try_other_parity(struct command *cmd,
/* Flip parity */
ca->node_id.k[0] = SECP256K1_TAG_PUBKEY_ODD;
ca->sent->path[0] = ca->node_id;
/* Path is us -> them, so they're second entry */
if (!pubkey_from_node_id(&ca->sent->path[1], &ca->node_id)) {
/* Should not happen!
* Pieter Wuille points out:
* y^2 = x^3 + 7 mod p
* negating y doesnt change the left hand side
*/
return command_done_err(cmd, LIGHTNINGD,
"Failed: could not convert inverted pubkey?",
NULL);
}
req = jsonrpc_request_start(cmd->plugin, cmd, "connect", connected,
connect_failed, ca);
json_add_node_id(req->js, "id", &ca->node_id);
@ -797,8 +812,14 @@ connect_direct(struct command *cmd,
}
/* Make a direct path -> dst. */
sent->path = tal_arr(sent, struct node_id, 1);
sent->path[0] = ca->node_id;
sent->path = tal_arr(sent, struct pubkey, 2);
sent->path[0] = local_id;
if (!pubkey_from_node_id(&sent->path[1], &ca->node_id)) {
/* Should not happen! */
return command_done_err(cmd, LIGHTNINGD,
"Failed: could not convert to pubkey?",
NULL);
}
if (disable_connect) {
/* FIXME: This means we will fail if parity is wrong! */
@ -918,7 +939,7 @@ static struct command_result *invreq_done(struct command *cmd,
}
}
sent->path = path_to_node(sent, get_gossmap(cmd->plugin),
sent->path = path_to_node(sent, cmd->plugin,
sent->offer->node_id,
&parity);
if (!sent->path)
@ -978,7 +999,7 @@ force_payer_secret(struct command *cmd,
"Failed to sign with payer_secret");
}
sent->path = path_to_node(sent, get_gossmap(cmd->plugin),
sent->path = path_to_node(sent, cmd->plugin,
sent->offer->node_id,
&parity);
if (!sent->path)
@ -1273,7 +1294,7 @@ static struct command_result *createinvoice_done(struct command *cmd,
"Bad createinvoice response %s", fail);
}
sent->path = path_to_node(sent, get_gossmap(cmd->plugin),
sent->path = path_to_node(sent, cmd->plugin,
sent->offer->node_id,
&parity);
if (!sent->path)
@ -1455,9 +1476,13 @@ static struct command_result *json_sendinvoice(struct command *cmd,
* - MUST set `description` the same as the offer.
*/
sent->inv->node_id = tal(sent->inv, struct pubkey32);
if (!pubkey32_from_node_id(sent->inv->node_id, &local_id))
plugin_err(cmd->plugin, "Invalid local_id %s?",
type_to_string(tmpctx, struct node_id, &local_id));
/* This only fails if pubkey is invalid. */
if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx,
&sent->inv->node_id->pubkey,
NULL,
&local_id.pubkey))
abort();
sent->inv->description
= tal_dup_talarr(sent->inv, char, sent->offer->description);
@ -1633,7 +1658,7 @@ static struct command_result *json_rawrequest(struct command *cmd,
sent->cmd = cmd;
sent->offer = NULL;
sent->path = path_to_node(sent, get_gossmap(cmd->plugin),
sent->path = path_to_node(sent, cmd->plugin,
&node_id32,
&parity);
if (!sent->path) {
@ -1680,7 +1705,7 @@ static const char *init(struct plugin *p, const char *buf UNUSED,
rpc_scan(p, "getinfo",
take(json_out_obj(NULL, NULL, NULL)),
"{id:%}", JSON_SCAN(json_to_node_id, &local_id));
"{id:%}", JSON_SCAN(json_to_pubkey, &local_id));
rpc_scan(p, "listconfigs",
take(json_out_obj(NULL, "config", "experimental-offers")),