mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
paymod: Add a deadline to the pay command and retry modifier
This commit is contained in:
@@ -36,6 +36,7 @@ struct payment *payment_new(tal_t *ctx, struct command *cmd,
|
||||
|
||||
/* Re-establish the unmodified constraints for our sub-payment. */
|
||||
p->constraints = *parent->start_constraints;
|
||||
p->deadline = parent->deadline;
|
||||
} else {
|
||||
assert(cmd != NULL);
|
||||
p->partid = 0;
|
||||
@@ -1317,10 +1318,21 @@ static inline void retry_step_cb(struct retry_mod_data *rd,
|
||||
{
|
||||
struct payment *subpayment;
|
||||
struct retry_mod_data *rdata = payment_mod_retry_get_data(p);
|
||||
struct timeabs now = time_now();
|
||||
|
||||
if (p->step != PAYMENT_STEP_FAILED)
|
||||
return payment_continue(p);
|
||||
|
||||
if (time_after(now, p->deadline)) {
|
||||
plugin_log(
|
||||
p->plugin, LOG_INFORM,
|
||||
"Payment deadline expired, not retrying (partial-)payment "
|
||||
"%s/%d",
|
||||
type_to_string(tmpctx, struct sha256, p->payment_hash),
|
||||
p->partid);
|
||||
return payment_continue(p);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if (p->route == NULL)
|
||||
@@ -1928,3 +1940,68 @@ static struct direct_pay_data *direct_pay_init(struct payment *p)
|
||||
|
||||
REGISTER_PAYMENT_MODIFIER(directpay, struct direct_pay_data *, direct_pay_init,
|
||||
direct_pay_cb);
|
||||
|
||||
static struct command_result *waitblockheight_rpc_cb(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *toks,
|
||||
struct payment *p)
|
||||
{
|
||||
struct payment *subpayment;
|
||||
subpayment = payment_new(p, NULL, p, p->modifiers);
|
||||
payment_start(subpayment);
|
||||
payment_set_step(p, PAYMENT_STEP_RETRY);
|
||||
subpayment->why =
|
||||
tal_fmt(subpayment, "Retrying after waiting for blockchain sync.");
|
||||
payment_continue(p);
|
||||
return command_still_pending(cmd);
|
||||
}
|
||||
|
||||
static void waitblockheight_cb(void *d, struct payment *p)
|
||||
{
|
||||
struct out_req *req;
|
||||
struct timeabs now = time_now();
|
||||
struct timerel remaining;
|
||||
u32 blockheight;
|
||||
int failcode;
|
||||
const u8 *raw_message;
|
||||
if (p->step != PAYMENT_STEP_FAILED)
|
||||
return payment_continue(p);
|
||||
|
||||
/* If we don't have an error message to parse we can't wait for blockheight. */
|
||||
if (p->result == NULL)
|
||||
return payment_continue(p);
|
||||
|
||||
if (time_after(now, p->deadline))
|
||||
return payment_continue(p);
|
||||
|
||||
failcode = p->result->failcode;
|
||||
raw_message = p->result->raw_message;
|
||||
remaining = time_between(p->deadline, now);
|
||||
|
||||
if (failcode != 17 /* Former final_expiry_too_soon */) {
|
||||
blockheight = p->start_block + 1;
|
||||
} else {
|
||||
/* If it's incorrect_or_unknown_payment_details, that tells us
|
||||
* what height they're at */
|
||||
struct amount_msat unused;
|
||||
const void *ptr = raw_message;
|
||||
if (!fromwire_incorrect_or_unknown_payment_details(
|
||||
ptr, &unused, &blockheight))
|
||||
return payment_continue(p);
|
||||
}
|
||||
|
||||
plugin_log(p->plugin, LOG_INFORM,
|
||||
"Remote node appears to be on a longer chain, which causes "
|
||||
"CLTV timeouts to be incorrect. Waiting up to %" PRIu64
|
||||
" seconds to catch up to block %d before retrying.",
|
||||
time_to_sec(remaining), blockheight);
|
||||
|
||||
req = jsonrpc_request_start(p->plugin, NULL, "waitblockheight",
|
||||
waitblockheight_rpc_cb,
|
||||
waitblockheight_rpc_cb, p);
|
||||
json_add_u32(req->js, "blockheight", blockheight);
|
||||
json_add_u32(req->js, "timeout", time_to_sec(remaining));
|
||||
send_outreq(p->plugin, req);
|
||||
}
|
||||
|
||||
REGISTER_PAYMENT_MODIFIER(waitblockheight, void *, NULL, waitblockheight_cb);
|
||||
|
||||
@@ -317,6 +317,7 @@ REGISTER_PAYMENT_MODIFIER_HEADER(routehints, struct routehints_data);
|
||||
REGISTER_PAYMENT_MODIFIER_HEADER(exemptfee, struct exemptfee_data);
|
||||
REGISTER_PAYMENT_MODIFIER_HEADER(shadowroute, struct shadow_route_data);
|
||||
REGISTER_PAYMENT_MODIFIER_HEADER(directpay, struct direct_pay_data);
|
||||
extern struct payment_modifier waitblockheight_pay_mod;
|
||||
|
||||
/* For the root payment we can seed the channel_hints with the result from
|
||||
* `listpeers`, hence avoid channels that we know have insufficient capacity
|
||||
|
||||
@@ -1842,6 +1842,7 @@ struct payment_modifier *paymod_mods[] = {
|
||||
&shadowroute_pay_mod,
|
||||
&exemptfee_pay_mod,
|
||||
&routehints_pay_mod,
|
||||
&waitblockheight_pay_mod,
|
||||
&retry_pay_mod,
|
||||
NULL,
|
||||
};
|
||||
@@ -1861,6 +1862,7 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
u32 *maxdelay;
|
||||
struct amount_msat *exemptfee, *msat;
|
||||
const char *label;
|
||||
unsigned int *retryfor;
|
||||
#if DEVELOPER
|
||||
bool *use_shadow;
|
||||
#endif
|
||||
@@ -1876,6 +1878,7 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
p_opt_def("exemptfee", param_msat, &exemptfee, AMOUNT_MSAT(5000)),
|
||||
p_opt_def("maxdelay", param_number, &maxdelay,
|
||||
maxdelay_default),
|
||||
p_opt_def("retry_for", param_number, &retryfor, 60),
|
||||
p_opt_def("maxfeepercent", param_millionths,
|
||||
&maxfee_pct_millionths, 500000),
|
||||
#if DEVELOPER
|
||||
@@ -1933,6 +1936,7 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
p->bolt11 = tal_steal(p, b11str);
|
||||
p->why = "Initial attempt";
|
||||
p->constraints.cltv_budget = *maxdelay;
|
||||
p->deadline = timeabs_add(time_now(), time_from_sec(*retryfor));
|
||||
|
||||
if (!amount_msat_fee(&p->constraints.fee_budget, p->amount, 0,
|
||||
*maxfee_pct_millionths / 100)) {
|
||||
|
||||
@@ -3077,7 +3077,7 @@ def test_pay_modifiers(node_factory):
|
||||
# Make sure that the dummy param is in the help (and therefore assigned to
|
||||
# the modifier data).
|
||||
hlp = l1.rpc.help("paymod")['help'][0]
|
||||
assert(hlp['command'] == 'paymod bolt11 [msatoshi] [label] [exemptfee] [maxdelay] [maxfeepercent] [use_shadow]')
|
||||
assert(hlp['command'] == 'paymod bolt11 [msatoshi] [label] [exemptfee] [maxdelay] [retry_for] [maxfeepercent] [use_shadow]')
|
||||
|
||||
inv = l2.rpc.invoice(123, 'lbl', 'desc')['bolt11']
|
||||
r = l1.rpc.paymod(inv)
|
||||
|
||||
Reference in New Issue
Block a user