mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-23 15:04:19 +01:00
libplugin/pay: allow shortcut for self-pay.
This is the simplest solution, not the best, but there's significant risk in try to remove the "we have a path" assumption in the code pay code. Includes removing a `tal_steal` which was incorrect: the buffer has the same lifetime as the plugin, so if we steal it then things get messy when we free the struct payment. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Added: Plugins: `pay` will now pay your own invoices if you try.
This commit is contained in:
@@ -1933,6 +1933,45 @@ static void payment_notify_failure(struct payment *p, const char *error_message)
|
||||
plugin_notification_end(p->plugin, n);
|
||||
}
|
||||
|
||||
/* Code shared by selfpay fast-path: populate JSON output for successful
|
||||
* payment, and send pay_success notification. */
|
||||
void json_add_payment_success(struct json_stream *js,
|
||||
struct payment *p,
|
||||
const struct preimage *preimage,
|
||||
const struct payment_tree_result *result)
|
||||
{
|
||||
struct json_stream *n;
|
||||
struct payment *root = payment_root(p);
|
||||
|
||||
json_add_node_id(js, "destination", p->destination);
|
||||
json_add_sha256(js, "payment_hash", p->payment_hash);
|
||||
json_add_timeabs(js, "created_at", p->start_time);
|
||||
if (result)
|
||||
json_add_num(js, "parts", result->attempts);
|
||||
else
|
||||
json_add_num(js, "parts", 1);
|
||||
|
||||
json_add_amount_msat(js, "amount_msat", p->amount);
|
||||
if (result)
|
||||
json_add_amount_msat(js, "amount_sent_msat", result->sent);
|
||||
else
|
||||
json_add_amount_msat(js, "amount_sent_msat", p->amount);
|
||||
|
||||
if (result && result->leafstates != PAYMENT_STEP_SUCCESS)
|
||||
json_add_string(js, "warning_partial_completion",
|
||||
"Some parts of the payment are not yet "
|
||||
"completed, but we have the confirmation "
|
||||
"from the recipient.");
|
||||
json_add_preimage(js, "payment_preimage", preimage);
|
||||
json_add_string(js, "status", "complete");
|
||||
|
||||
n = plugin_notification_start(p->plugin, "pay_success");
|
||||
json_add_sha256(n, "payment_hash", p->payment_hash);
|
||||
if (root->invstring != NULL)
|
||||
json_add_string(n, "bolt11", root->invstring);
|
||||
plugin_notification_end(p->plugin, n);
|
||||
}
|
||||
|
||||
/* This function is called whenever a payment ends up in a final state, or all
|
||||
* 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
|
||||
@@ -1943,8 +1982,6 @@ static void payment_finished(struct payment *p)
|
||||
struct json_stream *ret;
|
||||
struct command *cmd = p->cmd;
|
||||
const char *msg;
|
||||
struct json_stream *n;
|
||||
struct payment *root = payment_root(p);
|
||||
|
||||
/* Either none of the leaf attempts succeeded yet, or we have a
|
||||
* preimage. */
|
||||
@@ -1969,30 +2006,8 @@ static void payment_finished(struct payment *p)
|
||||
p->on_payment_success(p);
|
||||
|
||||
ret = jsonrpc_stream_success(cmd);
|
||||
json_add_node_id(ret, "destination", p->destination);
|
||||
json_add_sha256(ret, "payment_hash", p->payment_hash);
|
||||
json_add_timeabs(ret, "created_at", p->start_time);
|
||||
json_add_num(ret, "parts", result.attempts);
|
||||
|
||||
json_add_amount_msat(ret, "amount_msat", p->amount);
|
||||
json_add_amount_msat(ret, "amount_sent_msat",
|
||||
result.sent);
|
||||
|
||||
if (result.leafstates != PAYMENT_STEP_SUCCESS)
|
||||
json_add_string(
|
||||
ret, "warning_partial_completion",
|
||||
"Some parts of the payment are not yet "
|
||||
"completed, but we have the confirmation "
|
||||
"from the recipient.");
|
||||
json_add_preimage(ret, "payment_preimage", result.preimage);
|
||||
|
||||
json_add_string(ret, "status", "complete");
|
||||
|
||||
n = plugin_notification_start(p->plugin, "pay_success");
|
||||
json_add_sha256(n, "payment_hash", p->payment_hash);
|
||||
if (root->invstring != NULL)
|
||||
json_add_string(n, "bolt11", root->invstring);
|
||||
plugin_notification_end(p->plugin, n);
|
||||
json_add_payment_success(ret, p, result.preimage,
|
||||
&result);
|
||||
|
||||
if (command_finished(cmd, ret)) {/* Ignore result. */}
|
||||
p->cmd = NULL;
|
||||
|
||||
@@ -484,6 +484,12 @@ void payment_abort(struct payment *p, const char *fmt, ...) PRINTF_FMT(2,3);
|
||||
struct payment *payment_root(struct payment *p);
|
||||
struct payment_tree_result payment_collect_result(struct payment *p);
|
||||
|
||||
/* Add fields for successful payment: result can be NULL for selfpay */
|
||||
void json_add_payment_success(struct json_stream *js,
|
||||
struct payment *p,
|
||||
const struct preimage *preimage,
|
||||
const struct payment_tree_result *result);
|
||||
|
||||
/* For special effects, like inspecting your own routes. */
|
||||
struct gossmap *get_gossmap(struct plugin *plugin);
|
||||
|
||||
|
||||
@@ -799,6 +799,55 @@ static void on_payment_failure(struct payment *payment)
|
||||
}
|
||||
}
|
||||
|
||||
static struct command_result *selfpay_success(struct command *cmd,
|
||||
const char *buf,
|
||||
const jsmntok_t *result,
|
||||
struct payment *p)
|
||||
{
|
||||
struct json_stream *ret = jsonrpc_stream_success(cmd);
|
||||
struct preimage preimage;
|
||||
const char *err;
|
||||
|
||||
err = json_scan(tmpctx, buf, result,
|
||||
"{payment_preimage:%}",
|
||||
JSON_SCAN(json_to_preimage, &preimage));
|
||||
if (err)
|
||||
plugin_err(p->plugin,
|
||||
"selfpay didn't have payment_preimage? %.*s",
|
||||
json_tok_full_len(result),
|
||||
json_tok_full(buf, result));
|
||||
json_add_payment_success(ret, p, &preimage, NULL);
|
||||
return command_finished(cmd, ret);
|
||||
}
|
||||
|
||||
static struct command_result *selfpay(struct command *cmd, struct payment *p)
|
||||
{
|
||||
struct out_req *req;
|
||||
|
||||
/* This "struct payment" simply gets freed once command is done. */
|
||||
tal_steal(cmd, p);
|
||||
|
||||
req = jsonrpc_request_start(cmd->plugin, cmd, "sendpay",
|
||||
selfpay_success,
|
||||
forward_error, p);
|
||||
/* Empty route means "to-self" */
|
||||
json_array_start(req->js, "route");
|
||||
json_array_end(req->js);
|
||||
json_add_sha256(req->js, "payment_hash", p->payment_hash);
|
||||
if (p->label)
|
||||
json_add_string(req->js, "label", p->label);
|
||||
json_add_amount_msat(req->js, "amount_msat", p->amount);
|
||||
json_add_string(req->js, "bolt11", p->invstring);
|
||||
if (p->payment_secret)
|
||||
json_add_secret(req->js, "payment_secret", p->payment_secret);
|
||||
json_add_u64(req->js, "groupid", p->groupid);
|
||||
if (p->payment_metadata)
|
||||
json_add_hex_talarr(req->js, "payment_metadata", p->payment_metadata);
|
||||
if (p->description)
|
||||
json_add_string(req->js, "description", p->description);
|
||||
return send_outreq(cmd->plugin, req);
|
||||
}
|
||||
|
||||
/* We are interested in any prior attempts to pay this payment_hash /
|
||||
* invoice so we can set the `groupid` correctly and ensure we don't
|
||||
* already have a pending payment running. We also collect the summary
|
||||
@@ -916,6 +965,11 @@ payment_listsendpays_previous(struct command *cmd, const char *buf,
|
||||
p->groupid = last_group + 1;
|
||||
p->on_payment_success = on_payment_success;
|
||||
p->on_payment_failure = on_payment_failure;
|
||||
|
||||
/* Bypass everything if we're doing (synchronous) self-pay */
|
||||
if (node_id_eq(&my_id, p->destination))
|
||||
return selfpay(cmd, p);
|
||||
|
||||
payment_start(p);
|
||||
return command_still_pending(cmd);
|
||||
}
|
||||
@@ -1166,13 +1220,8 @@ static struct command_result *json_pay(struct command *cmd,
|
||||
"This payment blinded path fee overflows!");
|
||||
}
|
||||
|
||||
if (node_id_eq(&my_id, p->destination))
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"This payment is destined for ourselves. "
|
||||
"Self-payments are not supported");
|
||||
|
||||
p->local_id = &my_id;
|
||||
p->json_buffer = tal_steal(p, buf);
|
||||
p->json_buffer = buf;
|
||||
p->json_toks = params;
|
||||
p->why = "Initial attempt";
|
||||
p->constraints.cltv_budget = *maxdelay;
|
||||
|
||||
Reference in New Issue
Block a user