diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 969fc1a76..f287b6069 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -20,7 +20,7 @@ #include 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 doesn’t 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")),