#include "config.h" #include #include #include #include #include #include #include #include #include #include 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); /* 10ksat, budget is 0.5% */ const struct amount_msat sent = AMOUNT_MSAT(10000000); const struct amount_msat budget = amount_msat_div(sent, 200); struct amount_msat fee; const u32 riskfactor = 10; /* Max distance is 20 */ const u32 distance_budget = ROUTING_MAX_HOPS; struct amount_msat maxcost; struct route_hop *path; struct timemono tstart, tstop; setup_locale(); setup_tmpctx(); tstart = time_mono(); dij = dijkstra(tmpctx, map, dst, sent, riskfactor, route_can_carry, route_score_cheaper, NULL); tstop = time_mono(); printf("# Time to find route: %"PRIu64" usec\n", time_to_usec(timemono_between(tstop, tstart))); if (dijkstra_distance(dij, srcidx) > distance_budget) { printf("failed (too far)\n"); return NULL; } if (!amount_msat_add(&maxcost, sent, budget)) abort(); path = route_from_dijkstra(map, map, dij, src, sent, 0); if (amount_msat_greater(path[0].amount, maxcost)) { printf("failed (too expensive)\n"); return tal_free(path); } printf("# path length %zu\n", tal_count(path)); /* We don't pay fee on first hop! */ if (!amount_msat_sub(&fee, path[0].amount, sent)) abort(); printf("# path fee %s\n", type_to_string(tmpctx, struct amount_msat, &fee)); tal_free(dij); return path; } int main(int argc, char *argv[]) { struct timemono tstart, tstop; struct gossmap_node *n, *dst; struct gossmap *map; struct node_id dstid; bool clean_topology = false; size_t num_channel_updates_rejected; opt_register_noarg("--clean-topology", opt_set_bool, &clean_topology, "Clean up topology before run"); opt_register_noarg("-h|--help", opt_usage_and_exit, " |all \n" "A routing test and benchmark program.", "Get usage information"); opt_parse(&argc, argv, opt_log_stderr_exit); if (argc != 4) opt_usage_exit_fail("Expect 3 arguments"); tstart = time_mono(); map = gossmap_load(NULL, argv[1], &num_channel_updates_rejected); if (!map) err(1, "Loading gossip store %s", argv[1]); tstop = time_mono(); printf("# Time to load: %"PRIu64" msec (%zu ignored)\n", time_to_msec(timemono_between(tstop, tstart)), num_channel_updates_rejected); if (clean_topology) clean_topo(map, false); if (!node_id_from_hexstr(argv[3], strlen(argv[3]), &dstid)) errx(1, "Bad dstid"); dst = gossmap_find_node(map, &dstid); if (!dst) errx(1, "Unknown destination node '%s'", argv[3]); if (streq(argv[2], "all")) { for (n = gossmap_first_node(map); n; n = gossmap_next_node(map, n)) { struct node_id srcid, dstid; gossmap_node_get_id(map, n, &srcid); gossmap_node_get_id(map, dst, &dstid); printf("# %s->%s\n", type_to_string(tmpctx, struct node_id, &srcid), type_to_string(tmpctx, struct node_id, &dstid)); tal_free(least_cost(map, n, dst)); } } else { struct route_hop *path; struct node_id srcid; if (!node_id_from_hexstr(argv[2], strlen(argv[2]), &srcid)) errx(1, "Bad srcid"); n = gossmap_find_node(map, &srcid); if (!n) errx(1, "Unknown source node '%s'", argv[2]); path = least_cost(map, n, dst); if (!path) exit(1); for (size_t i = 0; i < tal_count(path); i++) { printf("%s->%s via %s\n", 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, &path[i].scid)); srcid = path[i].node_id; } } tal_free(map); }