Skip to content

Commit 5e2d154

Browse files
committed
askrene: refactor get_routes
Prefer the following programming pattern: do_getroutes(){ do_something1(); do_something2(); do_something3(); } rather than get_routes(){ do_something1(); do_something2(); } do_getroutes(){ get_routes(); do_something3(); } Changelog-None Signed-off-by: Lagrang3 <[email protected]>
1 parent 0581f8e commit 5e2d154

File tree

1 file changed

+162
-143
lines changed

1 file changed

+162
-143
lines changed

plugins/askrene/askrene.c

+162-143
Original file line numberDiff line numberDiff line change
@@ -331,60 +331,35 @@ const char *fmt_flow_full(const tal_t *ctx,
331331
return str;
332332
}
333333

334-
/* Returns an error message, or sets *routes */
335-
static const char *get_routes(const tal_t *ctx,
336-
struct command *cmd,
337-
const struct node_id *source,
338-
const struct node_id *dest,
339-
struct amount_msat amount,
340-
struct amount_msat maxfee,
341-
u32 finalcltv,
342-
u32 maxdelay,
343-
const char **layers,
344-
struct gossmap_localmods *localmods,
345-
const struct layer *local_layer,
346-
bool single_path,
347-
struct route ***routes,
348-
struct amount_msat **amounts,
349-
const struct additional_cost_htable *additional_costs,
350-
double *probability)
351-
{
352-
struct askrene *askrene = get_askrene(cmd->plugin);
353-
struct route_query *rq = tal(ctx, struct route_query);
354-
struct flow **flows;
355-
const struct gossmap_node *srcnode, *dstnode;
356-
const char *ret;
357-
struct timerel time_delta;
358-
struct timemono time_start = time_mono();
359-
360-
if (gossmap_refresh(askrene->gossmap)) {
361-
/* FIXME: gossmap_refresh callbacks to we can update in place */
362-
tal_free(askrene->capacities);
363-
askrene->capacities = get_capacities(askrene, askrene->plugin, askrene->gossmap);
364-
}
365-
366-
rq->cmd = cmd;
367-
rq->plugin = cmd->plugin;
368-
rq->gossmap = askrene->gossmap;
369-
rq->reserved = askrene->reserved;
370-
rq->layers = tal_arr(rq, const struct layer *, 0);
371-
rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
372-
rq->additional_costs = additional_costs;
334+
struct getroutes_info {
335+
struct command *cmd;
336+
struct node_id *source, *dest;
337+
struct amount_msat *amount, *maxfee;
338+
u32 *finalcltv, *maxdelay;
339+
const char **layers;
340+
struct additional_cost_htable *additional_costs;
341+
/* Non-NULL if we are told to use "auto.localchans" */
342+
struct layer *local_layer;
343+
};
373344

345+
static void apply_layers(struct askrene *askrene, struct route_query *rq,
346+
struct gossmap_localmods *localmods,
347+
const struct getroutes_info *info)
348+
{
374349
/* Layers must exist, but might be special ones! */
375-
for (size_t i = 0; i < tal_count(layers); i++) {
376-
const struct layer *l = find_layer(askrene, layers[i]);
350+
for (size_t i = 0; i < tal_count(info->layers); i++) {
351+
const struct layer *l = find_layer(askrene, info->layers[i]);
377352
if (!l) {
378-
if (streq(layers[i], "auto.localchans")) {
353+
if (streq(info->layers[i], "auto.localchans")) {
379354
plugin_log(rq->plugin, LOG_DBG, "Adding auto.localchans");
380-
l = local_layer;
381-
} else if (streq(layers[i], "auto.no_mpp_support")) {
355+
l = info->local_layer;
356+
} else if (streq(info->layers[i], "auto.no_mpp_support")) {
382357
plugin_log(rq->plugin, LOG_DBG, "Adding auto.no_mpp_support, sorry");
383-
l = remove_small_channel_layer(layers, askrene, amount, localmods);
358+
l = remove_small_channel_layer(info->layers, askrene, *info->amount, localmods);
384359
} else {
385-
assert(streq(layers[i], "auto.sourcefree"));
360+
assert(streq(info->layers[i], "auto.sourcefree"));
386361
plugin_log(rq->plugin, LOG_DBG, "Adding auto.sourcefree");
387-
l = source_free_layer(layers, askrene, source, localmods);
362+
l = source_free_layer(info->layers, askrene, info->source, localmods);
388363
}
389364
}
390365

@@ -396,46 +371,14 @@ static const char *get_routes(const tal_t *ctx,
396371
* override them (incl local channels) */
397372
layer_clear_overridden_capacities(l, askrene->gossmap, rq->capacities);
398373
}
374+
}
399375

400-
/* Clear scids with reservations, too, so we don't have to look up
401-
* all the time! */
402-
reserves_clear_capacities(askrene->reserved, askrene->gossmap, rq->capacities);
403-
404-
gossmap_apply_localmods(askrene->gossmap, localmods);
405-
406-
/* localmods can add channels, so we need to allocate biases array *afterwards* */
407-
rq->biases = tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
408-
409-
/* Note any channel biases */
410-
for (size_t i = 0; i < tal_count(rq->layers); i++)
411-
layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
412-
413-
srcnode = gossmap_find_node(askrene->gossmap, source);
414-
if (!srcnode) {
415-
ret = rq_log(ctx, rq, LOG_INFORM,
416-
"Unknown source node %s",
417-
fmt_node_id(tmpctx, source));
418-
goto fail;
419-
}
420-
421-
dstnode = gossmap_find_node(askrene->gossmap, dest);
422-
if (!dstnode) {
423-
ret = rq_log(ctx, rq, LOG_INFORM,
424-
"Unknown destination node %s",
425-
fmt_node_id(tmpctx, dest));
426-
goto fail;
427-
}
428-
429-
/* FIXME: single_path should signal a change in algorithm. */
430-
ret = default_routes(rq, rq, srcnode, dstnode, amount, single_path,
431-
maxfee, finalcltv, maxdelay, &flows, probability);
432-
if (ret) {
433-
goto fail;
434-
}
435-
assert(tal_count(flows) > 0);
436-
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
437-
tal_count(flows));
438-
376+
static void convert_flows_to_routes(const tal_t *ctx, struct route_query *rq,
377+
struct route ***routes,
378+
struct amount_msat **amounts,
379+
u32 finalcltv,
380+
struct flow **flows)
381+
{
439382
/* Convert back into routes, with delay and other information fixed */
440383
*routes = tal_arr(ctx, struct route *, tal_count(flows));
441384
*amounts = tal_arr(ctx, struct amount_msat, tal_count(flows));
@@ -473,22 +416,6 @@ static const char *get_routes(const tal_t *ctx,
473416
i, tal_count(flows),
474417
fmt_route(tmpctx, r, (*amounts)[i], finalcltv));
475418
}
476-
477-
gossmap_remove_localmods(askrene->gossmap, localmods);
478-
time_delta = timemono_between(time_mono(), time_start);
479-
rq_log(tmpctx, rq, LOG_DBG, "get_routes completed in %" PRIu64 " ms",
480-
time_to_msec(time_delta));
481-
return NULL;
482-
483-
/* Explicit failure path keeps the compiler (gcc version 12.3.0 -O3) from
484-
* warning about uninitialized variables in the caller */
485-
fail:
486-
assert(ret != NULL);
487-
gossmap_remove_localmods(askrene->gossmap, localmods);
488-
time_delta = timemono_between(time_mono(), time_start);
489-
rq_log(tmpctx, rq, LOG_DBG, "get_routes failed after %" PRIu64 " ms",
490-
time_to_msec(time_delta));
491-
return ret;
492419
}
493420

494421
void get_constraints(const struct route_query *rq,
@@ -527,16 +454,40 @@ void get_constraints(const struct route_query *rq,
527454
reserve_sub(rq->reserved, &scidd, max);
528455
}
529456

530-
struct getroutes_info {
531-
struct command *cmd;
532-
struct node_id *source, *dest;
533-
struct amount_msat *amount, *maxfee;
534-
u32 *finalcltv, *maxdelay;
535-
const char **layers;
536-
struct additional_cost_htable *additional_costs;
537-
/* Non-NULL if we are told to use "auto.localchans" */
538-
struct layer *local_layer;
539-
};
457+
static void json_add_getroutes(
458+
struct json_stream *js,
459+
struct route **routes,
460+
const struct amount_msat *amounts,
461+
double probability,
462+
u32 final_cltv)
463+
{
464+
json_add_u64(js, "probability_ppm", (u64)(probability * 1000000));
465+
json_array_start(js, "routes");
466+
for (size_t i = 0; i < tal_count(routes); i++) {
467+
json_object_start(js, NULL);
468+
json_add_u64(js, "probability_ppm",
469+
(u64)(routes[i]->success_prob * 1000000));
470+
json_add_amount_msat(js, "amount_msat", amounts[i]);
471+
json_add_u32(js, "final_cltv", final_cltv);
472+
json_array_start(js, "path");
473+
for (size_t j = 0; j < tal_count(routes[i]->hops); j++) {
474+
struct short_channel_id_dir scidd;
475+
const struct route_hop *r = &routes[i]->hops[j];
476+
json_object_start(js, NULL);
477+
scidd.scid = r->scid;
478+
scidd.dir = r->direction;
479+
json_add_short_channel_id_dir(
480+
js, "short_channel_id_dir", scidd);
481+
json_add_node_id(js, "next_node_id", &r->node_id);
482+
json_add_amount_msat(js, "amount_msat", r->amount);
483+
json_add_u32(js, "delay", r->delay);
484+
json_object_end(js);
485+
}
486+
json_array_end(js);
487+
json_object_end(js);
488+
}
489+
json_array_end(js);
490+
}
540491

541492
static struct command_result *do_getroutes(struct command *cmd,
542493
struct gossmap_localmods *localmods,
@@ -546,43 +497,111 @@ static struct command_result *do_getroutes(struct command *cmd,
546497
double probability;
547498
struct amount_msat *amounts;
548499
struct route **routes;
500+
struct flow **flows;
549501
struct json_stream *response;
550502

551-
err = get_routes(cmd, cmd,
552-
info->source, info->dest,
553-
*info->amount, *info->maxfee, *info->finalcltv,
554-
*info->maxdelay, info->layers, localmods, info->local_layer,
555-
have_layer(info->layers, "auto.no_mpp_support"),
556-
&routes, &amounts, info->additional_costs, &probability);
503+
/* get me the global state structure */
504+
struct askrene *askrene = get_askrene(cmd->plugin);
505+
506+
/* update the gossmap */
507+
if (gossmap_refresh(askrene->gossmap)) {
508+
/* FIXME: gossmap_refresh callbacks to we can update in place */
509+
tal_free(askrene->capacities);
510+
askrene->capacities =
511+
get_capacities(askrene, askrene->plugin, askrene->gossmap);
512+
}
513+
514+
/* build this request structure */
515+
struct route_query *rq = tal(cmd, struct route_query);
516+
rq->cmd = cmd;
517+
rq->plugin = cmd->plugin;
518+
rq->gossmap = askrene->gossmap;
519+
rq->reserved = askrene->reserved;
520+
rq->layers = tal_arr(rq, const struct layer *, 0);
521+
rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
522+
/* FIXME: we still need to do something useful with these */
523+
rq->additional_costs = info->additional_costs;
524+
525+
/* apply selected layers to the localmods */
526+
apply_layers(askrene, rq, localmods, info);
527+
528+
/* Clear scids with reservations, too, so we don't have to look up
529+
* all the time! */
530+
reserves_clear_capacities(askrene->reserved, askrene->gossmap,
531+
rq->capacities);
532+
533+
/* we temporarily apply localmods */
534+
gossmap_apply_localmods(askrene->gossmap, localmods);
535+
536+
/* localmods can add channels, so we need to allocate biases array
537+
* *afterwards* */
538+
rq->biases =
539+
tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
540+
541+
/* Note any channel biases */
542+
for (size_t i = 0; i < tal_count(rq->layers); i++)
543+
layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
544+
545+
/* checkout the source */
546+
const struct gossmap_node *srcnode =
547+
gossmap_find_node(askrene->gossmap, info->source);
548+
if (!srcnode) {
549+
err = rq_log(tmpctx, rq, LOG_INFORM, "Unknown source node %s",
550+
fmt_node_id(tmpctx, info->source));
551+
goto fail;
552+
}
553+
554+
/* checkout the destination */
555+
const struct gossmap_node *dstnode =
556+
gossmap_find_node(askrene->gossmap, info->dest);
557+
if (!dstnode) {
558+
err = rq_log(tmpctx, rq, LOG_INFORM,
559+
"Unknown destination node %s",
560+
fmt_node_id(tmpctx, info->dest));
561+
goto fail;
562+
}
563+
564+
/* Compute the routes. At this point we might select between multiple
565+
* algorithms. */
566+
struct timemono time_start = time_mono();
567+
err = default_routes(rq, rq, srcnode, dstnode, *info->amount,
568+
/* only one path? = */
569+
have_layer(info->layers, "auto.no_mpp_support"),
570+
*info->maxfee, *info->finalcltv, *info->maxdelay,
571+
&flows, &probability);
572+
struct timerel time_delta = timemono_between(time_mono(), time_start);
573+
574+
/* log the time of computation */
575+
rq_log(tmpctx, rq, LOG_DBG, "get_routes %s %" PRIu64 " ms",
576+
err ? "failed after" : "completed in",
577+
time_to_msec(time_delta));
557578
if (err)
558-
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
579+
goto fail;
559580

581+
/* otherwise we continue */
582+
assert(tal_count(flows) > 0);
583+
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
584+
tal_count(flows));
585+
586+
/* convert flows to routes */
587+
convert_flows_to_routes(rq, rq, &routes, &amounts, *info->finalcltv,
588+
flows);
589+
assert(tal_count(routes) == tal_count(flows));
590+
assert(tal_count(amounts) == tal_count(flows));
591+
592+
/* At last we remove the localmods from the gossmap. */
593+
gossmap_remove_localmods(askrene->gossmap, localmods);
594+
595+
/* output the results */
560596
response = jsonrpc_stream_success(cmd);
561-
json_add_u64(response, "probability_ppm", (u64)(probability * 1000000));
562-
json_array_start(response, "routes");
563-
for (size_t i = 0; i < tal_count(routes); i++) {
564-
json_object_start(response, NULL);
565-
json_add_u64(response, "probability_ppm", (u64)(routes[i]->success_prob * 1000000));
566-
json_add_amount_msat(response, "amount_msat", amounts[i]);
567-
json_add_u32(response, "final_cltv", *info->finalcltv);
568-
json_array_start(response, "path");
569-
for (size_t j = 0; j < tal_count(routes[i]->hops); j++) {
570-
struct short_channel_id_dir scidd;
571-
const struct route_hop *r = &routes[i]->hops[j];
572-
json_object_start(response, NULL);
573-
scidd.scid = r->scid;
574-
scidd.dir = r->direction;
575-
json_add_short_channel_id_dir(response, "short_channel_id_dir", scidd);
576-
json_add_node_id(response, "next_node_id", &r->node_id);
577-
json_add_amount_msat(response, "amount_msat", r->amount);
578-
json_add_u32(response, "delay", r->delay);
579-
json_object_end(response);
580-
}
581-
json_array_end(response);
582-
json_object_end(response);
583-
}
584-
json_array_end(response);
597+
json_add_getroutes(response, routes, amounts, probability,
598+
*info->finalcltv);
585599
return command_finished(cmd, response);
600+
601+
fail:
602+
assert(err);
603+
gossmap_remove_localmods(askrene->gossmap, localmods);
604+
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
586605
}
587606

588607
static void add_localchan(struct gossmap_localmods *mods,

0 commit comments

Comments
 (0)