mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
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:
parent
e531a38963
commit
2bb365a931
@ -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,
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (dist == 0)
|
||||
return true;
|
||||
|
||||
if (dist == UINT_MAX)
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
(*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 *cur)
|
||||
const struct gossmap_node *src,
|
||||
struct amount_msat final_amount,
|
||||
u32 final_cltv)
|
||||
{
|
||||
struct route **path = tal_arr(ctx, struct route *, 0);
|
||||
u32 curidx = gossmap_node_idx(map, cur);
|
||||
struct route_hop *hops = tal_arr(ctx, struct route_hop, 0);
|
||||
|
||||
while (dijkstra_distance(dij, curidx) != 0) {
|
||||
struct route *r;
|
||||
if (!dijkstra_to_hops(&hops, map, dij, src, &final_amount, &final_cltv))
|
||||
return tal_free(hops);
|
||||
|
||||
if (dijkstra_distance(dij, curidx) == UINT_MAX)
|
||||
return tal_free(path);
|
||||
|
||||
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);
|
||||
}
|
||||
return path;
|
||||
return hops;
|
||||
}
|
||||
|
@ -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,
|
||||
struct route_hop *route_from_dijkstra(const tal_t *ctx,
|
||||
const struct gossmap *map,
|
||||
const struct dijkstra *dij,
|
||||
const struct gossmap_node *cur);
|
||||
const struct gossmap_node *src,
|
||||
struct amount_msat final_amount,
|
||||
u32 final_cltv);
|
||||
#endif /* LIGHTNING_COMMON_ROUTE_H */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -13,23 +13,7 @@
|
||||
#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,
|
||||
static struct route_hop *least_cost(struct gossmap *map,
|
||||
struct gossmap_node *src,
|
||||
struct gossmap_node *dst)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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,26 +565,32 @@ 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(backwards) == 0)
|
||||
if (tal_bytelen(r) == 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,
|
||||
&sent->reply_blinding);
|
||||
|
@ -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. */
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <common/bolt11.h>
|
||||
#include <common/route.h>
|
||||
#include <plugins/libplugin.h>
|
||||
#include <wire/onion_wire.h>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user