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;
}

View File

@ -2,14 +2,41 @@
#ifndef LIGHTNING_COMMON_ROUTE_H
#define LIGHTNING_COMMON_ROUTE_H
#include "config.h"
#include <bitcoin/short_channel_id.h>
#include <common/amount.h>
#include <common/node_id.h>
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 */

View File

@ -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);

View File

@ -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);

View File

@ -13,25 +13,9 @@
#include <inttypes.h>
#include <stdio.h>
/* ->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;
}
}

View File

@ -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),

View File

@ -9,6 +9,7 @@
#include <common/amount.h>
#include <common/gossip_constants.h>
#include <common/node_id.h>
#include <common/route.h>
#include <gossipd/broadcast.h>
#include <gossipd/gossip_store.h>
#include <wire/onion_wire.h>
@ -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

View File

@ -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,

View File

@ -8,7 +8,6 @@
#include <common/memleak.h>
#include <common/pseudorand.h>
#include <common/random_select.h>
#include <common/route.h>
#include <common/type_to_string.h>
#include <errno.h>
#include <plugins/libplugin-pay.h>
@ -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. */

View File

@ -3,6 +3,7 @@
#include "config.h"
#include <common/bolt11.h>
#include <common/route.h>
#include <plugins/libplugin.h>
#include <wire/onion_wire.h>

View File

@ -6,6 +6,7 @@
#include <ccan/tal/str/str.h>
#include <common/daemon.h>
#include <common/json_stream.h>
#include <common/route.h>
#include <common/utils.h>
#include <errno.h>
#include <plugins/libplugin.h>

View File

@ -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);