Skip to content

Commit 9eeb1db

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 cf9bb86 commit 9eeb1db

File tree

1 file changed

+174
-145
lines changed

1 file changed

+174
-145
lines changed

plugins/askrene/askrene.c

+174-145
Original file line numberDiff line numberDiff line change
@@ -347,60 +347,35 @@ static struct amount_msat linear_flows_cost(struct flow **flows,
347347
return total;
348348
}
349349

350-
/* Returns an error message, or sets *routes */
351-
static const char *get_routes(const tal_t *ctx,
352-
struct command *cmd,
353-
const struct node_id *source,
354-
const struct node_id *dest,
355-
struct amount_msat amount,
356-
struct amount_msat maxfee,
357-
u32 finalcltv,
358-
u32 maxdelay,
359-
const char **layers,
360-
struct gossmap_localmods *localmods,
361-
const struct layer *local_layer,
362-
bool single_path,
363-
struct route ***routes,
364-
struct amount_msat **amounts,
365-
const struct additional_cost_htable *additional_costs,
366-
double *probability)
367-
{
368-
struct askrene *askrene = get_askrene(cmd->plugin);
369-
struct route_query *rq = tal(ctx, struct route_query);
370-
struct flow **flows;
371-
const struct gossmap_node *srcnode, *dstnode;
372-
const char *ret;
373-
struct timerel time_delta;
374-
struct timemono time_start = time_mono();
375-
376-
if (gossmap_refresh(askrene->gossmap)) {
377-
/* FIXME: gossmap_refresh callbacks to we can update in place */
378-
tal_free(askrene->capacities);
379-
askrene->capacities = get_capacities(askrene, askrene->plugin, askrene->gossmap);
380-
}
381-
382-
rq->cmd = cmd;
383-
rq->plugin = cmd->plugin;
384-
rq->gossmap = askrene->gossmap;
385-
rq->reserved = askrene->reserved;
386-
rq->layers = tal_arr(rq, const struct layer *, 0);
387-
rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
388-
rq->additional_costs = additional_costs;
350+
struct getroutes_info {
351+
struct command *cmd;
352+
struct node_id *source, *dest;
353+
struct amount_msat *amount, *maxfee;
354+
u32 *finalcltv, *maxdelay;
355+
const char **layers;
356+
struct additional_cost_htable *additional_costs;
357+
/* Non-NULL if we are told to use "auto.localchans" */
358+
struct layer *local_layer;
359+
};
389360

361+
static void apply_layers(struct askrene *askrene, struct route_query *rq,
362+
struct gossmap_localmods *localmods,
363+
const struct getroutes_info *info)
364+
{
390365
/* Layers must exist, but might be special ones! */
391-
for (size_t i = 0; i < tal_count(layers); i++) {
392-
const struct layer *l = find_layer(askrene, layers[i]);
366+
for (size_t i = 0; i < tal_count(info->layers); i++) {
367+
const struct layer *l = find_layer(askrene, info->layers[i]);
393368
if (!l) {
394-
if (streq(layers[i], "auto.localchans")) {
369+
if (streq(info->layers[i], "auto.localchans")) {
395370
plugin_log(rq->plugin, LOG_DBG, "Adding auto.localchans");
396-
l = local_layer;
397-
} else if (streq(layers[i], "auto.no_mpp_support")) {
371+
l = info->local_layer;
372+
} else if (streq(info->layers[i], "auto.no_mpp_support")) {
398373
plugin_log(rq->plugin, LOG_DBG, "Adding auto.no_mpp_support, sorry");
399-
l = remove_small_channel_layer(layers, askrene, amount, localmods);
374+
l = remove_small_channel_layer(info->layers, askrene, *info->amount, localmods);
400375
} else {
401-
assert(streq(layers[i], "auto.sourcefree"));
376+
assert(streq(info->layers[i], "auto.sourcefree"));
402377
plugin_log(rq->plugin, LOG_DBG, "Adding auto.sourcefree");
403-
l = source_free_layer(layers, askrene, source, localmods);
378+
l = source_free_layer(info->layers, askrene, info->source, localmods);
404379
}
405380
}
406381

@@ -412,46 +387,14 @@ static const char *get_routes(const tal_t *ctx,
412387
* override them (incl local channels) */
413388
layer_clear_overridden_capacities(l, askrene->gossmap, rq->capacities);
414389
}
390+
}
415391

416-
/* Clear scids with reservations, too, so we don't have to look up
417-
* all the time! */
418-
reserves_clear_capacities(askrene->reserved, askrene->gossmap, rq->capacities);
419-
420-
gossmap_apply_localmods(askrene->gossmap, localmods);
421-
422-
/* localmods can add channels, so we need to allocate biases array *afterwards* */
423-
rq->biases = tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
424-
425-
/* Note any channel biases */
426-
for (size_t i = 0; i < tal_count(rq->layers); i++)
427-
layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
428-
429-
srcnode = gossmap_find_node(askrene->gossmap, source);
430-
if (!srcnode) {
431-
ret = rq_log(ctx, rq, LOG_INFORM,
432-
"Unknown source node %s",
433-
fmt_node_id(tmpctx, source));
434-
goto fail;
435-
}
436-
437-
dstnode = gossmap_find_node(askrene->gossmap, dest);
438-
if (!dstnode) {
439-
ret = rq_log(ctx, rq, LOG_INFORM,
440-
"Unknown destination node %s",
441-
fmt_node_id(tmpctx, dest));
442-
goto fail;
443-
}
444-
445-
/* FIXME: single_path should signal a change in algorithm. */
446-
ret = default_routes(rq, rq, srcnode, dstnode, amount, single_path,
447-
maxfee, finalcltv, maxdelay, &flows, probability);
448-
if (ret) {
449-
goto fail;
450-
}
451-
assert(tal_count(flows) > 0);
452-
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
453-
tal_count(flows));
454-
392+
static void convert_flows_to_routes(const tal_t *ctx, struct route_query *rq,
393+
struct route ***routes,
394+
struct amount_msat **amounts,
395+
u32 finalcltv,
396+
struct flow **flows)
397+
{
455398
/* Convert back into routes, with delay and other information fixed */
456399
*routes = tal_arr(ctx, struct route *, tal_count(flows));
457400
*amounts = tal_arr(ctx, struct amount_msat, tal_count(flows));
@@ -485,26 +428,9 @@ static const char *get_routes(const tal_t *ctx,
485428
rh->delay = delay;
486429
}
487430
(*amounts)[i] = flows[i]->delivers;
488-
rq_log(tmpctx, rq, LOG_INFORM, "Flow %zu/%zu: %s",
489-
i, tal_count(flows),
431+
rq_log(tmpctx, rq, LOG_INFORM, "Flow %zu/%zu: %s", i, tal_count(flows),
490432
fmt_route(tmpctx, r, (*amounts)[i], finalcltv));
491433
}
492-
493-
gossmap_remove_localmods(askrene->gossmap, localmods);
494-
time_delta = timemono_between(time_mono(), time_start);
495-
rq_log(tmpctx, rq, LOG_DBG, "get_routes completed in %" PRIu64 " ms",
496-
time_to_msec(time_delta));
497-
return NULL;
498-
499-
/* Explicit failure path keeps the compiler (gcc version 12.3.0 -O3) from
500-
* warning about uninitialized variables in the caller */
501-
fail:
502-
assert(ret != NULL);
503-
gossmap_remove_localmods(askrene->gossmap, localmods);
504-
time_delta = timemono_between(time_mono(), time_start);
505-
rq_log(tmpctx, rq, LOG_DBG, "get_routes failed after %" PRIu64 " ms",
506-
time_to_msec(time_delta));
507-
return ret;
508434
}
509435

510436
void get_constraints(const struct route_query *rq,
@@ -543,61 +469,164 @@ void get_constraints(const struct route_query *rq,
543469
reserve_sub(rq->reserved, &scidd, max);
544470
}
545471

546-
struct getroutes_info {
547-
struct command *cmd;
548-
struct node_id *source, *dest;
549-
struct amount_msat *amount, *maxfee;
550-
u32 *finalcltv, *maxdelay;
551-
const char **layers;
552-
struct additional_cost_htable *additional_costs;
553-
/* Non-NULL if we are told to use "auto.localchans" */
554-
struct layer *local_layer;
555-
};
472+
static void json_add_getroutes(
473+
struct json_stream *js,
474+
struct route **routes,
475+
/* FIXME: can't we deduce these amounts from the routes themselves */
476+
struct amount_msat *amounts,
477+
double probability,
478+
/* FIXME: can't we have different final_cltv for every route? */
479+
u32 final_cltv)
480+
{
481+
json_add_u64(js, "probability_ppm", (u64)(probability * 1000000));
482+
json_array_start(js, "routes");
483+
for (size_t i = 0; i < tal_count(routes); i++) {
484+
json_object_start(js, NULL);
485+
json_add_u64(js, "probability_ppm",
486+
(u64)(routes[i]->success_prob * 1000000));
487+
json_add_amount_msat(js, "amount_msat", amounts[i]);
488+
json_add_u32(js, "final_cltv", final_cltv);
489+
json_array_start(js, "path");
490+
for (size_t j = 0; j < tal_count(routes[i]->hops); j++) {
491+
struct short_channel_id_dir scidd;
492+
const struct route_hop *r = &routes[i]->hops[j];
493+
json_object_start(js, NULL);
494+
scidd.scid = r->scid;
495+
scidd.dir = r->direction;
496+
json_add_short_channel_id_dir(
497+
js, "short_channel_id_dir", scidd);
498+
json_add_node_id(js, "next_node_id", &r->node_id);
499+
json_add_amount_msat(js, "amount_msat", r->amount);
500+
json_add_u32(js, "delay", r->delay);
501+
json_object_end(js);
502+
}
503+
json_array_end(js);
504+
json_object_end(js);
505+
}
506+
json_array_end(js);
507+
}
556508

557509
static struct command_result *do_getroutes(struct command *cmd,
558510
struct gossmap_localmods *localmods,
559511
const struct getroutes_info *info)
560512
{
513+
bool localmods_applied = false;
561514
const char *err;
562515
double probability;
563516
struct amount_msat *amounts;
564517
struct route **routes;
518+
struct flow **flows;
565519
struct json_stream *response;
566520

567-
err = get_routes(cmd, cmd,
568-
info->source, info->dest,
569-
*info->amount, *info->maxfee, *info->finalcltv,
570-
*info->maxdelay, info->layers, localmods, info->local_layer,
571-
have_layer(info->layers, "auto.no_mpp_support"),
572-
&routes, &amounts, info->additional_costs, &probability);
573-
if (err)
574-
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
521+
/* get me the global state structure */
522+
struct askrene *askrene = get_askrene(cmd->plugin);
575523

576-
response = jsonrpc_stream_success(cmd);
577-
json_add_u64(response, "probability_ppm", (u64)(probability * 1000000));
578-
json_array_start(response, "routes");
579-
for (size_t i = 0; i < tal_count(routes); i++) {
580-
json_object_start(response, NULL);
581-
json_add_u64(response, "probability_ppm", (u64)(routes[i]->success_prob * 1000000));
582-
json_add_amount_msat(response, "amount_msat", amounts[i]);
583-
json_add_u32(response, "final_cltv", *info->finalcltv);
584-
json_array_start(response, "path");
585-
for (size_t j = 0; j < tal_count(routes[i]->hops); j++) {
586-
struct short_channel_id_dir scidd;
587-
const struct route_hop *r = &routes[i]->hops[j];
588-
json_object_start(response, NULL);
589-
scidd.scid = r->scid;
590-
scidd.dir = r->direction;
591-
json_add_short_channel_id_dir(response, "short_channel_id_dir", scidd);
592-
json_add_node_id(response, "next_node_id", &r->node_id);
593-
json_add_amount_msat(response, "amount_msat", r->amount);
594-
json_add_u32(response, "delay", r->delay);
595-
json_object_end(response);
524+
/* update the gossmap */
525+
if (gossmap_refresh(askrene->gossmap)) {
526+
/* FIXME: gossmap_refresh callbacks to we can update in place */
527+
tal_free(askrene->capacities);
528+
askrene->capacities =
529+
get_capacities(askrene, askrene->plugin, askrene->gossmap);
530+
}
531+
532+
/* build this request structure */
533+
struct route_query *rq = tal(cmd, struct route_query);
534+
rq->cmd = cmd;
535+
rq->plugin = cmd->plugin;
536+
rq->gossmap = askrene->gossmap;
537+
rq->reserved = askrene->reserved;
538+
rq->layers = tal_arr(rq, const struct layer *, 0);
539+
rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
540+
/* FIXME: we still need to do something useful with these */
541+
rq->additional_costs = info->additional_costs;
542+
543+
/* apply selected layers to the localmods */
544+
apply_layers(askrene, rq, localmods, info);
545+
546+
/* Clear scids with reservations, too, so we don't have to look up
547+
* all the time! */
548+
reserves_clear_capacities(askrene->reserved, askrene->gossmap,
549+
rq->capacities);
550+
551+
/* we temporarily apply localmods */
552+
gossmap_apply_localmods(askrene->gossmap, localmods);
553+
localmods_applied = true;
554+
555+
/* localmods can add channels, so we need to allocate biases array
556+
* *afterwards* */
557+
rq->biases =
558+
tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
559+
560+
/* Note any channel biases */
561+
for (size_t i = 0; i < tal_count(rq->layers); i++)
562+
layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
563+
564+
/* checkout the source */
565+
const struct gossmap_node *srcnode =
566+
gossmap_find_node(askrene->gossmap, info->source);
567+
if (!srcnode) {
568+
err = rq_log(tmpctx, rq, LOG_INFORM, "Unknown source node %s",
569+
fmt_node_id(tmpctx, info->source));
570+
goto fail;
571+
}
572+
573+
/* checkout the destination */
574+
const struct gossmap_node *dstnode =
575+
gossmap_find_node(askrene->gossmap, info->dest);
576+
if (!dstnode) {
577+
err = rq_log(tmpctx, rq, LOG_INFORM,
578+
"Unknown destination node %s",
579+
fmt_node_id(tmpctx, info->dest));
580+
goto fail;
581+
}
582+
583+
/* Compute the routes. At this point we might select between multiple
584+
* algorithms. */
585+
struct timemono time_start = time_mono();
586+
err = default_routes(rq, rq, srcnode, dstnode, *info->amount,
587+
/* only one path? = */
588+
have_layer(info->layers, "auto.no_mpp_support"),
589+
*info->maxfee, *info->finalcltv, *info->maxdelay,
590+
&flows, &probability);
591+
struct timerel time_delta = timemono_between(time_mono(), time_start);
592+
593+
/* log the time of computation */
594+
rq_log(tmpctx, rq, LOG_INFORM, "get_routes %s %" PRIu64 " ms",
595+
err ? "failed after" : "completed in",
596+
time_delta_ms(time_delta));
597+
598+
fail:
599+
/* if we have an error we end the execution here */
600+
if (err) {
601+
/* Safety check, remove localmods only if we applied it. */
602+
if (localmods_applied){
603+
gossmap_remove_localmods(askrene->gossmap, localmods);
604+
localmods_applied = false;
596605
}
597-
json_array_end(response);
598-
json_object_end(response);
606+
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
599607
}
600-
json_array_end(response);
608+
609+
/* otherwise we continue */
610+
assert(tal_count(flows) > 0);
611+
rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
612+
tal_count(flows));
613+
614+
/* convert flows to routes */
615+
convert_flows_to_routes(rq, rq, &routes, &amounts, *info->finalcltv,
616+
flows);
617+
assert(tal_count(routes) == tal_count(flows));
618+
assert(tal_count(amounts) == tal_count(flows));
619+
620+
/* At last we remove the localmods from the gossmap. */
621+
if (localmods_applied) {
622+
gossmap_remove_localmods(askrene->gossmap, localmods);
623+
localmods_applied = false;
624+
}
625+
626+
/* output the results */
627+
response = jsonrpc_stream_success(cmd);
628+
json_add_getroutes(response, routes, amounts, probability,
629+
*info->finalcltv);
601630
return command_finished(cmd, response);
602631
}
603632

0 commit comments

Comments
 (0)