fetchinvoice: try direct peers if we can't route.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2021-01-08 05:14:47 +10:30
parent 3514c8a034
commit 55983827b6
2 changed files with 51 additions and 30 deletions

View File

@@ -548,24 +548,35 @@ static struct command_result *send_message(struct command *cmd,
const jsmntok_t *result UNUSED, const jsmntok_t *result UNUSED,
struct sent *sent)) struct sent *sent))
{ {
const struct dijkstra *dij; const struct gossmap_node *dst;
const struct gossmap_node *dst, *src;
struct route **r;
struct gossmap *gossmap = get_gossmap(cmd->plugin); struct gossmap *gossmap = get_gossmap(cmd->plugin);
const struct pubkey *backwards; const struct pubkey *backwards;
struct onionmsg_path **path; struct onionmsg_path **path;
struct pubkey blinding; struct pubkey blinding;
struct out_req *req; struct out_req *req;
struct node_id dstid; struct node_id dstid, *nodes;
/* FIXME: Use blinded path if avail. */ /* FIXME: Use blinded path if avail. */
gossmap_guess_node_id(gossmap, sent->offer->node_id, &dstid); gossmap_guess_node_id(gossmap, sent->offer->node_id, &dstid);
dst = gossmap_find_node(gossmap, &dstid); dst = gossmap_find_node(gossmap, &dstid);
if (!dst) if (!dst) {
return command_fail(cmd, LIGHTNINGD, /* Try direct. */
"Unknown destination %s", struct pubkey *us = tal_arr(tmpctx, struct pubkey, 1);
type_to_string(tmpctx, struct node_id, if (!pubkey_from_node_id(&us[0], &local_id))
&dstid)); abort();
backwards = us;
nodes = tal_arr(tmpctx, struct node_id, 1);
/* We don't know the pubkey y-sign, but sendonionmessage will
* fix it up if we guess wrong. */
nodes[0].k[0] = SECP256K1_TAG_PUBKEY_EVEN;
secp256k1_xonly_pubkey_serialize(secp256k1_ctx,
nodes[0].k+1,
&sent->offer->node_id->pubkey);
} else {
struct route **r;
const struct dijkstra *dij;
const struct gossmap_node *src;
/* If we don't exist in gossip, routing can't happen. */ /* If we don't exist in gossip, routing can't happen. */
src = gossmap_find_node(gossmap, &local_id); src = gossmap_find_node(gossmap, &local_id);
@@ -578,12 +589,20 @@ static struct command_result *send_message(struct command *cmd,
r = route_from_dijkstra(tmpctx, gossmap, dij, src); r = route_from_dijkstra(tmpctx, gossmap, dij, src);
if (!r) if (!r)
/* FIXME: We need to retry kind of like keysend here... */ /* FIXME: try connecting directly. */
return command_fail(cmd, OFFER_ROUTE_NOT_FOUND, return command_fail(cmd, OFFER_ROUTE_NOT_FOUND,
"Can't find route"); "Can't find route");
/* Ok, now make reply for onion_message */
backwards = route_backwards(tmpctx, gossmap, r); backwards = route_backwards(tmpctx, gossmap, r);
nodes = tal_arr(tmpctx, struct node_id, tal_count(r));
for (size_t i = 0; i < tal_count(r); i++) {
gossmap_node_get_id(gossmap,
gossmap_nth_node(gossmap, r[i]->c, !r[i]->dir),
&nodes[i]);
}
}
/* Ok, now make reply for onion_message */
path = make_blindedpath(tmpctx, backwards, &blinding, path = make_blindedpath(tmpctx, backwards, &blinding,
&sent->reply_blinding); &sent->reply_blinding);
@@ -592,15 +611,10 @@ static struct command_result *send_message(struct command *cmd,
forward_error, forward_error,
sent); sent);
json_array_start(req->js, "hops"); json_array_start(req->js, "hops");
for (size_t i = 0; i < tal_count(r); i++) { for (size_t i = 0; i < tal_count(nodes); i++) {
struct node_id id;
json_object_start(req->js, NULL); json_object_start(req->js, NULL);
gossmap_node_get_id(gossmap, json_add_node_id(req->js, "id", &nodes[i]);
gossmap_nth_node(gossmap, r[i]->c, !r[i]->dir), if (i == tal_count(nodes) - 1)
&id);
json_add_node_id(req->js, "id", &id);
if (i == tal_count(r) - 1)
json_add_hex_talarr(req->js, msgfield, msgval); json_add_hex_talarr(req->js, msgfield, msgval);
json_object_end(req->js); json_object_end(req->js);
} }

View File

@@ -3930,6 +3930,13 @@ def test_fetchinvoice(node_factory, bitcoind):
'recurrence_counter': 2, 'recurrence_counter': 2,
'recurrence_label': 'test recurrence'}) 'recurrence_label': 'test recurrence'})
# Check we can request invoice without a channel.
l4 = node_factory.get_node()
l4.rpc.connect(l2.info['id'], 'localhost', l2.port)
ret = l4.rpc.call('fetchinvoice', {'offer': offer3,
'recurrence_counter': 0,
'recurrence_label': 'test nochannel'})
# Test timeout. # Test timeout.
l3.stop() l3.stop()
with pytest.raises(RpcError, match='Timeout waiting for response'): with pytest.raises(RpcError, match='Timeout waiting for response'):