mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-24 01:24:26 +01:00
bolt12: use spec field names, update decode API.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
fdb3d9186a
commit
ef2f4a0648
567
plugins/offers.c
567
plugins/offers.c
@@ -230,9 +230,10 @@ static struct command_result *param_decodable(struct command *cmd,
|
||||
}
|
||||
|
||||
static void json_add_chains(struct json_stream *js,
|
||||
const char *fieldname,
|
||||
const struct bitcoin_blkid *chains)
|
||||
{
|
||||
json_array_start(js, "chains");
|
||||
json_array_start(js, fieldname);
|
||||
for (size_t i = 0; i < tal_count(chains); i++)
|
||||
json_add_sha256(js, NULL, &chains[i].shad.sha);
|
||||
json_array_end(js);
|
||||
@@ -247,7 +248,8 @@ static void json_add_onionmsg_path(struct json_stream *js,
|
||||
json_add_pubkey(js, "blinded_node_id", &hop->blinded_node_id);
|
||||
json_add_hex_talarr(js, "encrypted_recipient_data", hop->encrypted_recipient_data);
|
||||
if (payinfo) {
|
||||
json_add_u32(js, "fee_base_msat", payinfo->fee_base_msat);
|
||||
json_add_amount_msat_only(js, "fee_base_msat",
|
||||
amount_msat(payinfo->fee_base_msat));
|
||||
json_add_u32(js, "fee_proportional_millionths",
|
||||
payinfo->fee_proportional_millionths);
|
||||
json_add_u32(js, "cltv_expiry_delta",
|
||||
@@ -259,11 +261,12 @@ static void json_add_onionmsg_path(struct json_stream *js,
|
||||
|
||||
/* Returns true if valid */
|
||||
static bool json_add_blinded_paths(struct json_stream *js,
|
||||
const char *fieldname,
|
||||
struct blinded_path **paths,
|
||||
struct blinded_payinfo **blindedpay)
|
||||
{
|
||||
size_t n = 0;
|
||||
json_array_start(js, "paths");
|
||||
json_array_start(js, fieldname);
|
||||
for (size_t i = 0; i < tal_count(paths); i++) {
|
||||
json_object_start(js, NULL);
|
||||
json_add_pubkey(js, "first_node_id", &paths[i]->first_node_id);
|
||||
@@ -286,7 +289,7 @@ static bool json_add_blinded_paths(struct json_stream *js,
|
||||
* `blinded_path`.
|
||||
*/
|
||||
if (blindedpay && n != tal_count(blindedpay)) {
|
||||
json_add_string(js, "warning_invoice_invalid_blinded_payinfo",
|
||||
json_add_string(js, "warning_invalid_invoice_blindedpay",
|
||||
"invoice does not have correct number of blinded_payinfo");
|
||||
return false;
|
||||
}
|
||||
@@ -312,33 +315,57 @@ static const char *recurrence_time_unit_name(u8 time_unit)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer)
|
||||
static bool json_add_utf8(struct json_stream *js,
|
||||
const char *fieldname,
|
||||
const char *utf8str)
|
||||
{
|
||||
if (utf8_check(utf8str, tal_bytelen(utf8str))) {
|
||||
json_add_stringn(js, fieldname, utf8str, tal_bytelen(utf8str));
|
||||
return true;
|
||||
}
|
||||
json_add_string(js, tal_fmt(tmpctx, "warning_invalid_%s", fieldname),
|
||||
"invalid UTF8");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool json_add_offer_fields(struct json_stream *js,
|
||||
const struct bitcoin_blkid *offer_chains,
|
||||
const u8 *offer_metadata,
|
||||
const char *offer_currency,
|
||||
const u64 *offer_amount,
|
||||
const char *offer_description,
|
||||
const u8 *offer_features,
|
||||
const u64 *offer_absolute_expiry,
|
||||
struct blinded_path **offer_paths,
|
||||
const char *offer_issuer,
|
||||
const u64 *offer_quantity_max,
|
||||
const struct pubkey *offer_node_id,
|
||||
const struct recurrence *offer_recurrence,
|
||||
const struct recurrence_paywindow *offer_recurrence_paywindow,
|
||||
const u32 *offer_recurrence_limit,
|
||||
const struct recurrence_base *offer_recurrence_base)
|
||||
{
|
||||
struct sha256 offer_id;
|
||||
bool valid = true;
|
||||
|
||||
/* FIXME-OFFERS: Rename all fields to offer_ as per spec */
|
||||
offer_offer_id(offer, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
if (offer->offer_chains)
|
||||
json_add_chains(js, offer->offer_chains);
|
||||
if (offer->offer_currency) {
|
||||
if (offer_chains)
|
||||
json_add_chains(js, "offer_chains", offer_chains);
|
||||
if (offer_metadata)
|
||||
json_add_hex_talarr(js, "offer_metadata", offer_metadata);
|
||||
if (offer_currency) {
|
||||
const struct iso4217_name_and_divisor *iso4217;
|
||||
json_add_stringn(js, "currency",
|
||||
offer->offer_currency,
|
||||
tal_bytelen(offer->offer_currency));
|
||||
if (offer->offer_amount)
|
||||
json_add_u64(js, "amount", *offer->offer_amount);
|
||||
iso4217 = find_iso4217(offer->offer_currency,
|
||||
tal_bytelen(offer->offer_currency));
|
||||
valid &= json_add_utf8(js, "offer_currency", offer_currency);
|
||||
if (offer_amount)
|
||||
json_add_u64(js, "offer_amount", *offer_amount);
|
||||
iso4217 = find_iso4217(offer_currency,
|
||||
tal_bytelen(offer_currency));
|
||||
if (iso4217)
|
||||
json_add_num(js, "minor_unit", iso4217->minor_unit);
|
||||
json_add_num(js, "currency_minor_unit", iso4217->minor_unit);
|
||||
else
|
||||
json_add_string(js, "warning_offer_unknown_currency",
|
||||
json_add_string(js, "warning_unknown_offer_currency",
|
||||
"unknown currency code");
|
||||
} else if (offer->offer_amount)
|
||||
json_add_amount_msat_only(js, "amount_msat",
|
||||
amount_msat(*offer->offer_amount));
|
||||
} else if (offer_amount)
|
||||
json_add_amount_msat_only(js, "offer_amount_msat",
|
||||
amount_msat(*offer_amount));
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* A reader of an offer:
|
||||
@@ -346,71 +373,153 @@ static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer
|
||||
* - if `offer_description` is not set:
|
||||
* - MUST NOT respond to the offer.
|
||||
*/
|
||||
if (offer->offer_description)
|
||||
json_add_stringn(js, "description",
|
||||
offer->offer_description,
|
||||
tal_bytelen(offer->offer_description));
|
||||
if (offer_description)
|
||||
valid &= json_add_utf8(js, "offer_description",
|
||||
offer_description);
|
||||
else {
|
||||
json_add_string(js, "warning_offer_missing_description",
|
||||
json_add_string(js, "warning_missing_offer_description",
|
||||
"offers without a description are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (offer->offer_issuer)
|
||||
json_add_stringn(js, "issuer", offer->offer_issuer,
|
||||
tal_bytelen(offer->offer_issuer));
|
||||
if (offer->offer_features)
|
||||
json_add_hex_talarr(js, "features", offer->offer_features);
|
||||
if (offer->offer_absolute_expiry)
|
||||
json_add_u64(js, "absolute_expiry",
|
||||
*offer->offer_absolute_expiry);
|
||||
if (offer->offer_paths)
|
||||
valid &= json_add_blinded_paths(js, offer->offer_paths, NULL);
|
||||
if (offer_issuer)
|
||||
valid &= json_add_utf8(js, "offer_issuer", offer_issuer);
|
||||
if (offer_features)
|
||||
json_add_hex_talarr(js, "offer_features", offer_features);
|
||||
if (offer_absolute_expiry)
|
||||
json_add_u64(js, "offer_absolute_expiry",
|
||||
*offer_absolute_expiry);
|
||||
if (offer_paths)
|
||||
valid &= json_add_blinded_paths(js, "offer_paths",
|
||||
offer_paths, NULL);
|
||||
|
||||
if (offer->offer_quantity_max)
|
||||
json_add_u64(js, "quantity_max", *offer->offer_quantity_max);
|
||||
if (offer->offer_recurrence) {
|
||||
if (offer_quantity_max)
|
||||
json_add_u64(js, "offer_quantity_max", *offer_quantity_max);
|
||||
|
||||
if (offer_recurrence) {
|
||||
const char *name;
|
||||
json_object_start(js, "recurrence");
|
||||
json_add_num(js, "time_unit", offer->offer_recurrence->time_unit);
|
||||
name = recurrence_time_unit_name(offer->offer_recurrence->time_unit);
|
||||
json_object_start(js, "offer_recurrence");
|
||||
json_add_num(js, "time_unit", offer_recurrence->time_unit);
|
||||
name = recurrence_time_unit_name(offer_recurrence->time_unit);
|
||||
if (name)
|
||||
json_add_string(js, "time_unit_name", name);
|
||||
json_add_num(js, "period", offer->offer_recurrence->period);
|
||||
if (offer->offer_recurrence_base) {
|
||||
json_add_num(js, "period", offer_recurrence->period);
|
||||
if (offer_recurrence_base) {
|
||||
json_add_u64(js, "basetime",
|
||||
offer->offer_recurrence_base->basetime);
|
||||
if (offer->offer_recurrence_base->start_any_period)
|
||||
offer_recurrence_base->basetime);
|
||||
if (offer_recurrence_base->start_any_period)
|
||||
json_add_bool(js, "start_any_period", true);
|
||||
}
|
||||
if (offer->offer_recurrence_limit)
|
||||
json_add_u32(js, "limit", *offer->offer_recurrence_limit);
|
||||
if (offer->offer_recurrence_paywindow) {
|
||||
if (offer_recurrence_limit)
|
||||
json_add_u32(js, "limit", *offer_recurrence_limit);
|
||||
if (offer_recurrence_paywindow) {
|
||||
json_object_start(js, "paywindow");
|
||||
json_add_u32(js, "seconds_before",
|
||||
offer->offer_recurrence_paywindow->seconds_before);
|
||||
offer_recurrence_paywindow->seconds_before);
|
||||
json_add_u32(js, "seconds_after",
|
||||
offer->offer_recurrence_paywindow->seconds_after);
|
||||
if (offer->offer_recurrence_paywindow->proportional_amount)
|
||||
offer_recurrence_paywindow->seconds_after);
|
||||
if (offer_recurrence_paywindow->proportional_amount)
|
||||
json_add_bool(js, "proportional_amount", true);
|
||||
json_object_end(js);
|
||||
}
|
||||
json_object_end(js);
|
||||
}
|
||||
|
||||
/* Required for offers, *not* for others! */
|
||||
if (offer_node_id)
|
||||
json_add_pubkey(js, "offer_node_id", offer_node_id);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer)
|
||||
{
|
||||
struct sha256 offer_id;
|
||||
bool valid = true;
|
||||
|
||||
offer_offer_id(offer, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
|
||||
valid &= json_add_offer_fields(js,
|
||||
offer->offer_chains,
|
||||
offer->offer_metadata,
|
||||
offer->offer_currency,
|
||||
offer->offer_amount,
|
||||
offer->offer_description,
|
||||
offer->offer_features,
|
||||
offer->offer_absolute_expiry,
|
||||
offer->offer_paths,
|
||||
offer->offer_issuer,
|
||||
offer->offer_quantity_max,
|
||||
offer->offer_node_id,
|
||||
offer->offer_recurrence,
|
||||
offer->offer_recurrence_paywindow,
|
||||
offer->offer_recurrence_limit,
|
||||
offer->offer_recurrence_base);
|
||||
/* BOLT-offers #12:
|
||||
* - if `offer_node_id` is not set:
|
||||
* - MUST NOT respond to the offer.
|
||||
*/
|
||||
/* FIXME-OFFERS: Rename all fields to offer_ as per spec */
|
||||
if (offer->offer_node_id)
|
||||
json_add_pubkey(js, "node_id", offer->offer_node_id);
|
||||
else
|
||||
if (!offer->offer_node_id) {
|
||||
json_add_string(js, "warning_missing_offer_node_id",
|
||||
"offers without a node_id are invalid");
|
||||
valid = false;
|
||||
|
||||
}
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
static bool json_add_invreq_fields(struct json_stream *js,
|
||||
const u8 *invreq_metadata,
|
||||
const struct bitcoin_blkid *invreq_chain,
|
||||
const u64 *invreq_amount,
|
||||
const u8 *invreq_features,
|
||||
const u64 *invreq_quantity,
|
||||
const struct pubkey *invreq_payer_id,
|
||||
const utf8 *invreq_payer_note,
|
||||
const u32 *invreq_recurrence_counter,
|
||||
const u32 *invreq_recurrence_start)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata` are not present.
|
||||
*/
|
||||
if (invreq_metadata)
|
||||
json_add_hex_talarr(js, "invreq_metadata",
|
||||
invreq_metadata);
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invreq_metadata",
|
||||
"invreq_metadata required");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* This can be missing for an invoice though! */
|
||||
if (invreq_payer_id)
|
||||
json_add_pubkey(js, "invreq_payer_id", invreq_payer_id);
|
||||
|
||||
if (invreq_chain)
|
||||
json_add_sha256(js, "invreq_chain", &invreq_chain->shad.sha);
|
||||
|
||||
if (invreq_amount)
|
||||
json_add_amount_msat_only(js, "invreq_amount_msat",
|
||||
amount_msat(*invreq_amount));
|
||||
if (invreq_features)
|
||||
json_add_hex_talarr(js, "invreq_features", invreq_features);
|
||||
if (invreq_quantity)
|
||||
json_add_u64(js, "invreq_quantity", *invreq_quantity);
|
||||
if (invreq_payer_note)
|
||||
valid &= json_add_utf8(js, "invreq_payer_note", invreq_payer_note);
|
||||
if (invreq_recurrence_counter) {
|
||||
json_add_u32(js, "invreq_recurrence_counter",
|
||||
*invreq_recurrence_counter);
|
||||
if (invreq_recurrence_start)
|
||||
json_add_u32(js, "invreq_recurrence_start",
|
||||
*invreq_recurrence_start);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* Returns true if valid */
|
||||
static bool json_add_fallback_address(struct json_stream *js,
|
||||
const struct chainparams *chain,
|
||||
@@ -425,7 +534,7 @@ static bool json_add_fallback_address(struct json_stream *js,
|
||||
return true;
|
||||
}
|
||||
json_add_string(js,
|
||||
"warning_invoice_fallbacks_address_invalid",
|
||||
"warning_invalid_invoice_fallbacks_address",
|
||||
"invalid fallback address for this version");
|
||||
return false;
|
||||
}
|
||||
@@ -444,7 +553,7 @@ static bool json_add_fallbacks(struct json_stream *js,
|
||||
else
|
||||
chain = chainparams_for_network("bitcoin");
|
||||
|
||||
json_array_start(js, "fallbacks");
|
||||
json_array_start(js, "invoice_fallbacks");
|
||||
for (size_t i = 0; i < tal_count(fallbacks); i++) {
|
||||
size_t addrlen = tal_bytelen(fallbacks[i]->address);
|
||||
|
||||
@@ -463,12 +572,12 @@ static bool json_add_fallbacks(struct json_stream *js,
|
||||
*/
|
||||
if (fallbacks[i]->version > 16) {
|
||||
json_add_string(js,
|
||||
"warning_invoice_fallbacks_version_invalid",
|
||||
"warning_invalid_invoice_fallbacks_version",
|
||||
"invoice fallback version > 16");
|
||||
valid = false;
|
||||
} else if (addrlen < 2 || addrlen > 40) {
|
||||
json_add_string(js,
|
||||
"warning_invoice_fallbacks_address_invalid",
|
||||
"warning_invalid_invoice_fallbacks_address",
|
||||
"invoice fallback address bad length");
|
||||
valid = false;
|
||||
} else if (chain) {
|
||||
@@ -483,6 +592,82 @@ static bool json_add_fallbacks(struct json_stream *js,
|
||||
return valid;
|
||||
}
|
||||
|
||||
static void json_add_invoice_request(struct json_stream *js,
|
||||
const struct tlv_invoice_request *invreq)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* If there's an offer_node_id, then there's an offer. */
|
||||
if (invreq->offer_node_id) {
|
||||
struct sha256 offer_id;
|
||||
|
||||
invreq_offer_id(invreq, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
}
|
||||
|
||||
valid &= json_add_offer_fields(js,
|
||||
invreq->offer_chains,
|
||||
invreq->offer_metadata,
|
||||
invreq->offer_currency,
|
||||
invreq->offer_amount,
|
||||
invreq->offer_description,
|
||||
invreq->offer_features,
|
||||
invreq->offer_absolute_expiry,
|
||||
invreq->offer_paths,
|
||||
invreq->offer_issuer,
|
||||
invreq->offer_quantity_max,
|
||||
invreq->offer_node_id,
|
||||
invreq->offer_recurrence,
|
||||
invreq->offer_recurrence_paywindow,
|
||||
invreq->offer_recurrence_limit,
|
||||
invreq->offer_recurrence_base);
|
||||
valid &= json_add_invreq_fields(js,
|
||||
invreq->invreq_metadata,
|
||||
invreq->invreq_chain,
|
||||
invreq->invreq_amount,
|
||||
invreq->invreq_features,
|
||||
invreq->invreq_quantity,
|
||||
invreq->invreq_payer_id,
|
||||
invreq->invreq_payer_note,
|
||||
invreq->invreq_recurrence_counter,
|
||||
invreq->invreq_recurrence_start);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata` are not present.
|
||||
*/
|
||||
if (!invreq->invreq_payer_id) {
|
||||
json_add_string(js, "warning_missing_invreq_payer_id",
|
||||
"invreq_payer_id required");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `signature` is not correct as detailed
|
||||
* in [Signature Calculation](#signature-calculation) using the
|
||||
* `invreq_payer_id`.
|
||||
*/
|
||||
if (invreq->signature) {
|
||||
if (invreq->invreq_payer_id
|
||||
&& !bolt12_check_signature(invreq->fields,
|
||||
"invoice_request",
|
||||
"signature",
|
||||
invreq->invreq_payer_id,
|
||||
invreq->signature)) {
|
||||
json_add_string(js, "warning_invalid_invoice_request_signature",
|
||||
"Bad signature");
|
||||
valid = false;
|
||||
} else {
|
||||
json_add_bip340sig(js, "signature", invreq->signature);
|
||||
}
|
||||
} else {
|
||||
json_add_string(js, "warning_missing_invoice_request_signature",
|
||||
"Missing signature");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
static void json_add_b12_invoice(struct json_stream *js,
|
||||
const struct tlv_invoice *invoice)
|
||||
{
|
||||
@@ -496,66 +681,32 @@ static void json_add_b12_invoice(struct json_stream *js,
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
}
|
||||
|
||||
/* FIXME-OFFERS: Rename all fields to invoice_ as per spec */
|
||||
if (invoice->invreq_chain)
|
||||
json_add_sha256(js, "chain", &invoice->invreq_chain->shad.sha);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `invoice_amount` is not present.
|
||||
* - MUST reject the invoice if `invreq_payer_id` is not present.
|
||||
*/
|
||||
if (invoice->invoice_amount)
|
||||
json_add_amount_msat_only(js, "amount_msat",
|
||||
amount_msat(*invoice->invoice_amount));
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_amount",
|
||||
"invoices without an amount are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invreq_payer_id)
|
||||
json_add_pubkey(js, "payer_key", invoice->invreq_payer_id);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_invreq_payer_id",
|
||||
"invoices without an invreq_payer_id are invald");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `offer_description` is not present.
|
||||
* - MUST reject the invoice if `invoice_created_at` is not present.
|
||||
* - MUST reject the invoice if `invoice_payment_hash` is not present.
|
||||
*/
|
||||
if (invoice->offer_description)
|
||||
json_add_stringn(js, "description", invoice->offer_description,
|
||||
tal_bytelen(invoice->offer_description));
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_description",
|
||||
"invoices without a description are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invoice_created_at) {
|
||||
json_add_u64(js, "created_at", *invoice->invoice_created_at);
|
||||
} else {
|
||||
json_add_string(js, "warning_invoice_missing_created_at",
|
||||
"invoices without created_at are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invoice_payment_hash)
|
||||
json_add_sha256(js, "payment_hash", invoice->invoice_payment_hash);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_payment_hash",
|
||||
"invoices without a payment_hash are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->offer_issuer)
|
||||
json_add_stringn(js, "issuer", invoice->offer_issuer,
|
||||
tal_bytelen(invoice->offer_issuer));
|
||||
if (invoice->invoice_features)
|
||||
json_add_hex_talarr(js, "features", invoice->invoice_features);
|
||||
valid &= json_add_offer_fields(js,
|
||||
invoice->offer_chains,
|
||||
invoice->offer_metadata,
|
||||
invoice->offer_currency,
|
||||
invoice->offer_amount,
|
||||
invoice->offer_description,
|
||||
invoice->offer_features,
|
||||
invoice->offer_absolute_expiry,
|
||||
invoice->offer_paths,
|
||||
invoice->offer_issuer,
|
||||
invoice->offer_quantity_max,
|
||||
invoice->offer_node_id,
|
||||
invoice->offer_recurrence,
|
||||
invoice->offer_recurrence_paywindow,
|
||||
invoice->offer_recurrence_limit,
|
||||
invoice->offer_recurrence_base);
|
||||
valid &= json_add_invreq_fields(js,
|
||||
invoice->invreq_metadata,
|
||||
invoice->invreq_chain,
|
||||
invoice->invreq_amount,
|
||||
invoice->invreq_features,
|
||||
invoice->invreq_quantity,
|
||||
invoice->invreq_payer_id,
|
||||
invoice->invreq_payer_note,
|
||||
invoice->invreq_recurrence_counter,
|
||||
invoice->invreq_recurrence_start);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `invoice_paths` is not present
|
||||
@@ -574,48 +725,27 @@ static void json_add_b12_invoice(struct json_stream *js,
|
||||
* in `blinded_path`.
|
||||
*/
|
||||
if (!invoice->invoice_blindedpay) {
|
||||
json_add_string(js, "warning_invoice_missing_blinded_payinfo",
|
||||
"invoices with blinded_path without blinded_payinfo are invalid");
|
||||
json_add_string(js, "warning_missing_invoice_blindedpay",
|
||||
"invoices with paths without blindedpay are invalid");
|
||||
valid = false;
|
||||
}
|
||||
valid &= json_add_blinded_paths(js, invoice->invoice_paths,
|
||||
valid &= json_add_blinded_paths(js, "invoice_paths",
|
||||
invoice->invoice_paths,
|
||||
invoice->invoice_blindedpay);
|
||||
} else {
|
||||
json_add_string(js, "warning_invoice_missing_blinded_path",
|
||||
"invoices without a payment_hash are invalid");
|
||||
json_add_string(js, "warning_missing_invoice_paths",
|
||||
"invoices without a invoice_paths are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invreq_quantity)
|
||||
json_add_u64(js, "quantity", *invoice->invreq_quantity);
|
||||
if (invoice->invreq_recurrence_counter) {
|
||||
json_add_u32(js, "recurrence_counter",
|
||||
*invoice->invreq_recurrence_counter);
|
||||
if (invoice->invreq_recurrence_start)
|
||||
json_add_u32(js, "recurrence_start",
|
||||
*invoice->invreq_recurrence_start);
|
||||
/* BOLT-offers-recurrence #12:
|
||||
* - if the offer contained `recurrence`:
|
||||
* - MUST reject the invoice if `recurrence_basetime` is not
|
||||
* set.
|
||||
*/
|
||||
if (invoice->invoice_recurrence_basetime)
|
||||
json_add_u64(js, "recurrence_basetime",
|
||||
*invoice->invoice_recurrence_basetime);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_recurrence_basetime",
|
||||
"recurring invoices without a recurrence_basetime are invalid");
|
||||
valid = false;
|
||||
}
|
||||
if (invoice->invoice_created_at) {
|
||||
json_add_u64(js, "invoice_created_at", *invoice->invoice_created_at);
|
||||
} else {
|
||||
json_add_string(js, "warning_missing_invoice_created_at",
|
||||
"invoices without created_at are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invreq_metadata)
|
||||
json_add_hex_talarr(js, "invreq_metadata",
|
||||
invoice->invreq_metadata);
|
||||
if (invoice->invreq_payer_note)
|
||||
json_add_stringn(js, "payer_note", invoice->invreq_payer_note,
|
||||
tal_bytelen(invoice->invreq_payer_note));
|
||||
|
||||
/* BOLT-offers #12:
|
||||
*
|
||||
* - if `invoice_relative_expiry` is present:
|
||||
@@ -626,104 +756,65 @@ static void json_add_b12_invoice(struct json_stream *js,
|
||||
* is greater than `invoice_created_at` plus 7200.
|
||||
*/
|
||||
if (invoice->invoice_relative_expiry)
|
||||
json_add_u32(js, "relative_expiry", *invoice->invoice_relative_expiry);
|
||||
json_add_u32(js, "invoice_relative_expiry", *invoice->invoice_relative_expiry);
|
||||
else
|
||||
json_add_u32(js, "relative_expiry", 7200);
|
||||
json_add_u32(js, "invoice_relative_expiry", BOLT12_DEFAULT_REL_EXPIRY);
|
||||
|
||||
if (invoice->invoice_payment_hash)
|
||||
json_add_sha256(js, "invoice_payment_hash", invoice->invoice_payment_hash);
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invoice_payment_hash",
|
||||
"invoices without a payment_hash are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `invoice_amount` is not present.
|
||||
*/
|
||||
if (invoice->invoice_amount)
|
||||
json_add_amount_msat_only(js, "invoice_amount_msat",
|
||||
amount_msat(*invoice->invoice_amount));
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invoice_amount",
|
||||
"invoices without an amount are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invoice_fallbacks)
|
||||
valid &= json_add_fallbacks(js,
|
||||
invoice->invreq_chain,
|
||||
invoice->invoice_fallbacks);
|
||||
|
||||
/* invoice_decode checked these */
|
||||
json_add_pubkey(js, "node_id", invoice->offer_node_id);
|
||||
json_add_bip340sig(js, "signature", invoice->signature);
|
||||
if (invoice->invoice_features)
|
||||
json_add_hex_talarr(js, "features", invoice->invoice_features);
|
||||
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
static void json_add_invoice_request(struct json_stream *js,
|
||||
const struct tlv_invoice_request *invreq)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* If there's an offer_node_id, then there's an offer. */
|
||||
if (invreq->offer_node_id) {
|
||||
struct sha256 offer_id;
|
||||
|
||||
invreq_offer_id(invreq, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
}
|
||||
|
||||
/* FIXME-OFFERS: Rename all fields to invreq_ as per spec */
|
||||
if (invreq->invreq_chain)
|
||||
json_add_sha256(js, "chain", &invreq->invreq_chain->shad.sha);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `payer_key` is not present.
|
||||
*...
|
||||
* - MUST fail the request if `features` contains unknown even bits.
|
||||
* - MUST fail the request if `offer_id` is not present.
|
||||
*/
|
||||
if (invreq->invreq_amount)
|
||||
json_add_amount_msat_only(js, "amount_msat",
|
||||
amount_msat(*invreq->invreq_amount));
|
||||
if (invreq->invreq_features)
|
||||
json_add_hex_talarr(js, "features", invreq->invreq_features);
|
||||
if (invreq->invreq_quantity)
|
||||
json_add_u64(js, "quantity", *invreq->invreq_quantity);
|
||||
|
||||
if (invreq->invreq_recurrence_counter)
|
||||
json_add_u32(js, "recurrence_counter",
|
||||
*invreq->invreq_recurrence_counter);
|
||||
if (invreq->invreq_recurrence_start)
|
||||
json_add_u32(js, "recurrence_start",
|
||||
*invreq->invreq_recurrence_start);
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata`
|
||||
* are not present.
|
||||
*/
|
||||
if (invreq->invreq_payer_id)
|
||||
json_add_pubkey(js, "payer_key", invreq->invreq_payer_id);
|
||||
if (invoice->invoice_node_id)
|
||||
json_add_pubkey(js, "invoice_node_id", invoice->invoice_node_id);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_request_missing_payer_key",
|
||||
"invoice_request requires payer_key");
|
||||
valid = false;
|
||||
}
|
||||
if (invreq->invreq_metadata)
|
||||
json_add_hex_talarr(js, "invreq_metadata", invreq->invreq_metadata);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_request_missing_invreq_metadata",
|
||||
"invoice_request requires invreq_metadata");
|
||||
json_add_string(js, "warning_missing_invoice_node_id",
|
||||
"invoices without an invoice_node_id are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invreq->invreq_payer_note)
|
||||
json_add_stringn(js, "payer_note", invreq->invreq_payer_note,
|
||||
tal_bytelen(invreq->invreq_payer_note));
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `signature` is not correct as detailed
|
||||
* in [Signature Calculation](#signature-calculation) using the
|
||||
* `invreq_payer_id`.
|
||||
/* BOLT-offers-recurrence #12:
|
||||
* - if the offer contained `recurrence`:
|
||||
* - MUST reject the invoice if `recurrence_basetime` is not
|
||||
* set.
|
||||
*/
|
||||
if (invreq->signature) {
|
||||
if (invreq->invreq_payer_id
|
||||
&& !bolt12_check_signature(invreq->fields,
|
||||
"invoice_request",
|
||||
"signature",
|
||||
invreq->invreq_payer_id,
|
||||
invreq->signature)) {
|
||||
json_add_string(js, "warning_invoice_request_invalid_signature",
|
||||
"Bad signature");
|
||||
if (invoice->offer_recurrence) {
|
||||
if (invoice->invoice_recurrence_basetime)
|
||||
json_add_u64(js, "invoice_recurrence_basetime",
|
||||
*invoice->invoice_recurrence_basetime);
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invoice_recurrence_basetime",
|
||||
"recurring invoices without a recurrence_basetime are invalid");
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
json_add_string(js, "warning_invoice_request_missing_signature",
|
||||
"Missing signature");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* invoice_decode checked this */
|
||||
json_add_bip340sig(js, "signature", invoice->signature);
|
||||
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user