diff --git a/common/bolt12.c b/common/bolt12.c index 1910d26e9c00..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, @@ -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 c460f4eac492..e1b0c00e71bf 100644 --- a/common/bolt12.h +++ b/common/bolt12.h @@ -103,6 +103,11 @@ bool bolt12_check_signature(const struct tlv_field *fields, 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/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c index 521b47d4b82c..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) diff --git a/common/test/run-bolt12_merkle.c b/common/test/run-bolt12_merkle.c index 04a9e944592f..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, 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/devtools/bolt12-cli.c b/devtools/bolt12-cli.c index a941e70a7c34..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) { @@ -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)) diff --git a/doc/schemas/decode.schema.json b/doc/schemas/decode.schema.json index 7be8b710a6ba..d985e365a1fb 100644 --- a/doc/schemas/decode.schema.json +++ b/doc/schemas/decode.schema.json @@ -282,15 +282,11 @@ "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", @@ -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", @@ -620,7 +612,7 @@ "type": { }, "valid": { }, "offer_id": { }, - "chains": { }, + "chain": { }, "amount_msat": { }, "features": { }, "quantity": { }, diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index dfad64728f29..336d058e8a9a 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -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 @@ -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 diff --git a/plugins/offers.c b/plugins/offers.c index 0c2dff01727d..b89a12cc4998 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -565,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); @@ -700,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: @@ -749,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. 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 d2a1c98de807..0391b84e9b90 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -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. */ @@ -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/wire/bolt12_exp_wire.csv b/wire/bolt12_exp_wire.csv index 3b8b8de3fd33..a53ca3cdf8a5 100644 --- a/wire/bolt12_exp_wire.csv +++ b/wire/bolt12_exp_wire.csv @@ -44,6 +44,8 @@ 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 @@ -68,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 diff --git a/wire/bolt12_wire.csv b/wire/bolt12_wire.csv index 3b8b8de3fd33..a53ca3cdf8a5 100644 --- a/wire/bolt12_wire.csv +++ b/wire/bolt12_wire.csv @@ -44,6 +44,8 @@ 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 @@ -68,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