askrene: all remove_small_channel_layer when maxparts=1.
What changed, and why it matters
This change adjusts how the Core Lightning routing plugin (askrene) decides to ignore very small payment channels. Previously it only removed small channels when the payer did not support multi-part payments. Now it also does so when the caller explicitly requests a single payment part (maxparts=1). The effect is to make single-part route searches faster and more reliable, but it could also change which routes are chosen or whether any route is found at all.
Review whether removing small channels for maxparts=1 can cause route failure or fee/liquidity disclosure changes that affect privacy or liveness. Treat as a normal code review item; no immediate security patch is indicated by the diff alone.
Security signals we found
Routing behavior change in payment pathfinding
Single-part payment path selection altered
No explicit bounds check or input validation added
Evidence from the diff
The patch refactors askrene.c so that the ‘auto.no_mpp_support’ layer is no longer added inside apply_layers(). Instead, apply_layers() skips that layer, and the caller (do_getroutes()) adds a remove_small_channel_layer after all other layers whenever either ‘auto.no_mpp_support’ is present or info->maxparts == 1. A helper add_layer() is introduced to avoid duplicating localmods/capacity handling. The functional change is extending the small-channel pruning behavior to the maxparts=1 case.
Changed components
plugins/askrene/askrene.cgetroutes / do_getroutes pathremove_small_channel_layermaxparts routing logicInspect captured patch +28 / −11
diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c
index 54219e5e..5b087cca 100644
--- a/plugins/askrene/askrene.c
+++ b/plugins/askrene/askrene.c
@@ -355,12 +355,26 @@ struct getroutes_info {
u32 maxparts;
};
+static void add_layer(const struct layer ***layers,
+ const struct layer *l,
+ const struct gossmap *gossmap,
+ struct gossmap_localmods *localmods,
+ fp16_t *capacities)
+{
+ tal_arr_expand(layers, l);
+ /* FIXME: Implement localmods_merge, and cache this in layer? */
+ layer_add_localmods(l, gossmap, localmods);
+
+ /* Clear any entries in capacities array if we
+ * override them (incl local channels) */
+ layer_clear_overridden_capacities(l, gossmap, capacities);
+}
+
/* Gather layers, clear capacities where layers contains info */
static const struct layer **apply_layers(const tal_t *ctx,
struct askrene *askrene,
struct command *cmd,
const struct node_id *source,
- struct amount_msat amount,
struct gossmap_localmods *localmods,
const char **layernames,
const struct layer *local_layer,
@@ -376,7 +390,8 @@ static const struct layer **apply_layers(const tal_t *ctx,
l = local_layer;
} else if (streq(layernames[i], "auto.no_mpp_support")) {
cmd_log(tmpctx, cmd, LOG_DBG, "Adding auto.no_mpp_support, sorry");
- l = remove_small_channel_layer(layernames, askrene, amount, localmods);
+ /* We will add a layer later, in the caller. */
+ continue;
} else if (streq(layernames[i], "auto.include_fees")) {
cmd_log(tmpctx, cmd, LOG_DBG, "Adding auto.include_fees");
/* This layer takes effect when converting flows
@@ -388,14 +403,7 @@ static const struct layer **apply_layers(const tal_t *ctx,
l = source_free_layer(layernames, askrene, source, localmods);
}
}
-
- tal_arr_expand(&layers, l);
- /* FIXME: Implement localmods_merge, and cache this in layer? */
- layer_add_localmods(l, askrene->gossmap, localmods);
-
- /* Clear any entries in capacities array if we
- * override them (incl local channels) */
- layer_clear_overridden_capacities(l, askrene->gossmap, capacities);
+ add_layer(&layers, l, askrene->gossmap, localmods, capacities);
}
return layers;
}
@@ -566,9 +574,18 @@ static struct command_result *do_getroutes(struct command *cmd,
/* apply selected layers to the localmods */
layers = apply_layers(cmd, askrene, cmd,
- &info->source, info->amount, localmods,
+ &info->source, localmods,
info->layers, info->local_layer, capacities);
+
+ /* no parallel payments means we can drop any smaller channels */
+ if (have_layer(info->layers, "auto.no_mpp_support") || info->maxparts == 1) {
+ add_layer(&layers,
+ remove_small_channel_layer(layers, askrene, info->amount, localmods),
+ askrene->gossmap,
+ localmods, capacities);
+ }
+
/* Clear scids with reservations, too, so we don't have to look up
* all the time! */
reserves_clear_capacities(askrene->reserved, askrene->gossmap,
Why this scored 26/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.