Browse Source

gossipd: Implement improved randomization of routes.

Fixes: #928
ppa-0.6.1
ZmnSCPxj 7 years ago
committed by Rusty Russell
parent
commit
aff52ce5a8
  1. 5
      gossipd/gossip.c
  2. 40
      gossipd/routing.c
  3. 3
      gossipd/routing.h
  4. 1
      gossipd/test/run-bench-find_route.c
  5. 2
      gossipd/test/run-find_route-specific.c
  6. 10
      gossipd/test/run-find_route.c

5
gossipd/gossip.c

@ -1058,10 +1058,9 @@ static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon,
pubkey_to_hexstr(tmpctx, &source), pubkey_to_hexstr(tmpctx, &source),
pubkey_to_hexstr(tmpctx, &destination), msatoshi); pubkey_to_hexstr(tmpctx, &destination), msatoshi);
(void) fuzz;
(void) seed;
hops = get_route(tmpctx, daemon->rstate, &source, &destination, hops = get_route(tmpctx, daemon->rstate, &source, &destination,
msatoshi, 1, final_cltv); msatoshi, 1, final_cltv,
fuzz, seed);
out = towire_gossip_getroute_reply(msg, hops); out = towire_gossip_getroute_reply(msg, hops);
tal_free(tmpctx); tal_free(tmpctx);

40
gossipd/routing.c

@ -5,6 +5,7 @@
#include <ccan/array_size/array_size.h> #include <ccan/array_size/array_size.h>
#include <ccan/crypto/siphash24/siphash24.h> #include <ccan/crypto/siphash24/siphash24.h>
#include <ccan/endian/endian.h> #include <ccan/endian/endian.h>
#include <ccan/isaac/isaac64.h>
#include <ccan/structeq/structeq.h> #include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <common/features.h> #include <common/features.h>
@ -331,10 +332,30 @@ static u64 risk_fee(u64 amount, u32 delay, double riskfactor)
/* We track totals, rather than costs. That's because the fee depends /* We track totals, rather than costs. That's because the fee depends
* on the current amount passing through. */ * on the current amount passing through. */
static void bfg_one_edge(struct node *node, size_t edgenum, double riskfactor) static void bfg_one_edge(struct node *node, size_t edgenum, double riskfactor,
double fuzz, const struct isaac64_ctx *baserng)
{ {
struct node_connection *c = node->in[edgenum]; struct node_connection *c = node->in[edgenum];
size_t h; size_t h;
struct isaac64_ctx myrng;
double fee_scale = 1.0;
u8 *scid;
if (fuzz != 0.0) {
/* Copy RNG state */
myrng = *baserng;
/* Provide the channel short ID, as additional
* entropy. */
scid = tal_arr(NULL, u8, 0);
towire_short_channel_id(&scid, &c->short_channel_id);
isaac64_reseed(&myrng,
(const unsigned char *) scid, tal_len(scid));
tal_free(scid);
/* Scale fees for this channel */
fee_scale = 1.0 + fuzz * isaac64_next_signed_double(&myrng);
}
assert(c->dst == node); assert(c->dst == node);
for (h = 0; h < ROUTING_MAX_HOPS; h++) { for (h = 0; h < ROUTING_MAX_HOPS; h++) {
@ -345,7 +366,7 @@ static void bfg_one_edge(struct node *node, size_t edgenum, double riskfactor)
if (node->bfg[h].total == INFINITE) if (node->bfg[h].total == INFINITE)
continue; continue;
fee = connection_fee(c, node->bfg[h].total); fee = connection_fee(c, node->bfg[h].total) * fee_scale;
risk = node->bfg[h].risk + risk_fee(node->bfg[h].total + fee, risk = node->bfg[h].risk + risk_fee(node->bfg[h].total + fee,
c->delay, riskfactor); c->delay, riskfactor);
@ -380,7 +401,9 @@ static bool nc_is_routable(const struct node_connection *nc, time_t now)
static struct node_connection * static struct node_connection *
find_route(const tal_t *ctx, struct routing_state *rstate, find_route(const tal_t *ctx, struct routing_state *rstate,
const struct pubkey *from, const struct pubkey *to, u64 msatoshi, const struct pubkey *from, const struct pubkey *to, u64 msatoshi,
double riskfactor, u64 *fee, struct node_connection ***route) double riskfactor,
double fuzz, struct isaac64_ctx *baserng,
u64 *fee, struct node_connection ***route)
{ {
struct node *n, *src, *dst; struct node *n, *src, *dst;
struct node_map_iter it; struct node_map_iter it;
@ -440,7 +463,8 @@ find_route(const tal_t *ctx, struct routing_state *rstate,
SUPERVERBOSE("...unroutable"); SUPERVERBOSE("...unroutable");
continue; continue;
} }
bfg_one_edge(n, i, riskfactor); bfg_one_edge(n, i, riskfactor,
fuzz, baserng);
SUPERVERBOSE("...done"); SUPERVERBOSE("...done");
} }
} }
@ -1118,7 +1142,8 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
const struct pubkey *source, const struct pubkey *source,
const struct pubkey *destination, const struct pubkey *destination,
const u32 msatoshi, double riskfactor, const u32 msatoshi, double riskfactor,
u32 final_cltv) u32 final_cltv,
double fuzz, u8 *seed)
{ {
struct node_connection **route; struct node_connection **route;
u64 total_amount; u64 total_amount;
@ -1127,9 +1152,14 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
struct route_hop *hops; struct route_hop *hops;
int i; int i;
struct node_connection *first_conn; struct node_connection *first_conn;
isaac64_ctx baserng;
/* Load base RNG */
isaac64_init(&baserng, (const unsigned char*) seed, tal_count(seed));
first_conn = find_route(ctx, rstate, source, destination, msatoshi, first_conn = find_route(ctx, rstate, source, destination, msatoshi,
riskfactor / BLOCKS_PER_YEAR / 10000, riskfactor / BLOCKS_PER_YEAR / 10000,
fuzz, &baserng,
&fee, &route); &fee, &route);
if (!first_conn) { if (!first_conn) {

3
gossipd/routing.h

@ -186,7 +186,8 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
const struct pubkey *source, const struct pubkey *source,
const struct pubkey *destination, const struct pubkey *destination,
const u32 msatoshi, double riskfactor, const u32 msatoshi, double riskfactor,
u32 final_cltv); u32 final_cltv,
double fuzz, u8 *seed);
/* Disable channel(s) based on the given routing failure. */ /* Disable channel(s) based on the given routing failure. */
void routing_failure(struct routing_state *rstate, void routing_failure(struct routing_state *rstate,
const struct pubkey *erring_node, const struct pubkey *erring_node,

1
gossipd/test/run-bench-find_route.c

@ -212,6 +212,7 @@ int main(int argc, char *argv[])
nc = find_route(ctx, rstate, &from, &to, nc = find_route(ctx, rstate, &from, &to,
pseudorand(100000), pseudorand(100000),
riskfactor, riskfactor,
0.0, NULL,
&fee, &route); &fee, &route);
num_success += (nc != NULL); num_success += (nc != NULL);
tal_free(route); tal_free(route);

2
gossipd/test/run-find_route-specific.c

@ -127,7 +127,7 @@ int main(void)
nc->flags = 1; nc->flags = 1;
nc->last_timestamp = 1504064344; nc->last_timestamp = 1504064344;
nc = find_route(ctx, rstate, &a, &c, 100000, riskfactor, &fee, &route); nc = find_route(ctx, rstate, &a, &c, 100000, riskfactor, 0.0, NULL, &fee, &route);
assert(nc); assert(nc);
assert(tal_count(route) == 1); assert(tal_count(route) == 1);
assert(pubkey_eq(&route[0]->src->id, &b)); assert(pubkey_eq(&route[0]->src->id, &b));

10
gossipd/test/run-find_route.c

@ -108,7 +108,7 @@ int main(void)
/* A<->B */ /* A<->B */
add_connection(rstate, &a, &b, 1, 1, 1); add_connection(rstate, &a, &b, 1, 1, 1);
nc = find_route(ctx, rstate, &a, &b, 1000, riskfactor, &fee, &route); nc = find_route(ctx, rstate, &a, &b, 1000, riskfactor, 0.0, NULL, &fee, &route);
assert(nc); assert(nc);
assert(tal_count(route) == 0); assert(tal_count(route) == 0);
assert(fee == 0); assert(fee == 0);
@ -123,7 +123,7 @@ int main(void)
status_trace("C = %s", type_to_string(trc, struct pubkey, &c)); status_trace("C = %s", type_to_string(trc, struct pubkey, &c));
add_connection(rstate, &b, &c, 1, 1, 1); add_connection(rstate, &b, &c, 1, 1, 1);
nc = find_route(ctx, rstate, &a, &c, 1000, riskfactor, &fee, &route); nc = find_route(ctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, &fee, &route);
assert(nc); assert(nc);
assert(tal_count(route) == 1); assert(tal_count(route) == 1);
assert(fee == 1); assert(fee == 1);
@ -138,14 +138,14 @@ int main(void)
add_connection(rstate, &d, &c, 0, 2, 1); add_connection(rstate, &d, &c, 0, 2, 1);
/* Will go via D for small amounts. */ /* Will go via D for small amounts. */
nc = find_route(ctx, rstate, &a, &c, 1000, riskfactor, &fee, &route); nc = find_route(ctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, &fee, &route);
assert(nc); assert(nc);
assert(tal_count(route) == 1); assert(tal_count(route) == 1);
assert(pubkey_eq(&route[0]->src->id, &d)); assert(pubkey_eq(&route[0]->src->id, &d));
assert(fee == 0); assert(fee == 0);
/* Will go via B for large amounts. */ /* Will go via B for large amounts. */
nc = find_route(ctx, rstate, &a, &c, 3000000, riskfactor, &fee, &route); nc = find_route(ctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, &fee, &route);
assert(nc); assert(nc);
assert(tal_count(route) == 1); assert(tal_count(route) == 1);
assert(pubkey_eq(&route[0]->src->id, &b)); assert(pubkey_eq(&route[0]->src->id, &b));
@ -153,7 +153,7 @@ int main(void)
/* Make B->C inactive, force it back via D */ /* Make B->C inactive, force it back via D */
get_connection(rstate, &b, &c)->active = false; get_connection(rstate, &b, &c)->active = false;
nc = find_route(ctx, rstate, &a, &c, 3000000, riskfactor, &fee, &route); nc = find_route(ctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, &fee, &route);
assert(nc); assert(nc);
assert(tal_count(route) == 1); assert(tal_count(route) == 1);
assert(pubkey_eq(&route[0]->src->id, &d)); assert(pubkey_eq(&route[0]->src->id, &d));

Loading…
Cancel
Save