Browse Source

payalgo: Throttle pay command if failure is due to blockheight disagreement.

ppa-0.6.1
ZmnSCPxj 7 years ago
committed by Christian Decker
parent
commit
1f6008689d
  1. 51
      lightningd/payalgo.c

51
lightningd/payalgo.c

@ -4,6 +4,7 @@
#include <ccan/tal/str/str.h>
#include <ccan/time/time.h>
#include <common/bolt11.h>
#include <common/timeout.h>
#include <common/type_to_string.h>
#include <gossipd/gen_gossip_wire.h>
#include <gossipd/routing.h>
@ -122,14 +123,49 @@ static void json_pay_failure(struct pay *pay,
command_fail_detailed(pay->cmd, r->errorcode, data, "%s", msg);
}
/* Determine if we should delay before retrying. Return a reason
* string, or NULL if we will not retry */
static const char *should_delay_retry(const tal_t *ctx,
const struct sendpay_result *r)
{
/* The routing failures WIRE_EXPIRY_TOO_FAR, WIRE_EXPIRY_TOO_SOON,
* and WIRE_FINAL_EXPIRY_TOO_SOON may arise due to disagreement
* between the peers about what the block heights are. So
* delay for those before retrying. */
if (!r->succeeded && r->errorcode == PAY_TRY_OTHER_ROUTE) {
switch (r->routing_failure->failcode) {
case WIRE_EXPIRY_TOO_FAR:
case WIRE_EXPIRY_TOO_SOON:
case WIRE_FINAL_EXPIRY_TOO_SOON:
return tal_fmt(ctx,
"Possible blockheight disagreement "
"(%s from peer)",
onion_type_name(r->routing_failure->failcode));
default:
/* Do nothing */ ;
}
}
return NULL;
}
/* Start a payment attempt. */
static bool json_pay_try(struct pay *pay);
/* Used when delaying. */
static void do_pay_try(struct pay *pay)
{
log_info(pay->cmd->ld->log, "pay(%p): Try another route", pay);
json_pay_try(pay);
}
/* Call when sendpay returns to us. */
static void json_pay_sendpay_resolve(const struct sendpay_result *r,
void *vpay)
{
struct pay *pay = (struct pay *) vpay;
char const *why;
/* If we succeed, hurray */
if (r->succeeded) {
@ -148,8 +184,19 @@ static void json_pay_sendpay_resolve(const struct sendpay_result *r,
return;
}
log_info(pay->cmd->ld->log, "pay(%p): Try another route", pay);
json_pay_try(pay);
/* Should retry here, question is whether to retry now or later */
why = should_delay_retry(pay->try_parent, r);
if (why) {
log_info(pay->cmd->ld->log,
"pay(%p): Delay before retry: %s", pay, why);
/* Delay for 3 seconds if needed. FIXME: random
* exponential backoff */
new_reltimer(&pay->cmd->ld->timers, pay->try_parent,
time_from_sec(3),
&do_pay_try, pay);
} else
do_pay_try(pay);
}
/* Generates a string describing the route. Route should be a

Loading…
Cancel
Save