From cc9b8b0a19003e494c394501fd2c45795ac46c29 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 7 Jun 2024 09:57:18 +0100 Subject: [PATCH] renepay: bugfix finalized routes Changelog-Fixed: renepay: finalized routes have to be processed and determine the payment status even after the payment goes into the background (no current command active). Not doing so leads to finalized routes getting stuck in the payment internal data structure and their associated HTLCs in the uncertainty network don't get released. Signed-off-by: Lagrang3 --- plugins/renepay/payment.c | 29 +++++++++++++++++++++------ plugins/renepay/payment.h | 12 ++++++++++-- plugins/renepay/routetracker.c | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/plugins/renepay/payment.c b/plugins/renepay/payment.c index fcf85588a..5f36d01df 100644 --- a/plugins/renepay/payment.c +++ b/plugins/renepay/payment.c @@ -265,23 +265,28 @@ struct command *payment_command(struct payment *p) return p->cmd_array[0]; } -struct command_result *payment_success(struct payment *payment, - const struct preimage *preimage TAKES) +void register_payment_success(struct payment *payment, + const struct preimage *preimage TAKES) { assert(payment); assert(preimage); payment->status = PAYMENT_SUCCESS; payment->preimage = tal_free(payment->preimage); - if(taken(preimage)) + if (taken(preimage)) payment->preimage = tal_steal(payment, preimage); else payment->preimage = tal_dup(payment, struct preimage, preimage); +} + +struct command_result *payment_success(struct payment *payment, + const struct preimage *preimage TAKES) +{ + register_payment_success(payment, preimage); return payment_finish(payment); } -struct command_result *payment_fail(struct payment *payment, - enum jsonrpc_errcode code, const char *fmt, - ...) +void register_payment_fail(struct payment *payment, enum jsonrpc_errcode code, + const char *fmt, ...) { payment->status = PAYMENT_FAIL; payment->error_code = code; @@ -291,6 +296,18 @@ struct command_result *payment_fail(struct payment *payment, va_start(args, fmt); payment->error_msg = tal_vfmt(payment, fmt, args); va_end(args); +} + +struct command_result *payment_fail(struct payment *payment, + enum jsonrpc_errcode code, const char *fmt, + ...) +{ + /* can't pass variadic arguments forward, so let's expand them. */ + va_list args; + va_start(args, fmt); + const char *error_msg = tal_vfmt(tmpctx, fmt, args); + va_end(args); + register_payment_fail(payment, code, "%s", error_msg); payment_note(payment, LOG_DBG, "Payment failed: %s", payment->error_msg); diff --git a/plugins/renepay/payment.h b/plugins/renepay/payment.h index 39c41f3fd..2e176f833 100644 --- a/plugins/renepay/payment.h +++ b/plugins/renepay/payment.h @@ -147,11 +147,19 @@ struct command *payment_command(struct payment *p); /* get me the result of this payment, not necessarily a completed payment */ struct json_stream *payment_result(struct payment *p, struct command *cmd); -/* flag the payment as success and write the preimage as proof */ +/* Flag the payment as success and write the preimage as proof. */ +void register_payment_success(struct payment *payment, + const struct preimage *preimage TAKES); +/* Flag the payment as success and write the preimage as proof and end the + * payment execution. */ struct command_result *payment_success(struct payment *payment, const struct preimage *preimage TAKES); -/* flag the payment as failed and write the reason */ +/* Flag the payment as failed and write the reason. */ +void register_payment_fail(struct payment *payment, enum jsonrpc_errcode code, + const char *fmt, ...); +/* Flag the payment as failed and write the reason and end the payment + * execution. */ struct command_result *payment_fail(struct payment *payment, enum jsonrpc_errcode code, const char *fmt, ...); diff --git a/plugins/renepay/routetracker.c b/plugins/renepay/routetracker.c index 8f0f0d9dc..f7fd80416 100644 --- a/plugins/renepay/routetracker.c +++ b/plugins/renepay/routetracker.c @@ -50,7 +50,43 @@ static void routetracker_add_to_final(struct routetracker *routetracker, { tal_arr_expand(&routetracker->finalized_routes, route); tal_steal(routetracker->finalized_routes, route); + + struct payment *payment = + payment_map_get(pay_plugin->payment_map, route->key.payment_hash); + assert(payment); + if (payment->exec_state == INVALID_STATE) { + /* payment is offline, collect results now and set the payment + * state accordingly. */ + assert(payment_commands_empty(payment)); + assert(payment->status == PAYMENT_FAIL || + payment->status == PAYMENT_SUCCESS); + + struct preimage *payment_preimage = NULL; + enum jsonrpc_errcode final_error = LIGHTNINGD; + const char *final_msg = NULL; + + /* Finalized routes must be processed and removed in order to + * free the uncertainty network's HTLCs. */ + payment_collect_results(payment, &payment_preimage, + &final_error, &final_msg); + + if (payment_preimage) { + /* If we have the preimage that means one succeed, we + * inmediately finish the payment. */ + register_payment_success(payment, + take(payment_preimage)); + return; + } + if (final_msg) { + /* We received a sendpay result with a final error + * message, we inmediately finish the payment. */ + register_payment_fail(payment, final_error, "%s", + final_msg); + return; + } + } } + static void route_success_register(struct routetracker *routetracker, struct route *route) {