diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index 56fb5b5e1..d15607d94 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -35,6 +35,7 @@ gossip_getroute_request,,fuzz,double gossip_getroute_request,,num_excluded,u16 gossip_getroute_request,,excluded,num_excluded*struct short_channel_id gossip_getroute_request,,excluded_dir,num_excluded*bool +gossip_getroute_request,,max_hops,u32 gossip_getroute_reply,3106 gossip_getroute_reply,,num_hops,u16 diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 8d7c80a44..0d4ea1f34 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1867,6 +1867,7 @@ static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon, u64 msatoshi; u32 final_cltv; u16 riskfactor; + u32 max_hops; u8 *out; struct route_hop *hops; double fuzz; @@ -1883,7 +1884,8 @@ static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon, &source, &destination, &msatoshi, &riskfactor, &final_cltv, &fuzz, - &excluded, &excluded_dir)) + &excluded, &excluded_dir, + &max_hops)) master_badmsg(WIRE_GOSSIP_GETROUTE_REQUEST, msg); status_trace("Trying to find a route from %s to %s for %"PRIu64" msatoshi", @@ -1893,7 +1895,7 @@ static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon, /* routing.c does all the hard work; can return NULL. */ hops = get_route(tmpctx, daemon->rstate, &source, &destination, msatoshi, riskfactor, final_cltv, - fuzz, siphash_seed(), excluded, excluded_dir); + fuzz, siphash_seed(), excluded, excluded_dir, max_hops); out = towire_gossip_getroute_reply(NULL, hops); daemon_conn_send(daemon->master, take(out)); diff --git a/gossipd/routing.c b/gossipd/routing.c index 781d5c543..e8243dd0e 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -377,7 +377,8 @@ static bool hc_can_carry(const struct half_chan *hc, u64 requiredcap) static void bfg_one_edge(struct node *node, struct chan *chan, int idx, double riskfactor, - double fuzz, const struct siphash_seed *base_seed) + double fuzz, const struct siphash_seed *base_seed, + size_t max_hops) { size_t h; double fee_scale = 1.0; @@ -394,7 +395,7 @@ static void bfg_one_edge(struct node *node, fee_scale = 1.0 + (2.0 * fuzz * h / UINT64_MAX) - fuzz; } - for (h = 0; h < ROUTING_MAX_HOPS; h++) { + for (h = 0; h < max_hops; h++) { struct node *src; /* FIXME: Bias against smaller channels. */ u64 fee; @@ -450,6 +451,7 @@ find_route(const tal_t *ctx, struct routing_state *rstate, const struct pubkey *from, const struct pubkey *to, u64 msatoshi, double riskfactor, double fuzz, const struct siphash_seed *base_seed, + size_t max_hops, u64 *fee) { struct chan **route; @@ -486,6 +488,11 @@ find_route(const tal_t *ctx, struct routing_state *rstate, return NULL; } + if (max_hops > ROUTING_MAX_HOPS) { + status_info("find_route: max_hops huge amount %zu", max_hops); + return NULL; + } + /* Reset all the information. */ clear_bfg(rstate->nodes); @@ -494,7 +501,7 @@ find_route(const tal_t *ctx, struct routing_state *rstate, src->bfg[0].total = msatoshi; src->bfg[0].risk = 0; - for (runs = 0; runs < ROUTING_MAX_HOPS; runs++) { + for (runs = 0; runs < max_hops; runs++) { SUPERVERBOSE("Run %i", runs); /* Run through every edge. */ for (n = node_map_first(rstate->nodes, &it); @@ -518,14 +525,15 @@ find_route(const tal_t *ctx, struct routing_state *rstate, continue; } bfg_one_edge(n, chan, idx, - riskfactor, fuzz, base_seed); + riskfactor, fuzz, base_seed, + max_hops); SUPERVERBOSE("...done"); } } } best = 0; - for (i = 1; i <= ROUTING_MAX_HOPS; i++) { + for (i = 1; i <= max_hops; i++) { if (dst->bfg[i].total < dst->bfg[best].total) best = i; } @@ -1498,7 +1506,8 @@ struct route_hop *get_route(const tal_t *ctx, struct routing_state *rstate, u32 final_cltv, double fuzz, const struct siphash_seed *base_seed, const struct short_channel_id *excluded, - const bool *excluded_dir) + const bool *excluded_dir, + size_t max_hops) { struct chan **route; u64 total_amount; @@ -1523,7 +1532,7 @@ struct route_hop *get_route(const tal_t *ctx, struct routing_state *rstate, route = find_route(ctx, rstate, source, destination, msatoshi, riskfactor / BLOCKS_PER_YEAR / 10000, - fuzz, base_seed, &fee); + fuzz, base_seed, max_hops, &fee); /* Now restore the capacity. */ for (size_t i = 0; i < tal_count(excluded); i++) { diff --git a/gossipd/routing.h b/gossipd/routing.h index 930c6d44e..58576aedf 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -269,7 +269,8 @@ struct route_hop *get_route(const tal_t *ctx, struct routing_state *rstate, double fuzz, const struct siphash_seed *base_seed, const struct short_channel_id *excluded, - const bool *excluded_dir); + const bool *excluded_dir, + size_t max_hops); /* 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 fa74af109..418d45a65 100644 --- a/gossipd/test/run-bench-find_route.c +++ b/gossipd/test/run-bench-find_route.c @@ -258,10 +258,11 @@ int main(int argc, char *argv[]) struct chan **route; route = find_route(tmpctx, rstate, from, to, - pseudorand(100000), - riskfactor, - 0.75, &base_seed, - &fee); + pseudorand(100000), + riskfactor, + 0.75, &base_seed, + ROUTING_MAX_HOPS, + &fee); num_success += (route != NULL); tal_free(route); } diff --git a/gossipd/test/run-find_route-specific.c b/gossipd/test/run-find_route-specific.c index b273e4ab5..53bf1a105 100644 --- a/gossipd/test/run-find_route-specific.c +++ b/gossipd/test/run-find_route-specific.c @@ -222,7 +222,8 @@ int main(void) nc->message_flags = 0; nc->last_timestamp = 1504064344; - route = find_route(tmpctx, rstate, &a, &c, 100000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 100000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); assert(tal_count(route) == 2); assert(channel_is_between(route[0], &a, &b)); @@ -230,17 +231,20 @@ int main(void) /* We should not be able to find a route that exceeds our own capacity */ - route = find_route(tmpctx, rstate, &a, &c, 1000001, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 1000001, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(!route); /* Now test with a query that exceeds the channel capacity after adding * some fees */ - route = find_route(tmpctx, rstate, &a, &c, 999999, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 999999, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(!route); /* This should fail to return a route because it is smaller than these * htlc_minimum_msat on the last channel. */ - route = find_route(tmpctx, rstate, &a, &c, 1, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 1, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); 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}, */ @@ -255,12 +259,14 @@ int main(void) nc->htlc_maximum_msat = 500000; /* half capacity */ /* This should route correctly at the max_msat level */ - route = find_route(tmpctx, rstate, &a, &d, 500000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &d, 500000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); /* This should fail to return a route because it's larger than the * htlc_maximum_msat on the last channel. */ - route = find_route(tmpctx, rstate, &a, &d, 500001, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &d, 500001, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(!route); tal_free(tmpctx); diff --git a/gossipd/test/run-find_route.c b/gossipd/test/run-find_route.c index 26b5efffa..ea8becbee 100644 --- a/gossipd/test/run-find_route.c +++ b/gossipd/test/run-find_route.c @@ -222,7 +222,8 @@ int main(void) /* A<->B */ add_connection(rstate, &a, &b, 1, 1, 1); - route = find_route(tmpctx, rstate, &a, &b, 1000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &b, 1000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); assert(tal_count(route) == 1); assert(fee == 0); @@ -237,7 +238,8 @@ int main(void) status_trace("C = %s", type_to_string(tmpctx, struct pubkey, &c)); add_connection(rstate, &b, &c, 1, 1, 1); - route = find_route(tmpctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); assert(tal_count(route) == 2); assert(fee == 1); @@ -252,7 +254,8 @@ int main(void) add_connection(rstate, &d, &c, 0, 2, 1); /* Will go via D for small amounts. */ - route = find_route(tmpctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); assert(tal_count(route) == 2); assert(channel_is_between(route[0], &a, &d)); @@ -260,7 +263,8 @@ int main(void) assert(fee == 0); /* Will go via B for large amounts. */ - route = find_route(tmpctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); assert(tal_count(route) == 2); assert(channel_is_between(route[0], &a, &b)); @@ -269,7 +273,8 @@ int main(void) /* Make B->C inactive, force it back via D */ get_connection(rstate, &b, &c)->channel_flags |= ROUTING_FLAGS_DISABLED; - route = find_route(tmpctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, &fee); + route = find_route(tmpctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, + ROUTING_MAX_HOPS, &fee); assert(route); assert(tal_count(route) == 2); assert(channel_is_between(route[0], &a, &d)); diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index feee26a81..21f10aeb3 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -327,6 +327,7 @@ static struct command_result *json_getroute(struct command *cmd, double *riskfactor; struct short_channel_id *excluded; bool *excluded_dir; + u32 *max_hops; /* Higher fuzz means that some high-fee paths can be discounted * for an even larger value, increasing the scope for route @@ -343,6 +344,8 @@ static struct command_result *json_getroute(struct command *cmd, p_opt_def("fromid", param_pubkey, &source, ld->id), p_opt_def("fuzzpercent", param_percent, &fuzz, 5.0), p_opt("exclude", param_array, &excludetok), + p_opt_def("maxhops", param_number, &max_hops, + ROUTING_MAX_HOPS), NULL)) return command_param_failed(); @@ -378,7 +381,8 @@ static struct command_result *json_getroute(struct command *cmd, u8 *req = towire_gossip_getroute_request(cmd, source, destination, *msatoshi, *riskfactor * 1000, *cltv, fuzz, - excluded, excluded_dir); + excluded, excluded_dir, + *max_hops); subd_req(ld->gossip, ld->gossip, req, -1, 0, json_getroute_reply, cmd); return command_still_pending(cmd); } diff --git a/lightningd/payalgo.c b/lightningd/payalgo.c index 0295f893d..0a8d95cab 100644 --- a/lightningd/payalgo.c +++ b/lightningd/payalgo.c @@ -557,7 +557,8 @@ static struct command_result *json_pay_try(struct pay *pay) pay->msatoshi + overpayment, pay->riskfactor, pay->min_final_cltv_expiry, - &pay->fuzz, NULL, NULL); + &pay->fuzz, NULL, NULL, + ROUTING_MAX_HOPS); subd_req(pay->try_parent, cmd->ld->gossip, req, -1, 0, json_pay_getroute_reply, pay); return NULL;