mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-22 08:34:20 +01:00
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:
committed by
Christian Decker
parent
3afa5077fe
commit
846a520bc2
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user