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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2021-05-22 16:40:01 +09:30
parent e531a38963
commit 2bb365a931
12 changed files with 225 additions and 222 deletions

View File

@@ -4,8 +4,8 @@
#include <ccan/tal/str/str.h>
#include <ccan/time/time.h>
#include <common/dijkstra.h>
#include <common/features.h>
#include <common/gossmap.h>
#include <common/node_id.h>
#include <common/pseudorand.h>
#include <common/random_select.h>
#include <common/route.h>
@@ -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;
}