askrene: remove non child-friendly fields from struct route_query.

Notably no access to the struct command and struct plugin.

Note: we actually *do* mess with askrene->reserves, but the previous code
used cmd to get to it.  Now we need to include a non-const pointer in
struct route_query.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2026-02-16 17:33:33 +10:30
parent ac9aa975ad
commit 0f575ac85a
7 changed files with 66 additions and 77 deletions

View File

@@ -302,11 +302,12 @@ struct amount_msat get_additional_per_htlc_cost(const struct route_query *rq,
return AMOUNT_MSAT(0);
}
const char *rq_log(const tal_t *ctx,
const struct route_query *rq,
enum log_level level,
const char *fmt,
...)
PRINTF_FMT(4, 5)
static const char *cmd_log(const tal_t *ctx,
struct command *cmd,
enum log_level level,
const char *fmt,
...)
{
va_list args;
const char *msg;
@@ -315,14 +316,14 @@ const char *rq_log(const tal_t *ctx,
msg = tal_vfmt(ctx, fmt, args);
va_end(args);
plugin_notify_message(rq->cmd, level, "%s", msg);
plugin_notify_message(cmd, level, "%s", msg);
/* Notifications already get logged at debug. Otherwise reduce
* severity. */
if (level != LOG_DBG)
plugin_log(rq->plugin,
plugin_log(cmd->plugin,
level == LOG_BROKEN ? level : level - 1,
"%s: %s", rq->cmd->id, msg);
"%s: %s", cmd->id, msg);
return msg;
}
@@ -364,7 +365,9 @@ struct getroutes_info {
u32 maxparts;
};
static void apply_layers(struct askrene *askrene, struct route_query *rq,
static void apply_layers(struct askrene *askrene,
struct command *cmd,
struct route_query *rq,
const struct node_id *source,
struct amount_msat amount,
struct gossmap_localmods *localmods,
@@ -376,20 +379,19 @@ static void apply_layers(struct askrene *askrene, struct route_query *rq,
const struct layer *l = find_layer(askrene, layers[i]);
if (!l) {
if (streq(layers[i], "auto.localchans")) {
plugin_log(rq->plugin, LOG_DBG, "Adding auto.localchans");
cmd_log(tmpctx, cmd, LOG_DBG, "Adding auto.localchans");
l = local_layer;
} else if (streq(layers[i], "auto.no_mpp_support")) {
plugin_log(rq->plugin, LOG_DBG, "Adding auto.no_mpp_support, sorry");
cmd_log(tmpctx, cmd, LOG_DBG, "Adding auto.no_mpp_support, sorry");
l = remove_small_channel_layer(layers, askrene, amount, localmods);
} else if (streq(layers[i], "auto.include_fees")) {
plugin_log(rq->plugin, LOG_DBG,
"Adding auto.include_fees");
cmd_log(tmpctx, cmd, LOG_DBG, "Adding auto.include_fees");
/* This layer takes effect when converting flows
* into routes. */
continue;
} else {
assert(streq(layers[i], "auto.sourcefree"));
plugin_log(rq->plugin, LOG_DBG, "Adding auto.sourcefree");
cmd_log(tmpctx, cmd, LOG_DBG, "Adding auto.sourcefree");
l = source_free_layer(layers, askrene, source, localmods);
}
}
@@ -440,7 +442,8 @@ void get_constraints(const struct route_query *rq,
reserve_sub(rq->reserved, &scidd, rq->layers, max);
}
static void process_child_logs(struct route_query *rq, int log_fd)
static void process_child_logs(struct command *cmd,
int log_fd)
{
u8 *msg;
while ((msg = wire_sync_read(tmpctx, log_fd)) != NULL) {
@@ -448,7 +451,7 @@ static void process_child_logs(struct route_query *rq, int log_fd)
char *entry;
struct node_id *peer;
if (fromwire_status_log(tmpctx, msg, &level, &peer, &entry))
rq_log(tmpctx, rq, level, "%s", entry);
cmd_log(tmpctx, cmd, level, "%s", entry);
}
}
@@ -463,6 +466,7 @@ static struct command_result *do_getroutes(struct command *cmd,
const char *err, *json;
struct timemono time_start, deadline;
int child_fd, log_fd, child_pid, child_status;
s8 *biases;
/* update the gossmap */
if (gossmap_refresh(askrene->gossmap)) {
@@ -473,15 +477,13 @@ static struct command_result *do_getroutes(struct command *cmd,
}
/* build this request structure */
rq->cmd = cmd;
rq->plugin = cmd->plugin;
rq->cmd_id = cmd->id;
rq->gossmap = askrene->gossmap;
rq->reserved = askrene->reserved;
rq->layers = tal_arr(rq, const struct layer *, 0);
rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
/* FIXME: we still need to do something useful with these */
rq->additional_costs = info->additional_costs;
rq->maxparts = info->maxparts;
/* We also eliminate any local channels we *know* are dying.
* Most channels get 12 blocks grace in case it's a splice,
@@ -508,7 +510,7 @@ static struct command_result *do_getroutes(struct command *cmd,
}
/* apply selected layers to the localmods */
apply_layers(askrene, rq, &info->source, info->amount, localmods,
apply_layers(askrene, cmd, rq, &info->source, info->amount, localmods,
info->layers, info->local_layer);
/* Clear scids with reservations, too, so we don't have to look up
@@ -528,18 +530,19 @@ static struct command_result *do_getroutes(struct command *cmd,
/* localmods can add channels, so we need to allocate biases array
* *afterwards* */
rq->biases =
rq->biases = biases =
tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
/* Note any channel biases */
for (size_t i = 0; i < tal_count(rq->layers); i++)
layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
layer_apply_biases(rq->layers[i], askrene->gossmap, biases);
/* checkout the source */
const struct gossmap_node *srcnode =
gossmap_find_node(askrene->gossmap, &info->source);
if (!srcnode) {
err = rq_log(tmpctx, rq, LOG_INFORM, "Unknown source node %s",
err = cmd_log(tmpctx, cmd, LOG_INFORM,
"Unknown source node %s",
fmt_node_id(tmpctx, &info->source));
goto fail;
}
@@ -548,7 +551,7 @@ static struct command_result *do_getroutes(struct command *cmd,
const struct gossmap_node *dstnode =
gossmap_find_node(askrene->gossmap, &info->dest);
if (!dstnode) {
err = rq_log(tmpctx, rq, LOG_INFORM,
err = cmd_log(tmpctx, cmd, LOG_INFORM,
"Unknown destination node %s",
fmt_node_id(tmpctx, &info->dest));
goto fail;
@@ -558,14 +561,14 @@ static struct command_result *do_getroutes(struct command *cmd,
if (have_layer(info->layers, "auto.no_mpp_support") &&
info->dev_algo != ALGO_SINGLE_PATH) {
info->dev_algo = ALGO_SINGLE_PATH;
rq_log(tmpctx, rq, LOG_DBG,
cmd_log(tmpctx, cmd, LOG_DBG,
"Layer no_mpp_support is active we switch to a "
"single path algorithm.");
}
if (rq->maxparts == 1 &&
if (info->maxparts == 1 &&
info->dev_algo != ALGO_SINGLE_PATH) {
info->dev_algo = ALGO_SINGLE_PATH;
rq_log(tmpctx, rq, LOG_DBG,
cmd_log(tmpctx, cmd, LOG_DBG,
"maxparts == 1: switching to a single path algorithm.");
}
@@ -576,7 +579,7 @@ static struct command_result *do_getroutes(struct command *cmd,
time_from_sec(askrene->route_seconds));
child_fd = fork_router_child(rq, info->dev_algo == ALGO_SINGLE_PATH,
deadline, srcnode, dstnode, info->amount,
info->maxfee, info->finalcltv, info->maxdelay,
info->maxfee, info->finalcltv, info->maxdelay, info->maxparts,
include_fees,
cmd->id, cmd->filter, &log_fd, &child_pid);
if (child_fd == -1) {
@@ -585,7 +588,7 @@ static struct command_result *do_getroutes(struct command *cmd,
}
/* FIXME: Go async! */
process_child_logs(rq, log_fd);
process_child_logs(cmd, log_fd);
close(log_fd);
json = grab_fd_str(cmd, child_fd);
close(child_fd);
@@ -594,9 +597,9 @@ static struct command_result *do_getroutes(struct command *cmd,
struct timerel time_delta = timemono_between(time_mono(), time_start);
/* log the time of computation */
rq_log(tmpctx, rq, LOG_DBG, "get_routes %s %" PRIu64 " ms",
WEXITSTATUS(child_status) != 0 ? "failed after" : "completed in",
time_to_msec(time_delta));
cmd_log(tmpctx, cmd, LOG_DBG, "get_routes %s %" PRIu64 " ms",
WEXITSTATUS(child_status) != 0 ? "failed after" : "completed in",
time_to_msec(time_delta));
if (WIFSIGNALED(child_status)) {
err = tal_fmt(tmpctx, "child died with signal %u",

View File

@@ -32,35 +32,30 @@ struct askrene {
/* Information for a single route query. */
struct route_query {
/* Command pointer, mainly for command id. */
struct command *cmd;
/* Plugin pointer, for logging mainly */
struct plugin *plugin;
/* This is *not* updated during a query! Has all layers applied. */
const struct gossmap *gossmap;
/* We need to take in-flight payments into account */
const struct reserve_htable *reserved;
/* command id to use for reservations we create. */
const char *cmd_id;
/* Array of layers we're applying */
const struct layer **layers;
/* Cache of channel capacities for non-reserved, unknown channels. */
fp16_t *capacities;
/* Compact cache of biases */
s8 *biases;
const s8 *biases;
/* Additional per-htlc cost for local channels */
const struct additional_cost_htable *additional_costs;
/* We need to take in-flight payments into account (this is
* askrene->reserved, so make sure to undo changes! */
struct reserve_htable *reserved;
/* Cache of channel capacities for non-reserved, unknown channels. */
fp16_t *capacities;
/* channels we disable during computation to meet constraints */
bitmap *disabled_chans;
/* limit the number of paths in the solution */
u32 maxparts;
};
/* Given a gossmap channel, get the current known min/max */
@@ -70,14 +65,6 @@ void get_constraints(const struct route_query *rq,
struct amount_msat *min,
struct amount_msat *max);
/* Say something about this route_query */
const char *rq_log(const tal_t *ctx,
const struct route_query *rq,
enum log_level level,
const char *fmt,
...)
PRINTF_FMT(4, 5);
/* Is there a known additional per-htlc cost for this channel? */
struct amount_msat get_additional_per_htlc_cost(const struct route_query *rq,
const struct short_channel_id_dir *scidd);

View File

@@ -78,8 +78,7 @@ static struct route **convert_flows_to_routes(const tal_t *ctx,
if (!amount_msat_add_fee(&msat, h->base_fee,
h->proportional_fee))
plugin_err(rq->plugin,
"Adding fee to amount");
abort();
delay += h->delay;
rh->scid = gossmap_chan_scid(rq->gossmap,
@@ -178,7 +177,7 @@ int fork_router_child(struct route_query *rq,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode,
struct amount_msat amount, struct amount_msat maxfee,
u32 finalcltv, u32 maxdelay,
u32 finalcltv, u32 maxdelay, size_t maxparts,
bool include_fees,
const char *cmd_id,
struct json_filter *cmd_filter,
@@ -226,7 +225,7 @@ int fork_router_child(struct route_query *rq,
} else {
err = default_routes(rq, rq, deadline, srcnode, dstnode,
amount, maxfee, finalcltv, maxdelay,
&flows, &probability);
maxparts, &flows, &probability);
}
if (err) {
write_all(replyfds[1], err, strlen(err));

View File

@@ -17,7 +17,7 @@ int fork_router_child(struct route_query *rq,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode,
struct amount_msat amount, struct amount_msat maxfee,
u32 finalcltv, u32 maxdelay,
u32 finalcltv, u32 maxdelay, size_t maxparts,
bool include_fees,
const char *cmd_id,
struct json_filter *cmd_filter,

View File

@@ -1341,6 +1341,7 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode, struct amount_msat amount,
struct amount_msat maxfee, u32 finalcltv, u32 maxdelay,
size_t maxparts,
struct flow ***flows, double *probability,
struct flow **(*solver)(const tal_t *, const struct route_query *,
const struct gossmap_node *,
@@ -1551,10 +1552,10 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
/* If we're over the number of parts, try to cram excess into the
* largest-capacity parts */
if (tal_count(*flows) > rq->maxparts) {
if (tal_count(*flows) > maxparts) {
struct amount_msat fee;
error_message = reduce_num_flows(rq, rq, flows, amount, rq->maxparts);
error_message = reduce_num_flows(rq, rq, flows, amount, maxparts);
if (error_message) {
*flows = tal_free(*flows);
return error_message;
@@ -1594,14 +1595,13 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
return child_log(rq, LOG_BROKEN,
"%s: check_htlc_max_limits failed", __func__);
}
if (tal_count(*flows) > rq->maxparts) {
if (tal_count(*flows) > maxparts) {
size_t num_flows = tal_count(*flows);
*flows = tal_free(*flows);
return child_log(rq, LOG_BROKEN,
"%s: the number of flows (%zu) exceeds the limit set "
"on payment parts (%" PRIu32
"), please submit a bug report",
__func__, num_flows, rq->maxparts);
"on payment parts (%zu), please submit a bug report",
__func__, num_flows, maxparts);
}
return NULL;
@@ -1618,11 +1618,12 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *srcnode,
const struct gossmap_node *dstnode,
struct amount_msat amount, struct amount_msat maxfee,
u32 finalcltv, u32 maxdelay, struct flow ***flows,
u32 finalcltv, u32 maxdelay, size_t maxparts,
struct flow ***flows,
double *probability)
{
return linear_routes(ctx, rq, deadline, srcnode, dstnode, amount, maxfee,
finalcltv, maxdelay, flows, probability, minflow);
finalcltv, maxdelay, maxparts, flows, probability, minflow);
}
const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
@@ -1635,6 +1636,6 @@ const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
double *probability)
{
return linear_routes(ctx, rq, deadline, srcnode, dstnode, amount, maxfee,
finalcltv, maxdelay, flows, probability,
finalcltv, maxdelay, 1, flows, probability,
single_path_flow);
}

View File

@@ -17,7 +17,7 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
const struct gossmap_node *dstnode,
struct amount_msat amount,
struct amount_msat maxfee, u32 finalcltv,
u32 maxdelay, struct flow ***flows,
u32 maxdelay, size_t maxparts, struct flow ***flows,
double *probability);
/* A wrapper to the single-path constrained solver. */

View File

@@ -24,10 +24,10 @@ static void get_scidd(const struct gossmap *gossmap,
scidd->dir = flow->dirs[i];
}
static void destroy_reservations(struct reserve_hop *rhops, struct askrene *askrene)
static void destroy_reservations(struct reserve_hop *rhops, struct reserve_htable *reserved)
{
for (size_t i = 0; i < tal_count(rhops); i++)
reserve_remove(askrene->reserved, &rhops[i]);
reserve_remove(reserved, &rhops[i]);
}
struct reserve_hop *new_reservations(const tal_t *ctx,
@@ -36,7 +36,7 @@ struct reserve_hop *new_reservations(const tal_t *ctx,
struct reserve_hop *rhops = tal_arr(ctx, struct reserve_hop, 0);
/* Unreserve on free */
tal_add_destructor2(rhops, destroy_reservations, get_askrene(rq->plugin));
tal_add_destructor2(rhops, destroy_reservations, rq->reserved);
return rhops;
}
@@ -59,16 +59,15 @@ static void add_reservation(struct reserve_hop **reservations,
struct amount_msat amt)
{
struct reserve_hop rhop, *prev;
struct askrene *askrene = get_askrene(rq->plugin);
size_t idx;
/* Update in-place if possible */
prev = find_reservation(*reservations, scidd);
if (prev) {
reserve_remove(askrene->reserved, prev);
reserve_remove(rq->reserved, prev);
if (!amount_msat_accumulate(&prev->amount, amt))
abort();
reserve_add(askrene->reserved, prev, rq->cmd->id);
reserve_add(rq->reserved, prev, rq->cmd_id);
return;
}
rhop.scidd = *scidd;
@@ -76,7 +75,7 @@ static void add_reservation(struct reserve_hop **reservations,
/* We don't have to restrict it to a layer, since it's transitory:
* nobody else will see this. */
rhop.layer = NULL;
reserve_add(askrene->reserved, &rhop, rq->cmd->id);
reserve_add(rq->reserved, &rhop, rq->cmd_id);
/* Set capacities entry to 0 so it get_constraints() looks in reserve. */
idx = gossmap_chan_idx(rq->gossmap, chan);