mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +01:00
paymod: Simplify retry mod logic and add abort logic
This commit is contained in:
@@ -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 (p->step == PAYMENT_STEP_FAILED && rdata->retries > 0) {
|
/* 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 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)
|
||||||
|
|||||||
Reference in New Issue
Block a user