lightningd: make plugins set metadata for invoice requests.

They can do it now: before it would have been awkward to look up previous
payments to match it up for recurring offers (which need to use the same
key, hence the same invreq_metadata).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-08-01 09:33:36 +09:30
parent 401d85fce0
commit fa33a2fece
5 changed files with 58 additions and 33 deletions

View File

@ -15,7 +15,6 @@
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
#include <secp256k1_schnorrsig.h>
#include <sodium/randombytes.h>
static void json_populate_offer(struct json_stream *response,
const struct sha256 *offer_id,
@ -415,33 +414,20 @@ static struct command_result *json_createinvoicerequest(struct command *cmd,
else
status = OFFER_MULTIPLE_USE_UNUSED;
if (!invreq->invreq_metadata)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"invoice_request has no invreq_metadata");
if (invreq->invreq_payer_id)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"invoice_request already has invreq_payer_id");
/* If it's a recurring payment, we look for previous to copy basetime */
if (invreq->invreq_recurrence_counter) {
if (!label)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Need payment label for recurring payments");
/* Derive metadata (and thus temp key, if any) from offer data and label */
if (!invreq->invreq_metadata) {
struct sha256 offer_id, tweak;
u8 *tweak_input;
/* Use "offer_id || label" as tweak input */
invreq_offer_id(invreq, &offer_id);
tweak_input = tal_arr(tmpctx, u8,
sizeof(offer_id) + tal_bytelen(invreq->invreq_metadata));
memcpy(tweak_input, &offer_id, sizeof(offer_id));
memcpy(tweak_input + sizeof(offer_id),
invreq->invreq_metadata,
tal_bytelen(invreq->invreq_metadata));
bolt12_alias_tweak(&cmd->ld->nodealias_base,
tweak_input,
tal_bytelen(tweak_input),
&tweak);
invreq->invreq_metadata = (u8 *)tal_dup(invreq, struct sha256, &tweak);
}
if (*invreq->invreq_recurrence_counter != 0) {
struct command_result *err
= prev_payment(cmd, label, invreq,
@ -451,14 +437,6 @@ static struct command_result *json_createinvoicerequest(struct command *cmd,
}
}
/* invreq_metadata must be distinct: for non-recurring
* payments, make it random */
if (!invreq->invreq_metadata) {
invreq->invreq_metadata = tal_arr(invreq, u8, 16);
randombytes_buf(invreq->invreq_metadata,
tal_bytelen(invreq->invreq_metadata));
}
/* BOLT-offers #12:
*
* `invreq_metadata` might typically contain information about

View File

@ -7,6 +7,7 @@
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/blindedpath.h>
#include <common/bolt12_id.h>
#include <common/bolt12_merkle.h>
#include <common/dijkstra.h>
#include <common/gossmap.h>
@ -877,6 +878,9 @@ struct command_result *json_fetchinvoice(struct command *cmd,
* - if the offer contained `recurrence`:
*/
if (invreq->offer_recurrence) {
struct sha256 offer_id, tweak;
u8 *tweak_input;
/* BOLT-offers-recurrence #12:
* - for the initial request:
*...
@ -916,6 +920,29 @@ struct command_result *json_fetchinvoice(struct command *cmd,
if (!rec_label)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"needs recurrence_label");
/* BOLT-offers #12:
* - MUST set `invreq_metadata` to an unpredictable series of
* bytes.
*/
/* Derive metadata (and thus temp key) from offer data and label
* as payer_id must be same for all recurring payments. */
/* Use "offer_id || label" as tweak input */
invreq_offer_id(invreq, &offer_id);
tweak_input = tal_arr(tmpctx, u8,
sizeof(offer_id) + strlen(rec_label));
memcpy(tweak_input, &offer_id, sizeof(offer_id));
memcpy(tweak_input + sizeof(offer_id),
rec_label,
strlen(rec_label));
bolt12_alias_tweak(&nodealias_base,
tweak_input,
tal_bytelen(tweak_input),
&tweak);
invreq->invreq_metadata
= (u8 *)tal_dup(invreq, struct sha256, &tweak);
} else {
/* BOLT-offers-recurrence #12:
* - otherwise:
@ -928,6 +955,14 @@ struct command_result *json_fetchinvoice(struct command *cmd,
if (invreq->invreq_recurrence_start)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"unnecessary recurrence_start");
/* BOLT-offers #12:
* - MUST set `invreq_metadata` to an unpredictable series of
* bytes.
*/
invreq->invreq_metadata = tal_arr(invreq, u8, 16);
randombytes_buf(invreq->invreq_metadata,
tal_bytelen(invreq->invreq_metadata));
}
/* BOLT-offers #12:

View File

@ -39,6 +39,7 @@ bool dev_invoice_bpath_scid;
struct short_channel_id *dev_invoice_internal_scid;
struct secret invoicesecret_base;
struct secret offerblinding_base;
struct secret nodealias_base;
static struct gossmap *global_gossmap;
static void init_gossmap(struct plugin *plugin)
@ -1389,6 +1390,11 @@ static const char *init(struct plugin *p,
"{secret:%}",
JSON_SCAN(json_to_secret, &offerblinding_base));
rpc_scan(p, "makesecret",
take(json_out_obj(NULL, "string", NODE_ALIAS_BASE_STRING)),
"{secret:%}",
JSON_SCAN(json_to_secret, &nodealias_base));
return NULL;
}

View File

@ -21,6 +21,8 @@ extern u32 blockheight;
extern struct secret invoicesecret_base;
/* Base for offers path_secrets */
extern struct secret offerblinding_base;
/* Base for node aliases for invoice requests */
extern struct secret nodealias_base;
/* --dev-invoice-bpath-scid */
extern bool dev_invoice_bpath_scid;
/* --dev-invoice-internal-scid */

View File

@ -660,17 +660,21 @@ struct command_result *json_invoicerequest(struct command *cmd,
invreq->invreq_amount
= tal_dup(invreq, u64, &msat->millisatoshis); /* Raw: wire */
/* FIXME: enable blinded paths! */
/* BOLT-offers #12:
* - MUST set `invreq_metadata` to an unpredictable series of bytes.
*/
invreq->invreq_metadata = tal_arr(invreq, u8, 16);
randombytes_buf(invreq->invreq_metadata,
tal_bytelen(invreq->invreq_metadata));
/* FIXME: enable blinded paths! */
/* BOLT-offers #12:
* - otherwise (not responding to an offer):
*...
* - MUST set `invreq_payer_id` as it would set `offer_issuer_id` for an offer.
*/
/* createinvoicerequest sets these! */
/* createinvoicerequest sets this! */
/* BOLT-offers #12:
* - if it supports bolt12 invoice request features: