Browse Source

paymod: Simplify retry mod logic and add abort logic

paymod-03
Christian Decker 5 years ago
parent
commit
895542c6f1
  1. 79
      plugins/libplugin-pay.c

79
plugins/libplugin-pay.c

@ -937,9 +937,6 @@ static struct retry_mod_data *retry_data_init(struct payment *p);
static inline void retry_step_cb(struct retry_mod_data *rd, static inline void retry_step_cb(struct retry_mod_data *rd,
struct payment *p); struct payment *p);
REGISTER_PAYMENT_MODIFIER(retry, struct retry_mod_data *, retry_data_init,
retry_step_cb);
static struct retry_mod_data * static struct retry_mod_data *
retry_data_init(struct payment *p) retry_data_init(struct payment *p)
{ {
@ -954,18 +951,85 @@ retry_data_init(struct payment *p)
return rdata; return rdata;
} }
/* Determine whether retrying could possibly succeed. Retrying in this case
* means that we repeat the entire flow, including computing a new route, new
* payload and a new sendonion call. It does not mean we retry the exact same
* attempt that just failed. */
static bool payment_can_retry(struct payment *p)
{
struct payment_result *res = p->result;
u32 idx;
bool is_final;
if (p->result == NULL)
return false;
idx = res->erring_index != NULL ? *res->erring_index : 0;
is_final = (idx == tal_count(p->route));
/* Full matrix of failure code x is_final. Prefer to retry once too
* often over eagerly failing. */
switch (res->failcode) {
case WIRE_EXPIRY_TOO_FAR:
case WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS:
case WIRE_INVALID_ONION_PAYLOAD:
case WIRE_INVALID_ONION_VERSION:
case WIRE_INVALID_REALM:
case WIRE_MPP_TIMEOUT:
case WIRE_PERMANENT_NODE_FAILURE:
case WIRE_REQUIRED_NODE_FEATURE_MISSING:
case WIRE_TEMPORARY_NODE_FAILURE:
case WIRE_UNKNOWN_NEXT_PEER:
return !is_final;
case WIRE_AMOUNT_BELOW_MINIMUM:
case WIRE_CHANNEL_DISABLED:
case WIRE_EXPIRY_TOO_SOON:
case WIRE_FEE_INSUFFICIENT:
case WIRE_FINAL_INCORRECT_CLTV_EXPIRY:
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
case WIRE_INCORRECT_CLTV_EXPIRY:
case WIRE_INVALID_ONION_HMAC:
case WIRE_INVALID_ONION_KEY:
case WIRE_PERMANENT_CHANNEL_FAILURE:
case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING:
case WIRE_TEMPORARY_CHANNEL_FAILURE:
#if EXPERIMENTAL_FEATURES
case WIRE_INVALID_ONION_BLINDING:
#endif
return true;
}
/* We should never get here, otherwise the above `switch` isn't
* exhaustive. Nevertheless the failcode is provided by the erring
* node, so retry anyway. `abort()`ing on externally supplied info is
* not a good idea. */
return true;
}
static inline void retry_step_cb(struct retry_mod_data *rd, static inline void retry_step_cb(struct retry_mod_data *rd,
struct payment *p) struct payment *p)
{ {
struct payment *subpayment; struct payment *subpayment;
struct retry_mod_data *rdata = payment_mod_retry_get_data(p); struct retry_mod_data *rdata = payment_mod_retry_get_data(p);
if (p->step != PAYMENT_STEP_FAILED)
return payment_continue(p);
/* If we failed to find a route, it's unlikely we can suddenly find a /* If we failed to find a route, it's unlikely we can suddenly find a
* new one without any other changes, so it's time to give up. */ * new one without any other changes, so it's time to give up. */
if (p->step == PAYMENT_STEP_FAILED && p->route == NULL) if (p->route == NULL)
payment_continue(p); return payment_continue(p);
/* If the root is marked as abort, we do not retry anymore */
if (payment_root(p)->abort)
return payment_continue(p);
if (!payment_can_retry(p))
return payment_continue(p);
if (p->step == PAYMENT_STEP_FAILED && rdata->retries > 0) { /* If the failure was not final, and we tried a route, try again. */
if (rdata->retries > 0) {
subpayment = payment_new(p, NULL, p, p->modifiers); subpayment = payment_new(p, NULL, p, p->modifiers);
payment_start(subpayment); payment_start(subpayment);
p->step = PAYMENT_STEP_RETRY; p->step = PAYMENT_STEP_RETRY;
@ -974,6 +1038,9 @@ static inline void retry_step_cb(struct retry_mod_data *rd,
payment_continue(p); payment_continue(p);
} }
REGISTER_PAYMENT_MODIFIER(retry, struct retry_mod_data *, retry_data_init,
retry_step_cb);
static struct command_result * static struct command_result *
local_channel_hints_listpeers(struct command *cmd, const char *buffer, local_channel_hints_listpeers(struct command *cmd, const char *buffer,
const jsmntok_t *toks, struct payment *p) const jsmntok_t *toks, struct payment *p)

Loading…
Cancel
Save