keysend: move preapprovekeysend outside pay loop, so it can be called by check.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: JSON-RPC: `check` `keysend` now checks with HSM that it will approve it.
This commit is contained in:
Rusty Russell 2024-04-04 14:06:14 +10:30
parent c7339ea310
commit e1034eec43

View file

@ -109,59 +109,6 @@ REGISTER_PAYMENT_MODIFIER(keysend, struct keysend_data *, keysend_init,
* End of keysend modifier
*****************************************************************************/
/*****************************************************************************
* check_preapprovekeysend
*
* @desc submit the keysend to the HSM for approval, fail the payment if not approved.
*
* This paymod checks the keysend for approval with the HSM, which might:
* - check with the user for specific approval
* - enforce velocity controls
* - automatically approve the keysend (default)
*/
static struct command_result *
check_preapprovekeysend_allow(struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct payment *p)
{
/* On success, an empty object is returned. */
payment_continue(p);
return command_still_pending(cmd);
}
static struct command_result *preapprovekeysend_rpc_failure(struct command *cmd,
const char *buffer,
const jsmntok_t *toks,
struct payment *p)
{
payment_abort(p,
"Failing payment due to a failed RPC call: %.*s",
toks->end - toks->start, buffer + toks->start);
return command_still_pending(cmd);
}
static void check_preapprovekeysend_start(void *d UNUSED, struct payment *p)
{
/* Ask the HSM if the keysend is OK to pay */
struct out_req *req;
req = jsonrpc_request_start(p->plugin, NULL, "preapprovekeysend",
&check_preapprovekeysend_allow,
&preapprovekeysend_rpc_failure, p);
json_add_node_id(req->js, "destination", p->destination);
json_add_sha256(req->js, "payment_hash", p->payment_hash);
json_add_amount_msat(req->js, "amount_msat", p->our_amount);
(void) send_outreq(p->plugin, req);
}
REGISTER_PAYMENT_MODIFIER(check_preapprovekeysend, void *, NULL,
check_preapprovekeysend_start);
/*
* End of check_preapprovekeysend modifier
*****************************************************************************/
/* Deprecated: comma-separated string containing integers */
static bool json_accumulate_uintarr(const char *buffer,
const jsmntok_t *tok,
@ -227,7 +174,6 @@ static const char *init(struct plugin *p, const char *buf UNUSED,
struct payment_modifier *pay_mods[] = {
&keysend_pay_mod,
&check_preapprovekeysend_pay_mod,
&local_channel_hints_pay_mod,
&directpay_pay_mod,
&shadowroute_pay_mod,
@ -238,6 +184,23 @@ struct payment_modifier *pay_mods[] = {
NULL,
};
static struct command_result *
preapprovekeysend_succeed(struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct payment *p)
{
/* Now we can conclude `check` command */
if (command_check_only(cmd)) {
return command_check_done(cmd);
}
/* We're keeping this around now */
tal_steal(cmd->plugin, notleak(p));
payment_start(p);
return command_still_pending(cmd);
}
static struct command_result *json_keysend(struct command *cmd, const char *buf,
const jsmntok_t *params)
{
@ -251,8 +214,9 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
struct route_info **hints;
struct tlv_field *extra_fields;
bool *dev_use_shadow;
struct out_req *req;
if (!param(cmd, buf, params,
if (!param_check(cmd, buf, params,
p_req("destination", param_node_id, &destination),
p_req("amount_msat", param_msat, &msat),
p_opt("label", param_string, &label),
@ -313,10 +277,22 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
payment_mod_exemptfee_get_data(p)->amount = *exemptfee;
payment_mod_shadowroute_get_data(p)->use_shadow = *dev_use_shadow;
p->label = tal_steal(p, label);
payment_start(p);
/* We're keeping this around now */
tal_steal(cmd->plugin, notleak(p));
return command_still_pending(cmd);
/* We do pre-approval immediately (note: even if command_check_only!) */
if (command_check_only(cmd)) {
req = jsonrpc_request_start(p->plugin, cmd, "check",
preapprovekeysend_succeed,
forward_error, p);
json_add_string(req->js, "command_to_check", "preapprovekeysend");
} else {
req = jsonrpc_request_start(p->plugin, cmd, "preapprovekeysend",
preapprovekeysend_succeed,
forward_error, p);
}
json_add_node_id(req->js, "destination", p->destination);
json_add_sha256(req->js, "payment_hash", p->payment_hash);
json_add_amount_msat(req->js, "amount_msat", p->our_amount);
return send_outreq(cmd->plugin, req);
}
static const struct plugin_command commands[] = {