From aaa1ea6478183566f08f640d6168a28335d7a7e6 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Thu, 14 May 2026 18:00:46 +0100 Subject: [PATCH 1/4] xpay: add traces for payments Produce traces (see common/trace.h) for every payment in order to gather statistics about the duration of a full payment execution. Changelog-None Signed-off-by: Lagrang3 --- plugins/xpay/xpay.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index 277f1a556eaa..5c6bfc5bc9bb 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -1,4 +1,5 @@ #include "config.h" +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -2439,6 +2441,11 @@ static struct payment *new_payment(const tal_t *ctx, { struct xpay *xpay = xpay_of(cmd->plugin); struct payment *payment = tal(ctx, struct payment); + /* Start tracing the payment until it is destroyed. */ + trace_span_start("xpay/payment", payment); + trace_span_tag(payment, "payment_hash", + fmt_sha256(payment, payment_hash)); + trace_span_suspend_may_free(payment); payment->plugin = cmd->plugin; payment->deadline = timemono_add(time_mono(), time_from_sec(retryfor)); From 52957a25fe0ff86855f40bda5a06172ae75117b9 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Wed, 20 May 2026 12:59:37 +0100 Subject: [PATCH 2/4] xpay: added subtrace to measure getroutes Changelog-None Signed-off-by: Lagrang3 --- plugins/xpay/xpay.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index 5c6bfc5bc9bb..16b9b7d079be 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -1606,16 +1606,24 @@ static void add_cltv_shadow(struct payment *payment, } } +/* Just a wrapper around payment so that we can trace the execution time of a + * getroutes request. */ +struct getroutes_request { + struct payment *payment; +}; + static struct command_result *getroutes_done(struct command *aux_cmd, const char *method, const char *buf, const jsmntok_t *result, - struct payment *payment) + struct getroutes_request *getroutes_request) { const jsmntok_t *t, *routes; size_t i; struct amount_msat needs_routing, was_routing; + struct payment *payment = getroutes_request->payment; struct gossmap *gossmap = get_gossmap(xpay_of(payment->plugin)); + tal_free(getroutes_request); payment_log(payment, LOG_DBG, "getroutes_done: %s", payment->cmd ? "continuing" : "ignoring"); @@ -1726,8 +1734,10 @@ static struct command_result *getroutes_done_err(struct command *aux_cmd, const char *method, const char *buf, const jsmntok_t *error, - struct payment *payment) + struct getroutes_request *getroutes_request) { + struct payment *payment = getroutes_request->payment; + tal_free(getroutes_request); int code; const char *msg, *complaint; @@ -1856,10 +1866,17 @@ static struct command_result *getroutes_for(struct command *aux_cmd, maxfee = AMOUNT_MSAT(0); } + struct getroutes_request *getroutes_request = + tal(payment, struct getroutes_request); + getroutes_request->payment = payment; + trace_span_resume(payment); // payment is the parent span + trace_span_start("xpay/getroutes", getroutes_request); + trace_span_suspend_may_free(getroutes_request); + trace_span_suspend(payment); req = jsonrpc_request_start(aux_cmd, "getroutes", getroutes_done, getroutes_done_err, - payment); + getroutes_request); json_add_pubkey(req->js, "source", &xpay->local_id); json_add_pubkey(req->js, "destination", dst); From a1e7021dfd5a1129d04de7c433e9aebc93724a32 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Wed, 20 May 2026 13:46:48 +0100 Subject: [PATCH 3/4] xpay: add sub-trace to measure injectpaymentonion Changelog-None Signed-off-by: Lagrang3 --- plugins/xpay/xpay.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index 16b9b7d079be..fc50f8ec3757 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -1225,6 +1225,8 @@ static struct command_result *injectpaymentonion_failed(struct command *aux_cmd, { struct payment *payment = attempt->payment; struct amount_msat amount = attempt->amount; + trace_span_resume(attempt); + trace_span_end(attempt); payment->num_failures++; @@ -1308,6 +1310,8 @@ static struct command_result *injectpaymentonion_succeeded(struct command *aux_c { struct preimage preimage; struct payment *payment = attempt->payment; + trace_span_resume(attempt); + trace_span_end(attempt); if (!json_to_preimage(buf, json_get_member(buf, result, "payment_preimage"), @@ -1473,6 +1477,12 @@ static struct command_result *do_inject(struct command *aux_cmd, outgoing_notify_start(attempt); attempt->start_time = time_mono(); + trace_span_resume(attempt->payment); // payment is the parent span + trace_span_start("xpay/injectpaymentonion", attempt); + trace_span_tag(attempt, "partid", + tal_fmt(attempt, "%d", (int)(attempt->partid))); + trace_span_suspend(attempt); + trace_span_suspend(attempt->payment); req = jsonrpc_request_start(aux_cmd, "injectpaymentonion", From c07fba9e4d1c6dbd7aadfbb7519db0f1a453b79f Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Thu, 21 May 2026 07:02:00 +0100 Subject: [PATCH 4/4] xpay: add traces to fetchinvoice Changelog-None Signed-off-by: Lagrang3 --- plugins/xpay/xpay.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index fc50f8ec3757..fd23bec62d6c 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -2261,6 +2261,9 @@ invoice_fetched(struct command *cmd, struct xpay_params *params) { const char *inv; + trace_span_resume(params); + trace_span_tag(params, "status", "success"); + trace_span_end(params); inv = json_strdup(tmpctx, buf, json_get_member(buf, result, "invoice")); inv = to_canonical_invstr(NULL, inv); @@ -2271,6 +2274,26 @@ invoice_fetched(struct command *cmd, params->includefees_msat); } +/* A wrapper around the possibility of an invoice fetch failure, just to put a + * trace_span_end. */ +static struct command_result *invoice_fetched_failed(struct command_result *ret, + struct xpay_params *params) +{ + trace_span_resume(params); + trace_span_tag(params, "status", "failed"); + trace_span_end(params); + return ret; +} + +static struct command_result * +invoice_fetched_rpcerror(struct command *cmd, const char *method, + const char *buf, const jsmntok_t *error, + struct xpay_params *params) +{ + return invoice_fetched_failed( + forward_error(cmd, method, buf, error, params), params); +} + static struct command_result * do_fetchinvoice(struct command *cmd, const char *offerstr, struct xpay_params *xparams) { @@ -2278,7 +2301,7 @@ do_fetchinvoice(struct command *cmd, const char *offerstr, struct xpay_params *x req = jsonrpc_request_start(cmd, "fetchinvoice", invoice_fetched, - forward_error, + invoice_fetched_rpcerror, xparams); json_add_string(req->js, "offer", offerstr); if (xparams->msat) @@ -2310,11 +2333,13 @@ bip353_fetched(struct command *cmd, break; } - if (!offertok) - return command_fail(cmd, PAY_UNSPECIFIED_ERROR, + if (!offertok) { + ret = command_fail(cmd, PAY_UNSPECIFIED_ERROR, "BIP353 response did not contain an offer (%.*s)", json_tok_full_len(result), json_tok_full(buf, result)); + goto failed; + } offerstr = json_strdup(tmpctx, buf, offertok); if (xparams->includefees_msat) @@ -2323,9 +2348,12 @@ bip353_fetched(struct command *cmd, ret = check_offer_payable(cmd, offerstr, xparams->msat); if (ret) - return ret; + goto failed; return do_fetchinvoice(cmd, offerstr, xparams); + +failed: + return invoice_fetched_failed(ret, xparams); } static struct command_result *json_xpay_params(struct command *cmd, @@ -2380,6 +2408,8 @@ static struct command_result *json_xpay_params(struct command *cmd, return command_check_done(cmd); xparams = tal(cmd, struct xpay_params); + trace_span_start("xpay/fetchinvoice", xparams); + trace_span_suspend(xparams); xparams->msat = msat; xparams->maxfee = maxfee; xparams->partial = partial; @@ -2408,6 +2438,8 @@ static struct command_result *json_xpay_params(struct command *cmd, return command_check_done(cmd); xparams = tal(cmd, struct xpay_params); + trace_span_start("xpay/fetchinvoice", xparams); + trace_span_suspend(xparams); xparams->msat = msat; xparams->maxfee = maxfee; xparams->partial = partial; @@ -2421,7 +2453,7 @@ static struct command_result *json_xpay_params(struct command *cmd, req = jsonrpc_request_start(cmd, "fetchbip353", bip353_fetched, - forward_error, xparams); + invoice_fetched_rpcerror, xparams); json_add_string(req->js, "address", invstring); return send_outreq(req); }