Skip to content

Commit 10f333b

Browse files
rustyrussellendothermicdev
authored andcommitted
devtools/bolt12-cli: fix interpretation of blindedpay, amounts.
The old blindedpay fields would have an entry per hop, but that was changed to a single per-path entry. The devtools hadn't caught up. Similarly, it didn't like descriptionless offer fields in invreqs and invoices. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 5e4c1b7 commit 10f333b

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

devtools/bolt12-cli.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,6 @@ static bool print_blindedpaths(const char *fieldname,
266266
struct blinded_path **paths,
267267
struct blinded_payinfo **blindedpay)
268268
{
269-
size_t bp_idx = 0;
270-
271269
for (size_t i = 0; i < tal_count(paths); i++) {
272270
struct blinded_path_hop **p = paths[i]->path;
273271
printf("%s %zu/%zu: first_path_key %s ",
@@ -282,22 +280,24 @@ static bool print_blindedpaths(const char *fieldname,
282280
fmt_pubkey(tmpctx,
283281
&p[j]->blinded_node_id),
284282
tal_hex(tmpctx, p[j]->encrypted_recipient_data));
285-
if (blindedpay) {
286-
if (bp_idx < tal_count(blindedpay))
287-
printf("fee=%u/%u,cltv=%u,features=%s",
288-
blindedpay[bp_idx]->fee_base_msat,
289-
blindedpay[bp_idx]->fee_proportional_millionths,
290-
blindedpay[bp_idx]->cltv_expiry_delta,
291-
tal_hex(tmpctx,
292-
blindedpay[bp_idx]->features));
293-
bp_idx++;
294-
}
283+
}
284+
if (i < tal_count(blindedpay)) {
285+
printf(" blindedpay: fee=%u/%u,cltv=%u,features=%s",
286+
blindedpay[i]->fee_base_msat,
287+
blindedpay[i]->fee_proportional_millionths,
288+
blindedpay[i]->cltv_expiry_delta,
289+
tal_hex(tmpctx, blindedpay[i]->features));
295290
}
296291
printf("\n");
297292
}
298-
if (blindedpay && tal_count(blindedpay) != bp_idx) {
293+
/* BOLT #12:
294+
* - MUST reject the invoice if `invoice_blindedpay` does not
295+
* contain exactly one `blinded_payinfo` per
296+
* `invoice_paths`.`blinded_path`.
297+
*/
298+
if (blindedpay && tal_count(blindedpay) != tal_count(paths)) {
299299
fprintf(stderr, "Expected %zu blindedpay fields, got %zu\n",
300-
bp_idx, tal_count(blindedpay));
300+
tal_count(paths), tal_count(blindedpay));
301301
return false;
302302
}
303303
return true;
@@ -893,7 +893,11 @@ int main(int argc, char *argv[])
893893
well_formed &= print_offer_amount(invreq->offer_chains,
894894
invreq->offer_currency,
895895
*invreq->offer_amount);
896-
if (must_have(invreq, offer_description))
896+
if (invreq->offer_amount && !invreq->offer_description) {
897+
fprintf(stderr, "Missing offer_description (with offer_amount)\n");
898+
well_formed = false;
899+
}
900+
if (invreq->offer_description)
897901
well_formed &= print_utf8("offer_description", invreq->offer_description);
898902
if (invreq->offer_features)
899903
print_features("offer_features", invreq->offer_features);
@@ -971,7 +975,11 @@ int main(int argc, char *argv[])
971975
well_formed &= print_offer_amount(invoice->offer_chains,
972976
invoice->offer_currency,
973977
*invoice->offer_amount);
974-
if (must_have(invoice, offer_description))
978+
if (invoice->offer_amount && !invoice->offer_description) {
979+
fprintf(stderr, "Missing offer_description (with offer_amount)\n");
980+
well_formed = false;
981+
}
982+
if (invoice->offer_description)
975983
well_formed &= print_utf8("offer_description", invoice->offer_description);
976984
if (invoice->offer_features)
977985
print_features("offer_features", invoice->offer_features);

tests/test_misc.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4680,3 +4680,13 @@ def test_listaddresses(node_factory):
46804680
# start and limit from future
46814681
addresses = l1.rpc.listaddresses(start=21, limit=5)["addresses"]
46824682
assert len(addresses) == 0
4683+
4684+
4685+
def test_bolt12_invoice_decode(node_factory):
4686+
"""Test decode of a real invoice."""
4687+
l1 = node_factory.get_node()
4688+
4689+
inv = 'lni1qqg26r8checx54jang4393z59wa6293pqvvhnlnvurnfanndnxjtcjnmxrkj92xtsupa6lwjm7hkr8s8zflqk5sz82v9gqzcyypsvsgehgxpnlapwnahwt89fjrad8nzlxn0z0dmn46gqpk2qd2n8mdql5q0uqh34ry8vpl5zhy0ytqqtycqya6eg802fzrfec3sj6hj0vx0mnqtdypsz43dexx9tyt8ak270h957cedaw952ryqjzwgmzuvunqv53878sqzqg2upz426juplphy68fqqafavzzqm6msnsnsehgjmsnqhv39v7v3cqzraklvv0rl4sg654t44ujvetklp6urayt9vjprjgy35paec0a373khaj9r6cqg5x6u4qqvg24eqj3nn8gpfx3tv0075g5mmz6k6jezhnx6wh6s9atydz30ektzmhexua6ayuzuq53mayp8d5h8yhfdf373kzyzvecuqqep0zy8qljenhelz0awkws6p4llvg5tgcty6ev53l6pmgeqd5zmqgryr5wm968uchxmwr2k86qqtyymgze2y8qqqqqqqqqqq86qpgsqqqqqqqqqq05qqqqqqpq3qqqqqqq2gpr8hhtq82pqcel324ms8wd6vwphtm33l883xmh7hm2dwruc4v95xvn85kq46rw25q36nzhqxqsqqzczzqce08lxec8xnm8xmxdyh398kv8dy25vhpcrm47a9ha0vx0qwyn7p0cyqkm8qvweh5akjqjhlys34ys6gmm25jxrk3syearzr33qfk5czq8dxu04qq8njp0l3f0n6cuvyphqhtcjnaqg05vrgnhwzzmgm825383s'
4690+
4691+
assert l1.rpc.decode(inv)['valid'] is True
4692+
subprocess.run(["devtools/bolt12-cli", "decode", inv], check=True)

0 commit comments

Comments
 (0)