From bb9aacb855bb1a2ca8894be9fdb49d54febf2bd3 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Mon, 15 Jun 2026 07:08:43 +0100 Subject: [PATCH 1/2] xpay: clean preapprove*_succeed functions preapproveinvoice_succeed and preapprovekeysend_succeed do the same thing: acknowledge that preapproval rpc call have succeeded and continue the payment execution via populate_private_layers. Therefore we use a unique function for both cases: preapprove_succeed. Changelog-None. Signed-off-by: Lagrang3 --- plugins/xpay/xpay.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index 277f1a556eaa..d7a0649d9500 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -2133,11 +2133,8 @@ static struct command_result *populate_private_layer(struct command *cmd, } static struct command_result * -preapproveinvoice_succeed(struct command *cmd, - const char *method, - const char *buf, - const jsmntok_t *result, - struct payment *payment) +preapprove_succeed(struct command *cmd, const char *method, const char *buf, + const jsmntok_t *result, struct payment *payment) { /* Now we can conclude `check` command */ if (command_check_only(cmd)) { @@ -2782,12 +2779,12 @@ static struct command_result *xpay_core(struct command *cmd, /* Now preapprove, then start payment. */ if (command_check_only(cmd)) { req = jsonrpc_request_start(cmd, "check", - &preapproveinvoice_succeed, + &preapprove_succeed, &forward_error, payment); json_add_string(req->js, "command_to_check", "preapproveinvoice"); } else { req = jsonrpc_request_start(cmd, "preapproveinvoice", - &preapproveinvoice_succeed, + &preapprove_succeed, &forward_error, payment); } json_add_string(req->js, "bolt11", payment->invstring); @@ -2984,22 +2981,6 @@ static struct command_result *xpay_layer_created(struct command *aux_cmd, return aux_command_done(aux_cmd); } -static struct command_result * -preapprovekeysend_succeed(struct command *cmd, - const char *method, - const char *buf, - const jsmntok_t *result, - struct payment *payment) -{ - /* Now we can conclude `check` command */ - if (command_check_only(cmd)) { - return command_check_done(cmd); - } - - /* Actually we don't need a private layer, but unification is easy. */ - return populate_private_layer(cmd, payment); -} - static struct command_result *json_xkeysend(struct command *cmd, const char *buf, const jsmntok_t *params) @@ -3083,12 +3064,12 @@ static struct command_result *json_xkeysend(struct command *cmd, /* We do pre-approval immediately (note: even if command_check_only!) */ if (command_check_only(cmd)) { req = jsonrpc_request_start(cmd, "check", - preapprovekeysend_succeed, + preapprove_succeed, forward_error, payment); json_add_string(req->js, "command_to_check", "preapprovekeysend"); } else { req = jsonrpc_request_start(cmd, "preapprovekeysend", - preapprovekeysend_succeed, + preapprove_succeed, forward_error, payment); } json_add_pubkey(req->js, "destination", &payment->destination); From d1b7a990fa0121a0efc28bb9da50191aab542ccc Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Mon, 15 Jun 2026 07:20:39 +0100 Subject: [PATCH 2/2] xpay: age layer before payment instead on timer We use to call askrene-age on xpay layer every 60 seconds to remove old entries. But for payments to discard old entries it is enough to call askrene-age before getroutes. True as long as: age(t1) * age(t2) * ... * age(tN) = age(tN) Reduces flakyness caused by xpay failing to call askrene-age during lightningd shutdown. Changelog-None Signed-off-by: Lagrang3 --- plugins/xpay/xpay.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index d7a0649d9500..7cf2c2061ccc 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); }