From 2bb365a93188ca6a411d419eef9ed14ecda66bbd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 22 May 2021 16:40:01 +0930 Subject: [PATCH] common/route: route_from_dijkstra returns route_hop array. This is what (most) callers actually want, so unify it into one place. Signed-off-by: Rusty Russell --- common/route.c | 97 ++++++++++++++++++++++++-------- common/route.h | 43 +++++++++++--- common/test/run-route-specific.c | 32 +++++++---- common/test/run-route.c | 53 ++++++++++++----- devtools/route.c | 49 ++++------------ devtools/topology.c | 14 +++-- gossipd/routing.h | 17 +----- plugins/fetchinvoice.c | 58 +++++++------------ plugins/libplugin-pay.c | 67 +++++----------------- plugins/libplugin-pay.h | 1 + plugins/libplugin.c | 1 + plugins/libplugin.h | 15 ----- 12 files changed, 225 insertions(+), 222 deletions(-) diff --git a/common/route.c b/common/route.c index dfa538ab8..152b9fbae 100644 --- a/common/route.c +++ b/common/route.c @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -64,31 +64,82 @@ u64 route_score_cheaper(u32 distance, return ((u64)costs_to_score(cost, risk) << 32) + distance; } -struct route **route_from_dijkstra(const tal_t *ctx, - const struct gossmap *map, - const struct dijkstra *dij, - const struct gossmap_node *cur) +/* Recursive version: return false if we can't get there. + * + * amount and cltv are updated, and reflect the amount we + * and delay would have to put into the first channel (usually + * ignored, since we don't pay for our own channels!). + */ +static bool dijkstra_to_hops(struct route_hop **hops, + const struct gossmap *gossmap, + const struct dijkstra *dij, + const struct gossmap_node *cur, + struct amount_msat *amount, + u32 *cltv) { - struct route **path = tal_arr(ctx, struct route *, 0); - u32 curidx = gossmap_node_idx(map, cur); + u32 curidx = gossmap_node_idx(gossmap, cur); + u32 dist = dijkstra_distance(dij, curidx); + struct gossmap_chan *c; + const struct gossmap_node *next; + size_t num_hops = tal_count(*hops); + const struct half_chan *h; - while (dijkstra_distance(dij, curidx) != 0) { - struct route *r; + if (dist == 0) + return true; - if (dijkstra_distance(dij, curidx) == UINT_MAX) - return tal_free(path); + if (dist == UINT_MAX) + return false; - r = tal(path, struct route); - r->c = dijkstra_best_chan(dij, curidx); - if (r->c->half[0].nodeidx == curidx) { - r->dir = 0; - } else { - assert(r->c->half[1].nodeidx == curidx); - r->dir = 1; - } - tal_arr_expand(&path, r); - cur = gossmap_nth_node(map, r->c, !r->dir); - curidx = gossmap_node_idx(map, cur); + tal_resize(hops, num_hops + 1); + + /* OK, populate other fields. */ + c = dijkstra_best_chan(dij, curidx); + if (c->half[0].nodeidx == curidx) { + (*hops)[num_hops].direction = 0; + } else { + assert(c->half[1].nodeidx == curidx); + (*hops)[num_hops].direction = 1; } - return path; + (*hops)[num_hops].scid = gossmap_chan_scid(gossmap, c); + + /* Find other end of channel. */ + next = gossmap_nth_node(gossmap, c, !(*hops)[num_hops].direction); + gossmap_node_get_id(gossmap, next, &(*hops)[num_hops].node_id); + if (gossmap_node_get_feature(gossmap, next, OPT_VAR_ONION) != -1) + (*hops)[num_hops].style = ROUTE_HOP_TLV; + else + (*hops)[num_hops].style = ROUTE_HOP_LEGACY; + + /* These are (ab)used by others. */ + (*hops)[num_hops].blinding = NULL; + (*hops)[num_hops].enctlv = NULL; + + if (!dijkstra_to_hops(hops, gossmap, dij, next, amount, cltv)) + return false; + + (*hops)[num_hops].amount = *amount; + (*hops)[num_hops].delay = *cltv; + + h = &c->half[(*hops)[num_hops].direction]; + if (!amount_msat_add_fee(amount, h->base_fee, h->proportional_fee)) + /* Shouldn't happen, since we said it would route, + * amounts must be sane. */ + abort(); + *cltv += h->delay; + return true; +} + +struct route_hop *route_from_dijkstra(const tal_t *ctx, + const struct gossmap *map, + const struct dijkstra *dij, + const struct gossmap_node *src, + struct amount_msat final_amount, + u32 final_cltv) +{ + struct route_hop *hops = tal_arr(ctx, struct route_hop, 0); + + if (!dijkstra_to_hops(&hops, map, dij, src, &final_amount, &final_cltv)) + return tal_free(hops); + + return hops; } diff --git a/common/route.h b/common/route.h index 78631670a..1f8a86a5e 100644 --- a/common/route.h +++ b/common/route.h @@ -2,14 +2,41 @@ #ifndef LIGHTNING_COMMON_ROUTE_H #define LIGHTNING_COMMON_ROUTE_H #include "config.h" +#include #include +#include struct dijkstra; struct gossmap; +struct gossmap_chan; +struct gossmap_node; -struct route { - int dir; - struct gossmap_chan *c; +enum route_hop_style { + ROUTE_HOP_LEGACY = 1, + ROUTE_HOP_TLV = 2, +}; + +/** + * struct route_hop: a hop in a route. + * + * @scid: the short_channel_id. + * @direction: 0 (dest node_id < src node_id), 1 (dest node_id > src). + * @node_id: the node_id of the destination of this hop. + * @amount: amount to send through this hop. + * @delay: total cltv delay at this hop. + * @blinding: blinding key for this hop (if any) + * @enctlv: encrypted TLV for this hop (if any) + * @style: onion encoding style for this hop. + */ +struct route_hop { + struct short_channel_id scid; + int direction; + struct node_id node_id; + struct amount_msat amount; + u32 delay; + struct pubkey *blinding; + u8 *enctlv; + enum route_hop_style style; }; /* Can c carry amount in dir? */ @@ -37,8 +64,10 @@ u64 route_score_cheaper(u32 distance, struct amount_msat risk); /* Extract route tal_arr from completed dijkstra: NULL if none. */ -struct route **route_from_dijkstra(const tal_t *ctx, - const struct gossmap *map, - const struct dijkstra *dij, - const struct gossmap_node *cur); +struct route_hop *route_from_dijkstra(const tal_t *ctx, + const struct gossmap *map, + const struct dijkstra *dij, + const struct gossmap_node *src, + struct amount_msat final_amount, + u32 final_cltv); #endif /* LIGHTNING_COMMON_ROUTE_H */ diff --git a/common/test/run-route-specific.c b/common/test/run-route-specific.c index 0901fa68b..5f77965b8 100644 --- a/common/test/run-route-specific.c +++ b/common/test/run-route-specific.c @@ -143,14 +143,16 @@ static void add_connection(int store_fd, } static bool channel_is_between(const struct gossmap *gossmap, - const struct route *route, + const struct route_hop *route, const struct gossmap_node *a, const struct gossmap_node *b) { - if (route->c->half[route->dir].nodeidx + const struct gossmap_chan *c = gossmap_find_chan(gossmap, &route->scid); + + if (c->half[route->direction].nodeidx != gossmap_node_idx(gossmap, a)) return false; - if (route->c->half[!route->dir].nodeidx + if (c->half[!route->direction].nodeidx != gossmap_node_idx(gossmap, b)) return false; @@ -177,7 +179,7 @@ int main(void) struct node_id a, b, c, d; struct gossmap_node *a_node, *b_node, *c_node, *d_node; const struct dijkstra *dij; - struct route **route; + struct route_hop *route; int store_fd; struct gossmap *gossmap; const double riskfactor = 1.0; @@ -238,17 +240,19 @@ int main(void) dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1000), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(1000), 0); assert(route); assert(tal_count(route) == 2); - assert(channel_is_between(gossmap, route[0], a_node, b_node)); - assert(channel_is_between(gossmap, route[1], b_node, c_node)); + assert(channel_is_between(gossmap, &route[0], a_node, b_node)); + assert(channel_is_between(gossmap, &route[1], b_node, c_node)); /* We should not be able to find a route that exceeds our own capacity */ dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1000001), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(1000), 0); assert(!route); /* Now test with a query that exceeds the channel capacity after adding @@ -256,7 +260,8 @@ int main(void) dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(999999), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(999999), 0); assert(!route); /* This should fail to return a route because it is smaller than these @@ -264,7 +269,8 @@ int main(void) dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(1), 0); assert(!route); /* {'active': True, 'short_id': '6990:2:1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 1, 'htlc_maximum_msat': 500000, 'htlc_minimum_msat': 100, 'channel_flags': 0, 'destination': '02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636', 'source': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'last_update': 1504064344}, */ @@ -282,7 +288,8 @@ int main(void) dij = dijkstra(tmpctx, gossmap, d_node, AMOUNT_MSAT(499968), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(499968), 0); assert(route); /* This should fail to return a route because it's larger than the @@ -290,7 +297,8 @@ int main(void) dij = dijkstra(tmpctx, gossmap, d_node, AMOUNT_MSAT(499968+1), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(499968+1), 0); assert(!route); tal_free(tmpctx); diff --git a/common/test/run-route.c b/common/test/run-route.c index bed43f045..5b6f47aa9 100644 --- a/common/test/run-route.c +++ b/common/test/run-route.c @@ -131,14 +131,15 @@ static void add_connection(int store_fd, } static bool channel_is_between(const struct gossmap *gossmap, - const struct route *route, + const struct route_hop *route, const struct gossmap_node *a, const struct gossmap_node *b) { - if (route->c->half[route->dir].nodeidx + const struct gossmap_chan *c = gossmap_find_chan(gossmap, &route->scid); + if (c->half[route->direction].nodeidx != gossmap_node_idx(gossmap, a)) return false; - if (route->c->half[!route->dir].nodeidx + if (c->half[!route->direction].nodeidx != gossmap_node_idx(gossmap, b)) return false; @@ -173,7 +174,7 @@ int main(void) struct gossmap_node *a_node, *b_node, *c_node, *d_node; struct privkey tmp; const struct dijkstra *dij; - struct route **route; + struct route_hop *route; int store_fd; struct gossmap *gossmap; const double riskfactor = 1.0; @@ -207,9 +208,11 @@ int main(void) route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, AMOUNT_MSAT(1000), 10); assert(route); assert(tal_count(route) == 1); + assert(amount_msat_eq(route[0].amount, AMOUNT_MSAT(1000))); + assert(route[0].delay == 10); /* A<->B<->C */ memset(&tmp, 'c', sizeof(tmp)); @@ -224,9 +227,14 @@ int main(void) dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1000), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(1000), 11); assert(route); assert(tal_count(route) == 2); + assert(amount_msat_eq(route[1].amount, AMOUNT_MSAT(1000))); + assert(route[1].delay == 11); + assert(amount_msat_eq(route[0].amount, AMOUNT_MSAT(1001))); + assert(route[0].delay == 12); /* A<->D<->C: Lower base, higher percentage. */ memset(&tmp, 'd', sizeof(tmp)); @@ -246,22 +254,32 @@ int main(void) dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1000), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(1000), 12); assert(route); assert(tal_count(route) == 2); - assert(channel_is_between(gossmap, route[0], a_node, d_node)); - assert(channel_is_between(gossmap, route[1], d_node, c_node)); + assert(channel_is_between(gossmap, &route[0], a_node, d_node)); + assert(channel_is_between(gossmap, &route[1], d_node, c_node)); + assert(amount_msat_eq(route[1].amount, AMOUNT_MSAT(1000))); + assert(route[1].delay == 12); + assert(amount_msat_eq(route[0].amount, AMOUNT_MSAT(1000))); + assert(route[0].delay == 13); /* Will go via B for large amounts. */ dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(3000000), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(3000000), 13); assert(route); assert(tal_count(route) == 2); - assert(channel_is_between(gossmap, route[0], a_node, b_node)); - assert(channel_is_between(gossmap, route[1], b_node, c_node)); + assert(channel_is_between(gossmap, &route[0], a_node, b_node)); + assert(channel_is_between(gossmap, &route[1], b_node, c_node)); + assert(amount_msat_eq(route[1].amount, AMOUNT_MSAT(3000000))); + assert(route[1].delay == 13); + assert(amount_msat_eq(route[0].amount, AMOUNT_MSAT(3000000 + 3 + 1))); + assert(route[0].delay == 14); /* Make B->C inactive, force it back via D */ update_connection(store_fd, &b, &c, 1, 1, 1, true); @@ -276,11 +294,16 @@ int main(void) dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(3000000), riskfactor, route_can_carry_unless_disabled, route_score_cheaper, NULL); - route = route_from_dijkstra(tmpctx, gossmap, dij, a_node); + route = route_from_dijkstra(tmpctx, gossmap, dij, a_node, + AMOUNT_MSAT(3000000), 14); assert(route); assert(tal_count(route) == 2); - assert(channel_is_between(gossmap, route[0], a_node, d_node)); - assert(channel_is_between(gossmap, route[1], d_node, c_node)); + assert(channel_is_between(gossmap, &route[0], a_node, d_node)); + assert(channel_is_between(gossmap, &route[1], d_node, c_node)); + assert(amount_msat_eq(route[1].amount, AMOUNT_MSAT(3000000))); + assert(route[1].delay == 14); + assert(amount_msat_eq(route[0].amount, AMOUNT_MSAT(3000000 + 6))); + assert(route[0].delay == 15); tal_free(tmpctx); secp256k1_context_destroy(secp256k1_ctx); diff --git a/devtools/route.c b/devtools/route.c index ffca5d458..3aa76bc9a 100644 --- a/devtools/route.c +++ b/devtools/route.c @@ -13,25 +13,9 @@ #include #include -/* ->B->C->D. D needs 100msat, each charges 10msat. */ -static struct amount_msat route_amount(struct route **path, - size_t npath, - struct amount_msat amount) -{ - if (npath == 0) - return amount; - - amount = route_amount(path+1, npath-1, amount); - if (!amount_msat_add_fee(&amount, - path[0]->c->half[path[0]->dir].base_fee, - path[0]->c->half[path[0]->dir].proportional_fee)) - abort(); - return amount; -} - -static struct route **least_cost(struct gossmap *map, - struct gossmap_node *src, - struct gossmap_node *dst) +static struct route_hop *least_cost(struct gossmap *map, + struct gossmap_node *src, + struct gossmap_node *dst) { const struct dijkstra *dij; u32 srcidx = gossmap_node_idx(map, src); @@ -43,7 +27,7 @@ static struct route **least_cost(struct gossmap *map, /* Max distance is 20 */ const u32 distance_budget = ROUTING_MAX_HOPS; struct amount_msat maxcost; - struct route **path; + struct route_hop *path; struct timemono tstart, tstop; setup_locale(); @@ -69,12 +53,10 @@ static struct route **least_cost(struct gossmap *map, return NULL; } - path = route_from_dijkstra(map, map, dij, src); + path = route_from_dijkstra(map, map, dij, src, sent, 0); printf("# path length %zu\n", tal_count(path)); /* We don't pay fee on first hop! */ - if (!amount_msat_sub(&fee, - route_amount(path+1, tal_count(path)-1, sent), - sent)) + if (!amount_msat_sub(&fee, path[0].amount, sent)) abort(); printf("# path fee %s\n", type_to_string(tmpctx, struct amount_msat, &fee)); @@ -132,7 +114,7 @@ int main(int argc, char *argv[]) tal_free(least_cost(map, n, dst)); } } else { - struct route **path; + struct route_hop *path; struct node_id srcid; if (!node_id_from_hexstr(argv[2], strlen(argv[2]), &srcid)) @@ -144,20 +126,13 @@ int main(int argc, char *argv[]) if (!path) exit(1); for (size_t i = 0; i < tal_count(path); i++) { - struct gossmap_node *from, *to; - struct node_id fromid, toid; - struct short_channel_id scid; - - from = gossmap_nth_node(map, path[i]->c, path[i]->dir); - to = gossmap_nth_node(map, path[i]->c, !path[i]->dir); - gossmap_node_get_id(map, from, &fromid); - gossmap_node_get_id(map, to, &toid); - scid = gossmap_chan_scid(map, path[i]->c); printf("%s->%s via %s\n", - type_to_string(tmpctx, struct node_id, &fromid), - type_to_string(tmpctx, struct node_id, &toid), + type_to_string(tmpctx, struct node_id, &srcid), + type_to_string(tmpctx, struct node_id, + &path[i].node_id), type_to_string(tmpctx, struct short_channel_id, - &scid)); + &path[i].scid)); + srcid = path[i].node_id; } } diff --git a/devtools/topology.c b/devtools/topology.c index 770451c28..cc2cf2303 100644 --- a/devtools/topology.c +++ b/devtools/topology.c @@ -180,7 +180,7 @@ static bool measure_least_cost(struct gossmap *map, /* Max distance is 20 */ const u32 distance_budget = ROUTING_MAX_HOPS; struct amount_msat maxcost, fee; - struct route **path; + struct route_hop *path; struct timemono tstart, tstop; struct node_id srcid; @@ -210,7 +210,7 @@ static bool measure_least_cost(struct gossmap *map, return false; } - path = route_from_dijkstra(map, map, dij, src); + path = route_from_dijkstra(map, map, dij, src, sent, 0); printf("# path length %zu\n", tal_count(path)); if (!amount_msat_sub(&fee, dijkstra_amount(dij, srcidx), sent)) abort(); @@ -220,10 +220,11 @@ static bool measure_least_cost(struct gossmap *map, /* Count possible sources */ for (size_t i = 0; i < tal_count(path); i++) { struct gossmap_node *prev, *cur; + struct gossmap_chan *c = gossmap_find_chan(map, &path[i].scid); /* N+1th node is at end of Nth hop */ - prev = gossmap_nth_node(map, path[i]->c, path[i]->dir); - cur = gossmap_nth_node(map, path[i]->c, !path[i]->dir); + prev = gossmap_nth_node(map, c, path[i].direction); + cur = gossmap_nth_node(map, c, !path[i].direction); printf("source set size node %zu/%zu: %zu\n", i+1, tal_count(path), @@ -233,10 +234,11 @@ static bool measure_least_cost(struct gossmap *map, /* Count possible destinations. */ for (size_t i = 0; i < tal_count(path); i++) { struct gossmap_node *cur, *next; + struct gossmap_chan *c = gossmap_find_chan(map, &path[i].scid); /* N+1th node is at end of Nth hop */ - cur = gossmap_nth_node(map, path[i]->c, path[i]->dir); - next = gossmap_nth_node(map, path[i]->c, !path[i]->dir); + cur = gossmap_nth_node(map, c, path[i].direction); + next = gossmap_nth_node(map, c, !path[i].direction); printf("destination set size node %zu/%zu: %zu\n", i, tal_count(path), diff --git a/gossipd/routing.h b/gossipd/routing.h index cf7fca056..367054108 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -137,11 +138,6 @@ HTABLE_DEFINE_TYPE(struct local_chan, local_chan_map_scid, hash_scid, local_chan_eq_scid, local_chan_map); -enum route_hop_style { - ROUTE_HOP_LEGACY = 1, - ROUTE_HOP_TLV = 2, -}; - /* For a small number of channels (by far the most common) we use a simple * array, with empty buckets NULL. For larger, we use a proper hash table, * with the extra allocation that implies. */ @@ -323,17 +319,6 @@ get_channel(const struct routing_state *rstate, return uintmap_get(&rstate->chanmap, scid->u64); } -struct route_hop { - struct short_channel_id scid; - int direction; - struct node_id node_id; - struct amount_msat amount; - u32 delay; - struct pubkey *blinding; - u8 *enctlv; - enum route_hop_style style; -}; - enum exclude_entry_type { EXCLUDE_CHANNEL = 1, EXCLUDE_NODE = 2 diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 1ba20561b..15762849c 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -516,28 +516,6 @@ static bool can_carry_onionmsg(const struct gossmap *map, return n && gossmap_node_get_feature(map, n, OPT_ONION_MESSAGES) != -1; } -/* make_blindedpath only needs pubkeys */ -static const struct pubkey *route_backwards(const tal_t *ctx, - const struct gossmap *gossmap, - struct route **r) -{ - struct pubkey *rarr; - - rarr = tal_arr(ctx, struct pubkey, tal_count(r)); - for (size_t i = 0; i < tal_count(r); i++) { - const struct gossmap_node *dst; - struct node_id id; - - dst = gossmap_nth_node(gossmap, r[i]->c, r[i]->dir); - gossmap_node_get_id(gossmap, dst, &id); - /* We're going backwards */ - if (!pubkey_from_node_id(&rarr[tal_count(rarr) - 1 - i], &id)) - abort(); - } - - return rarr; -} - static struct command_result *send_message(struct command *cmd, struct sent *sent, const char *msgfield, @@ -550,7 +528,7 @@ static struct command_result *send_message(struct command *cmd, { const struct gossmap_node *dst; struct gossmap *gossmap = get_gossmap(cmd->plugin); - const struct pubkey *backwards; + struct pubkey *backwards; struct onionmsg_path **path; struct pubkey blinding; struct out_req *req; @@ -574,7 +552,7 @@ static struct command_result *send_message(struct command *cmd, nodes[0].k+1, &sent->offer->node_id->pubkey); } else { - struct route **r; + struct route_hop *r; const struct dijkstra *dij; const struct gossmap_node *src; @@ -587,25 +565,31 @@ static struct command_result *send_message(struct command *cmd, dij = dijkstra(tmpctx, gossmap, dst, AMOUNT_MSAT(0), 0, can_carry_onionmsg, route_score_shorter, NULL); - r = route_from_dijkstra(tmpctx, gossmap, dij, src); + r = route_from_dijkstra(tmpctx, gossmap, dij, src, AMOUNT_MSAT(0), 0); if (!r) /* FIXME: try connecting directly. */ return command_fail(cmd, OFFER_ROUTE_NOT_FOUND, "Can't find route"); - 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]); - } - } + /* FIXME: Maybe we should allow this? */ + if (tal_bytelen(r) == 0) + return command_fail(cmd, PAY_ROUTE_NOT_FOUND, + "Refusing to talk to ourselves"); - /* FIXME: Maybe we should allow this? */ - if (tal_bytelen(backwards) == 0) - return command_fail(cmd, PAY_ROUTE_NOT_FOUND, - "Refusing to talk to ourselves"); + nodes = tal_arr(tmpctx, struct node_id, tal_count(r)); + for (size_t i = 0; i < tal_count(r); i++) + nodes[i] = r[i].node_id; + + /* Reverse path is offset by one: we are the final node. */ + backwards = tal_arr(tmpctx, struct pubkey, tal_count(r)); + for (size_t i = 0; i < tal_count(r) - 1; i++) { + if (!pubkey_from_node_id(&backwards[tal_count(r)-2-i], + &nodes[i])) + abort(); + } + if (!pubkey_from_node_id(&backwards[tal_count(r)-1], &local_id)) + abort(); + } /* Ok, now make reply for onion_message */ path = make_blindedpath(tmpctx, backwards, &blinding, diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index 32b1565a6..496ea0766 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -687,50 +686,6 @@ static bool payment_route_can_carry_even_disabled(const struct gossmap *map, return payment_route_check(map, c, dir, amount, p); } -static struct route_hop *route_hops_from_route(const tal_t *ctx, - struct gossmap *gossmap, - struct amount_msat amount, - u32 final_delay, - struct route **r) -{ - struct route_hop *hops = tal_arr(ctx, struct route_hop, tal_count(r)); - struct amount_msat amt; - u32 delay; - - for (size_t i = 0; i < tal_count(hops); i++) { - const struct gossmap_node *dst; - - hops[i].scid = gossmap_chan_scid(gossmap, r[i]->c); - hops[i].direction = r[i]->dir; - hops[i].blinding = NULL; - - /* nodeid is nodeid of *dst* */ - dst = gossmap_nth_node(gossmap, r[i]->c, !r[i]->dir); - gossmap_node_get_id(gossmap, dst, &hops[i].node_id); - if (gossmap_node_get_feature(gossmap, dst, OPT_VAR_ONION) != -1) - hops[i].style = ROUTE_HOP_TLV; - else - hops[i].style = ROUTE_HOP_LEGACY; - } - - /* Now iterate backwards to derive amount and delay. */ - amt = amount; - delay = final_delay; - for (int i = tal_count(hops) - 1; i >= 0; i--) { - const struct half_chan *h = &r[i]->c->half[r[i]->dir]; - - hops[i].amount = amt; - hops[i].delay = delay; - - if (!amount_msat_add_fee(&amt, - h->base_fee, h->proportional_fee)) - abort(); - delay += h->delay; - } - - return hops; -} - static struct route_hop *route(const tal_t *ctx, struct gossmap *gossmap, const struct gossmap_node *src, @@ -743,7 +698,7 @@ static struct route_hop *route(const tal_t *ctx, const char **errmsg) { const struct dijkstra *dij; - struct route **r; + struct route_hop *r; bool (*can_carry)(const struct gossmap *, const struct gossmap_chan *, int, @@ -753,14 +708,15 @@ static struct route_hop *route(const tal_t *ctx, can_carry = payment_route_can_carry; dij = dijkstra(tmpctx, gossmap, dst, amount, riskfactor, can_carry, route_score_cheaper, p); - r = route_from_dijkstra(tmpctx, gossmap, dij, src); + r = route_from_dijkstra(ctx, gossmap, dij, src, amount, final_delay); if (!r) { /* Try using disabled channels too */ /* FIXME: is there somewhere we can annotate this for paystatus? */ can_carry = payment_route_can_carry_even_disabled; - dij = dijkstra(tmpctx, gossmap, dst, amount, riskfactor, + dij = dijkstra(ctx, gossmap, dst, amount, riskfactor, can_carry, route_score_cheaper, p); - r = route_from_dijkstra(tmpctx, gossmap, dij, src); + r = route_from_dijkstra(ctx, gossmap, dij, src, + amount, final_delay); if (!r) { *errmsg = "No path found"; return NULL; @@ -769,10 +725,12 @@ static struct route_hop *route(const tal_t *ctx, /* If it's too far, fall back to using shortest path. */ if (tal_count(r) > max_hops) { + tal_free(r); /* FIXME: is there somewhere we can annotate this for paystatus? */ dij = dijkstra(tmpctx, gossmap, dst, amount, riskfactor, can_carry, route_score_shorter, p); - r = route_from_dijkstra(tmpctx, gossmap, dij, src); + r = route_from_dijkstra(ctx, gossmap, dij, src, + amount, final_delay); if (!r) { *errmsg = "No path found"; return NULL; @@ -782,11 +740,11 @@ static struct route_hop *route(const tal_t *ctx, if (tal_count(r) > max_hops) { *errmsg = tal_fmt(ctx, "Shortest path found was length %zu", tal_count(r)); - return NULL; + return tal_free(r); } } - return route_hops_from_route(ctx, gossmap, amount, final_delay, r); + return r; } static struct command_result *payment_getroute(struct payment *p) @@ -2658,7 +2616,7 @@ static void routehint_check_reachable(struct payment *p) const struct gossmap_node *dst, *src; struct gossmap *gossmap = get_gossmap(p->plugin); const struct dijkstra *dij; - struct route **r; + struct route_hop *r; struct payment *root = payment_root(p); struct routehints_data *d = payment_mod_routehints_get_data(root); @@ -2675,7 +2633,8 @@ static void routehint_check_reachable(struct payment *p) 10 / 1000000.0, payment_route_can_carry_even_disabled, route_score_cheaper, p); - r = route_from_dijkstra(tmpctx, gossmap, dij, src); + r = route_from_dijkstra(tmpctx, gossmap, dij, src, + AMOUNT_MSAT(1000), 0); /* If there was a route the destination is reachable * without routehints. */ diff --git a/plugins/libplugin-pay.h b/plugins/libplugin-pay.h index e1c355516..7cc13a747 100644 --- a/plugins/libplugin-pay.h +++ b/plugins/libplugin-pay.h @@ -3,6 +3,7 @@ #include "config.h" #include +#include #include #include diff --git a/plugins/libplugin.c b/plugins/libplugin.c index 5ac96f1f3..b522dbcaf 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/libplugin.h b/plugins/libplugin.h index f78657756..a70fa8078 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -340,21 +340,6 @@ struct createonion_response *json_to_createonion_response(const tal_t *ctx, const char *buffer, const jsmntok_t *toks); -enum route_hop_style { - ROUTE_HOP_LEGACY = 1, - ROUTE_HOP_TLV = 2, -}; - -struct route_hop { - struct short_channel_id scid; - int direction; - struct node_id node_id; - struct amount_msat amount; - u32 delay; - struct pubkey *blinding; - enum route_hop_style style; -}; - struct route_hop *json_to_route(const tal_t *ctx, const char *buffer, const jsmntok_t *toks);