diff --git a/Makefile b/Makefile index 01d3a83ce0c2..a3c852fee323 100644 --- a/Makefile +++ b/Makefile @@ -580,6 +580,9 @@ $(CCAN_OBJS) $(CDUMP_OBJS): $(CCAN_HEADERS) Makefile # Except for CCAN, we treat everything else as dependent on external/ bitcoin/ common/ wire/ and all generated headers, and Makefile $(ALL_OBJS): $(BITCOIN_HEADERS) $(COMMON_HEADERS) $(CCAN_HEADERS) $(WIRE_HEADERS) $(ALL_GEN_HEADERS) $(EXTERNAL_HEADERS) Makefile +# Test files can literally #include generated C files. +$(ALL_TEST_PROGRAMS:=.o): $(ALL_GEN_SOURCES) + update-ccan: mv ccan ccan.old DIR=$$(pwd)/ccan; cd ../ccan && ./tools/create-ccan-tree -a $$DIR `cd $$DIR.old/ccan && find * -name _info | sed s,/_info,, | $(SORT)` $(CCAN_NEW) diff --git a/bitcoin/pubkey.c b/bitcoin/pubkey.c index 0b731a614436..2e26259ec068 100644 --- a/bitcoin/pubkey.c +++ b/bitcoin/pubkey.c @@ -125,7 +125,7 @@ void towire_pubkey(u8 **pptr, const struct pubkey *pubkey) towire(pptr, output, outputlen); } -void fromwire_pubkey32(const u8 **cursor, size_t *max, struct pubkey32 *pubkey32) +void fromwire_point32(const u8 **cursor, size_t *max, struct point32 *point32) { u8 raw[32]; @@ -133,28 +133,28 @@ void fromwire_pubkey32(const u8 **cursor, size_t *max, struct pubkey32 *pubkey32 return; if (secp256k1_xonly_pubkey_parse(secp256k1_ctx, - &pubkey32->pubkey, + &point32->pubkey, raw) != 1) { SUPERVERBOSE("not a valid point"); fromwire_fail(cursor, max); } } -void towire_pubkey32(u8 **pptr, const struct pubkey32 *pubkey32) +void towire_point32(u8 **pptr, const struct point32 *point32) { u8 output[32]; secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, - &pubkey32->pubkey); + &point32->pubkey); towire(pptr, output, sizeof(output)); } -char *pubkey32_to_hexstr(const tal_t *ctx, const struct pubkey32 *pubkey32) +char *point32_to_hexstr(const tal_t *ctx, const struct point32 *point32) { u8 output[32]; secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, - &pubkey32->pubkey); + &point32->pubkey); return tal_hexstr(ctx, output, sizeof(output)); } -REGISTER_TYPE_TO_STRING(pubkey32, pubkey32_to_hexstr); +REGISTER_TYPE_TO_STRING(point32, point32_to_hexstr); diff --git a/bitcoin/pubkey.h b/bitcoin/pubkey.h index b24cc2aa298e..4474c91c96ef 100644 --- a/bitcoin/pubkey.h +++ b/bitcoin/pubkey.h @@ -19,12 +19,12 @@ struct pubkey { /* Define pubkey_eq (no padding) */ STRUCTEQ_DEF(pubkey, 0, pubkey.data); -struct pubkey32 { +struct point32 { /* Unpacked pubkey (as used by libsecp256k1 internally) */ secp256k1_xonly_pubkey pubkey; }; /* Define pubkey_eq (no padding) */ -STRUCTEQ_DEF(pubkey32, 0, pubkey.data); +STRUCTEQ_DEF(point32, 0, pubkey.data); /* Convert from hex string of DER (scriptPubKey from validateaddress) */ bool pubkey_from_hexstr(const char *derstr, size_t derlen, struct pubkey *key); @@ -66,9 +66,14 @@ void pubkey_to_hash160(const struct pubkey *pk, struct ripemd160 *hash); void towire_pubkey(u8 **pptr, const struct pubkey *pubkey); void fromwire_pubkey(const u8 **cursor, size_t *max, struct pubkey *pubkey); +/* FIXME: Old spec uses pubkey32 */ +#define pubkey32 point32 +#define towire_pubkey32 towire_point32 +#define fromwire_pubkey32 fromwire_point32 + /* marshal/unmarshal functions */ -void towire_pubkey32(u8 **pptr, const struct pubkey32 *pubkey); -void fromwire_pubkey32(const u8 **cursor, size_t *max, struct pubkey32 *pubkey); +void towire_point32(u8 **pptr, const struct point32 *pubkey); +void fromwire_point32(const u8 **cursor, size_t *max, struct point32 *pubkey); -char *pubkey32_to_hexstr(const tal_t *ctx, const struct pubkey32 *pubkey32); +char *point32_to_hexstr(const tal_t *ctx, const struct point32 *point32); #endif /* LIGHTNING_BITCOIN_PUBKEY_H */ diff --git a/common/bolt12.c b/common/bolt12.c index 9da10c473893..0c95c732e611 100644 --- a/common/bolt12.c +++ b/common/bolt12.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,21 @@ bool bolt12_chains_match(const struct bitcoin_blkid *chains, return false; } +bool bolt12_chain_matches(const struct bitcoin_blkid *chain, + const struct chainparams *must_be_chain, + const struct bitcoin_blkid *deprecated_chains) +{ + /* Obsolete: We used to put an array in here, but we only ever + * used a single value */ + if (deprecated_apis && !chain) + chain = deprecated_chains; + + if (!chain) + chain = &chainparams_for_network("bitcoin")->genesis_blockhash; + + return bitcoin_blkid_eq(chain, &must_be_chain->genesis_blockhash); +} + static char *check_features_and_chain(const tal_t *ctx, const struct feature_set *our_features, const struct chainparams *must_be_chain, @@ -70,7 +86,7 @@ static char *check_features_and_chain(const tal_t *ctx, bool bolt12_check_signature(const struct tlv_field *fields, const char *messagename, const char *fieldname, - const struct pubkey32 *key, + const struct point32 *key, const struct bip340sig *sig) { struct sha256 m, shash; @@ -87,7 +103,7 @@ static char *check_signature(const tal_t *ctx, const struct tlv_field *fields, const char *messagename, const char *fieldname, - const struct pubkey32 *node_id, + const struct point32 *node_id, const struct bip340sig *sig) { if (!node_id) @@ -231,7 +247,9 @@ struct tlv_invoice_request *invrequest_decode(const tal_t *ctx, *fail = check_features_and_chain(ctx, our_features, must_be_chain, invrequest->features, - invrequest->chains); + invrequest->chain + ? invrequest->chain + : invrequest->chains); if (*fail) return tal_free(invrequest); @@ -270,7 +288,8 @@ struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx, *fail = check_features_and_chain(ctx, our_features, must_be_chain, invoice->features, - invoice->chains); + invoice->chain + ? invoice->chain : invoice->chains); if (*fail) return tal_free(invoice); diff --git a/common/bolt12.h b/common/bolt12.h index 71d17ce894cb..e1b0c00e71bf 100644 --- a/common/bolt12.h +++ b/common/bolt12.h @@ -96,13 +96,18 @@ struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx, bool bolt12_check_signature(const struct tlv_field *fields, const char *messagename, const char *fieldname, - const struct pubkey32 *key, + const struct point32 *key, const struct bip340sig *sig); /* Given a tal_arr of chains, does it contain this chain? */ bool bolt12_chains_match(const struct bitcoin_blkid *chains, const struct chainparams *must_be_chain); +/* Given a single bolt12 chain, does it match? (NULL == bitcoin) */ +bool bolt12_chain_matches(const struct bitcoin_blkid *chain, + const struct chainparams *must_be_chain, + const struct bitcoin_blkid *deprecated_chains); + /* Given a basetime, when does period N start? */ u64 offer_period_start(u64 basetime, size_t n, const struct tlv_offer_recurrence *recurrence); diff --git a/common/bolt12_merkle.c b/common/bolt12_merkle.c index c96dfdc8c76b..2865b7e5528b 100644 --- a/common/bolt12_merkle.c +++ b/common/bolt12_merkle.c @@ -220,7 +220,7 @@ void sighash_from_merkle(const char *messagename, /* We use the SHA(pubkey | publictweak); so reader cannot figure out the * tweak and derive the base key */ -void payer_key_tweak(const struct pubkey32 *bolt12, +void payer_key_tweak(const struct point32 *bolt12, const u8 *publictweak, size_t publictweaklen, struct sha256 *tweak) { diff --git a/common/bolt12_merkle.h b/common/bolt12_merkle.h index af8b4bad369c..08ae9fc208fc 100644 --- a/common/bolt12_merkle.h +++ b/common/bolt12_merkle.h @@ -25,7 +25,7 @@ void sighash_from_merkle(const char *messagename, /** * payer_key_tweak - get the actual tweak to use for a payer_key */ -void payer_key_tweak(const struct pubkey32 *bolt12, +void payer_key_tweak(const struct point32 *bolt12, const u8 *publictweak, size_t publictweaklen, struct sha256 *tweak); diff --git a/common/gossmap.c b/common/gossmap.c index 67aafd51679b..ff27b974b2ac 100644 --- a/common/gossmap.c +++ b/common/gossmap.c @@ -1255,13 +1255,13 @@ int gossmap_node_get_feature(const struct gossmap *map, /* There are two 33-byte pubkeys possible: choose the one which appears * in the graph (otherwise payment will fail anyway). */ void gossmap_guess_node_id(const struct gossmap *map, - const struct pubkey32 *pubkey32, + const struct point32 *point32, struct node_id *id) { id->k[0] = SECP256K1_TAG_PUBKEY_EVEN; secp256k1_xonly_pubkey_serialize(secp256k1_ctx, id->k + 1, - &pubkey32->pubkey); + &point32->pubkey); /* If we don't find this, let's assume it's odd. */ if (!gossmap_find_node(map, id)) diff --git a/common/gossmap.h b/common/gossmap.h index 92880f098472..728dc8385160 100644 --- a/common/gossmap.h +++ b/common/gossmap.h @@ -8,7 +8,7 @@ #include struct node_id; -struct pubkey32; +struct point32; struct gossmap_node { /* Offset in memory map for node_announce, or 0. */ @@ -202,7 +202,7 @@ struct gossmap_chan *gossmap_next_chan(const struct gossmap *map, /* Each x-only pubkey has two possible values: we can figure out which by * examining the gossmap. */ void gossmap_guess_node_id(const struct gossmap *map, - const struct pubkey32 *pubkey32, + const struct point32 *point32, struct node_id *id); #endif /* LIGHTNING_COMMON_GOSSMAP_H */ diff --git a/common/json_helpers.c b/common/json_helpers.c index 6de4860675d9..0629b03e7f47 100644 --- a/common/json_helpers.c +++ b/common/json_helpers.c @@ -201,9 +201,9 @@ void json_add_pubkey(struct json_stream *response, json_add_hex(response, fieldname, der, sizeof(der)); } -void json_add_pubkey32(struct json_stream *response, - const char *fieldname, - const struct pubkey32 *key) +void json_add_point32(struct json_stream *response, + const char *fieldname, + const struct point32 *key) { u8 output[32]; diff --git a/common/json_helpers.h b/common/json_helpers.h index 7dd4b7ba1533..e3001a0e7b16 100644 --- a/common/json_helpers.h +++ b/common/json_helpers.h @@ -14,7 +14,7 @@ struct lease_rates; struct node_id; struct preimage; struct pubkey; -struct pubkey32; +struct point32; struct secret; struct short_channel_id; struct short_channel_id_dir; @@ -91,9 +91,9 @@ void json_add_pubkey(struct json_stream *response, const struct pubkey *key); /* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ -void json_add_pubkey32(struct json_stream *response, +void json_add_point32(struct json_stream *response, const char *fieldname, - const struct pubkey32 *key); + const struct point32 *key); /* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ void json_add_bip340sig(struct json_stream *response, diff --git a/common/node_id.c b/common/node_id.c index 4444ec9be1f7..d130dcff4330 100644 --- a/common/node_id.c +++ b/common/node_id.c @@ -26,7 +26,7 @@ bool pubkey_from_node_id(struct pubkey *key, const struct node_id *id) } WARN_UNUSED_RESULT -bool pubkey32_from_node_id(struct pubkey32 *key, const struct node_id *id) +bool point32_from_node_id(struct point32 *key, const struct node_id *id) { struct pubkey k; if (!pubkey_from_node_id(&k, id)) diff --git a/common/node_id.h b/common/node_id.h index 35134d03599f..5f9fbb1ff456 100644 --- a/common/node_id.h +++ b/common/node_id.h @@ -26,7 +26,7 @@ bool pubkey_from_node_id(struct pubkey *key, const struct node_id *id); /* Returns false if not a valid pubkey: relatively expensive */ WARN_UNUSED_RESULT -bool pubkey32_from_node_id(struct pubkey32 *key, const struct node_id *id); +bool point32_from_node_id(struct point32 *key, const struct node_id *id); /* Convert to hex string of SEC1 encoding. */ char *node_id_to_hexstr(const tal_t *ctx, const struct node_id *id); diff --git a/common/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c index 4e6ee7658295..0cac9920e775 100644 --- a/common/test/run-bolt12_decode.c +++ b/common/test/run-bolt12_decode.c @@ -7,6 +7,8 @@ #include #include +bool deprecated_apis = false; + /* AUTOGENERATED MOCKS START */ /* Generated stub for amount_asset_is_main */ bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) @@ -208,7 +210,7 @@ int main(int argc, char *argv[]) strtok->end - strtok->start); str = json_escape_unescape(tmpctx, esc); actual = (string_to_data(tmpctx, str, strlen(str), - "lni", &dlen, &fail) != NULL); + "lno", &dlen, &fail) != NULL); assert(actual == valid); } tal_free(tmpctx); diff --git a/common/test/run-bolt12_merkle.c b/common/test/run-bolt12_merkle.c index 8b762ab9b724..f403361904a1 100644 --- a/common/test/run-bolt12_merkle.c +++ b/common/test/run-bolt12_merkle.c @@ -12,6 +12,8 @@ /* Definition of n1 from the spec */ #include +bool deprecated_apis = false; + /* AUTOGENERATED MOCKS START */ /* Generated stub for features_unsupported */ int features_unsupported(const struct feature_set *our_features UNNEEDED, @@ -330,14 +332,14 @@ int main(int argc, char *argv[]) fieldwires[1] = tlv(8, "\x03\xe8", 2); /* description: 10USD every day */ fieldwires[2] = tlv(10, "10USD every day", strlen("10USD every day")); - /* vendor: rusty.ozlabs.org */ + /* issuer: rusty.ozlabs.org */ fieldwires[3] = tlv(20, "rusty.ozlabs.org", strlen("rusty.ozlabs.org")); /* recurrence: time_unit = 1, period = 1 */ fieldwires[4] = tlv(26, "\x01\x01", 2); /* node_id: 4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 */ fieldwires[5] = tlv(30, "\x4b\x9a\x1f\xa8\xe0\x06\xf1\xe3\x93\x7f\x65\xf6\x6c\x40\x8e\x6d\xa8\xe1\xca\x72\x8e\xa4\x32\x22\xa7\x38\x1d\xf1\xcc\x44\x96\x05", 32); - json_out("{\"comment\": \"offer test, currency = USD, amount = 1000, description = 10USD every day, vendor = rusty.ozlabs.org, recurrence = time_unit = 1, period = 1, node_id = 4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605\","); + json_out("{\"comment\": \"offer test, currency = USD, amount = 1000, description = 10USD every day, issuer = rusty.ozlabs.org, recurrence = time_unit = 1, period = 1, node_id = 4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605\","); json_out("\"tlv\": \"offer\","); all = concat(fieldwires[0], fieldwires[1], fieldwires[2], @@ -364,7 +366,7 @@ int main(int argc, char *argv[]) json_out("{ \"desc\": \"1: currency+nonce and amount+nonce\", \"H(`LnBranch`,%s)\": \"%s\" },", tal_hex(tmpctx, ordered(leaf[0], leaf[1])), tal_hex(tmpctx, H(LnBranch, ordered(leaf[0], leaf[1])))); - json_out("{ \"desc\": \"2: description+nonce and vendor+nonce\", \"H(`LnBranch`,%s)\": \"%s\"},", + json_out("{ \"desc\": \"2: description+nonce and issuer+nonce\", \"H(`LnBranch`,%s)\": \"%s\"},", tal_hex(tmpctx, ordered(leaf[2], leaf[3])), tal_hex(tmpctx, H(LnBranch, ordered(leaf[2], leaf[3])))); struct sha256 *b12 = H(LnBranch, diff --git a/common/test/run-bolt12_period.c b/common/test/run-bolt12_period.c index 12d5c4868a06..556cf51b233f 100644 --- a/common/test/run-bolt12_period.c +++ b/common/test/run-bolt12_period.c @@ -5,6 +5,8 @@ #include #include +bool deprecated_apis = false; + /* AUTOGENERATED MOCKS START */ /* Generated stub for amount_asset_is_main */ bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) diff --git a/common/type_to_string.h b/common/type_to_string.h index 40834c49eec8..1bdc66542ac8 100644 --- a/common/type_to_string.h +++ b/common/type_to_string.h @@ -7,7 +7,7 @@ /* This must match the type_to_string_ cases. */ union printable_types { const struct pubkey *pubkey; - const struct pubkey32 *pubkey32; + const struct point32 *point32; const struct node_id *node_id; const struct bitcoin_txid *bitcoin_txid; const struct bitcoin_blkid *bitcoin_blkid; diff --git a/contrib/pyln-testing/pyln/testing/fixtures.py b/contrib/pyln-testing/pyln/testing/fixtures.py index 53eafd99d6ed..8742bf7270ce 100644 --- a/contrib/pyln-testing/pyln/testing/fixtures.py +++ b/contrib/pyln-testing/pyln/testing/fixtures.py @@ -274,7 +274,7 @@ def is_pubkey(checker, instance): return False return instance[0:2] == "02" or instance[0:2] == "03" - def is_pubkey32(checker, instance): + def is_point32(checker, instance): """x-only BIP-340 public key""" if not checker.is_type(instance, "hex"): return False @@ -319,7 +319,7 @@ def is_txid(checker, instance): "txid": is_txid, "signature": is_signature, "bip340sig": is_bip340sig, - "pubkey32": is_pubkey32, + "point32": is_point32, "short_channel_id": is_short_channel_id, }) diff --git a/devtools/bolt12-cli.c b/devtools/bolt12-cli.c index 7ffdfbcc273d..aa4dbf2bbfdb 100644 --- a/devtools/bolt12-cli.c +++ b/devtools/bolt12-cli.c @@ -19,6 +19,7 @@ #define ERROR_USAGE 3 static bool well_formed = true; +bool deprecated_apis = true; /* Tal wrappers for opt. */ static void *opt_allocfn(size_t size) @@ -72,6 +73,12 @@ static void print_chains(const struct bitcoin_blkid *chains) printf("\n"); } +static void print_chain(const struct bitcoin_blkid *chain) +{ + printf("chain: %s\n", + type_to_string(tmpctx, struct bitcoin_blkid, chain)); +} + static bool print_amount(const struct bitcoin_blkid *chains, const char *iso4217, u64 amount) { @@ -139,14 +146,14 @@ static void print_description(const char *description) (int)tal_bytelen(description), description); } -static void print_vendor(const char *vendor) +static void print_issuer(const char *issuer) { - printf("vendor: %.*s\n", (int)tal_bytelen(vendor), vendor); + printf("issuer: %.*s\n", (int)tal_bytelen(issuer), issuer); } -static void print_node_id(const struct pubkey32 *node_id) +static void print_node_id(const struct point32 *node_id) { - printf("node_id: %s\n", type_to_string(tmpctx, struct pubkey32, node_id)); + printf("node_id: %s\n", type_to_string(tmpctx, struct point32, node_id)); } static void print_quantity_min(u64 min) @@ -299,7 +306,7 @@ static void print_refund_for(const struct sha256 *payment_hash) static bool print_signature(const char *messagename, const char *fieldname, const struct tlv_field *fields, - const struct pubkey32 *node_id, + const struct point32 *node_id, const struct bip340sig *sig) { struct sha256 m, shash; @@ -358,11 +365,11 @@ static bool print_recurrence_counter_with_base(const u32 *recurrence_counter, return true; } -static void print_payer_key(const struct pubkey32 *payer_key, +static void print_payer_key(const struct point32 *payer_key, const u8 *payer_info) { printf("payer_key: %s", - type_to_string(tmpctx, struct pubkey32, payer_key)); + type_to_string(tmpctx, struct point32, payer_key)); if (payer_info) printf(" (payer_info %s)", tal_hex(tmpctx, payer_info)); printf("\n"); @@ -499,8 +506,8 @@ int main(int argc, char *argv[]) *offer->amount); if (must_have(offer, description)) print_description(offer->description); - if (offer->vendor) - print_vendor(offer->vendor); + if (offer->issuer) + print_issuer(offer->issuer); if (must_have(offer, node_id)) print_node_id(offer->node_id); if (offer->quantity_min) @@ -532,8 +539,8 @@ int main(int argc, char *argv[]) if (!invreq) errx(ERROR_BAD_DECODE, "Bad invoice_request: %s", fail); - if (invreq->chains) - print_chains(invreq->chains); + if (invreq->chain) + print_chain(invreq->chain); if (must_have(invreq, payer_key)) print_payer_key(invreq->payer_key, invreq->payer_info); if (invreq->payer_note) @@ -541,7 +548,7 @@ int main(int argc, char *argv[]) if (must_have(invreq, offer_id)) print_offer_id(invreq->offer_id); if (must_have(invreq, amount)) - well_formed &= print_amount(invreq->chains, + well_formed &= print_amount(invreq->chain, NULL, *invreq->amount); if (invreq->features) @@ -569,14 +576,14 @@ int main(int argc, char *argv[]) if (!invoice) errx(ERROR_BAD_DECODE, "Bad invoice: %s", fail); - if (invoice->chains) - print_chains(invoice->chains); + if (invoice->chain) + print_chain(invoice->chain); if (invoice->offer_id) { print_offer_id(invoice->offer_id); } if (must_have(invoice, amount)) - well_formed &= print_amount(invoice->chains, + well_formed &= print_amount(invoice->chain, NULL, *invoice->amount); if (must_have(invoice, description)) @@ -589,8 +596,8 @@ int main(int argc, char *argv[]) invoice->blindedpay); } else must_not_have(invoice, blindedpay); - if (invoice->vendor) - print_vendor(invoice->vendor); + if (invoice->issuer) + print_issuer(invoice->issuer); if (must_have(invoice, node_id)) print_node_id(invoice->node_id); if (invoice->quantity) diff --git a/doc/lightning-decode.7.md b/doc/lightning-decode.7.md index a5958755f519..c12deaad9531 100644 --- a/doc/lightning-decode.7.md +++ b/doc/lightning-decode.7.md @@ -24,7 +24,7 @@ On success, an object is returned, containing: If **type** is "bolt12 offer", and **valid** is *true*: - **offer_id** (hex): the id of this offer (merkle hash of non-signature fields) (always 64 characters) - - **node_id** (pubkey32): x-only public key of the offering node + - **node_id** (point32): x-only public key of the offering node - **description** (string): the description of the purpose of the offer - **signature** (bip340sig, optional): BIP-340 signature of the *node_id* on this offer - **chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only): @@ -64,7 +64,7 @@ If **type** is "bolt12 offer", and **valid** is *false*: - **warning_offer_missing_description**: No **description** If **type** is "bolt12 invoice", and **valid** is *true*: - - **node_id** (pubkey32): x-only public key of the offering node + - **node_id** (point32): x-only public key of the offering node - **signature** (bip340sig): BIP-340 signature of the *node_id* on this offer - **amount_msat** (msat): the amount in bitcoin - **description** (string): the description of the purpose of the offer @@ -88,7 +88,7 @@ If **type** is "bolt12 invoice", and **valid** is *true*: - **recurrence_counter** (u32, optional): the 0-based counter for a recurring payment - **recurrence_start** (u32, optional): the optional start period for a recurring payment - **recurrence_basetime** (u32, optional): the UNIX timestamp of the first recurrence period start - - **payer_key** (pubkey32, optional): the transient key which identifies the payer + - **payer_key** (point32, optional): the transient key which identifies the payer - **payer_info** (hex, optional): the payer-provided blob to derive payer_key - **fallbacks** (array of objects, optional): onchain addresses: - **version** (u8): Segwit address version @@ -114,7 +114,7 @@ If **type** is "bolt12 invoice", and **valid** is *false*: If **type** is "bolt12 invoice_request", and **valid** is *true*: - **offer_id** (hex): the id of this offer (merkle hash of non-signature fields) (always 64 characters) - - **payer_key** (pubkey32): the transient key which identifies the payer + - **payer_key** (point32): the transient key which identifies the payer - **chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only): - the genesis blockhash (always 64 characters) - **amount_msat** (msat, optional): the amount in bitcoin @@ -182,4 +182,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:d9e00b0a8c93fecd75aab0688204601a7ceeca0f424012cf0d04ce24b6017aee) +[comment]: # ( SHA256STAMP:f12157fe0af8ff3c9569374cc95bdbdd9df00c9a818fbfe30450a3eea020053a) diff --git a/doc/lightning-offer.7.md b/doc/lightning-offer.7.md index 898f69297211..bc6d5421b950 100644 --- a/doc/lightning-offer.7.md +++ b/doc/lightning-offer.7.md @@ -6,7 +6,7 @@ SYNOPSIS **(WARNING: experimental-offers only)** -**offer** *amount* *description* \[*vendor*\] \[*label*\] \[*quantity_min*\] \[*quantity_max*\] \[*absolute_expiry*\] \[*recurrence*\] \[*recurrence_base*\] \[*recurrence_paywindow*\] \[*recurrence_limit*\] \[*single_use*\] +**offer** *amount* *description* \[*issuer*\] \[*label*\] \[*quantity_min*\] \[*quantity_max*\] \[*absolute_expiry*\] \[*recurrence*\] \[*recurrence_base*\] \[*recurrence_paywindow*\] \[*recurrence_limit*\] \[*single_use*\] DESCRIPTION ----------- @@ -37,7 +37,7 @@ e.g. *coffee*. This value is encoded into the resulting offer and is viewable by anyone you expose this offer to. It must be UTF-8, and cannot use *\\u* JSON escape codes. -The *vendor* is another (optional) field exposed in the offer, and +The *issuer* is another (optional) field exposed in the offer, and reflects who is issuing this offer (i.e. you) if appropriate. The *label* field is an internal-use name for the offer, which can diff --git a/doc/lightning-offerout.7.md b/doc/lightning-offerout.7.md index 445671c98608..b52d408c7ac9 100644 --- a/doc/lightning-offerout.7.md +++ b/doc/lightning-offerout.7.md @@ -7,7 +7,7 @@ SYNOPSIS **(WARNING: experimental-offers only)** -**offerout** *amount* *description* \[*vendor*\] \[*label*\] \[*absolute_expiry*\] \[*refund_for*\] +**offerout** *amount* *description* \[*issuer*\] \[*label*\] \[*absolute_expiry*\] \[*refund_for*\] DESCRIPTION ----------- @@ -34,7 +34,7 @@ e.g. *withdrawl from ATM*. This value is encoded into the resulting offer and is viewable by anyone you expose this offer to. It must be UTF-8, and cannot use *\\u* JSON escape codes. -The *vendor* is another (optional) field exposed in the offer, and +The *issuer* is another (optional) field exposed in the offer, and reflects who is issuing this offer (i.e. you) if appropriate. The *label* field is an internal-use name for the offer, which can diff --git a/doc/schemas/decode.schema.json b/doc/schemas/decode.schema.json index 33890f511075..d985e365a1fb 100644 --- a/doc/schemas/decode.schema.json +++ b/doc/schemas/decode.schema.json @@ -40,7 +40,7 @@ "minLength": 64 }, "node_id": { - "type": "pubkey32", + "type": "point32", "description": "x-only public key of the offering node" }, "signature": { @@ -275,22 +275,18 @@ "minLength": 64 }, "node_id": { - "type": "pubkey32", + "type": "point32", "description": "x-only public key of the offering node" }, "signature": { "type": "bip340sig", "description": "BIP-340 signature of the *node_id* on this offer" }, - "chains": { - "type": "array", - "description": "which blockchains this offer is for (missing implies bitcoin mainnet only)", - "items": { - "type": "hex", - "description": "the genesis blockhash", - "maxLength": 64, - "minLength": 64 - } + "chain": { + "type": "hex", + "description": "which blockchain this invoice is for (missing implies bitcoin mainnet only)", + "maxLength": 64, + "minLength": 64 }, "amount_msat": { "type": "msat", @@ -370,7 +366,7 @@ "description": "the UNIX timestamp of the first recurrence period start" }, "payer_key": { - "type": "pubkey32", + "type": "point32", "description": "the transient key which identifies the payer" }, "payer_info": { @@ -450,7 +446,7 @@ "offer_id": { }, "node_id": { }, "signature": { }, - "chains": { }, + "chain": { }, "amount_msat": { }, "send_invoice": { }, "refund_for": { }, @@ -551,19 +547,15 @@ "valid": { }, "offer_id": { "type": "hex", - "description": "the id of this offer (merkle hash of non-signature fields)", + "description": "the id of the offer this is requesting (merkle hash of non-signature fields)", "maxLength": 64, "minLength": 64 }, - "chains": { - "type": "array", - "description": "which blockchains this offer is for (missing implies bitcoin mainnet only)", - "items": { - "type": "hex", - "description": "the genesis blockhash", - "maxLength": 64, - "minLength": 64 - } + "chain": { + "type": "hex", + "description": "which blockchain this invoice_request is for (missing implies bitcoin mainnet only)", + "maxLength": 64, + "minLength": 64 }, "amount_msat": { "type": "msat", @@ -586,7 +578,7 @@ "description": "the optional start period for a recurring payment" }, "payer_key": { - "type": "pubkey32", + "type": "point32", "description": "the transient key which identifies the payer" }, "payer_info": { @@ -620,7 +612,7 @@ "type": { }, "valid": { }, "offer_id": { }, - "chains": { }, + "chain": { }, "amount_msat": { }, "features": { }, "quantity": { }, diff --git a/hsmd/hsmd_wire.csv b/hsmd/hsmd_wire.csv index 051b09fcd2d8..2aada572727c 100644 --- a/hsmd/hsmd_wire.csv +++ b/hsmd/hsmd_wire.csv @@ -20,7 +20,7 @@ msgdata,hsmd_init,dev_force_channel_secrets_shaseed,?sha256, msgtype,hsmd_init_reply,111 msgdata,hsmd_init_reply,node_id,node_id, msgdata,hsmd_init_reply,bip32,ext_key, -msgdata,hsmd_init_reply,bolt12,pubkey32, +msgdata,hsmd_init_reply,bolt12,point32, msgdata,hsmd_init_reply,onion_reply_secret,secret, # Get a new HSM FD, with the specified capabilities diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 648b4b0095d7..8a358bcc8dd2 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -210,7 +210,7 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id) /*~ This returns the secret and/or public x-only key for this node. */ static void node_schnorrkey(secp256k1_keypair *node_keypair, - struct pubkey32 *node_id32) + struct point32 *node_id32) { secp256k1_keypair unused_kp; struct privkey node_privkey; @@ -536,7 +536,7 @@ static u8 *handle_sign_bolt12(struct hsmd_client *c, const u8 *msg_in) node_schnorrkey(&kp, NULL); } else { /* If we're tweaking key, we use bolt12 key */ - struct pubkey32 bolt12; + struct point32 bolt12; struct sha256 tweak; if (secp256k1_keypair_xonly_pub(secp256k1_ctx, @@ -1465,7 +1465,7 @@ u8 *hsmd_init(struct secret hsm_secret, { u8 bip32_seed[BIP32_ENTROPY_LEN_256]; struct pubkey key; - struct pubkey32 bolt12; + struct point32 bolt12; u32 salt = 0; struct ext_key master_extkey, child_extkey; struct node_id node_id; diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index d04b45964ad0..274995422500 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -107,7 +107,7 @@ struct lightningd { struct node_id id; /* The public base for our payer_id keys */ - struct pubkey32 bolt12_base; + struct point32 bolt12_base; /* The secret we put in onion message paths to know it's ours. */ struct secret onion_reply_secret; diff --git a/lightningd/offer.c b/lightningd/offer.c index a5569599017a..da81c9f53f23 100644 --- a/lightningd/offer.c +++ b/lightningd/offer.c @@ -54,7 +54,7 @@ static void hsm_sign_b12(struct lightningd *ld, const char *fieldname, const struct sha256 *merkle, const u8 *publictweak, - const struct pubkey32 *key, + const struct point32 *key, struct bip340sig *sig) { u8 *msg; @@ -76,7 +76,7 @@ static void hsm_sign_b12(struct lightningd *ld, sighash.u.u8, &key->pubkey) != 1) fatal("HSM gave bad signature %s for pubkey %s", type_to_string(tmpctx, struct bip340sig, sig), - type_to_string(tmpctx, struct pubkey32, key)); + type_to_string(tmpctx, struct point32, key)); } static struct command_result *json_createoffer(struct command *cmd, @@ -91,7 +91,7 @@ static struct command_result *json_createoffer(struct command *cmd, const char *b12str, *b12str_nosig; bool *single_use; enum offer_status status; - struct pubkey32 key; + struct point32 key; bool created; if (!param(cmd, buffer, params, @@ -107,7 +107,7 @@ static struct command_result *json_createoffer(struct command *cmd, status = OFFER_MULTIPLE_USE_UNUSED; merkle_tlv(offer->fields, &merkle); offer->signature = tal(offer, struct bip340sig); - if (!pubkey32_from_node_id(&key, &cmd->ld->id)) + if (!point32_from_node_id(&key, &cmd->ld->id)) fatal("invalid own node_id?"); hsm_sign_b12(cmd->ld, "offer", "signature", &merkle, NULL, &key, offer->signature); @@ -388,7 +388,7 @@ static struct command_result *param_b12_invreq(struct command *cmd, static bool payer_key(struct lightningd *ld, const u8 *public_tweak, size_t public_tweak_len, - struct pubkey32 *key) + struct point32 *key) { struct sha256 tweakhash; secp256k1_pubkey tweaked; @@ -454,7 +454,7 @@ static struct command_result *json_createinvoicerequest(struct command *cmd, tal_bytelen(invreq->payer_info)); } - invreq->payer_key = tal(invreq, struct pubkey32); + invreq->payer_key = tal(invreq, struct point32); if (!payer_key(cmd->ld, invreq->payer_info, tal_bytelen(invreq->payer_info), invreq->payer_key)) { @@ -502,7 +502,7 @@ static struct command_result *json_payersign(struct command *cmd, u8 *tweak; struct bip340sig sig; const char *messagename, *fieldname; - struct pubkey32 key; + struct point32 key; if (!param(cmd, buffer, params, p_req("messagename", param_string, &messagename), diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 2f942ba4e6ab..336d058e8a9a 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -216,7 +216,7 @@ static struct command_result *handle_invreq_response(struct command *cmd, /* BOLT-offers #12: * - MUST reject the invoice unless `node_id` is equal to the offer. */ - if (!pubkey32_eq(sent->offer->node_id, inv->node_id)) { + if (!point32_eq(sent->offer->node_id, inv->node_id)) { badfield = "node_id"; goto badinv; } @@ -329,18 +329,18 @@ static struct command_result *handle_invreq_response(struct command *cmd, } /* BOLT-offers #12: - * - SHOULD confirm authorization if `vendor` does not exactly + * - SHOULD confirm authorization if `issuer` does not exactly * match the `offer` */ - if (field_diff(sent->offer, inv, vendor)) { - if (!inv->vendor) - json_add_stringn(out, "vendor_removed", - sent->offer->vendor, - tal_bytelen(sent->offer->vendor)); + if (field_diff(sent->offer, inv, issuer)) { + if (!inv->issuer) + json_add_stringn(out, "issuer_removed", + sent->offer->issuer, + tal_bytelen(sent->offer->issuer)); else - json_add_stringn(out, "vendor", - inv->vendor, - tal_bytelen(inv->vendor)); + json_add_stringn(out, "issuer", + inv->issuer, + tal_bytelen(inv->issuer)); } /* BOLT-offers #12: * - SHOULD confirm authorization if `msat` is not within the amount @@ -613,8 +613,8 @@ static enum nodeid_parity node_parity(const struct gossmap *gossmap, return id.k[0]; } -static void node_id_from_pubkey32(struct node_id *nid, - const struct pubkey32 *node32_id, +static void node_id_from_point32(struct node_id *nid, + const struct point32 *node32_id, enum nodeid_parity parity) { assert(parity == SECP256K1_TAG_PUBKEY_EVEN @@ -629,7 +629,7 @@ static void node_id_from_pubkey32(struct node_id *nid, * for 33rd nodeid byte. */ static struct pubkey *path_to_node(const tal_t *ctx, struct plugin *plugin, - const struct pubkey32 *node32_id, + const struct point32 *node32_id, enum nodeid_parity *parity) { struct route_hop *r; @@ -642,11 +642,11 @@ static struct pubkey *path_to_node(const tal_t *ctx, /* We try both parities. */ *parity = nodeid_parity_even; - node_id_from_pubkey32(&dstid, node32_id, *parity); + node_id_from_point32(&dstid, node32_id, *parity); dst = gossmap_find_node(gossmap, &dstid); if (!dst) { *parity = nodeid_parity_odd; - node_id_from_pubkey32(&dstid, node32_id, *parity); + node_id_from_point32(&dstid, node32_id, *parity); dst = gossmap_find_node(gossmap, &dstid); if (!dst) { *parity = nodeid_parity_unknown; @@ -999,7 +999,7 @@ static struct command_result *try_other_parity(struct command *cmd, * to them. */ static struct command_result * connect_direct(struct command *cmd, - const struct pubkey32 *dst, + const struct point32 *dst, enum nodeid_parity parity, struct command_result *(*cb)(struct command *command, const char *buf, @@ -1016,15 +1016,15 @@ connect_direct(struct command *cmd, if (parity == nodeid_parity_unknown) { plugin_notify_message(cmd, LOG_INFORM, "Cannot find route, trying connect to 02/03%s directly", - type_to_string(tmpctx, struct pubkey32, dst)); + type_to_string(tmpctx, struct point32, dst)); /* Try even first. */ - node_id_from_pubkey32(&ca->node_id, dst, SECP256K1_TAG_PUBKEY_EVEN); + node_id_from_point32(&ca->node_id, dst, SECP256K1_TAG_PUBKEY_EVEN); } else { plugin_notify_message(cmd, LOG_INFORM, "Cannot find route, trying connect to %02x%s directly", parity, - type_to_string(tmpctx, struct pubkey32, dst)); - node_id_from_pubkey32(&ca->node_id, dst, parity); + type_to_string(tmpctx, struct point32, dst)); + node_id_from_point32(&ca->node_id, dst, parity); } /* Make a direct path -> dst. */ @@ -1043,7 +1043,7 @@ connect_direct(struct command *cmd, "Cannot find route, but" " fetchplugin-noconnect set:" " trying direct anyway to %s", - type_to_string(tmpctx, struct pubkey32, + type_to_string(tmpctx, struct point32, dst)); return cb(cmd, NULL, NULL, sent); } @@ -1183,7 +1183,7 @@ force_payer_secret(struct command *cmd, if (secp256k1_keypair_create(secp256k1_ctx, &kp, payer_secret->data) != 1) return command_fail(cmd, LIGHTNINGD, "Bad payer_secret"); - invreq->payer_key = tal(invreq, struct pubkey32); + invreq->payer_key = tal(invreq, struct point32); /* Docs say this only happens if arguments are invalid! */ if (secp256k1_keypair_xonly_pub(secp256k1_ctx, &invreq->payer_key->pubkey, NULL, @@ -1395,8 +1395,12 @@ static struct command_result *json_fetchinvoice(struct command *cmd, * - the bitcoin chain is implied as the first and only entry. */ if (!streq(chainparams->network_name, "bitcoin")) { - invreq->chains = tal_arr(invreq, struct bitcoin_blkid, 1); - invreq->chains[0] = chainparams->genesis_blockhash; + if (deprecated_apis) { + invreq->chains = tal_arr(invreq, struct bitcoin_blkid, 1); + invreq->chains[0] = chainparams->genesis_blockhash; + } + invreq->chain = tal_dup(invreq, struct bitcoin_blkid, + &chainparams->genesis_blockhash); } invreq->features @@ -1691,7 +1695,7 @@ static struct command_result *json_sendinvoice(struct command *cmd, * - 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 pubkey32); + sent->inv->node_id = tal(sent->inv, struct point32); /* This only fails if pubkey is invalid. */ if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx, @@ -1790,8 +1794,12 @@ static struct command_result *json_sendinvoice(struct command *cmd, * - the bitcoin chain is implied as the first and only entry. */ if (!streq(chainparams->network_name, "bitcoin")) { - sent->inv->chains = tal_arr(sent->inv, struct bitcoin_blkid, 1); - sent->inv->chains[0] = chainparams->genesis_blockhash; + if (deprecated_apis) { + sent->inv->chains = tal_arr(sent->inv, struct bitcoin_blkid, 1); + sent->inv->chains[0] = chainparams->genesis_blockhash; + } + sent->inv->chain = tal_dup(sent->inv, struct bitcoin_blkid, + &chainparams->genesis_blockhash); } sent->inv->features @@ -1853,7 +1861,7 @@ static struct command_result *json_rawrequest(struct command *cmd, struct sent *sent = tal(cmd, struct sent); u32 *timeout; struct node_id *node_id; - struct pubkey32 node_id32; + struct point32 node_id32; enum nodeid_parity parity; if (!param(cmd, buffer, params, diff --git a/plugins/offers.c b/plugins/offers.c index 906ae07e8b30..b89a12cc4998 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -14,7 +14,7 @@ #include #include -struct pubkey32 id; +struct point32 id; u32 cltv_final; bool offers_enabled; @@ -425,9 +425,14 @@ static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer valid = false; } - if (offer->vendor) - json_add_stringn(js, "vendor", offer->vendor, - tal_bytelen(offer->vendor)); + if (offer->issuer) { + json_add_stringn(js, "issuer", offer->issuer, + tal_bytelen(offer->issuer)); + if (deprecated_apis) { + json_add_stringn(js, "vendor", offer->issuer, + tal_bytelen(offer->issuer)); + } + } if (offer->features) json_add_hex_talarr(js, "features", offer->features); if (offer->absolute_expiry) @@ -470,7 +475,7 @@ static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer } if (offer->node_id) - json_add_pubkey32(js, "node_id", offer->node_id); + json_add_point32(js, "node_id", offer->node_id); else valid = false; @@ -560,6 +565,8 @@ static void json_add_b12_invoice(struct json_stream *js, if (invoice->chains) json_add_chains(js, invoice->chains); + if (invoice->chain) + json_add_sha256(js, "chain", &invoice->chain->shad.sha); if (invoice->offer_id) json_add_sha256(js, "offer_id", invoice->offer_id); @@ -587,9 +594,14 @@ static void json_add_b12_invoice(struct json_stream *js, valid = false; } - if (invoice->vendor) - json_add_stringn(js, "vendor", invoice->vendor, - tal_bytelen(invoice->vendor)); + if (invoice->issuer) { + json_add_stringn(js, "issuer", invoice->issuer, + tal_bytelen(invoice->issuer)); + if (deprecated_apis) { + json_add_stringn(js, "vendor", invoice->issuer, + tal_bytelen(invoice->issuer)); + } + } if (invoice->features) json_add_hex_talarr(js, "features", invoice->features); if (invoice->paths) { @@ -636,7 +648,7 @@ static void json_add_b12_invoice(struct json_stream *js, } if (invoice->payer_key) - json_add_pubkey32(js, "payer_key", invoice->payer_key); + json_add_point32(js, "payer_key", invoice->payer_key); if (invoice->payer_info) json_add_hex_talarr(js, "payer_info", invoice->payer_info); if (invoice->payer_note) @@ -690,7 +702,8 @@ static void json_add_b12_invoice(struct json_stream *js, json_add_u32(js, "min_final_cltv_expiry", 18); if (invoice->fallbacks) - valid &= json_add_fallbacks(js, invoice->chains, + valid &= json_add_fallbacks(js, + invoice->chain ? invoice->chain : invoice->chains, invoice->fallbacks->fallbacks); /* BOLT-offers #12: @@ -726,7 +739,7 @@ static void json_add_b12_invoice(struct json_stream *js, } /* invoice_decode checked these */ - json_add_pubkey32(js, "node_id", invoice->node_id); + json_add_point32(js, "node_id", invoice->node_id); json_add_bip340sig(js, "signature", invoice->signature); json_add_bool(js, "valid", valid); @@ -739,6 +752,9 @@ static void json_add_invoice_request(struct json_stream *js, if (invreq->chains) json_add_chains(js, invreq->chains); + if (invreq->chain) + json_add_sha256(js, "chain", &invreq->chain->shad.sha); + /* BOLT-offers #12: * - MUST fail the request if `payer_key` is not present. * - MUST fail the request if `chains` does not include (or imply) a supported chain. @@ -767,7 +783,7 @@ static void json_add_invoice_request(struct json_stream *js, json_add_u32(js, "recurrence_start", *invreq->recurrence_start); if (invreq->payer_key) - json_add_pubkey32(js, "payer_key", invreq->payer_key); + json_add_point32(js, "payer_key", invreq->payer_key); else { json_add_string(js, "warning_invoice_request_missing_payer_key", "invoice_request requires payer_key"); @@ -858,14 +874,14 @@ static const struct plugin_command commands[] = { "offer", "payment", "Create an offer to accept money", - "Create an offer for invoices of {amount} with {description}, optional {vendor}, internal {label}, {quantity_min}, {quantity_max}, {absolute_expiry}, {recurrence}, {recurrence_base}, {recurrence_paywindow}, {recurrence_limit} and {single_use}", + "Create an offer for invoices of {amount} with {description}, optional {issuer}, internal {label}, {quantity_min}, {quantity_max}, {absolute_expiry}, {recurrence}, {recurrence_base}, {recurrence_paywindow}, {recurrence_limit} and {single_use}", json_offer }, { "offerout", "payment", "Create an offer to send money", - "Create an offer to pay invoices of {amount} with {description}, optional {vendor}, internal {label}, {absolute_expiry} and {refund_for}", + "Create an offer to pay invoices of {amount} with {description}, optional {issuer}, internal {label}, {absolute_expiry} and {refund_for}", json_offerout }, { diff --git a/plugins/offers_inv_hook.c b/plugins/offers_inv_hook.c index ece5e1179a25..a2fa9e56b1d6 100644 --- a/plugins/offers_inv_hook.c +++ b/plugins/offers_inv_hook.c @@ -369,10 +369,10 @@ struct command_result *handle_invoice(struct command *cmd, * - MUST fail the request if `chains` does not include (or imply) a * supported chain. */ - if (!bolt12_chains_match(inv->inv->chains, chainparams)) { + if (!bolt12_chain_matches(inv->inv->chain, chainparams, inv->inv->chains)) { return fail_inv(cmd, inv, "Wrong chains %s", - tal_hex(tmpctx, inv->inv->chains)); + tal_hex(tmpctx, inv->inv->chain)); } /* BOLT-offers #12: diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c index b622c5b94d2c..0391b84e9b90 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -137,14 +137,14 @@ static void set_recurring_inv_expiry(struct tlv_invoice *inv, u64 last_pay) /* We rely on label forms for uniqueness. */ static void json_add_label(struct json_stream *js, const struct sha256 *offer_id, - const struct pubkey32 *payer_key, + const struct point32 *payer_key, const u32 counter) { char *label; label = tal_fmt(tmpctx, "%s-%s-%u", type_to_string(tmpctx, struct sha256, offer_id), - type_to_string(tmpctx, struct pubkey32, + type_to_string(tmpctx, struct point32, payer_key), counter); json_add_string(js, "label", label); @@ -423,7 +423,7 @@ static struct command_result *check_previous_invoice(struct command *cmd, * - MUST fail the request if `payer_signature` is not correct. */ static bool check_payer_sig(const struct tlv_invoice_request *invreq, - const struct pubkey32 *payer_key, + const struct point32 *payer_key, const struct bip340sig *sig) { struct sha256 merkle, sighash; @@ -758,9 +758,14 @@ static struct command_result *listoffers_done(struct command *cmd, * - MUST specify `chains` the offer is valid for. */ if (!streq(chainparams->network_name, "bitcoin")) { - ir->inv->chains = tal_arr(ir->inv, struct bitcoin_blkid, 1); - ir->inv->chains[0] = chainparams->genesis_blockhash; + if (deprecated_apis) { + ir->inv->chains = tal_arr(ir->inv, struct bitcoin_blkid, 1); + ir->inv->chains[0] = chainparams->genesis_blockhash; + } + ir->inv->chain = tal_dup(ir->inv, struct bitcoin_blkid, + &chainparams->genesis_blockhash); } + /* BOLT-offers #12: * - MUST set `offer_id` to the id of the offer. */ @@ -774,8 +779,8 @@ static struct command_result *listoffers_done(struct command *cmd, ->bits[BOLT11_FEATURE]); /* FIXME: Insert paths and payinfo */ - ir->inv->vendor = tal_dup_talarr(ir->inv, char, ir->offer->vendor); - ir->inv->node_id = tal_dup(ir->inv, struct pubkey32, ir->offer->node_id); + ir->inv->issuer = tal_dup_talarr(ir->inv, char, ir->offer->issuer); + ir->inv->node_id = tal_dup(ir->inv, struct point32, ir->offer->node_id); /* BOLT-offers #12: * - MUST set (or not set) `quantity` exactly as the invoice_request * did. @@ -786,7 +791,7 @@ static struct command_result *listoffers_done(struct command *cmd, /* BOLT-offers #12: * - MUST set `payer_key` exactly as the invoice_request did. */ - ir->inv->payer_key = tal_dup(ir->inv, struct pubkey32, + ir->inv->payer_key = tal_dup(ir->inv, struct point32, ir->invreq->payer_key); /* BOLT-offers #12: @@ -883,10 +888,11 @@ struct command_result *handle_invoice_request(struct command *cmd, * - MUST fail the request if `chains` does not include (or imply) a * supported chain. */ - if (!bolt12_chains_match(ir->invreq->chains, chainparams)) { + if (!bolt12_chain_matches(ir->invreq->chain, chainparams, + ir->invreq->chains)) { return fail_invreq(cmd, ir, - "Wrong chains %s", - tal_hex(tmpctx, ir->invreq->chains)); + "Wrong chain %s", + tal_hex(tmpctx, ir->invreq->chain)); } /* BOLT-offers #12: diff --git a/plugins/offers_offer.c b/plugins/offers_offer.c index 9769d25bccd5..54c97b97bd8f 100644 --- a/plugins/offers_offer.c +++ b/plugins/offers_offer.c @@ -314,16 +314,46 @@ struct command_result *json_offer(struct command *cmd, const char *buffer, const jsmntok_t *params) { - const char *desc, *vendor; + const char *desc, *issuer; struct tlv_offer *offer; struct offer_info *offinfo = tal(cmd, struct offer_info); offinfo->offer = offer = tlv_offer_new(offinfo); + /* "issuer" used to be called "vendor" */ + if (deprecated_apis + && params + && params->type == JSMN_OBJECT + && json_get_member(buffer, params, "vendor")) { + if (!param(cmd, buffer, params, + p_req("amount", param_amount, offer), + p_req("description", param_escaped_string, &desc), + p_opt("vendor", param_escaped_string, &issuer), + p_opt("label", param_escaped_string, &offinfo->label), + p_opt("quantity_min", param_u64, &offer->quantity_min), + p_opt("quantity_max", param_u64, &offer->quantity_max), + p_opt("absolute_expiry", param_u64, &offer->absolute_expiry), + p_opt("recurrence", param_recurrence, &offer->recurrence), + p_opt("recurrence_base", + param_recurrence_base, + &offer->recurrence_base), + p_opt("recurrence_paywindow", + param_recurrence_paywindow, + &offer->recurrence_paywindow), + p_opt("recurrence_limit", + param_number, + &offer->recurrence_limit), + p_opt_def("single_use", param_bool, + &offinfo->single_use, false), + NULL)) + return command_param_failed(); + goto after_params; + } + if (!param(cmd, buffer, params, p_req("amount", param_amount, offer), p_req("description", param_escaped_string, &desc), - p_opt("vendor", param_escaped_string, &vendor), + p_opt("issuer", param_escaped_string, &issuer), p_opt("label", param_escaped_string, &offinfo->label), p_opt("quantity_min", param_u64, &offer->quantity_min), p_opt("quantity_max", param_u64, &offer->quantity_max), @@ -344,6 +374,7 @@ struct command_result *json_offer(struct command *cmd, NULL)) return command_param_failed(); +after_params: if (!offers_enabled) return command_fail(cmd, LIGHTNINGD, "experimental-offers not enabled"); @@ -398,12 +429,12 @@ struct command_result *json_offer(struct command *cmd, } offer->description = tal_dup_arr(offer, char, desc, strlen(desc), 0); - if (vendor) { - offer->vendor - = tal_dup_arr(offer, char, vendor, strlen(vendor), 0); + if (issuer) { + offer->issuer + = tal_dup_arr(offer, char, issuer, strlen(issuer), 0); } - offer->node_id = tal_dup(offer, struct pubkey32, &id); + offer->node_id = tal_dup(offer, struct point32, &id); /* If they specify a different currency, warn if we can't * convert it! */ @@ -427,16 +458,34 @@ struct command_result *json_offerout(struct command *cmd, const char *buffer, const jsmntok_t *params) { - const char *desc, *vendor, *label; + const char *desc, *issuer, *label; struct tlv_offer *offer; struct out_req *req; offer = tlv_offer_new(cmd); + /* "issuer" used to be called "vendor" */ + if (deprecated_apis + && params + && params->type == JSMN_OBJECT + && json_get_member(buffer, params, "vendor")) { + if (!param(cmd, buffer, params, + p_req("amount", param_msat_or_any, offer), + p_req("description", param_escaped_string, &desc), + p_opt("vendor", param_escaped_string, &issuer), + p_opt("label", param_escaped_string, &label), + p_opt("absolute_expiry", param_u64, &offer->absolute_expiry), + p_opt("refund_for", param_invoice_payment_hash, &offer->refund_for), + /* FIXME: hints support! */ + NULL)) + return command_param_failed(); + goto after_params; + } + if (!param(cmd, buffer, params, p_req("amount", param_msat_or_any, offer), p_req("description", param_escaped_string, &desc), - p_opt("vendor", param_escaped_string, &vendor), + p_opt("issuer", param_escaped_string, &issuer), p_opt("label", param_escaped_string, &label), p_opt("absolute_expiry", param_u64, &offer->absolute_expiry), p_opt("refund_for", param_invoice_payment_hash, &offer->refund_for), @@ -444,6 +493,7 @@ struct command_result *json_offerout(struct command *cmd, NULL)) return command_param_failed(); +after_params: if (!offers_enabled) return command_fail(cmd, LIGHTNINGD, "experimental-offers not enabled"); @@ -463,11 +513,11 @@ struct command_result *json_offerout(struct command *cmd, } offer->description = tal_dup_arr(offer, char, desc, strlen(desc), 0); - if (vendor) - offer->vendor = tal_dup_arr(offer, char, - vendor, strlen(vendor), 0); + if (issuer) + offer->issuer = tal_dup_arr(offer, char, + issuer, strlen(issuer), 0); - offer->node_id = tal_dup(offer, struct pubkey32, &id); + offer->node_id = tal_dup(offer, struct point32, &id); req = jsonrpc_request_start(cmd->plugin, cmd, "createoffer", check_result, forward_error, diff --git a/plugins/offers_offer.h b/plugins/offers_offer.h index 1cec6e26800f..a0e436ac2993 100644 --- a/plugins/offers_offer.h +++ b/plugins/offers_offer.h @@ -3,7 +3,7 @@ #include "config.h" #include -extern struct pubkey32 id; +extern struct point32 id; extern bool offers_enabled; struct command_result *json_offer(struct command *cmd, diff --git a/plugins/pay.c b/plugins/pay.c index e4ab9247059a..2a46cb8dcebe 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -2073,7 +2073,7 @@ static struct command_result *json_paymod(struct command *cmd, } else invmsat = NULL; - /* FIXME: gossmap should store as pubkey32 */ + /* FIXME: gossmap should store as point32 */ p->destination = tal(p, struct node_id); gossmap_guess_node_id(get_gossmap(cmd->plugin), b12->node_id, p->destination); diff --git a/tests/test_pay.py b/tests/test_pay.py index d07ab9175ba9..a10a0ea8bbf1 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -3984,16 +3984,16 @@ def test_offer(node_factory, bitcoind): offer['bolt12']]).decode('UTF-8') assert 'description: ' + weird_desc in output - # Test vendor - weird_vendor = 'description \\ " \t \n ナンセンス 1杯' + # Test issuer + weird_issuer = 'description \\ " \t \n ナンセンス 1杯' ret = l1.rpc.call('offer', {'amount': '100000sat', - 'description': 'vendor test', - 'vendor': weird_vendor}) + 'description': 'issuer test', + 'issuer': weird_issuer}) offer = only_one(l1.rpc.call('listoffers', [ret['offer_id']])['offers']) output = subprocess.check_output([bolt12tool, 'decode', offer['bolt12']]).decode('UTF-8') - assert 'vendor: ' + weird_vendor in output + assert 'issuer: ' + weird_issuer in output # Test quantity min/max ret = l1.rpc.call('offer', {'amount': '100000sat', @@ -4508,16 +4508,16 @@ def do_test_sendinvoice(node_factory, bitcoind, disable): 'label': 'test sendinvoice refund'}) wait_for(lambda: only_one(l2.rpc.call('listoffers', [refund['offer_id']])['offers'])['used'] is True) - # Offer with vendor: we must not copy vendor into our invoice! + # Offer with issuer: we must not copy issuer into our invoice! offer = l1.rpc.call('offerout', {'amount': '10000sat', 'description': 'simple test', - 'vendor': "clightning test suite"}) + 'issuer': "clightning test suite"}) out = l2.rpc.call('sendinvoice', {'offer': offer['bolt12'], 'label': 'test sendinvoice 3'}) assert out['label'] == 'test sendinvoice 3' assert out['description'] == 'simple test' - assert 'vendor' not in out + assert 'issuer' not in out assert 'bolt12' in out assert 'payment_hash' in out assert out['status'] == 'paid' diff --git a/wire/bolt12_exp_wire.csv b/wire/bolt12_exp_wire.csv index 4eb79522033b..a53ca3cdf8a5 100644 --- a/wire/bolt12_exp_wire.csv +++ b/wire/bolt12_exp_wire.csv @@ -12,8 +12,8 @@ tlvtype,offer,absolute_expiry,14 tlvdata,offer,absolute_expiry,seconds_from_epoch,tu64, tlvtype,offer,paths,16 tlvdata,offer,paths,paths,blinded_path,... -tlvtype,offer,vendor,20 -tlvdata,offer,vendor,vendor,utf8,... +tlvtype,offer,issuer,20 +tlvdata,offer,issuer,issuer,utf8,... tlvtype,offer,quantity_min,22 tlvdata,offer,quantity_min,min,tu64, tlvtype,offer,quantity_max,24 @@ -31,18 +31,21 @@ tlvtype,offer,recurrence_base,28 tlvdata,offer,recurrence_base,start_any_period,byte, tlvdata,offer,recurrence_base,basetime,tu64, tlvtype,offer,node_id,30 -tlvdata,offer,node_id,node_id,pubkey32, +tlvdata,offer,node_id,node_id,point32, tlvtype,offer,send_invoice,54 tlvtype,offer,refund_for,34 tlvdata,offer,refund_for,refunded_payment_hash,sha256, tlvtype,offer,signature,240 tlvdata,offer,signature,sig,bip340sig, subtype,blinded_path +subtypedata,blinded_path,first_node_id,point, subtypedata,blinded_path,blinding,point, -subtypedata,blinded_path,num_hops,u16, +subtypedata,blinded_path,num_hops,byte, subtypedata,blinded_path,path,onionmsg_path,num_hops tlvtype,invoice_request,chains,2 tlvdata,invoice_request,chains,chains,chain_hash,... +tlvtype,invoice_request,chain,3 +tlvdata,invoice_request,chain,chain,chain_hash, tlvtype,invoice_request,offer_id,4 tlvdata,invoice_request,offer_id,offer_id,sha256, tlvtype,invoice_request,amount,8 @@ -56,7 +59,7 @@ tlvdata,invoice_request,recurrence_counter,counter,tu32, tlvtype,invoice_request,recurrence_start,68 tlvdata,invoice_request,recurrence_start,period_offset,tu32, tlvtype,invoice_request,payer_key,38 -tlvdata,invoice_request,payer_key,key,pubkey32, +tlvdata,invoice_request,payer_key,key,point32, tlvtype,invoice_request,payer_note,39 tlvdata,invoice_request,payer_note,note,utf8,... tlvtype,invoice_request,payer_info,50 @@ -67,6 +70,8 @@ tlvtype,invoice_request,payer_signature,240 tlvdata,invoice_request,payer_signature,sig,bip340sig, tlvtype,invoice,chains,2 tlvdata,invoice,chains,chains,chain_hash,... +tlvtype,invoice,chain,3 +tlvdata,invoice,chain,chain,chain_hash, tlvtype,invoice,offer_id,4 tlvdata,invoice,offer_id,offer_id,sha256, tlvtype,invoice,amount,8 @@ -81,10 +86,10 @@ tlvtype,invoice,blindedpay,18 tlvdata,invoice,blindedpay,payinfo,blinded_payinfo,... tlvtype,invoice,blinded_capacities,19 tlvdata,invoice,blinded_capacities,incoming_msat,u64,... -tlvtype,invoice,vendor,20 -tlvdata,invoice,vendor,vendor,utf8,... +tlvtype,invoice,issuer,20 +tlvdata,invoice,issuer,issuer,utf8,... tlvtype,invoice,node_id,30 -tlvdata,invoice,node_id,node_id,pubkey32, +tlvdata,invoice,node_id,node_id,point32, tlvtype,invoice,quantity,32 tlvdata,invoice,quantity,quantity,tu64, tlvtype,invoice,refund_for,34 @@ -97,7 +102,7 @@ tlvdata,invoice,recurrence_start,period_offset,tu32, tlvtype,invoice,recurrence_basetime,64 tlvdata,invoice,recurrence_basetime,basetime,tu64, tlvtype,invoice,payer_key,38 -tlvdata,invoice,payer_key,key,pubkey32, +tlvdata,invoice,payer_key,key,point32, tlvtype,invoice,payer_note,39 tlvdata,invoice,payer_note,note,utf8,... tlvtype,invoice,payer_info,50 @@ -111,7 +116,7 @@ tlvdata,invoice,relative_expiry,seconds_from_creation,tu32, tlvtype,invoice,cltv,46 tlvdata,invoice,cltv,min_final_cltv_expiry,tu32, tlvtype,invoice,fallbacks,48 -tlvdata,invoice,fallbacks,num,u8, +tlvdata,invoice,fallbacks,num,byte, tlvdata,invoice,fallbacks,fallbacks,fallback_address,num tlvtype,invoice,refund_signature,52 tlvdata,invoice,refund_signature,payer_signature,bip340sig, diff --git a/wire/bolt12_wire.csv b/wire/bolt12_wire.csv index 4eb79522033b..a53ca3cdf8a5 100644 --- a/wire/bolt12_wire.csv +++ b/wire/bolt12_wire.csv @@ -12,8 +12,8 @@ tlvtype,offer,absolute_expiry,14 tlvdata,offer,absolute_expiry,seconds_from_epoch,tu64, tlvtype,offer,paths,16 tlvdata,offer,paths,paths,blinded_path,... -tlvtype,offer,vendor,20 -tlvdata,offer,vendor,vendor,utf8,... +tlvtype,offer,issuer,20 +tlvdata,offer,issuer,issuer,utf8,... tlvtype,offer,quantity_min,22 tlvdata,offer,quantity_min,min,tu64, tlvtype,offer,quantity_max,24 @@ -31,18 +31,21 @@ tlvtype,offer,recurrence_base,28 tlvdata,offer,recurrence_base,start_any_period,byte, tlvdata,offer,recurrence_base,basetime,tu64, tlvtype,offer,node_id,30 -tlvdata,offer,node_id,node_id,pubkey32, +tlvdata,offer,node_id,node_id,point32, tlvtype,offer,send_invoice,54 tlvtype,offer,refund_for,34 tlvdata,offer,refund_for,refunded_payment_hash,sha256, tlvtype,offer,signature,240 tlvdata,offer,signature,sig,bip340sig, subtype,blinded_path +subtypedata,blinded_path,first_node_id,point, subtypedata,blinded_path,blinding,point, -subtypedata,blinded_path,num_hops,u16, +subtypedata,blinded_path,num_hops,byte, subtypedata,blinded_path,path,onionmsg_path,num_hops tlvtype,invoice_request,chains,2 tlvdata,invoice_request,chains,chains,chain_hash,... +tlvtype,invoice_request,chain,3 +tlvdata,invoice_request,chain,chain,chain_hash, tlvtype,invoice_request,offer_id,4 tlvdata,invoice_request,offer_id,offer_id,sha256, tlvtype,invoice_request,amount,8 @@ -56,7 +59,7 @@ tlvdata,invoice_request,recurrence_counter,counter,tu32, tlvtype,invoice_request,recurrence_start,68 tlvdata,invoice_request,recurrence_start,period_offset,tu32, tlvtype,invoice_request,payer_key,38 -tlvdata,invoice_request,payer_key,key,pubkey32, +tlvdata,invoice_request,payer_key,key,point32, tlvtype,invoice_request,payer_note,39 tlvdata,invoice_request,payer_note,note,utf8,... tlvtype,invoice_request,payer_info,50 @@ -67,6 +70,8 @@ tlvtype,invoice_request,payer_signature,240 tlvdata,invoice_request,payer_signature,sig,bip340sig, tlvtype,invoice,chains,2 tlvdata,invoice,chains,chains,chain_hash,... +tlvtype,invoice,chain,3 +tlvdata,invoice,chain,chain,chain_hash, tlvtype,invoice,offer_id,4 tlvdata,invoice,offer_id,offer_id,sha256, tlvtype,invoice,amount,8 @@ -81,10 +86,10 @@ tlvtype,invoice,blindedpay,18 tlvdata,invoice,blindedpay,payinfo,blinded_payinfo,... tlvtype,invoice,blinded_capacities,19 tlvdata,invoice,blinded_capacities,incoming_msat,u64,... -tlvtype,invoice,vendor,20 -tlvdata,invoice,vendor,vendor,utf8,... +tlvtype,invoice,issuer,20 +tlvdata,invoice,issuer,issuer,utf8,... tlvtype,invoice,node_id,30 -tlvdata,invoice,node_id,node_id,pubkey32, +tlvdata,invoice,node_id,node_id,point32, tlvtype,invoice,quantity,32 tlvdata,invoice,quantity,quantity,tu64, tlvtype,invoice,refund_for,34 @@ -97,7 +102,7 @@ tlvdata,invoice,recurrence_start,period_offset,tu32, tlvtype,invoice,recurrence_basetime,64 tlvdata,invoice,recurrence_basetime,basetime,tu64, tlvtype,invoice,payer_key,38 -tlvdata,invoice,payer_key,key,pubkey32, +tlvdata,invoice,payer_key,key,point32, tlvtype,invoice,payer_note,39 tlvdata,invoice,payer_note,note,utf8,... tlvtype,invoice,payer_info,50 @@ -111,7 +116,7 @@ tlvdata,invoice,relative_expiry,seconds_from_creation,tu32, tlvtype,invoice,cltv,46 tlvdata,invoice,cltv,min_final_cltv_expiry,tu32, tlvtype,invoice,fallbacks,48 -tlvdata,invoice,fallbacks,num,u8, +tlvdata,invoice,fallbacks,num,byte, tlvdata,invoice,fallbacks,fallbacks,fallback_address,num tlvtype,invoice,refund_signature,52 tlvdata,invoice,refund_signature,payer_signature,bip340sig, diff --git a/wire/extracted_bolt12_tlv_csv b/wire/extracted_bolt12_tlv_csv deleted file mode 100644 index a43366c03ade..000000000000 --- a/wire/extracted_bolt12_tlv_csv +++ /dev/null @@ -1,102 +0,0 @@ -tlvtype,offer_tlvs,chains,2 -tlvdata,offer_tlvs,chains,chains,chain_hash,... -tlvtype,offer_tlvs,currency,6 -tlvdata,offer_tlvs,currency,iso4217,byte,... -tlvtype,offer_tlvs,amount,8 -tlvdata,offer_tlvs,amount,amount,tu64, -tlvtype,offer_tlvs,description,10 -tlvdata,offer_tlvs,description,description,byte,... -tlvtype,offer_tlvs,features,12 -tlvdata,offer_tlvs,features,features,byte,... -tlvtype,offer_tlvs,expiry_timestamp,14 -tlvdata,offer_tlvs,expiry_timestamp,expiry_timestamp,tu64, -tlvtype,offer_tlvs,paths,16 -tlvdata,offer_tlvs,paths,paths,blinded_path,... -tlvtype,offer_tlvs,vendor,20 -tlvdata,offer_tlvs,vendor,vendor,byte,... -tlvtype,offer_tlvs,quantity_min,22 -tlvdata,offer_tlvs,quantity_min,min,tu64, -tlvtype,offer_tlvs,quantity_max,24 -tlvdata,offer_tlvs,quantity_max,max,tu64, -tlvtype,offer_tlvs,recurrence,26 -tlvdata,offer_tlvs,recurrence,time_unit,byte, -tlvdata,offer_tlvs,recurrence,period,u32, -tlvdata,offer_tlvs,recurrence,limit,tu32, -tlvtype,offer_tlvs,recurrence_base,28 -tlvdata,offer_tlvs,recurrence_base,basetime,u32, -tlvdata,offer_tlvs,recurrence_base,paywindow,tu32, -tlvtype,offer_tlvs,node_id,30 -tlvdata,offer_tlvs,node_id,node_id,pubkey32, -tlvtype,offer_tlvs,signature,240 -tlvdata,offer_tlvs,signature,sig,signature, -subtype,blinded_path -subtypedata,blinded_path,blinding,point, -tlvtype,invoice_request_tlvs,chains,2 -tlvdata,invoice_request_tlvs,chains,chains,chain_hash,... -tlvtype,invoice_request_tlvs,offer_id,4 -tlvdata,invoice_request_tlvs,offer_id,offer_id,sha256, -tlvtype,invoice_request_tlvs,amount,8 -tlvdata,invoice_request_tlvs,amount,amount,tu64, -tlvtype,invoice_request_tlvs,description,10 -tlvdata,invoice_request_tlvs,description,description,byte,... -tlvtype,invoice_request_tlvs,features,12 -tlvdata,invoice_request_tlvs,features,features,byte,... -tlvtype,invoice_request_tlvs,paths,16 -tlvdata,invoice_request_tlvs,paths,paths,blinded_path,... -tlvtype,invoice_request_tlvs,quantity,32 -tlvdata,invoice_request_tlvs,quantity,quantity,tu64, -tlvtype,invoice_request_tlvs,refund_for,34 -tlvdata,invoice_request_tlvs,refund_for,refunded_payment_hash,sha256, -tlvtype,invoice_request_tlvs,invoice_request_recurrence,36 -tlvdata,invoice_request_tlvs,invoice_request_recurrence,counter,tu64, -tlvtype,invoice_request_tlvs,payer_key,38 -tlvdata,invoice_request_tlvs,payer_key,key,pubkey32, -tlvtype,invoice_tlvs,chains,2 -tlvdata,invoice_tlvs,chains,chains,chain_hash,... -tlvtype,invoice_tlvs,offer_id,4 -tlvdata,invoice_tlvs,offer_id,offer_id,sha256, -tlvtype,invoice_tlvs,amount,8 -tlvdata,invoice_tlvs,amount,amount,tu64, -tlvtype,invoice_tlvs,description,10 -tlvdata,invoice_tlvs,description,description,byte,... -tlvtype,invoice_tlvs,features,12 -tlvdata,invoice_tlvs,features,features,byte,... -tlvtype,invoice_tlvs,paths,16 -tlvdata,invoice_tlvs,paths,paths,blinded_path,... -tlvtype,invoice_tlvs,blindedpay,18 -tlvdata,invoice_tlvs,blindedpay,payinfo,blinded_payinfo,... -tlvtype,invoice_tlvs,vendor,20 -tlvdata,invoice_tlvs,vendor,vendor,byte,... -tlvtype,invoice_tlvs,node_id,30 -tlvdata,invoice_tlvs,node_id,node_id,pubkey32, -tlvtype,invoice_tlvs,quantity,32 -tlvdata,invoice_tlvs,quantity,quantity,tu64, -tlvtype,invoice_tlvs,refund_for,34 -tlvdata,invoice_tlvs,refund_for,refunded_payment_hash,sha256, -tlvtype,invoice_tlvs,payer_key,38 -tlvdata,invoice_tlvs,payer_key,key,pubkey32, -tlvtype,invoice_tlvs,timestamp,40 -tlvdata,invoice_tlvs,timestamp,timestamp,tu32, -tlvtype,invoice_tlvs,payment_hash,42 -tlvdata,invoice_tlvs,payment_hash,payment_hash,sha256, -tlvtype,invoice_tlvs,expiry,44 -tlvdata,invoice_tlvs,expiry,expiry_seconds,tu32, -tlvtype,invoice_tlvs,cltv,46 -tlvdata,invoice_tlvs,cltv,min_final_cltv_expiry,tu32, -tlvtype,invoice_tlvs,fallbacks,48 -tlvdata,invoice_tlvs,fallbacks,num,u8, -tlvdata,invoice_tlvs,fallbacks,fallbacks,fallback_address,num -tlvtype,invoice_tlvs,refund_signature,52 -tlvdata,invoice_tlvs,refund_signature,payer_signature,signature, -tlvtype,invoice_tlvs,signature,240 -tlvdata,invoice_tlvs,signature,sig,signature, -subtype,blinded_payinfo -subtypedata,blinded_payinfo,fee_base_msat,u32, -subtypedata,blinded_payinfo,fee_proportional_millionths,u32, -subtypedata,blinded_payinfo,cltv_expiry_delta,u16, -subtypedata,blinded_payinfo,flen,u16, -subtypedata,blinded_payinfo,features,byte,flen -subtype,fallback_address -subtypedata,fallback_address,type,byte, -subtypedata,fallback_address,len,u16, -subtypedata,fallback_address,address,byte,len