libplugin-pay: always use a non-NULL struct command.

This means we replace p->cmd with an auxillary command after we've
finished, so we have a valid command to use.

It also means we weave `struct command_result` returns back through
all the callers.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-11-06 21:26:36 +10:30
parent 0a909bdea5
commit ec8293d215
6 changed files with 134 additions and 155 deletions

View file

@ -62,7 +62,7 @@ static struct keysend_data *keysend_init(struct payment *p)
} }
} }
static void keysend_cb(struct keysend_data *d, struct payment *p) { static struct command_result *keysend_cb(struct keysend_data *d, struct payment *p) {
struct createonion_hop *last_payload; struct createonion_hop *last_payload;
size_t hopcount; size_t hopcount;

View file

@ -69,6 +69,12 @@ int libplugin_pay_poll(struct pollfd *fds, nfds_t nfds, int timeout)
return daemon_poll(fds, nfds, timeout); return daemon_poll(fds, nfds, timeout);
} }
/* Only root has a non-NULL cmd ptr */
static struct command *payment_cmd(struct payment *p)
{
return payment_root(p)->cmd;
}
struct payment *payment_new(tal_t *ctx, struct command *cmd, struct payment *payment_new(tal_t *ctx, struct command *cmd,
struct payment *parent, struct payment *parent,
struct channel_hint_set *channel_hints, struct channel_hint_set *channel_hints,
@ -82,6 +88,7 @@ struct payment *payment_new(tal_t *ctx, struct command *cmd,
p->parent = parent; p->parent = parent;
p->modifiers = mods; p->modifiers = mods;
p->cmd = cmd; p->cmd = cmd;
p->finished = false;
p->start_time = time_now(); p->start_time = time_now();
p->result = NULL; p->result = NULL;
p->why = NULL; p->why = NULL;
@ -230,10 +237,9 @@ static struct command_result *payment_rpc_failure(struct command *cmd,
const jsmntok_t *toks, const jsmntok_t *toks,
struct payment *p) struct payment *p)
{ {
payment_fail(p, return payment_fail(p,
"Failing a partial payment due to a failed RPC call: %.*s", "Failing a partial payment due to a failed RPC call: %.*s",
toks->end - toks->start, buffer + toks->start); toks->end - toks->start, buffer + toks->start);
return command_still_pending(cmd);
} }
struct payment_tree_result payment_collect_result(struct payment *p) struct payment_tree_result payment_collect_result(struct payment *p)
@ -306,8 +312,7 @@ static struct command_result *payment_waitblockheight_cb(struct command *cmd,
"(syncheight=%d < headercount=%d)", "(syncheight=%d < headercount=%d)",
p->chainlag, syncheight, p->start_block); p->chainlag, syncheight, p->start_block);
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} }
static struct command_result * static struct command_result *
@ -330,19 +335,17 @@ payment_getblockheight_success(struct command *cmd,
/* Now we just need to ask `lightningd` what height it has /* Now we just need to ask `lightningd` what height it has
* synced up to, and we remember that as chainlag. */ * synced up to, and we remember that as chainlag. */
req = jsonrpc_request_start(p->plugin, NULL, "waitblockheight", req = jsonrpc_request_start(p->plugin, cmd, "waitblockheight",
&payment_waitblockheight_cb, &payment_waitblockheight_cb,
&payment_rpc_failure, p); &payment_rpc_failure, p);
json_add_u32(req->js, "blockheight", 0); json_add_u32(req->js, "blockheight", 0);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
return command_still_pending(cmd);
} }
#define INVALID_BLOCKHEIGHT UINT32_MAX #define INVALID_BLOCKHEIGHT UINT32_MAX
static static struct command_result *
void payment_start_at_blockheight(struct payment *p, u32 blockheight) payment_start_at_blockheight(struct payment *p, u32 blockheight)
{ {
struct payment *root = payment_root(p); struct payment *root = payment_root(p);
@ -378,11 +381,11 @@ void payment_start_at_blockheight(struct payment *p, u32 blockheight)
* height, allowing us to send while still syncing. * height, allowing us to send while still syncing.
*/ */
struct out_req *req; struct out_req *req;
req = jsonrpc_request_start(p->plugin, NULL, "getchaininfo", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "getchaininfo",
&payment_getblockheight_success, &payment_getblockheight_success,
&payment_rpc_failure, p); &payment_rpc_failure, p);
json_add_u32(req->js, "last_height", 0); json_add_u32(req->js, "last_height", 0);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
} }
void payment_start(struct payment *p) void payment_start(struct payment *p)
@ -864,22 +867,16 @@ static struct command_result *payment_getroute(struct payment *p)
dst = gossmap_find_node(gossmap, p->getroute->destination); dst = gossmap_find_node(gossmap, p->getroute->destination);
if (!dst) { if (!dst) {
put_gossmap(p); put_gossmap(p);
payment_fail( return payment_fail(
p, "Unknown destination %s", p, "Unknown destination %s",
fmt_node_id(tmpctx, p->getroute->destination)); fmt_node_id(tmpctx, p->getroute->destination));
/* Let payment_finished_ handle this, so we mark it as pending */
return command_still_pending(p->cmd);
} }
/* If we don't exist in gossip, routing can't happen. */ /* If we don't exist in gossip, routing can't happen. */
src = gossmap_find_node(gossmap, p->local_id); src = gossmap_find_node(gossmap, p->local_id);
if (!src) { if (!src) {
put_gossmap(p); put_gossmap(p);
payment_fail(p, "We don't have any channels"); return payment_fail(p, "We don't have any channels");
/* Let payment_finished_ handle this, so we mark it as pending */
return command_still_pending(p->cmd);
} }
p->route = route(p, gossmap, src, dst, p->getroute->amount, p->getroute->cltv, p->route = route(p, gossmap, src, dst, p->getroute->amount, p->getroute->cltv,
@ -888,9 +885,7 @@ static struct command_result *payment_getroute(struct payment *p)
put_gossmap(p); put_gossmap(p);
if (!p->route) { if (!p->route) {
payment_fail(p, "%s", errstr); return payment_fail(p, "%s", errstr);
/* Let payment_finished_ handle this, so we mark it as pending */
return command_still_pending(p->cmd);
} }
/* OK, now we *have* a route */ /* OK, now we *have* a route */
@ -898,9 +893,8 @@ static struct command_result *payment_getroute(struct payment *p)
if (tal_count(p->route) == 0) { if (tal_count(p->route) == 0) {
payment_root(p)->abort = true; payment_root(p)->abort = true;
payment_fail(p, "Empty route returned by getroute, are you " return payment_fail(p, "Empty route returned by getroute, are you "
"trying to pay yourself?"); "trying to pay yourself?");
return command_still_pending(p->cmd);
} }
fee = payment_route_fee(p); fee = payment_route_fee(p);
@ -908,19 +902,17 @@ static struct command_result *payment_getroute(struct payment *p)
/* Ensure that our fee and CLTV budgets are respected. */ /* Ensure that our fee and CLTV budgets are respected. */
if (amount_msat_greater(fee, p->constraints.fee_budget)) { if (amount_msat_greater(fee, p->constraints.fee_budget)) {
p->route = tal_free(p->route); p->route = tal_free(p->route);
payment_fail( return payment_fail(
p, "Fee exceeds our fee budget: %s > %s, discarding route", p, "Fee exceeds our fee budget: %s > %s, discarding route",
fmt_amount_msat(tmpctx, fee), fmt_amount_msat(tmpctx, fee),
fmt_amount_msat(tmpctx, p->constraints.fee_budget)); fmt_amount_msat(tmpctx, p->constraints.fee_budget));
return command_still_pending(p->cmd);
} }
if (p->route[0].delay > p->constraints.cltv_budget) { if (p->route[0].delay > p->constraints.cltv_budget) {
u32 delay = p->route[0].delay; u32 delay = p->route[0].delay;
p->route = tal_free(p->route); p->route = tal_free(p->route);
payment_fail(p, "CLTV delay exceeds our CLTV budget: %d > %d", return payment_fail(p, "CLTV delay exceeds our CLTV budget: %d > %d",
delay, p->constraints.cltv_budget); delay, p->constraints.cltv_budget);
return command_still_pending(p->cmd);
} }
/* Now update the constraints in fee_budget and cltv_budget so /* Now update the constraints in fee_budget and cltv_budget so
@ -934,8 +926,7 @@ static struct command_result *payment_getroute(struct payment *p)
/* Allow modifiers to modify the route, before /* Allow modifiers to modify the route, before
* payment_compute_onion_payloads uses the route to generate the * payment_compute_onion_payloads uses the route to generate the
* onion_payloads */ * onion_payloads */
payment_continue(p); return payment_continue(p);
return command_still_pending(p->cmd);
} }
/** /**
@ -1018,12 +1009,11 @@ payment_listpeerchannels_success(struct command *cmd, const char *buffer,
"spendable=%s < payment=%s", "spendable=%s < payment=%s",
fmt_amount_msat(tmpctx, spendable), fmt_amount_msat(tmpctx, spendable),
fmt_amount_msat(tmpctx, p->getroute->amount)); fmt_amount_msat(tmpctx, p->getroute->amount));
payment_abort(p, PAY_INSUFFICIENT_FUNDS, return payment_abort(p, PAY_INSUFFICIENT_FUNDS,
"Insufficient funds to perform the payment: " "Insufficient funds to perform the payment: "
"spendable=%s < payment=%s", "spendable=%s < payment=%s",
fmt_amount_msat(tmpctx, spendable), fmt_amount_msat(tmpctx, spendable),
fmt_amount_msat(tmpctx, p->getroute->amount)); fmt_amount_msat(tmpctx, p->getroute->amount));
return command_still_pending(p->cmd);
} else if (amount_msat_greater(maxrequired, spendable)) { } else if (amount_msat_greater(maxrequired, spendable)) {
char *msg = tal_fmt( char *msg = tal_fmt(
tmpctx, tmpctx,
@ -1034,7 +1024,7 @@ payment_listpeerchannels_success(struct command *cmd, const char *buffer,
fmt_amount_msat(tmpctx, p->getroute->amount), fmt_amount_msat(tmpctx, p->getroute->amount),
fmt_amount_msat(tmpctx, p->constraints.fee_budget)); fmt_amount_msat(tmpctx, p->constraints.fee_budget));
plugin_notify_message(p->cmd, LOG_INFORM, "%s", msg); plugin_notify_message(payment_cmd(p), LOG_INFORM, "%s", msg);
} }
return payment_getroute(p); return payment_getroute(p);
@ -1048,7 +1038,7 @@ static struct command_result *payment_getlocalmods(struct payment *p)
if (p->mods) if (p->mods)
return payment_getroute(p); return payment_getroute(p);
req = jsonrpc_request_start(p->plugin, NULL, "listpeerchannels", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "listpeerchannels",
&payment_listpeerchannels_success, &payment_listpeerchannels_success,
&payment_rpc_failure, p); &payment_rpc_failure, p);
return send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
@ -1393,9 +1383,7 @@ error:
payment_root(p)->abort = true; payment_root(p)->abort = true;
nonerror: nonerror:
payment_fail(p, "%s", p->result->message); return payment_fail(p, "%s", p->result->message);
return command_still_pending(cmd);
} }
@ -1494,8 +1482,7 @@ strange_error:
failcode, describe_failcode(tmpctx, failcode)); failcode, describe_failcode(tmpctx, failcode));
error: error:
payment_fail(p, "%s", p->result->message); return payment_fail(p, "%s", p->result->message);
return command_still_pending(cmd);
} }
/* From the docs: /* From the docs:
@ -1609,8 +1596,7 @@ payment_addgossip_success(struct command *cmd, const char *buffer,
json_tok_full(buffer, toks)); json_tok_full(buffer, toks));
/* FIXME: Pick a random channel to fail? */ /* FIXME: Pick a random channel to fail? */
payment_set_step(p, PAYMENT_STEP_FAILED); payment_set_step(p, PAYMENT_STEP_FAILED);
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} }
if (!errchan) if (!errchan)
@ -1650,16 +1636,14 @@ payment_waitsendpay_finished(struct command *cmd, const char *buffer,
json_tok_full_len(toks), json_tok_full_len(toks),
json_tok_full(buffer, toks)); json_tok_full(buffer, toks));
payment_set_step(p, PAYMENT_STEP_FAILED); payment_set_step(p, PAYMENT_STEP_FAILED);
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} }
payment_result_infer(p->route, p->result); payment_result_infer(p->route, p->result);
if (p->result->state == PAYMENT_COMPLETE) { if (p->result->state == PAYMENT_COMPLETE) {
payment_set_step(p, PAYMENT_STEP_SUCCESS); payment_set_step(p, PAYMENT_STEP_SUCCESS);
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} }
payment_chanhints_unapply_route(p); payment_chanhints_unapply_route(p);
@ -1672,12 +1656,11 @@ payment_waitsendpay_finished(struct command *cmd, const char *buffer,
"Extracted channel_update %s from onionreply %s", "Extracted channel_update %s from onionreply %s",
tal_hex(tmpctx, update), tal_hex(tmpctx, update),
tal_hex(tmpctx, p->result->raw_message)); tal_hex(tmpctx, p->result->raw_message));
req = jsonrpc_request_start(p->plugin, NULL, "addgossip", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "addgossip",
payment_addgossip_success, payment_addgossip_success,
payment_addgossip_failure, p); payment_addgossip_failure, p);
json_add_hex_talarr(req->js, "message", update); json_add_hex_talarr(req->js, "message", update);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
return command_still_pending(cmd);
} }
return payment_addgossip_success(cmd, NULL, NULL, p); return payment_addgossip_success(cmd, NULL, NULL, p);
@ -1689,15 +1672,13 @@ static struct command_result *payment_sendonion_success(struct command *cmd,
struct payment *p) struct payment *p)
{ {
struct out_req *req; struct out_req *req;
req = jsonrpc_request_start(p->plugin, NULL, "waitsendpay", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "waitsendpay",
payment_waitsendpay_finished, payment_waitsendpay_finished,
payment_waitsendpay_finished, p); payment_waitsendpay_finished, p);
json_add_sha256(req->js, "payment_hash", p->payment_hash); json_add_sha256(req->js, "payment_hash", p->payment_hash);
json_add_num(req->js, "partid", p->partid); json_add_num(req->js, "partid", p->partid);
json_add_u64(req->js, "groupid", p->groupid); json_add_u64(req->js, "groupid", p->groupid);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
return command_still_pending(cmd);
} }
static struct command_result *payment_createonion_success(struct command *cmd, static struct command_result *payment_createonion_success(struct command *cmd,
@ -1719,7 +1700,7 @@ static struct command_result *payment_createonion_success(struct command *cmd,
p->createonion_response = json_to_createonion_response(p, buffer, toks); p->createonion_response = json_to_createonion_response(p, buffer, toks);
req = jsonrpc_request_start(p->plugin, NULL, "sendonion", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "sendonion",
payment_sendonion_success, payment_sendonion_success,
payment_rpc_failure, p); payment_rpc_failure, p);
json_add_hex_talarr(req->js, "onion", p->createonion_response->onion); json_add_hex_talarr(req->js, "onion", p->createonion_response->onion);
@ -1762,8 +1743,7 @@ static struct command_result *payment_createonion_success(struct command *cmd,
if (p->local_invreq_id) if (p->local_invreq_id)
json_add_sha256(req->js, "localinvreqid", p->local_invreq_id); json_add_sha256(req->js, "localinvreqid", p->local_invreq_id);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
return command_still_pending(cmd);
} }
/* Temporary serialization method for the tlv_payload.data until we rework the /* Temporary serialization method for the tlv_payload.data until we rework the
@ -1857,7 +1837,7 @@ static void payment_add_blindedpath(const tal_t *ctx,
} }
} }
static void payment_compute_onion_payloads(struct payment *p) static struct command_result *payment_compute_onion_payloads(struct payment *p)
{ {
struct createonion_request *cr; struct createonion_request *cr;
size_t hopcount; size_t hopcount;
@ -1943,14 +1923,14 @@ static void payment_compute_onion_payloads(struct payment *p)
/* Now allow all the modifiers to mess with the payloads, before we /* Now allow all the modifiers to mess with the payloads, before we
* serialize via a call to createonion in the next step. */ * serialize via a call to createonion in the next step. */
payment_continue(p); return payment_continue(p);
} }
static void payment_sendonion(struct payment *p) static struct command_result *payment_sendonion(struct payment *p)
{ {
struct out_req *req; struct out_req *req;
u8 *payload, *tlv; u8 *payload, *tlv;
req = jsonrpc_request_start(p->plugin, NULL, "createonion", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "createonion",
payment_createonion_success, payment_createonion_success,
payment_rpc_failure, p); payment_rpc_failure, p);
@ -1979,11 +1959,11 @@ static void payment_sendonion(struct payment *p)
json_add_secret(req->js, "sessionkey", json_add_secret(req->js, "sessionkey",
p->createonion_request->session_key); p->createonion_request->session_key);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
} }
/* Mutual recursion. */ /* Mutual recursion. */
static void payment_finished(struct payment *p); static struct command_result *payment_finished(struct payment *p);
/* A payment is finished if a) it is in a final state, of b) it's in a /* A payment is finished if a) it is in a final state, of b) it's in a
* child-spawning state and all of its children are in a final state. */ * child-spawning state and all of its children are in a final state. */
@ -2033,14 +2013,14 @@ static bool payment_is_success(struct payment *p)
/* Function to bubble up completions to the root, which actually holds on to /* Function to bubble up completions to the root, which actually holds on to
* the command that initiated the flow. */ * the command that initiated the flow. */
static void payment_child_finished(struct payment *p, static struct command_result *payment_child_finished(struct payment *p,
struct payment *child) struct payment *child)
{ {
if (!payment_is_finished(p)) if (!payment_is_finished(p))
return; return command_still_pending(payment_cmd(p));
/* Should we continue bubbling up? */ /* Should we continue bubbling up? */
payment_finished(p); return payment_finished(p);
} }
static void payment_add_attempt(struct json_stream *s, const char *fieldname, struct payment *p, bool recurse) static void payment_add_attempt(struct json_stream *s, const char *fieldname, struct payment *p, bool recurse)
@ -2144,7 +2124,7 @@ void json_add_payment_success(struct json_stream *js,
* leafs in the subtree rooted in the payment are all in a final state. It is * leafs in the subtree rooted in the payment are all in a final state. It is
* called only once, and it is guaranteed to be called in post-order * called only once, and it is guaranteed to be called in post-order
* traversal, i.e., all children are finished before the parent is called. */ * traversal, i.e., all children are finished before the parent is called. */
static void payment_finished(struct payment *p) static struct command_result *payment_finished(struct payment *p)
{ {
struct payment_tree_result result = payment_collect_result(p); struct payment_tree_result result = payment_collect_result(p);
struct json_stream *ret; struct json_stream *ret;
@ -2159,14 +2139,14 @@ static void payment_finished(struct payment *p)
if (p->parent != NULL) if (p->parent != NULL)
return payment_child_finished(p->parent, p); return payment_child_finished(p->parent, p);
/* We are about to reply, unset the pointer to the cmd so we if (p->finished) {
* don't attempt to return a response twice. */ /* cmd is the aux_command: real cmd has been freed. */
p->cmd = NULL; return command_still_pending(p->cmd);
if (cmd == NULL) { }
/* This is the tree root, but we already reported
* success or failure, so noop. */ /* on_payment_failure / on_payment_success looks at this! */
return; p->finished = true;
} else if (payment_is_success(p)) { if (payment_is_success(p)) {
assert(result.treestates & PAYMENT_STEP_SUCCESS); assert(result.treestates & PAYMENT_STEP_SUCCESS);
assert(result.leafstates & PAYMENT_STEP_SUCCESS); assert(result.leafstates & PAYMENT_STEP_SUCCESS);
assert(result.preimage != NULL); assert(result.preimage != NULL);
@ -2266,7 +2246,11 @@ static void payment_finished(struct payment *p)
payment_notify_failure(p, failure->message); payment_notify_failure(p, failure->message);
} }
if (command_finished(cmd, ret)) { /* Ignore result. */} /* We're going to resolve p->cmd. Put an aux_command in place
* so we can use that to wrap up any remaining payments */
p->cmd = aux_command(cmd);
return command_finished(cmd, ret);
} }
void payment_set_step(struct payment *p, enum payment_step newstep) void payment_set_step(struct payment *p, enum payment_step newstep)
@ -2279,7 +2263,7 @@ void payment_set_step(struct payment *p, enum payment_step newstep)
p->end_time = time_now(); p->end_time = time_now();
} }
void payment_continue(struct payment *p) struct command_result *payment_continue(struct payment *p)
{ {
struct payment_modifier *mod; struct payment_modifier *mod;
void *moddata; void *moddata;
@ -2299,27 +2283,23 @@ void payment_continue(struct payment *p)
switch (p->step) { switch (p->step) {
case PAYMENT_STEP_INITIALIZED: case PAYMENT_STEP_INITIALIZED:
case PAYMENT_STEP_RETRY_GETROUTE: case PAYMENT_STEP_RETRY_GETROUTE:
payment_getlocalmods(p); return payment_getlocalmods(p);
return;
case PAYMENT_STEP_GOT_ROUTE: case PAYMENT_STEP_GOT_ROUTE:
payment_compute_onion_payloads(p); return payment_compute_onion_payloads(p);
return;
case PAYMENT_STEP_ONION_PAYLOAD: case PAYMENT_STEP_ONION_PAYLOAD:
payment_sendonion(p); return payment_sendonion(p);
return;
case PAYMENT_STEP_SUCCESS: case PAYMENT_STEP_SUCCESS:
case PAYMENT_STEP_FAILED: case PAYMENT_STEP_FAILED:
payment_finished(p); return payment_finished(p);
return;
case PAYMENT_STEP_RETRY: case PAYMENT_STEP_RETRY:
case PAYMENT_STEP_SPLIT: case PAYMENT_STEP_SPLIT:
/* Do nothing, we'll get pinged by a child succeeding /* Do nothing, we'll get pinged by a child succeeding
* or failing. */ * or failing. */
return; return command_still_pending(payment_cmd(p));
} }
} }
/* We should never get here, it'd mean one of the state machine called /* We should never get here, it'd mean one of the state machine called
@ -2327,7 +2307,7 @@ void payment_continue(struct payment *p)
abort(); abort();
} }
void payment_abort(struct payment *p, enum jsonrpc_errcode code, const char *fmt, ...) { struct command_result *payment_abort(struct payment *p, enum jsonrpc_errcode code, const char *fmt, ...) {
va_list ap; va_list ap;
struct payment *root = payment_root(p); struct payment *root = payment_root(p);
payment_set_step(p, PAYMENT_STEP_FAILED); payment_set_step(p, PAYMENT_STEP_FAILED);
@ -2352,10 +2332,10 @@ void payment_abort(struct payment *p, enum jsonrpc_errcode code, const char *fmt
/* Do not use payment_continue, because that'd continue /* Do not use payment_continue, because that'd continue
* applying the modifiers before calling * applying the modifiers before calling
* payment_finished(). */ * payment_finished(). */
payment_finished(p); return payment_finished(p);
} }
void payment_fail(struct payment *p, const char *fmt, ...) struct command_result *payment_fail(struct payment *p, const char *fmt, ...)
{ {
va_list ap; va_list ap;
p->end_time = time_now(); p->end_time = time_now();
@ -2368,7 +2348,7 @@ void payment_fail(struct payment *p, const char *fmt, ...)
paymod_log(p, LOG_INFORM, "%s", p->failreason); paymod_log(p, LOG_INFORM, "%s", p->failreason);
payment_continue(p); return payment_continue(p);
} }
void *payment_mod_get_data(const struct payment *p, void *payment_mod_get_data(const struct payment *p,
@ -2386,8 +2366,8 @@ void *payment_mod_get_data(const struct payment *p,
static struct retry_mod_data *retry_data_init(struct payment *p); static struct retry_mod_data *retry_data_init(struct payment *p);
static inline void retry_step_cb(struct retry_mod_data *rd, static struct command_result *retry_step_cb(struct retry_mod_data *rd,
struct payment *p); struct payment *p);
static struct retry_mod_data * static struct retry_mod_data *
retry_data_init(struct payment *p) retry_data_init(struct payment *p)
@ -2460,8 +2440,8 @@ static bool payment_can_retry(struct payment *p)
return true; return true;
} }
static inline void retry_step_cb(struct retry_mod_data *rd, static struct command_result *retry_step_cb(struct retry_mod_data *rd,
struct payment *p) struct payment *p)
{ {
struct payment *subpayment, *root = payment_root(p); struct payment *subpayment, *root = payment_root(p);
struct retry_mod_data *rdata = payment_mod_retry_get_data(p); struct retry_mod_data *rdata = payment_mod_retry_get_data(p);
@ -2511,7 +2491,7 @@ static inline void retry_step_cb(struct retry_mod_data *rd,
rdata->retries - 1); rdata->retries - 1);
} }
payment_continue(p); return payment_continue(p);
} }
REGISTER_PAYMENT_MODIFIER(retry, struct retry_mod_data *, retry_data_init, REGISTER_PAYMENT_MODIFIER(retry, struct retry_mod_data *, retry_data_init,
@ -2586,11 +2566,10 @@ local_channel_hints_listpeerchannels(struct command *cmd, const char *buffer,
p->mods = gossmods_from_listpeerchannels( p->mods = gossmods_from_listpeerchannels(
p, p->local_id, buffer, toks, true, gossmod_add_localchan, NULL); p, p->local_id, buffer, toks, true, gossmod_add_localchan, NULL);
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} }
static void local_channel_hints_cb(void *d UNUSED, struct payment *p) static struct command_result *local_channel_hints_cb(void *d UNUSED, struct payment *p)
{ {
struct out_req *req; struct out_req *req;
/* If we are not the root we don't look up the channel balances since /* If we are not the root we don't look up the channel balances since
@ -2601,10 +2580,10 @@ static void local_channel_hints_cb(void *d UNUSED, struct payment *p)
if (p->parent != NULL || p->step != PAYMENT_STEP_INITIALIZED) if (p->parent != NULL || p->step != PAYMENT_STEP_INITIALIZED)
return payment_continue(p); return payment_continue(p);
req = jsonrpc_request_start(p->plugin, NULL, "listpeerchannels", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "listpeerchannels",
local_channel_hints_listpeerchannels, local_channel_hints_listpeerchannels,
local_channel_hints_listpeerchannels, p); local_channel_hints_listpeerchannels, p);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
} }
REGISTER_PAYMENT_MODIFIER(local_channel_hints, void *, NULL, local_channel_hints_cb); REGISTER_PAYMENT_MODIFIER(local_channel_hints, void *, NULL, local_channel_hints_cb);
@ -2908,7 +2887,7 @@ static void routehint_pre_getroute(struct routehints_data *d, struct payment *p)
paymod_log(p, LOG_DBG, "Not using a routehint"); paymod_log(p, LOG_DBG, "Not using a routehint");
} }
static void routehint_check_reachable(struct payment *p) static struct command_result *routehint_check_reachable(struct payment *p)
{ {
const struct gossmap_node *dst, *src; const struct gossmap_node *dst, *src;
struct gossmap *gossmap = get_gossmap(p); struct gossmap *gossmap = get_gossmap(p);
@ -2962,14 +2941,13 @@ static void routehint_check_reachable(struct payment *p)
* isn't reachable, then there is no point in * isn't reachable, then there is no point in
* continuing. */ * continuing. */
payment_abort( put_gossmap(p);
return payment_abort(
p, p,
PAY_UNREACHABLE, PAY_UNREACHABLE,
"Destination %s is not reachable directly and " "Destination %s is not reachable directly and "
"all routehints were unusable.", "all routehints were unusable.",
fmt_node_id(tmpctx, p->route_destination)); fmt_node_id(tmpctx, p->route_destination));
put_gossmap(p);
return;
} }
routehint_pre_getroute(d, p); routehint_pre_getroute(d, p);
@ -2982,10 +2960,10 @@ static void routehint_check_reachable(struct payment *p)
d->destination_reachable ? "including" : "excluding"); d->destination_reachable ? "including" : "excluding");
/* Now we can continue on our merry way. */ /* Now we can continue on our merry way. */
payment_continue(p); return payment_continue(p);
} }
static void routehint_step_cb(struct routehints_data *d, struct payment *p) static struct command_result *routehint_step_cb(struct routehints_data *d, struct payment *p)
{ {
struct route_hop hop; struct route_hop hop;
const struct payment *root = payment_root(p); const struct payment *root = payment_root(p);
@ -3075,7 +3053,7 @@ static void routehint_step_cb(struct routehints_data *d, struct payment *p)
} }
} }
payment_continue(p); return payment_continue(p);
} }
static struct routehints_data *routehint_data_init(struct payment *p) static struct routehints_data *routehint_data_init(struct payment *p)
@ -3157,7 +3135,7 @@ static struct exemptfee_data *exemptfee_data_init(struct payment *p)
} }
} }
static void exemptfee_cb(struct exemptfee_data *d, struct payment *p) static struct command_result *exemptfee_cb(struct exemptfee_data *d, struct payment *p)
{ {
if (p->step != PAYMENT_STEP_INITIALIZED || p->parent != NULL) if (p->step != PAYMENT_STEP_INITIALIZED || p->parent != NULL)
return payment_continue(p); return payment_continue(p);
@ -3223,7 +3201,7 @@ static struct command_result *shadow_route_extend(struct shadow_route_data *d,
struct payment *p) struct payment *p)
{ {
struct out_req *req; struct out_req *req;
req = jsonrpc_request_start(p->plugin, NULL, "listchannels", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "listchannels",
shadow_route_listchannels, shadow_route_listchannels,
payment_rpc_failure, p); payment_rpc_failure, p);
json_add_node_id(req->js, "source", &d->destination); json_add_node_id(req->js, "source", &d->destination);
@ -3364,14 +3342,13 @@ next:
/* Now it's time to decide whether we want to extend or continue. */ /* Now it's time to decide whether we want to extend or continue. */
if (best == NULL || pseudorand(2) == 0) { if (best == NULL || pseudorand(2) == 0) {
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} else { } else {
return shadow_route_extend(d, p); return shadow_route_extend(d, p);
} }
} }
static void shadow_route_cb(struct shadow_route_data *d, static struct command_result *shadow_route_cb(struct shadow_route_data *d,
struct payment *p) struct payment *p)
{ {
if (!d->use_shadow) if (!d->use_shadow)
@ -3390,15 +3367,15 @@ static void shadow_route_cb(struct shadow_route_data *d,
if (pseudorand(2) == 0) { if (pseudorand(2) == 0) {
return payment_continue(p); return payment_continue(p);
} else { } else {
shadow_route_extend(d, p); return shadow_route_extend(d, p);
} }
} }
REGISTER_PAYMENT_MODIFIER(shadowroute, struct shadow_route_data *, REGISTER_PAYMENT_MODIFIER(shadowroute, struct shadow_route_data *,
shadow_route_init, shadow_route_cb); shadow_route_init, shadow_route_cb);
static void direct_pay_override(struct payment *p) { static struct command_result *direct_pay_override(struct payment *p)
{
/* The root has performed the search for a direct channel. */ /* The root has performed the search for a direct channel. */
struct payment *root = payment_root(p); struct payment *root = payment_root(p);
struct direct_pay_data *d; struct direct_pay_data *d;
@ -3432,8 +3409,7 @@ static void direct_pay_override(struct payment *p) {
payment_set_step(p, PAYMENT_STEP_GOT_ROUTE); payment_set_step(p, PAYMENT_STEP_GOT_ROUTE);
} }
return payment_continue(p);
payment_continue(p);
} }
/* Now that we have the listpeerchannels result for the root payment, let's search /* Now that we have the listpeerchannels result for the root payment, let's search
@ -3480,12 +3456,11 @@ static struct command_result *direct_pay_listpeerchannels(struct command *cmd,
gossmod_add_localchan, gossmod_add_localchan,
NULL); NULL);
direct_pay_override(p); return direct_pay_override(p);
return command_still_pending(cmd);
} }
static void direct_pay_cb(struct direct_pay_data *d, struct payment *p) static struct command_result *direct_pay_cb(struct direct_pay_data *d, struct payment *p)
{ {
struct out_req *req; struct out_req *req;
@ -3493,14 +3468,12 @@ static void direct_pay_cb(struct direct_pay_data *d, struct payment *p)
if (p->step != PAYMENT_STEP_INITIALIZED) if (p->step != PAYMENT_STEP_INITIALIZED)
return payment_continue(p); return payment_continue(p);
req = jsonrpc_request_start(p->plugin, payment_cmd(p), "listpeerchannels",
req = jsonrpc_request_start(p->plugin, NULL, "listpeerchannels",
direct_pay_listpeerchannels, direct_pay_listpeerchannels,
direct_pay_listpeerchannels, direct_pay_listpeerchannels,
p); p);
json_add_node_id(req->js, "id", p->route_destination); json_add_node_id(req->js, "id", p->route_destination);
send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
} }
static struct direct_pay_data *direct_pay_init(struct payment *p) static struct direct_pay_data *direct_pay_init(struct payment *p)
@ -3596,7 +3569,7 @@ static struct adaptive_split_mod_data *adaptive_splitter_data_init(struct paymen
} }
} }
static void adaptive_splitter_cb(struct adaptive_split_mod_data *d, struct payment *p) static struct command_result *adaptive_splitter_cb(struct adaptive_split_mod_data *d, struct payment *p)
{ {
struct payment *root = payment_root(p); struct payment *root = payment_root(p);
struct adaptive_split_mod_data *root_data = struct adaptive_split_mod_data *root_data =
@ -3705,7 +3678,7 @@ static void adaptive_splitter_cb(struct adaptive_split_mod_data *d, struct payme
MPP_ADAPTIVE_LOWER_LIMIT)); MPP_ADAPTIVE_LOWER_LIMIT));
} }
} }
payment_continue(p); return payment_continue(p);
} }
REGISTER_PAYMENT_MODIFIER(adaptive_splitter, struct adaptive_split_mod_data *, REGISTER_PAYMENT_MODIFIER(adaptive_splitter, struct adaptive_split_mod_data *,
@ -3785,11 +3758,10 @@ payee_incoming_limit_count(struct command *cmd,
payment_lower_max_htlcs(p, lim, why); payment_lower_max_htlcs(p, lim, why);
} }
payment_continue(p); return payment_continue(p);
return command_still_pending(cmd);
} }
static void payee_incoming_limit_step_cb(void *d UNUSED, struct payment *p) static struct command_result *payee_incoming_limit_step_cb(void *d UNUSED, struct payment *p)
{ {
/* Only operate at the initialization of te root payment. /* Only operate at the initialization of te root payment.
* Also, no point operating if payment does not support MPP anyway. * Also, no point operating if payment does not support MPP anyway.
@ -3800,11 +3772,11 @@ static void payee_incoming_limit_step_cb(void *d UNUSED, struct payment *p)
/* Get information on the destination. */ /* Get information on the destination. */
struct out_req *req; struct out_req *req;
req = jsonrpc_request_start(p->plugin, NULL, "listchannels", req = jsonrpc_request_start(p->plugin, payment_cmd(p), "listchannels",
&payee_incoming_limit_count, &payee_incoming_limit_count,
&payment_rpc_failure, p); &payment_rpc_failure, p);
json_add_node_id(req->js, "source", p->route_destination); json_add_node_id(req->js, "source", p->route_destination);
(void) send_outreq(p->plugin, req); return send_outreq(p->plugin, req);
} }
REGISTER_PAYMENT_MODIFIER(payee_incoming_limit, void *, NULL, REGISTER_PAYMENT_MODIFIER(payee_incoming_limit, void *, NULL,
@ -3823,7 +3795,7 @@ route_exclusions_data_init(struct payment *p)
return d; return d;
} }
static void route_exclusions_step_cb(struct route_exclusions_data *d, static struct command_result *route_exclusions_step_cb(struct route_exclusions_data *d,
struct payment *p) struct payment *p)
{ {
if (p->parent) if (p->parent)
@ -3841,17 +3813,15 @@ static void route_exclusions_step_cb(struct route_exclusions_data *d,
NULL, total, NULL); NULL, total, NULL);
} else { } else {
if (node_id_eq(&e->u.node_id, p->route_destination)) { if (node_id_eq(&e->u.node_id, p->route_destination)) {
payment_abort(p, PAY_USER_ERROR, "Payee is manually excluded"); return payment_abort(p, PAY_USER_ERROR, "Payee is manually excluded");
return;
} else if (node_id_eq(&e->u.node_id, p->local_id)) { } else if (node_id_eq(&e->u.node_id, p->local_id)) {
payment_abort(p, PAY_USER_ERROR, "Payer is manually excluded"); return payment_abort(p, PAY_USER_ERROR, "Payer is manually excluded");
return;
} }
tal_arr_expand(&p->excluded_nodes, e->u.node_id); tal_arr_expand(&p->excluded_nodes, e->u.node_id);
} }
} }
payment_continue(p); return payment_continue(p);
} }
REGISTER_PAYMENT_MODIFIER(route_exclusions, struct route_exclusions_data *, REGISTER_PAYMENT_MODIFIER(route_exclusions, struct route_exclusions_data *,

View file

@ -145,8 +145,9 @@ struct payment {
/* Usually in global payments list */ /* Usually in global payments list */
struct list_node list; struct list_node list;
/* The command that triggered this payment. Only set for the root /* The command that triggered this payment. Only set for the root
* payment. */ * payment. It's an aux command if finished is set. */
struct command *cmd; struct command *cmd;
bool finished;
struct plugin *plugin; struct plugin *plugin;
struct node_id *local_id; struct node_id *local_id;
@ -322,7 +323,7 @@ struct payment {
struct payment_modifier { struct payment_modifier {
const char *name; const char *name;
void *(*data_init)(struct payment *p); void *(*data_init)(struct payment *p);
void (*post_step_cb)(void *data, struct payment *p); struct command_result *(*post_step_cb)(void *data, struct payment *p);
}; };
void *payment_mod_get_data(const struct payment *payment, void *payment_mod_get_data(const struct payment *payment,
@ -333,8 +334,8 @@ void *payment_mod_get_data(const struct payment *payment,
stringify(name), \ stringify(name), \
typesafe_cb_cast(void *(*)(struct payment *), \ typesafe_cb_cast(void *(*)(struct payment *), \
data_type (*)(struct payment *), data_init_cb), \ data_type (*)(struct payment *), data_init_cb), \
typesafe_cb_cast(void (*)(void *, struct payment *), \ typesafe_cb_cast(struct command_result *(*)(void *, struct payment *), \
void (*)(data_type, struct payment *), step_cb), \ struct command_result *(*)(data_type, struct payment *), step_cb), \
}; };
/* The UNUSED marker is used to shut some compilers up. */ /* The UNUSED marker is used to shut some compilers up. */
@ -450,7 +451,7 @@ struct payment *payment_new(tal_t *ctx, struct command *cmd,
struct payment_modifier **mods); struct payment_modifier **mods);
void payment_start(struct payment *p); void payment_start(struct payment *p);
void payment_continue(struct payment *p); struct command_result *payment_continue(struct payment *p);
/** /**
* Set the payment to the current step. * Set the payment to the current step.
@ -463,14 +464,14 @@ void payment_set_step(struct payment *p, enum payment_step newstep);
/* Fails a partial payment and continues with the core flow. */ /* Fails a partial payment and continues with the core flow. */
void payment_fail(struct payment *p, const char *fmt, ...) PRINTF_FMT(2,3); struct command_result *payment_fail(struct payment *p, const char *fmt, ...) PRINTF_FMT(2,3);
/* Fails a payment process by setting the root payment to /* Fails a payment process by setting the root payment to
* aborted. This will cause all subpayments to terminate as soon as * aborted. This will cause all subpayments to terminate as soon as
* they can, and sets the root failreason so we have a sensible error * they can, and sets the root failreason so we have a sensible error
* message. The failreason is overwritten if it is already set, since * message. The failreason is overwritten if it is already set, since
* we probably know better what happened in the modifier.. */ * we probably know better what happened in the modifier.. */
void payment_abort(struct payment *p, enum jsonrpc_errcode code, const char *fmt, ...) PRINTF_FMT(3,4); struct command_result *payment_abort(struct payment *p, enum jsonrpc_errcode code, const char *fmt, ...) PRINTF_FMT(3,4);
struct payment *payment_root(struct payment *p); struct payment *payment_root(struct payment *p);
struct payment_tree_result payment_collect_result(struct payment *p); struct payment_tree_result payment_collect_result(struct payment *p);

View file

@ -625,11 +625,12 @@ static void on_payment_success(struct payment *payment)
if (!sha256_eq(payment->payment_hash, p->payment_hash) || if (!sha256_eq(payment->payment_hash, p->payment_hash) ||
payment->groupid != p->groupid) payment->groupid != p->groupid)
continue; continue;
if (p->cmd == NULL) if (p->finished)
continue; continue;
cmd = p->cmd; cmd = p->cmd;
p->cmd = NULL; p->cmd = aux_command(cmd);
p->finished = true;
ret = jsonrpc_stream_success(cmd); ret = jsonrpc_stream_success(cmd);
json_add_node_id(ret, "destination", p->pay_destination); json_add_node_id(ret, "destination", p->pay_destination);
@ -713,11 +714,12 @@ static void on_payment_failure(struct payment *payment)
if (!sha256_eq(payment->payment_hash, p->payment_hash) || if (!sha256_eq(payment->payment_hash, p->payment_hash) ||
payment->groupid != p->groupid) payment->groupid != p->groupid)
continue; continue;
if (p->cmd == NULL) if (p->finished)
continue; continue;
cmd = p->cmd; cmd = p->cmd;
p->cmd = NULL; p->cmd = aux_command(cmd);
p->finished = true;
if (p->aborterror != NULL) { if (p->aborterror != NULL) {
/* We set an explicit toplevel error message, /* We set an explicit toplevel error message,
* so let's report that. */ * so let's report that. */

View file

@ -12,6 +12,9 @@
#include <unistd.h> #include <unistd.h>
/* AUTOGENERATED MOCKS START */ /* AUTOGENERATED MOCKS START */
/* Generated stub for aux_command */
struct command *aux_command(const struct command *cmd UNNEEDED)
{ fprintf(stderr, "aux_command called!\n"); abort(); }
/* Generated stub for blinded_onion_hops */ /* Generated stub for blinded_onion_hops */
u8 **blinded_onion_hops(const tal_t *ctx UNNEEDED, u8 **blinded_onion_hops(const tal_t *ctx UNNEEDED,
struct amount_msat final_amount UNNEEDED, struct amount_msat final_amount UNNEEDED,

View file

@ -9,6 +9,9 @@
#include <unistd.h> #include <unistd.h>
/* AUTOGENERATED MOCKS START */ /* AUTOGENERATED MOCKS START */
/* Generated stub for aux_command */
struct command *aux_command(const struct command *cmd UNNEEDED)
{ fprintf(stderr, "aux_command called!\n"); abort(); }
/* Generated stub for blinded_onion_hops */ /* Generated stub for blinded_onion_hops */
u8 **blinded_onion_hops(const tal_t *ctx UNNEEDED, u8 **blinded_onion_hops(const tal_t *ctx UNNEEDED,
struct amount_msat final_amount UNNEEDED, struct amount_msat final_amount UNNEEDED,