Skip to content

Commit bf54913

Browse files
committed
global: update BOLT12 quotes.
This is a final sweep to match the current BOLT12 text: 1563d13999d342680140c693de0b9d65aa522372 ("More bolt12 test vectors.") Only two code changes, to change the order of checks to match the bolt, and to give a warning on decode if a path is empty. Signed-off-by: Rusty Russell <[email protected]>
1 parent f2a7b19 commit bf54913

File tree

16 files changed

+657
-615
lines changed

16 files changed

+657
-615
lines changed

.msggen.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,7 @@
997997
"Decode.unknown_offer_tlvs[]": 19,
998998
"Decode.valid": 2,
999999
"Decode.version": 71,
1000+
"Decode.warning_empty_blinded_path": 86,
10001001
"Decode.warning_invalid_invoice_request_signature": 39,
10011002
"Decode.warning_invalid_invoice_signature": 58,
10021003
"Decode.warning_invalid_invreq_payer_note": 37,
@@ -4815,6 +4816,10 @@
48154816
"added": "pre-v0.10.1",
48164817
"deprecated": null
48174818
},
4819+
"Decode.warning_empty_blinded_path": {
4820+
"added": "v24.08",
4821+
"deprecated": null
4822+
},
48184823
"Decode.warning_invalid_invoice_request_signature": {
48194824
"added": "pre-v0.10.1",
48204825
"deprecated": null

cln-grpc/proto/node.proto

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cln-grpc/src/convert.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cln-rpc/src/model.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/test/run-bolt12-encode-test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ int main(int argc, char *argv[])
248248
/* BOLT-offers #12:
249249
* - if it includes `offer_paths`:
250250
* - SHOULD ignore any invoice_request which does not use the path.
251-
* - MAY set `offer_issuer_id` to the node's public key to request the invoice from.
251+
* - MAY set `offer_issuer_id`.
252252
* - otherwise:
253253
* - MUST set `offer_issuer_id` to the node's public key to request the invoice from.
254254
*/

common/test/run-bolt12-format-string-test.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,7 @@ int main(int argc, char *argv[])
117117
offer = tlv_offer_new(tmpctx);
118118
/* BOLT-offers #12:
119119
* A writer of an offer:
120-
* - MUST NOT set any tlv fields greater or equal to 80, or tlv field 0.
121-
* - MUST set `offer_issuer_id` to the node's public key to request the invoice from.
122-
* - MUST set `offer_description` to a complete description of the purpose
123-
* of the payment.
120+
* - MUST NOT set any TLV fields outside the inclusive ranges: 1 to 79 and 1000000000 to 1999999999.
124121
* - if the chain for the invoice is not solely bitcoin:
125122
* - MUST specify `offer_chains` the offer is valid for.
126123
* - otherwise:
@@ -134,9 +131,12 @@ int main(int argc, char *argv[])
134131
* - MUST specify `offer_currency` `iso4217` as an ISO 4712 three-letter code.
135132
* - MUST specify `offer_amount` in the currency unit adjusted by the ISO 4712
136133
* exponent (e.g. USD cents).
134+
* - MUST set `offer_description` to a complete description of the purpose
135+
* of the payment.
137136
* - otherwise:
138137
* - MUST NOT set `offer_amount`
139138
* - MUST NOT set `offer_currency`
139+
* - MAY set `offer_description`
140140
* - MAY set `offer_metadata` for its own use.
141141
* - if it supports bolt12 offer features:
142142
* - MUST set `offer_features`.`features` to the bitmap of bolt12 features.
@@ -151,6 +151,9 @@ int main(int argc, char *argv[])
151151
* - MAY include `offer_paths`.
152152
* - if it includes `offer_paths`:
153153
* - SHOULD ignore any invoice_request which does not use the path.
154+
* - MAY set `offer_issuer_id`.
155+
* - otherwise:
156+
* - MUST set `offer_issuer_id` to the node's public key to request the invoice from.
154157
* - if it sets `offer_issuer`:
155158
* - SHOULD set it to identify the issuer of the invoice clearly.
156159
* - if it includes a domain name:

contrib/msggen/msggen/schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5726,6 +5726,13 @@
57265726
}
57275727
}
57285728
},
5729+
"warning_empty_blinded_path": {
5730+
"added": "v24.08",
5731+
"type": "string",
5732+
"description": [
5733+
"The blinded path has 0 hops."
5734+
]
5735+
},
57295736
"offer_node_id": {
57305737
"type": "pubkey",
57315738
"deprecated": [

contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py

Lines changed: 588 additions & 588 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/pyln-testing/pyln/testing/grpc2py.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,7 @@ def decode2py(m):
13121312
"unique_id": m.unique_id, # PrimitiveField in generate_composite
13131313
"valid": m.valid, # PrimitiveField in generate_composite
13141314
"version": m.version, # PrimitiveField in generate_composite
1315+
"warning_empty_blinded_path": m.warning_empty_blinded_path, # PrimitiveField in generate_composite
13151316
"warning_invalid_invoice_request_signature": m.warning_invalid_invoice_request_signature, # PrimitiveField in generate_composite
13161317
"warning_invalid_invoice_signature": m.warning_invalid_invoice_signature, # PrimitiveField in generate_composite
13171318
"warning_invalid_invreq_payer_note": m.warning_invalid_invreq_payer_note, # PrimitiveField in generate_composite

devtools/bolt12-cli.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ static u64 get_offer_type(const char *name)
459459
* * [`tu64`:`max`]
460460
* 1. type: 22 (`offer_issuer_id`)
461461
* 2. data:
462-
* * [`point`:`node_id`]
462+
* * [`point`:`id`]
463463
*/
464464
{ "offer_chains", 2 },
465465
{ "offer_metadata", 4 },
@@ -510,7 +510,7 @@ static u64 get_offer_type(const char *name)
510510
* * [`tu64`:`max`]
511511
* 1. type: 22 (`offer_issuer_id`)
512512
* 2. data:
513-
* * [`point`:`node_id`]
513+
* * [`point`:`id`]
514514
* 1. type: 80 (`invreq_chain`)
515515
* 2. data:
516516
* * [`chain_hash`:`chain`]
@@ -583,7 +583,7 @@ static u64 get_offer_type(const char *name)
583583
* * [`tu64`:`max`]
584584
* 1. type: 22 (`offer_issuer_id`)
585585
* 2. data:
586-
* * [`point`:`node_id`]
586+
* * [`point`:`id`]
587587
* 1. type: 80 (`invreq_chain`)
588588
* 2. data:
589589
* * [`chain_hash`:`chain`]
@@ -602,6 +602,9 @@ static u64 get_offer_type(const char *name)
602602
* 1. type: 89 (`invreq_payer_note`)
603603
* 2. data:
604604
* * [`...*utf8`:`note`]
605+
* 1. type: 90 (`invreq_paths`)
606+
* 2. data:
607+
* * [`...*blinded_path`:`paths`]
605608
* 1. type: 160 (`invoice_paths`)
606609
* 2. data:
607610
* * [`...*blinded_path`:`paths`]

doc/schemas/lightning-decode.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@
235235
}
236236
}
237237
},
238+
"warning_empty_blinded_path": {
239+
"added": "v24.08",
240+
"type": "string",
241+
"description": [
242+
"The blinded path has 0 hops."
243+
]
244+
},
238245
"offer_node_id": {
239246
"type": "pubkey",
240247
"deprecated": [

plugins/fetchinvoice.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,11 @@ static struct command_result *handle_invreq_response(struct command *cmd,
221221
}
222222

223223
/* BOLT-offers #12:
224-
* - if `offer_node_id` or `offer_paths` are present (invoice_request for an offer):
225-
* - MUST reject the invoice if `invoice_node_id` is not equal to the public key it sent the `invoice_request` to.
224+
* - if `offer_issuer_id` is present (invoice_request for an offer):
225+
* - MUST reject the invoice if `invoice_node_id` is not equal to `offer_issuer_id`
226+
* - otherwise, if `offer_paths` is present (invoice_request for an offer without id):
227+
* - MUST reject the invoice if `invoice_node_id` is not equal to the final
228+
* `blinded_node_id` it sent the `invoice_request` to.
226229
*/
227230
if (!inv->invoice_node_id || !pubkey_eq(inv->offer_issuer_id, sent->issuer_key)) {
228231
badfield = "invoice_node_id";
@@ -560,7 +563,7 @@ static struct command_result *try_establish(struct command *cmd,
560563
target = first.pubkey;
561564
/* BOLT-offers #12:
562565
* - if `offer_issuer_id` is present (invoice_request for an offer):
563-
* - MUST reject the invoice if `invoice_node_id` is not equal `offer_issuer_id`
566+
* - MUST reject the invoice if `invoice_node_id` is not equal to `offer_issuer_id`
564567
* - otherwise, if `offer_paths` is present (invoice_request for an offer without id):
565568
* - MUST reject the invoice if `invoice_node_id` is not equal to the final `blinded_node_id` it sent the `invoice_request` to.
566569
*/
@@ -1171,7 +1174,7 @@ static struct command_result *param_invreq(struct command *cmd,
11711174
* The reader:
11721175
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata`
11731176
* are not present.
1174-
* - MUST fail the request if any non-signature TLV fields are outside the inclusive ranges: 0 to 159 and 1000000000 to 2999999999.
1177+
* - MUST fail the request if any non-signature TLV fields are outside the inclusive ranges: 0 to 159 and 1000000000 to 2999999999
11751178
* - if `invreq_features` contains unknown _odd_ bits that are
11761179
* non-zero:
11771180
* - MUST ignore the bit.
@@ -1228,7 +1231,7 @@ static struct command_result *param_invreq(struct command *cmd,
12281231
}
12291232

12301233
/* BOLT-offers #12:
1231-
* - otherwise (no `offer_node_id` or `offer_paths`, not a response to our offer):
1234+
* - otherwise (no `offer_issuer_id` or `offer_paths`, not a response to our offer):
12321235
* - MUST fail the request if any of the following are present:
12331236
* - `offer_chains`, `offer_features` or `offer_quantity_max`.
12341237
* - MUST fail the request if `invreq_amount` is not present.
@@ -1338,7 +1341,7 @@ struct command_result *json_sendinvoice(struct command *cmd,
13381341

13391342
/* BOLT-offers #12:
13401343
* - if `offer_issuer_id` is present:
1341-
* - MUST set `invoice_node_id` to `offer_issuer_id`.
1344+
* - MUST set `invoice_node_id` to the `offer_issuer_id`
13421345
* - otherwise, if `offer_paths` is present:
13431346
* - MUST set `invoice_node_id` to the final `blinded_node_id` on the path it received the `invoice_request`
13441347
* - otherwise:

plugins/offers.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,19 @@ static bool json_add_blinded_paths(struct json_stream *js,
565565
return false;
566566
}
567567

568+
/* BOLT-offers #12:
569+
* - if `num_hops` is 0 in any `blinded_path` in `offer_paths`:
570+
* - MUST NOT respond to the offer.
571+
*/
572+
for (size_t i = 0; i < tal_count(paths); i++) {
573+
if (tal_count(paths[i]->path) == 0) {
574+
json_add_str_fmt(js, "warning_empty_blinded_path",
575+
"blinded path %zu has 0 hops",
576+
i);
577+
return false;
578+
}
579+
}
580+
568581
return true;
569582
}
570583

@@ -1011,6 +1024,7 @@ static void json_add_b12_invoice(struct json_stream *js,
10111024
/* BOLT-offers #12:
10121025
* - MUST reject the invoice if `invoice_paths` is not present
10131026
* or is empty.
1027+
* - MUST reject the invoice if `num_hops` is 0 in any `blinded_path` in `invoice_paths`.
10141028
* - MUST reject the invoice if `invoice_blindedpay` is not present.
10151029
* - MUST reject the invoice if `invoice_blindedpay` does not contain
10161030
* exactly one `blinded_payinfo` per `invoice_paths`.`blinded_path`.

plugins/offers_inv_hook.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,11 @@ static struct command_result *listinvreqs_done(struct command *cmd,
136136
* - if the invoice is a response to an `invoice_request`:
137137
* - MUST reject the invoice if all fields in ranges 0 to 159 and 1000000000 to 2999999999 (inclusive) do not exactly match the `invoice_request`.
138138
* - if `offer_issuer_id` is present (invoice_request for an offer):
139-
* - MUST reject the invoice if `invoice_node_id` is not equal to `offer_issuer_id`.
139+
* - MUST reject the invoice if `invoice_node_id` is not equal to `offer_issuer_id`
140140
* - otherwise, if `offer_paths` is present (invoice_request for an offer without id):
141141
* - MUST reject the invoice if `invoice_node_id` is not equal to the final `blinded_node_id` it sent the `invoice_request` to.
142142
* - otherwise (invoice_request without an offer):
143143
* - MAY reject the invoice if it cannot confirm that `invoice_node_id` is correct, out-of-band.
144-
*
145-
* - otherwise: (a invoice presented without being requested, eg. scanned by user):
146144
*/
147145

148146
/* Since the invreq_id hashes all fields in those ranges, we know it matches */
@@ -317,26 +315,23 @@ struct command_result *handle_invoice(struct command *cmd,
317315
* A reader of an invoice:
318316
*...
319317
* - MUST reject the invoice if `invoice_paths` is not present or is empty.
318+
* - MUST reject the invoice if `num_hops` is 0 in any `blinded_path` in `invoice_paths`.
320319
* - MUST reject the invoice if `invoice_blindedpay` is not present.
321320
* - MUST reject the invoice if `invoice_blindedpay` does not contain exactly one `blinded_payinfo` per `invoice_paths`.`blinded_path`.
322321
*/
323322
if (!inv->inv->invoice_paths)
324323
return fail_inv(cmd, inv, "Missing invoice_paths");
324+
for (size_t i = 0; i < tal_count(inv->inv->invoice_paths); i++) {
325+
if (tal_count(inv->inv->invoice_paths[i]->path) == 0)
326+
return fail_inv(cmd, inv, "Empty path in invoice_paths");
327+
}
325328
if (!inv->inv->invoice_blindedpay)
326329
return fail_inv(cmd, inv, "Missing invoice_blindedpay");
327330
if (tal_count(inv->inv->invoice_blindedpay)
328331
!= tal_count(inv->inv->invoice_paths))
329332
return fail_inv(cmd, inv,
330333
"Mismatch between invoice_blindedpay and invoice_paths");
331334

332-
/* BOLT-offers #12:
333-
* - MUST reject the invoice if `num_hops` is 0 in any `blinded_path` in `invoice_paths`.
334-
*/
335-
for (size_t i = 0; i < tal_count(inv->inv->invoice_paths); i++) {
336-
if (tal_count(inv->inv->invoice_paths[i]->path) == 0)
337-
return fail_inv(cmd, inv, "Empty path in invoice_paths");
338-
}
339-
340335
/* BOLT-offers #12:
341336
* A reader of an invoice:
342337
*...

plugins/offers_invreq_hook.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ static struct command_result *listoffers_done(struct command *cmd,
930930

931931
/* BOLT-offers #12:
932932
* - if `offer_issuer_id` is present:
933-
* - MUST set `invoice_node_id` to `offer_issuer_id`.
933+
* - MUST set `invoice_node_id` to the `offer_issuer_id`
934934
*/
935935
/* FIXME: We always provide an offer_issuer_id! */
936936
ir->inv->invoice_node_id = ir->inv->offer_issuer_id;

plugins/offers_offer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ struct command_result *json_invoicerequest(struct command *cmd,
745745
/* BOLT-offers #12:
746746
* - otherwise (not responding to an offer):
747747
*...
748-
* - MUST set `invreq_payer_id` as it would set `offer_issuer_id` for an offer.
748+
* - MUST set `invreq_payer_id` (as it would set `offer_issuer_id` for an offer).
749749
*/
750750
/* FIXME: Allow invoicerequests using aliases! */
751751
invreq->invreq_payer_id = tal_dup(invreq, struct pubkey, &id);

0 commit comments

Comments
 (0)