From d181ecbeea374f91cd225f3bb0dde0a56a0d2da6 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj Date: Sun, 11 Mar 2018 14:30:34 +0000 Subject: [PATCH] payalgo: Implement retry_for for pay command. --- lightningd/jsonrpc_errors.h | 1 + lightningd/payalgo.c | 48 +++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lightningd/jsonrpc_errors.h b/lightningd/jsonrpc_errors.h index 6ead2d26a..91762399a 100644 --- a/lightningd/jsonrpc_errors.h +++ b/lightningd/jsonrpc_errors.h @@ -21,5 +21,6 @@ #define PAY_INVOICE_EXPIRED 207 #define PAY_NO_SUCH_PAYMENT 208 #define PAY_UNSPECIFIED_ERROR 209 +#define PAY_STOPPED_RETRYING 210 #endif /* !defined (LIGHTNING_LIGHTNINGD_JSONRPC_ERRORS_H) */ diff --git a/lightningd/payalgo.c b/lightningd/payalgo.c index 332e09e5d..6558e7f44 100644 --- a/lightningd/payalgo.c +++ b/lightningd/payalgo.c @@ -149,6 +149,9 @@ struct pay { /* List of failures to pay. */ struct list_head pay_failures; + + /* Whether we are attempting payment or not. */ + bool in_sendpay; }; static struct routing_failure * @@ -237,6 +240,7 @@ static void json_pay_failure(struct pay *pay, switch (r->errorcode) { case PAY_IN_PROGRESS: case PAY_RHASH_ALREADY_USED: + case PAY_STOPPED_RETRYING: json_object_start(data, NULL); json_add_num(data, "getroute_tries", pay->getroute_tries); json_add_num(data, "sendpay_tries", pay->sendpay_tries); @@ -332,6 +336,8 @@ static void json_pay_sendpay_resolve(const struct sendpay_result *r, struct pay *pay = (struct pay *) vpay; char const *why; + pay->in_sendpay = false; + /* If we succeed, hurray */ if (r->succeeded) { log_info(pay->cmd->ld->log, "pay(%p): Success", pay); @@ -486,6 +492,7 @@ static void json_pay_getroute_reply(struct subd *gossip UNUSED, pay->route = tal_dup_arr(pay, struct route_hop, route, tal_count(route), 0); + pay->in_sendpay = true; send_payment(pay->try_parent, pay->cmd->ld, &pay->payment_hash, route, &json_pay_sendpay_resume, pay); @@ -542,16 +549,37 @@ static bool json_pay_try(struct pay *pay) return true; } +static void json_pay_stop_retrying(struct pay *pay) +{ + struct sendpay_result *sr; + sr = tal(pay, struct sendpay_result); + sr->succeeded = false; + if (pay->in_sendpay) { + /* Still in sendpay. Return with PAY_IN_PROGRESS */ + sr->errorcode = PAY_IN_PROGRESS; + sr->details = "Stopped retrying during payment attempt; " + "continue monitoring with " + "pay or listpayments"; + } else { + /* Outside sendpay, no ongoing payment */ + sr->errorcode = PAY_STOPPED_RETRYING; + sr->details = "Stopped retrying, no ongoing payment"; + } + json_pay_failure(pay, sr); +} + static void json_pay(struct command *cmd, const char *buffer, const jsmntok_t *params) { jsmntok_t *bolt11tok, *msatoshitok, *desctok, *riskfactortok, *maxfeetok; + jsmntok_t *retryfortok; double riskfactor = 1.0; double maxfeepercent = 0.5; u64 msatoshi; struct pay *pay = tal(cmd, struct pay); struct bolt11 *b11; char *fail, *b11str, *desc; + unsigned int retryfor = 60; if (!json_get_params(cmd, buffer, params, "bolt11", &bolt11tok, @@ -559,6 +587,7 @@ static void json_pay(struct command *cmd, "?description", &desctok, "?riskfactor", &riskfactortok, "?maxfeepercent", &maxfeetok, + "?retry_for", &retryfortok, NULL)) { return; } @@ -584,6 +613,13 @@ static void json_pay(struct command *cmd, pay->expiry.ts.tv_sec = b11->timestamp + b11->expiry; pay->min_final_cltv_expiry = b11->min_final_cltv_expiry; + if (retryfortok && !json_tok_number(buffer, retryfortok, &retryfor)) { + command_fail(cmd, "'%.*s' is not an integer", + retryfortok->end - retryfortok->start, + buffer + retryfortok->start); + return; + } + if (b11->msatoshi) { msatoshi = *b11->msatoshi; if (msatoshitok) { @@ -650,10 +686,17 @@ static void json_pay(struct command *cmd, pay->route = NULL; /* Start with no failures */ list_head_init(&pay->pay_failures); + pay->in_sendpay = false; /* Initiate payment */ if (json_pay_try(pay)) command_still_pending(cmd); + else + return; + + /* Set up timeout. */ + new_reltimer(&cmd->ld->timers, pay, time_from_sec(retryfor), + &json_pay_stop_retrying, pay); } static const struct json_command pay_command = { @@ -662,7 +705,8 @@ static const struct json_command pay_command = { "Send payment specified by {bolt11} with optional {msatoshi} " "(if and only if {bolt11} does not have amount), " "{description} (required if {bolt11} uses description hash), " - "{riskfactor} (default 1.0), and " - "{maxfeepercent} (default 0.5) the maximum acceptable fee as a percentage (e.g. 0.5 => 0.5%)" + "{riskfactor} (default 1.0), " + "{maxfeepercent} (default 0.5) the maximum acceptable fee as a percentage (e.g. 0.5 => 0.5%), and " + "{retry_for} (default 60) the integer number of seconds before we stop retrying" }; AUTODATA(json_command, &pay_command);