Skip to content

Commit 1581ca2

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 <lagrang3@protonmail.com>
1 parent 0581f8e commit 1581ca2

File tree

1 file changed

+171
-143
lines changed

1 file changed

+171
-143
lines changed

plugins/askrene/askrene.c

+171-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,61 +454,162 @@ 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,
543494
const struct getroutes_info *info)
544495
{
496+
bool localmods_applied = false;
545497
const char *err;
546498
double probability;
547499
struct amount_msat *amounts;
548500
struct route **routes;
501+
struct flow **flows;
549502
struct json_stream *response;
550503

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);
557-
if (err)
558-
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
504+
/* get me the global state structure */
505+
struct askrene *askrene = get_askrene(cmd->plugin);
559506

560-
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);
507+
/* update the gossmap */
508+
if (gossmap_refresh(askrene->gossmap)) {
509+
/* FIXME: gossmap_refresh callbacks to we can update in place */
510+
tal_free(askrene->capacities);
511+
askrene->capacities =
512+
get_capacities(askrene, askrene->plugin, askrene->gossmap);
513+
}
514+
515+
/* build this request structure */
516+
struct route_query *rq = tal(cmd, struct route_query);
517+
rq->cmd = cmd;
518+
rq->plugin = cmd->plugin;
519+
rq->gossmap = askrene->gossmap;
520+
rq->reserved = askrene->reserved;
521+
rq->layers = tal_arr(rq, const struct layer *, 0);
522+
rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
523+
/* FIXME: we still need to do something useful with these */
524+
rq->additional_costs = info->additional_costs;
525+
526+
/* apply selected layers to the localmods */
527+
apply_layers(askrene, rq, localmods, info);
528+
529+
/* Clear scids with reservations, too, so we don't have to look up
530+
* all the time! */
531+
reserves_clear_capacities(askrene->reserved, askrene->gossmap,
532+
rq->capacities);
533+
534+
/* we temporarily apply localmods */
535+
gossmap_apply_localmods(askrene->gossmap, localmods);
536+
localmods_applied = true;
537+
538+
/* localmods can add channels, so we need to allocate biases array
539+
* *afterwards* */
540+
rq->biases =
541+
tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
542+
543+
/* Note any channel biases */
544+
for (size_t i = 0; i < tal_count(rq->layers); i++)
545+
layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
546+
547+
/* checkout the source */
548+
const struct gossmap_node *srcnode =
549+
gossmap_find_node(askrene->gossmap, info->source);
550+
if (!srcnode) {
551+
err = rq_log(tmpctx, rq, LOG_INFORM, "Unknown source node %s",
552+
fmt_node_id(tmpctx, info->source));
553+
goto fail;
554+
}
555+
556+
/* checkout the destination */
557+
const struct gossmap_node *dstnode =
558+
gossmap_find_node(askrene->gossmap, info->dest);
559+
if (!dstnode) {
560+
err = rq_log(tmpctx, rq, LOG_INFORM,
561+
"Unknown destination node %s",
562+
fmt_node_id(tmpctx, info->dest));
563+
goto fail;
564+
}
565+
566+
/* Compute the routes. At this point we might select between multiple
567+
* algorithms. */
568+
struct timemono time_start = time_mono();
569+
err = default_routes(rq, rq, srcnode, dstnode, *info->amount,
570+
/* only one path? = */
571+
have_layer(info->layers, "auto.no_mpp_support"),
572+
*info->maxfee, *info->finalcltv, *info->maxdelay,
573+
&flows, &probability);
574+
struct timerel time_delta = timemono_between(time_mono(), time_start);
575+
576+
/* log the time of computation */
577+
rq_log(tmpctx, rq, LOG_DBG, "get_routes %s %" PRIu64 " ms",
578+
err ? "failed after" : "completed in",
579+
time_to_msec(time_delta));
580+
581+
fail:
582+
/* if we have an error we end the execution here */
583+
if (err) {
584+
/* Safety check, remove localmods only if we applied it. */
585+
if (localmods_applied){
586+
gossmap_remove_localmods(askrene->gossmap, localmods);
587+
localmods_applied = false;
580588
}
581-
json_array_end(response);
582-
json_object_end(response);
589+
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
583590
}
584-
json_array_end(response);
591+
592+
/* otherwise we continue */
593+
assert(tal_count(flows) > 0);
594+
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
595+
tal_count(flows));
596+
597+
/* convert flows to routes */
598+
convert_flows_to_routes(rq, rq, &routes, &amounts, *info->finalcltv,
599+
flows);
600+
assert(tal_count(routes) == tal_count(flows));
601+
assert(tal_count(amounts) == tal_count(flows));
602+
603+
/* At last we remove the localmods from the gossmap. */
604+
if (localmods_applied) {
605+
gossmap_remove_localmods(askrene->gossmap, localmods);
606+
localmods_applied = false;
607+
}
608+
609+
/* output the results */
610+
response = jsonrpc_stream_success(cmd);
611+
json_add_getroutes(response, routes, amounts, probability,
612+
*info->finalcltv);
585613
return command_finished(cmd, response);
586614
}
587615

0 commit comments

Comments
 (0)