xpay: age layer before payment instead on timer
What changed, and why it matters
This change adjusts when the xpay plugin cleans up old routing data. Previously, cleanup ran on a 60-second timer, which could fail during shutdown and cause test flakiness. Now cleanup happens right before each payment is routed. The patch is a reliability improvement, not a security fix, and does not introduce obvious new attack paths.
No security action required. Treat as a normal reliability/refactoring change. Reviewers may want to confirm that `age_layer` is always invoked before routing and that `dev_no_age` still correctly skips aging in developer mode.
Security signals we found
No security-relevant keywords in commit title or message
Change is described as reducing test flakiness, not fixing a vulnerability
No input validation changes, no memory safety changes, no authentication/authorization changes
Removes a periodic timer and replaces it with a synchronous pre-payment call
No CVE, advisory, or vendor security disclosure referenced
Evidence from the diff
The commit removes the periodic timer-based invocation of askrene-age in the xpay plugin and instead calls it synchronously before getroutes during payment flow (preapprove_succeed -> age_layer -> populate_private_layer). It also removes start_aging_timer and the age_done timer completion callback. The mathematical justification given is that aging is idempotent over time: age(t1) * age(t2) * ... * age(tN) = age(tN). The change is framed as reducing flakiness during lightningd shutdown.
Changed components
plugins/xpay/xpay.cxpay pluginaskrene-age RPC interactionInspect captured patch +19 / −23
diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c
index d7a0649d..7cf2c206 100644
--- a/plugins/xpay/xpay.c
+++ b/plugins/xpay/xpay.c
@@ -2132,6 +2132,8 @@ static struct command_result *populate_private_layer(struct command *cmd,
return batch_done(aux_cmd, batch);
}
+static struct command_result *age_layer(struct command *cmd, struct payment *payment);
+
static struct command_result *
preapprove_succeed(struct command *cmd, const char *method, const char *buf,
const jsmntok_t *result, struct payment *payment)
@@ -2141,7 +2143,7 @@ preapprove_succeed(struct command *cmd, const char *method, const char *buf,
return command_check_done(cmd);
}
- return populate_private_layer(cmd, payment);
+ return age_layer(cmd, payment);
}
static struct command_result *check_offer_payable(struct command *cmd,
@@ -2937,47 +2939,41 @@ static struct command_result *getinfo_done(struct command *aux_cmd,
return aux_command_done(aux_cmd);
}
-/* Recursion */
-static void start_aging_timer(struct plugin *plugin);
+static struct command_result *populate_private_layer(struct command *cmd,
+ struct payment *payment);
-static struct command_result *age_done(struct command *timer_cmd,
- const char *method,
- const char *buf,
- const jsmntok_t *result,
- void *unused)
+static struct command_result *age_done(struct command *cmd,
+ const char *method UNUSED,
+ const char *buf UNUSED,
+ const jsmntok_t *result UNUSED,
+ struct payment *payment)
{
- start_aging_timer(timer_cmd->plugin);
- return timer_complete(timer_cmd);
+ return populate_private_layer(cmd, payment);
}
-static struct command_result *age_layer(struct command *timer_cmd, void *unused)
+static struct command_result *age_layer(struct command *cmd, struct payment *payment)
{
+ struct xpay *xpay = xpay_of(cmd->plugin);
+
+ if (xpay->dev_no_age)
+ return populate_private_layer(cmd, payment);
+
struct out_req *req;
- req = jsonrpc_request_start(timer_cmd, "askrene-age",
+ req = jsonrpc_request_start(cmd, "askrene-age",
age_done,
plugin_broken_cb,
- NULL);
+ payment);
json_add_string(req->js, "layer", "xpay");
json_add_u64(req->js, "cutoff", clock_time().ts.tv_sec - 3600);
return send_outreq(req);
}
-static void start_aging_timer(struct plugin *plugin)
-{
- struct xpay *xpay = xpay_of(plugin);
-
- if (xpay->dev_no_age)
- return;
- notleak(global_timer(plugin, time_from_sec(60), age_layer, NULL));
-}
-
static struct command_result *xpay_layer_created(struct command *aux_cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
void *unused)
{
- start_aging_timer(aux_cmd->plugin);
return aux_command_done(aux_cmd);
}
Why this scored 18/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.