mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-07 16:14:26 +01:00
createinvoice: make a minimal blinded "path" in bolt12 invoice if none presented.
The "path" is just a message to ourselves. This meets the minimal requirement for bolt12 invoices: that there be a blinded path (at least so we can use the path_id inside in place of "payment_secret"). We expose the method to make this path_id to a common routine: offers will need this for generating more sophisticated paths. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
a5471a405b
commit
595fbd2a19
@@ -99,6 +99,7 @@ LIGHTNINGD_COMMON_OBJS := \
|
||||
common/htlc_state.o \
|
||||
common/htlc_trim.o \
|
||||
common/htlc_wire.o \
|
||||
common/invoice_path_id.o \
|
||||
common/key_derive.o \
|
||||
common/keyset.o \
|
||||
common/json_filter.o \
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <common/errcode.h>
|
||||
#include <common/hsm_encryption.h>
|
||||
#include <common/hsm_version.h>
|
||||
#include <common/invoice_path_id.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_param.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
@@ -140,6 +141,17 @@ struct ext_key *hsm_init(struct lightningd *ld)
|
||||
"HSM gave invalid v1 bolt12_base");
|
||||
}
|
||||
|
||||
/* This is equivalent to makesecret("bolt12-invoice-base") */
|
||||
msg = towire_hsmd_derive_secret(NULL, tal_dup_arr(tmpctx, u8,
|
||||
(const u8 *)INVOICE_PATH_BASE_STRING,
|
||||
strlen(INVOICE_PATH_BASE_STRING), 0));
|
||||
if (!wire_sync_write(ld->hsm_fd, take(msg)))
|
||||
err(EXITCODE_HSM_GENERIC_ERROR, "Writing derive_secret msg to hsm");
|
||||
|
||||
msg = wire_sync_read(tmpctx, ld->hsm_fd);
|
||||
if (!fromwire_hsmd_derive_secret_reply(msg, &ld->invoicesecret_base))
|
||||
err(EXITCODE_HSM_GENERIC_ERROR, "Bad derive_secret_reply");
|
||||
|
||||
return bip32_base;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
#include <ccan/json_escape/json_escape.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/blindedpath.h>
|
||||
#include <common/bolt11_json.h>
|
||||
#include <common/bolt12_merkle.h>
|
||||
#include <common/configdir.h>
|
||||
#include <common/invoice_path_id.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_param.h>
|
||||
#include <common/overflows.h>
|
||||
@@ -1641,6 +1643,69 @@ static struct command_result *fail_exists(struct command *cmd,
|
||||
return command_failed(cmd, data);
|
||||
}
|
||||
|
||||
/* This is only if we're a public node; otherwise, the offers plugin
|
||||
* will have populated a real blinded path */
|
||||
static struct tlv_invoice *add_stub_blindedpath(const tal_t *ctx,
|
||||
struct lightningd *ld,
|
||||
struct tlv_invoice *inv STEALS)
|
||||
{
|
||||
struct blinded_path *path;
|
||||
struct privkey blinding;
|
||||
struct tlv_encrypted_data_tlv *tlv;
|
||||
u8 *wire;
|
||||
size_t dlen;
|
||||
|
||||
path = tal(NULL, struct blinded_path);
|
||||
if (!pubkey_from_node_id(&path->first_node_id, &ld->id))
|
||||
abort();
|
||||
randombytes_buf(&blinding, sizeof(blinding));
|
||||
if (!pubkey_from_privkey(&blinding, &path->blinding))
|
||||
abort();
|
||||
path->path = tal_arr(path, struct onionmsg_hop *, 1);
|
||||
path->path[0] = tal(path->path, struct onionmsg_hop);
|
||||
|
||||
/* A message in a bottle to ourselves: match it with
|
||||
* the invoice: we assume the payment_hash is unique! */
|
||||
tlv = tlv_encrypted_data_tlv_new(tmpctx);
|
||||
tlv->path_id = invoice_path_id(inv,
|
||||
&ld->invoicesecret_base,
|
||||
inv->payment_hash);
|
||||
|
||||
path->path[0]->encrypted_recipient_data
|
||||
= encrypt_tlv_encrypted_data(path->path[0],
|
||||
&blinding,
|
||||
&path->first_node_id,
|
||||
tlv,
|
||||
NULL,
|
||||
&path->path[0]->blinded_node_id);
|
||||
|
||||
inv->paths = tal_arr(inv, struct blinded_path *, 1);
|
||||
inv->paths[0] = tal_steal(inv->paths, path);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST include `invoice_paths` containing one or more paths to the node.
|
||||
* - MUST specify `invoice_paths` in order of most-preferred to least-preferred if it has a preference.
|
||||
* - MUST include `invoice_blindedpay` with exactly one `blinded_payinfo` for each `blinded_path` in `paths`, in order.
|
||||
*/
|
||||
inv->blindedpay = tal_arr(inv, struct blinded_payinfo *, 1);
|
||||
inv->blindedpay[0] = tal(inv->blindedpay, struct blinded_payinfo);
|
||||
inv->blindedpay[0]->fee_base_msat = 0;
|
||||
inv->blindedpay[0]->fee_proportional_millionths = 0;
|
||||
inv->blindedpay[0]->cltv_expiry_delta = ld->config.cltv_final;
|
||||
inv->blindedpay[0]->htlc_minimum_msat = AMOUNT_MSAT(0);
|
||||
inv->blindedpay[0]->htlc_maximum_msat = AMOUNT_MSAT(21000000 * MSAT_PER_BTC);
|
||||
inv->blindedpay[0]->features = NULL;
|
||||
|
||||
/* But we need to update ->fields, so re-linearize */
|
||||
wire = tal_arr(tmpctx, u8, 0);
|
||||
towire_tlv_invoice(&wire, inv);
|
||||
tal_free(inv);
|
||||
|
||||
dlen = tal_bytelen(wire);
|
||||
return fromwire_tlv_invoice(ctx,
|
||||
cast_const2(const u8 **, &wire), &dlen);
|
||||
}
|
||||
|
||||
static struct command_result *json_createinvoice(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
@@ -1717,6 +1782,12 @@ static struct command_result *json_createinvoice(struct command *cmd,
|
||||
"Unparsable invoice '%s': %s",
|
||||
invstring, fail);
|
||||
|
||||
/* If they don't create a blinded path, add a simple one so we
|
||||
* can recognize payments (bolt12 doesn't use
|
||||
* payment_secret) */
|
||||
if (!inv->paths)
|
||||
inv = add_stub_blindedpath(cmd, cmd->ld, inv);
|
||||
|
||||
if (inv->signature)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"invoice already signed");
|
||||
|
||||
@@ -124,6 +124,9 @@ struct lightningd {
|
||||
/* The public base for our payer_id keys */
|
||||
struct pubkey bolt12_base;
|
||||
|
||||
/* Secret base for our invoices */
|
||||
struct secret invoicesecret_base;
|
||||
|
||||
/* Feature set we offer. */
|
||||
struct feature_set *our_features;
|
||||
|
||||
|
||||
@@ -182,6 +182,15 @@ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED,
|
||||
const struct chainparams *chainparams UNNEEDED,
|
||||
const u8 *scriptPubkey UNNEEDED)
|
||||
{ fprintf(stderr, "encode_scriptpubkey_to_addr called!\n"); abort(); }
|
||||
/* Generated stub for encrypt_tlv_encrypted_data */
|
||||
u8 *encrypt_tlv_encrypted_data(const tal_t *ctx UNNEEDED,
|
||||
const struct privkey *blinding UNNEEDED,
|
||||
const struct pubkey *node UNNEEDED,
|
||||
const struct tlv_encrypted_data_tlv *tlv UNNEEDED,
|
||||
struct privkey *next_blinding UNNEEDED,
|
||||
struct pubkey *node_alias)
|
||||
|
||||
{ fprintf(stderr, "encrypt_tlv_encrypted_data called!\n"); abort(); }
|
||||
/* Generated stub for failmsg_incorrect_or_unknown_ */
|
||||
const u8 *failmsg_incorrect_or_unknown_(const tal_t *ctx UNNEEDED,
|
||||
struct lightningd *ld UNNEEDED,
|
||||
@@ -306,6 +315,11 @@ struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx UNNEEDED,
|
||||
/* Generated stub for invoice_encode */
|
||||
char *invoice_encode(const tal_t *ctx UNNEEDED, const struct tlv_invoice *bolt12_tlv UNNEEDED)
|
||||
{ fprintf(stderr, "invoice_encode called!\n"); abort(); }
|
||||
/* Generated stub for invoice_path_id */
|
||||
u8 *invoice_path_id(const tal_t *ctx UNNEEDED,
|
||||
const struct secret *base_secret UNNEEDED,
|
||||
const struct sha256 *payment_hash UNNEEDED)
|
||||
{ fprintf(stderr, "invoice_path_id called!\n"); abort(); }
|
||||
/* Generated stub for json_add_address */
|
||||
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
||||
const struct wireaddr *addr UNNEEDED)
|
||||
@@ -687,6 +701,9 @@ bool plugin_hook_call_(struct lightningd *ld UNNEEDED,
|
||||
void plugin_request_send(struct plugin *plugin UNNEEDED,
|
||||
struct jsonrpc_request *req TAKES UNNEEDED)
|
||||
{ fprintf(stderr, "plugin_request_send called!\n"); abort(); }
|
||||
/* Generated stub for pubkey_from_node_id */
|
||||
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
|
||||
{ fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); }
|
||||
/* Generated stub for report_subd_memleak */
|
||||
void report_subd_memleak(struct leak_detect *leak_detect UNNEEDED, struct subd *leaker UNNEEDED)
|
||||
{ fprintf(stderr, "report_subd_memleak called!\n"); abort(); }
|
||||
|
||||
Reference in New Issue
Block a user