From 2dec805465fb3c812be5f6e4bd3c280d34bf53bf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Jan 2023 14:28:03 +1030 Subject: [PATCH] decode: fix handling of blinded_payinfo. Our pay code handles this correctly, but decode was still using an old model where there was a payinfo per hop, not per path. Reported-by: @t-bast See: #5823 Signed-off-by: Rusty Russell --- doc/lightning-decode.7.md | 11 +++++---- doc/schemas/decode.schema.json | 45 ++++++++++++++++++++++------------ plugins/offers.c | 39 +++++++++++++++-------------- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/doc/lightning-decode.7.md b/doc/lightning-decode.7.md index a8a78096c..78a5578dd 100644 --- a/doc/lightning-decode.7.md +++ b/doc/lightning-decode.7.md @@ -148,13 +148,14 @@ If **type** is "bolt12 invoice", and **valid** is *true*: - **invoice\_paths** (array of objects): Paths to pay the destination: - **first\_node\_id** (pubkey): the (presumably well-known) public key of the start of the path - **blinding** (pubkey): blinding factor for this path + - **payinfo** (object): + - **fee\_base\_msat** (msat): basefee for path + - **fee\_proportional\_millionths** (u32): proportional fee for path + - **cltv\_expiry\_delta** (u32): CLTV delta for path + - **features** (hex): features allowed for path - **path** (array of objects): an individual path: - **blinded\_node\_id** (pubkey): node\_id of the hop - **encrypted\_recipient\_data** (hex): encrypted TLV entry for this hop - - **fee\_base\_msat** (msat, optional): basefee for path - - **fee\_proportional\_millionths** (u32, optional): proportional fee for path - - **cltv\_expiry\_delta** (u32, optional): CLTV delta for path - - **features** (hex, optional): features allowed for path - **invoice\_created\_at** (u64): the UNIX timestamp of invoice creation - **invoice\_payment\_hash** (hex): the hash of the *payment\_preimage* (always 64 characters) - **invoice\_amount\_msat** (msat): the amount required to fulfill invoice @@ -302,4 +303,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:eadd9b06e6cb495a794568f3a9e2371c09718311c0b61ad05b0fca3014c429d3) +[comment]: # ( SHA256STAMP:a8843027b18a1d54efcf0ca423fc6fbe0c2136d32fa3d8c552a875b6844dd950) diff --git a/doc/schemas/decode.schema.json b/doc/schemas/decode.schema.json index ca5d94358..9635b5693 100644 --- a/doc/schemas/decode.schema.json +++ b/doc/schemas/decode.schema.json @@ -927,6 +927,7 @@ "required": [ "first_node_id", "blinding", + "payinfo", "path" ], "additionalProperties": false, @@ -939,6 +940,34 @@ "type": "pubkey", "description": "blinding factor for this path" }, + "payinfo": { + "type": "object", + "required": [ + "fee_base_msat", + "fee_proportional_millionths", + "cltv_expiry_delta", + "features" + ], + "additionalProperties": false, + "properties": { + "fee_base_msat": { + "type": "msat", + "description": "basefee for path" + }, + "fee_proportional_millionths": { + "type": "u32", + "description": "proportional fee for path" + }, + "cltv_expiry_delta": { + "type": "u32", + "description": "CLTV delta for path" + }, + "features": { + "type": "hex", + "description": "features allowed for path" + } + } + }, "path": { "type": "array", "description": "an individual path", @@ -957,22 +986,6 @@ "encrypted_recipient_data": { "type": "hex", "description": "encrypted TLV entry for this hop" - }, - "fee_base_msat": { - "type": "msat", - "description": "basefee for path" - }, - "fee_proportional_millionths": { - "type": "u32", - "description": "proportional fee for path" - }, - "cltv_expiry_delta": { - "type": "u32", - "description": "CLTV delta for path" - }, - "features": { - "type": "hex", - "description": "features allowed for path" } } } diff --git a/plugins/offers.c b/plugins/offers.c index a34e0f07a..5dadd97ed 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -249,21 +249,11 @@ static void json_add_chains(struct json_stream *js, static void json_add_onionmsg_path(struct json_stream *js, const char *fieldname, - const struct onionmsg_hop *hop, - const struct blinded_payinfo *payinfo) + const struct onionmsg_hop *hop) { json_object_start(js, fieldname); 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_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", - payinfo->cltv_expiry_delta); - json_add_hex_talarr(js, "features", payinfo->features); - } json_object_end(js); } @@ -273,18 +263,28 @@ static bool json_add_blinded_paths(struct json_stream *js, struct blinded_path **paths, struct blinded_payinfo **blindedpay) { - size_t n = 0; 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); json_add_pubkey(js, "blinding", &paths[i]->blinding); + + /* Don't crash if we're short a payinfo! */ + if (i < tal_count(blindedpay)) { + json_object_start(js, "payinfo"); + json_add_amount_msat_only(js, "fee_base_msat", + amount_msat(blindedpay[i]->fee_base_msat)); + json_add_u32(js, "fee_proportional_millionths", + blindedpay[i]->fee_proportional_millionths); + json_add_u32(js, "cltv_expiry_delta", + blindedpay[i]->cltv_expiry_delta); + json_add_hex_talarr(js, "features", blindedpay[i]->features); + json_object_end(js); + } + json_array_start(js, "path"); for (size_t j = 0; j < tal_count(paths[i]->path); j++) { - json_add_onionmsg_path(js, NULL, paths[i]->path[j], - n < tal_count(blindedpay) - ? blindedpay[n] : NULL); - n++; + json_add_onionmsg_path(js, NULL, paths[i]->path[j]); } json_array_end(js); json_object_end(js); @@ -295,9 +295,10 @@ static bool json_add_blinded_paths(struct json_stream *js, * - MUST reject the invoice if `invoice_blindedpay` does not contain * exactly one `blinded_payinfo` per `invoice_paths`.`blinded_path`. */ - if (blindedpay && n != tal_count(blindedpay)) { - json_add_string(js, "warning_invalid_invoice_blindedpay", - "invoice does not have correct number of blinded_payinfo"); + if (blindedpay && tal_count(blindedpay) != tal_count(paths)) { + json_add_str_fmt(js, "warning_invalid_invoice_blindedpay", + "invoice has %zu blinded_payinfo but %zu paths", + tal_count(blindedpay), tal_count(paths)); return false; }