From aff52ce5a885046ba16b1b068347c463c7b3c899 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj Date: Fri, 16 Feb 2018 03:50:51 +0000 Subject: [PATCH] gossipd: Implement improved randomization of routes. Fixes: #928 --- gossipd/gossip.c | 5 ++-- gossipd/routing.c | 40 ++++++++++++++++++++++---- gossipd/routing.h | 3 +- gossipd/test/run-bench-find_route.c | 1 + gossipd/test/run-find_route-specific.c | 2 +- gossipd/test/run-find_route.c | 10 +++---- 6 files changed, 46 insertions(+), 15 deletions(-) diff --git a/gossipd/gossip.c b/gossipd/gossip.c index 6605bd618..fb53279b5 100644 --- a/gossipd/gossip.c +++ b/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, &destination), msatoshi); - (void) fuzz; - (void) seed; 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); tal_free(tmpctx); diff --git a/gossipd/routing.c b/gossipd/routing.c index 6392b43e0..5c54c8515 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -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 * 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]; 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); 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) 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, c->delay, riskfactor); @@ -380,7 +401,9 @@ static bool nc_is_routable(const struct node_connection *nc, time_t now) static struct node_connection * find_route(const tal_t *ctx, struct routing_state *rstate, 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_map_iter it; @@ -440,7 +463,8 @@ find_route(const tal_t *ctx, struct routing_state *rstate, SUPERVERBOSE("...unroutable"); continue; } - bfg_one_edge(n, i, riskfactor); + bfg_one_edge(n, i, riskfactor, + fuzz, baserng); 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 *destination, const u32 msatoshi, double riskfactor, - u32 final_cltv) + u32 final_cltv, + double fuzz, u8 *seed) { struct node_connection **route; u64 total_amount; @@ -1127,9 +1152,14 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate, struct route_hop *hops; int i; 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, riskfactor / BLOCKS_PER_YEAR / 10000, + fuzz, &baserng, &fee, &route); if (!first_conn) { diff --git a/gossipd/routing.h b/gossipd/routing.h index 214985a3b..1afd71b15 100644 --- a/gossipd/routing.h +++ b/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 *destination, const u32 msatoshi, double riskfactor, - u32 final_cltv); + u32 final_cltv, + double fuzz, u8 *seed); /* Disable channel(s) based on the given routing failure. */ void routing_failure(struct routing_state *rstate, const struct pubkey *erring_node, diff --git a/gossipd/test/run-bench-find_route.c b/gossipd/test/run-bench-find_route.c index 376f4e9fa..8b9667f1a 100644 --- a/gossipd/test/run-bench-find_route.c +++ b/gossipd/test/run-bench-find_route.c @@ -212,6 +212,7 @@ int main(int argc, char *argv[]) nc = find_route(ctx, rstate, &from, &to, pseudorand(100000), riskfactor, + 0.0, NULL, &fee, &route); num_success += (nc != NULL); tal_free(route); diff --git a/gossipd/test/run-find_route-specific.c b/gossipd/test/run-find_route-specific.c index eac0ae878..ae638bc07 100644 --- a/gossipd/test/run-find_route-specific.c +++ b/gossipd/test/run-find_route-specific.c @@ -127,7 +127,7 @@ int main(void) nc->flags = 1; 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(tal_count(route) == 1); assert(pubkey_eq(&route[0]->src->id, &b)); diff --git a/gossipd/test/run-find_route.c b/gossipd/test/run-find_route.c index 6a83fb158..e25bd48bd 100644 --- a/gossipd/test/run-find_route.c +++ b/gossipd/test/run-find_route.c @@ -108,7 +108,7 @@ int main(void) /* A<->B */ 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(tal_count(route) == 0); assert(fee == 0); @@ -123,7 +123,7 @@ int main(void) status_trace("C = %s", type_to_string(trc, struct pubkey, &c)); 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(tal_count(route) == 1); assert(fee == 1); @@ -138,14 +138,14 @@ int main(void) add_connection(rstate, &d, &c, 0, 2, 1); /* 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(tal_count(route) == 1); assert(pubkey_eq(&route[0]->src->id, &d)); assert(fee == 0); /* 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(tal_count(route) == 1); assert(pubkey_eq(&route[0]->src->id, &b)); @@ -153,7 +153,7 @@ int main(void) /* Make B->C inactive, force it back via D */ 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(tal_count(route) == 1); assert(pubkey_eq(&route[0]->src->id, &d));