offers: remove 'send-invoice' offers support.

This has radically changed in the spec, so remove it now, and we'll
reintroduce / rewrite it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-11-09 13:02:00 +10:30
committed by Christian Decker
parent 3afa5077fe
commit 846a520bc2
7 changed files with 3 additions and 998 deletions

View File

@@ -751,32 +751,6 @@ static struct command_result *send_message(struct command *cmd,
return make_reply_path(cmd, sending);
}
/* We've received neither a reply nor a payment; return failure. */
static void timeout_sent_inv(struct sent *sent)
{
struct json_out *details = json_out_new(sent);
json_out_start(details, NULL, '{');
json_out_addstr(details, "invstring", invoice_encode(tmpctx, sent->inv));
json_out_end(details, '}');
/* This will free sent! */
discard_result(command_done_err(sent->cmd, OFFER_TIMEOUT,
"Failed: timeout waiting for response",
details));
}
static struct command_result *prepare_inv_timeout(struct command *cmd,
const char *buf UNUSED,
const jsmntok_t *result UNUSED,
struct sent *sent)
{
tal_steal(cmd, plugin_timer(cmd->plugin,
time_from_sec(sent->wait_timeout),
timeout_sent_inv, sent));
return sendonionmsg_done(cmd, buf, result, sent);
}
/* We've connected (if we tried), so send the invreq. */
static struct command_result *
sendinvreq_after_connect(struct command *cmd,
@@ -1276,354 +1250,6 @@ static struct command_result *invoice_payment(struct command *cmd,
return command_hook_success(cmd);
}
/* We've connected (if we tried), so send the invoice. */
static struct command_result *
sendinvoice_after_connect(struct command *cmd,
const char *buf UNUSED,
const jsmntok_t *result UNUSED,
struct sent *sent)
{
struct tlv_onionmsg_tlv *payload = tlv_onionmsg_tlv_new(sent);
payload->invoice = tal_arr(payload, u8, 0);
towire_tlv_invoice(&payload->invoice, sent->inv);
return send_message(cmd, sent, payload, prepare_inv_timeout);
}
static struct command_result *createinvoice_done(struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct sent *sent)
{
const jsmntok_t *invtok = json_get_member(buf, result, "bolt12");
char *fail;
/* Replace invoice with signed one */
tal_free(sent->inv);
sent->inv = invoice_decode(sent,
buf + invtok->start,
invtok->end - invtok->start,
plugin_feature_set(cmd->plugin),
chainparams,
&fail);
if (!sent->inv) {
plugin_log(cmd->plugin, LOG_BROKEN,
"Bad createinvoice %.*s: %s",
json_tok_full_len(invtok),
json_tok_full(buf, invtok),
fail);
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Bad createinvoice response %s", fail);
}
sent->path = path_to_node(sent, cmd->plugin,
sent->offer->node_id);
if (!sent->path)
return connect_direct(cmd, sent->offer->node_id,
sendinvoice_after_connect, sent);
return sendinvoice_after_connect(cmd, NULL, NULL, sent);
}
static struct command_result *sign_invoice(struct command *cmd,
struct sent *sent)
{
struct out_req *req;
/* Get invoice signature and put in db so we can receive payment */
req = jsonrpc_request_start(cmd->plugin, cmd, "createinvoice",
&createinvoice_done,
&forward_error,
sent);
json_add_string(req->js, "invstring", invoice_encode(tmpctx, sent->inv));
json_add_preimage(req->js, "preimage", &sent->inv_preimage);
json_add_escaped_string(req->js, "label", sent->inv_label);
return send_outreq(cmd->plugin, req);
}
static bool json_to_bip340sig(const char *buffer, const jsmntok_t *tok,
struct bip340sig *sig)
{
return hex_decode(buffer + tok->start, tok->end - tok->start,
sig->u8, sizeof(sig->u8));
}
static struct command_result *payersign_done(struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct sent *sent)
{
const jsmntok_t *sig;
sent->inv->refund_signature = tal(sent->inv, struct bip340sig);
sig = json_get_member(buf, result, "signature");
json_to_bip340sig(buf, sig, sent->inv->refund_signature);
return sign_invoice(cmd, sent);
}
/* They're offering a refund, so we need to sign with same key as used
* in initial payment. */
static struct command_result *listsendpays_done(struct command *cmd,
const char *buf,
const jsmntok_t *result,
struct sent *sent)
{
const jsmntok_t *t, *arr = json_get_member(buf, result, "payments");
size_t i;
const u8 *public_tweak = NULL, *p;
u8 *msg;
size_t len;
struct sha256 merkle;
struct out_req *req;
/* Linearize populates ->fields */
msg = tal_arr(tmpctx, u8, 0);
towire_tlv_invoice(&msg, sent->inv);
p = msg;
len = tal_bytelen(msg);
sent->inv = fromwire_tlv_invoice(cmd, &p, &len);
if (!sent->inv)
plugin_err(cmd->plugin,
"Could not remarshall %s", tal_hex(tmpctx, msg));
merkle_tlv(sent->inv->fields, &merkle);
json_for_each_arr(i, t, arr) {
const jsmntok_t *b12tok;
struct tlv_invoice *inv;
char *fail;
b12tok = json_get_member(buf, t, "bolt12");
if (!b12tok) {
/* This could happen if they try to refund a bolt11 */
plugin_log(cmd->plugin, LOG_UNUSUAL,
"Not bolt12 string in %.*s?",
json_tok_full_len(t),
json_tok_full(buf, t));
continue;
}
inv = invoice_decode(tmpctx, buf + b12tok->start,
b12tok->end - b12tok->start,
plugin_feature_set(cmd->plugin),
chainparams,
&fail);
if (!inv) {
plugin_log(cmd->plugin, LOG_BROKEN,
"Bad bolt12 string in %.*s?",
json_tok_full_len(t),
json_tok_full(buf, t));
continue;
}
public_tweak = inv->payer_info;
break;
}
if (!public_tweak)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Cannot find invoice %s for refund",
type_to_string(tmpctx, struct sha256,
sent->offer->refund_for));
/* BOLT-offers #12:
* - MUST set `refund_signature` to the signature of the
* `refunded_payment_hash` using prefix `refund_signature` and the
* `payer_key` from the to-be-refunded invoice.
*/
req = jsonrpc_request_start(cmd->plugin, cmd, "payersign",
&payersign_done,
&forward_error,
sent);
json_add_string(req->js, "messagename", "invoice");
json_add_string(req->js, "fieldname", "refund_signature");
json_add_sha256(req->js, "merkle", &merkle);
json_add_hex_talarr(req->js, "tweak", public_tweak);
return send_outreq(cmd->plugin, req);
}
static struct command_result *json_sendinvoice(struct command *cmd,
const char *buffer,
const jsmntok_t *params)
{
struct amount_msat *msat;
struct out_req *req;
u32 *timeout;
struct sent *sent = tal(cmd, struct sent);
sent->inv = tlv_invoice_new(cmd);
sent->invreq = NULL;
sent->cmd = cmd;
/* FIXME: Support recurring send_invoice offers? */
if (!param(cmd, buffer, params,
p_req("offer", param_offer, &sent->offer),
p_req("label", param_label, &sent->inv_label),
p_opt("amount_msat|msatoshi", param_msat, &msat),
p_opt_def("timeout", param_number, &timeout, 90),
p_opt("quantity", param_u64, &sent->inv->quantity),
NULL))
return command_param_failed();
/* This is how long we'll wait for a reply for. */
sent->wait_timeout = *timeout;
/* Check they are really trying to send us money. */
if (!sent->offer->send_invoice)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Offer wants an invoice_request, not invoice");
/* If they don't tell us how much, base it on offer. */
if (!msat) {
if (sent->offer->currency)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Offer in different currency: need amount");
if (!sent->offer->amount)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Offer did not specify: need amount");
sent->inv->amount = tal_dup(sent->inv, u64, sent->offer->amount);
if (sent->inv->quantity)
*sent->inv->amount *= *sent->inv->quantity;
} else
sent->inv->amount = tal_dup(sent->inv, u64,
&msat->millisatoshis); /* Raw: tlv */
/* FIXME: Support blinded paths, in which case use fake nodeid */
/* BOLT-offers #12:
* - otherwise (responding to a `send_invoice` offer):
* - MUST set `node_id` to the id of the node to send payment to.
* - MUST set `description` the same as the offer.
*/
sent->inv->node_id = tal(sent->inv, struct pubkey);
sent->inv->node_id->pubkey = local_id.pubkey;
sent->inv->description
= tal_dup_talarr(sent->inv, char, sent->offer->description);
/* BOLT-offers #12:
* - MUST set (or not set) `send_invoice` the same as the offer.
*/
sent->inv->send_invoice = tal(sent->inv, struct tlv_invoice_send_invoice);
/* BOLT-offers #12:
* - MUST set `offer_id` to the id of the offer.
*/
sent->inv->offer_id = tal(sent->inv, struct sha256);
merkle_tlv(sent->offer->fields, sent->inv->offer_id);
/* BOLT-offers #12:
* - SHOULD not respond to an offer if the current time is after
* `absolute_expiry`.
*/
if (sent->offer->absolute_expiry
&& time_now().ts.tv_sec > *sent->offer->absolute_expiry)
return command_fail(cmd, OFFER_EXPIRED, "Offer expired");
/* BOLT-offers #12:
* - otherwise (responding to a `send_invoice` offer):
*...
* - if the offer had a `quantity_min` or `quantity_max` field:
* - MUST set `quantity`
* - MUST set it within that (inclusive) range.
* - otherwise:
* - MUST NOT set `quantity`
*/
if (sent->offer->quantity_min || sent->offer->quantity_max) {
if (!sent->inv->quantity)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"quantity parameter required");
if (sent->offer->quantity_min
&& *sent->inv->quantity < *sent->offer->quantity_min)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"quantity must be >= %"PRIu64,
*sent->offer->quantity_min);
if (sent->offer->quantity_max
&& *sent->inv->quantity > *sent->offer->quantity_max)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"quantity must be <= %"PRIu64,
*sent->offer->quantity_max);
} else {
if (sent->inv->quantity)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"quantity parameter unnecessary");
}
/* BOLT-offers #12:
* - MUST set `created_at` to the number of seconds since Midnight 1
* January 1970, UTC when the offer was created.
*/
sent->inv->created_at = tal(sent->inv, u64);
*sent->inv->created_at = time_now().ts.tv_sec;
/* BOLT-offers #12:
* - if the expiry for accepting payment is not 7200 seconds after
* `created_at`:
* - MUST set `relative_expiry` `seconds_from_creation` to the number
* of seconds after `created_at` that payment of this invoice should
* not be attempted.
*/
if (sent->wait_timeout != 7200) {
sent->inv->relative_expiry = tal(sent->inv, u32);
*sent->inv->relative_expiry = sent->wait_timeout;
}
/* BOLT-offers #12:
* - MUST set `payer_key` to the `node_id` of the offer.
*/
sent->inv->payer_key = sent->offer->node_id;
/* FIXME: recurrence? */
if (sent->offer->recurrence)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"FIXME: handle recurring send_invoice offer!");
/* BOLT-offers #12:
*
* - if the chain for the invoice is not solely bitcoin:
* - MUST specify `chains` the offer is valid for.
* - otherwise:
* - the bitcoin chain is implied as the first and only entry.
*/
if (!streq(chainparams->network_name, "bitcoin")) {
sent->inv->chain = tal_dup(sent->inv, struct bitcoin_blkid,
&chainparams->genesis_blockhash);
}
sent->inv->features
= plugin_feature_set(cmd->plugin)->bits[BOLT11_FEATURE];
randombytes_buf(&sent->inv_preimage, sizeof(sent->inv_preimage));
sent->inv->payment_hash = tal(sent->inv, struct sha256);
sha256(sent->inv->payment_hash,
&sent->inv_preimage, sizeof(sent->inv_preimage));
/* BOLT-offers #12:
* - MUST set (or not set) `refund_for` exactly as the offer did.
* - if it sets `refund_for`:
* - MUST set `refund_signature` to the signature of the
* `refunded_payment_hash` using prefix `refund_signature` and
* the `payer_key` from the to-be-refunded invoice.
* - otherwise:
* - MUST NOT set `refund_signature`
*/
if (sent->offer->refund_for) {
sent->inv->refund_for = sent->offer->refund_for;
/* Find original payment invoice */
req = jsonrpc_request_start(cmd->plugin, cmd, "listsendpays",
&listsendpays_done,
&forward_error,
sent);
json_add_sha256(req->js, "payment_hash",
sent->offer->refund_for);
return send_outreq(cmd->plugin, req);
}
return sign_invoice(cmd, sent);
}
#if DEVELOPER
static struct command_result *param_invreq(struct command *cmd,
const char *name,
@@ -1682,13 +1308,6 @@ static const struct plugin_command commands[] = {
NULL,
json_fetchinvoice,
},
{
"sendinvoice",
"payment",
"Request remote node for to pay this send_invoice {offer}, with {amount}, {quanitity}, {recurrence_counter}, {recurrence_start} and {recurrence_label} iff required.",
NULL,
json_sendinvoice,
},
#if DEVELOPER
{
"dev-rawrequest",