Skip to content

Commit 78b5a37

Browse files
committed
bolt11: reorder invoice production to match test vectors.
After this, we can exactly reproduce the vectors (in DEVELOPER mode). 1. Move payment_metadata position to match test vector. 2. Create flag to suppress `c` field production. 3. Some vectors put secret before payment_hash, hack that in. Signed-off-by: Rusty Russell <[email protected]>
1 parent 7d1823f commit 78b5a37

File tree

3 files changed

+54
-13
lines changed

3 files changed

+54
-13
lines changed

common/bolt11.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@
1111
#include <inttypes.h>
1212
#include <lightningd/lightningd.h>
1313

14+
#if DEVELOPER
15+
bool dev_bolt11_no_c_generation;
16+
17+
/* For test vectors, older ones put p before s. */
18+
static bool modern_order(const struct bolt11 *b11)
19+
{
20+
if (!b11->description)
21+
return true;
22+
if (streq(b11->description,
23+
"Blockstream Store: 88.85 USD for Blockstream Ledger Nano S x 1, \"Back In My Day\" Sticker x 2, \"I Got Lightning Working\" Sticker x 2 and 1 more items"))
24+
return false;
25+
if (streq(b11->description, "coffee beans"))
26+
return false;
27+
if (streq(b11->description, "payment metadata inside"))
28+
return false;
29+
return true;
30+
}
31+
#endif
32+
1433
struct multiplier {
1534
const char letter;
1635
/* We can't represent p postfix to msat, so we multiply this by 10 */
@@ -996,6 +1015,8 @@ static void encode_x(u5 **data, u64 expiry)
9961015

9971016
static void encode_c(u5 **data, u16 min_final_cltv_expiry)
9981017
{
1018+
if (IFDEV(dev_bolt11_no_c_generation, false))
1019+
return;
9991020
push_varlen_field(data, 'c', min_final_cltv_expiry);
10001021
}
10011022

@@ -1154,6 +1175,13 @@ char *bolt11_encode_(const tal_t *ctx,
11541175
*/
11551176
push_varlen_uint(&data, b11->timestamp, 35);
11561177

1178+
/* This is a hack to match the test vectors, *some* of which
1179+
* order differently! */
1180+
if (IFDEV(modern_order(b11), true)) {
1181+
if (b11->payment_secret)
1182+
encode_s(&data, b11->payment_secret);
1183+
}
1184+
11571185
/* BOLT #11:
11581186
*
11591187
* if a writer offers more than one of any field type,
@@ -1174,23 +1202,25 @@ char *bolt11_encode_(const tal_t *ctx,
11741202
else if (b11->description)
11751203
encode_d(&data, b11->description);
11761204

1205+
if (b11->metadata)
1206+
encode_m(&data, b11->metadata);
1207+
11771208
if (n_field)
11781209
encode_n(&data, &b11->receiver_id);
11791210

1211+
if (IFDEV(!modern_order(b11), false)) {
1212+
if (b11->payment_secret)
1213+
encode_s(&data, b11->payment_secret);
1214+
}
1215+
11801216
if (b11->expiry != DEFAULT_X)
11811217
encode_x(&data, b11->expiry);
11821218

1183-
if (b11->metadata)
1184-
encode_m(&data, b11->metadata);
1185-
11861219
/* BOLT #11:
11871220
* - MUST include one `c` field (`min_final_cltv_expiry`).
11881221
*/
11891222
encode_c(&data, b11->min_final_cltv_expiry);
11901223

1191-
if (b11->payment_secret)
1192-
encode_s(&data, b11->payment_secret);
1193-
11941224
for (size_t i = 0; i < tal_count(b11->fallbacks); i++)
11951225
encode_f(&data, b11->fallbacks[i]);
11961226

common/bolt11.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,9 @@ char *bolt11_encode_(const tal_t *ctx,
125125
secp256k1_ecdsa_recoverable_signature *rsig), \
126126
(arg))
127127

128+
#if DEVELOPER
129+
/* Flag for tests to suppress `min_final_cltv_expiry` field generation, to match test vectors */
130+
extern bool dev_bolt11_no_c_generation;
131+
#endif
132+
128133
#endif /* LIGHTNING_COMMON_BOLT11_H */

common/test/run-bolt11.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ static void test_b11(const char *b11str,
4949
{
5050
struct bolt11 *b11;
5151
char *fail;
52-
char *reproduce;
5352
struct bolt11_field *b11_extra, *expect_extra;
5453

5554
b11 = bolt11_decode(tmpctx, b11str, NULL, hashed_desc,
@@ -115,20 +114,22 @@ static void test_b11(const char *b11str,
115114
assert(!expect_extra);
116115

117116
/* FIXME: Spec changed to require c fields, but test vectors don't! */
118-
if (b11->min_final_cltv_expiry == 18)
119-
return;
117+
118+
#if DEVELOPER
119+
char *reproduce;
120+
121+
dev_bolt11_no_c_generation = (b11->min_final_cltv_expiry == 18);
120122

121123
/* Also blockstream store example signature doesn't match? */
122124
/* Re-encode to check */
123125
reproduce = bolt11_encode(tmpctx, b11, false, test_sign, NULL);
124-
#if 0
125126
for (size_t i = 0; i < strlen(reproduce); i++) {
126127
if (reproduce[i] != b11str[i]
127128
&& reproduce[i] != tolower(b11str[i]))
128129
abort();
129130
}
130-
#endif
131131
assert(strlen(reproduce) == strlen(b11str));
132+
#endif
132133
}
133134

134135
int main(int argc, char *argv[])
@@ -478,8 +479,13 @@ int main(int argc, char *argv[])
478479
set_feature_bit(&b11->features, 100);
479480
badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL);
480481

481-
/* FIXME: above has missing c field! */
482-
assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeescqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqjckhuumq7mk7pdua9s6umdg34sjhlju9qgcvclxl35guw3dhhyrrtnmudz3kspyqk6k6r7thyzyrleq9s9lmgh59zlc49mc3nd7ngecqllqtym"));
482+
/* Needs DEVELOPER to munge this into BOLT example order! */
483+
#if DEVELOPER
484+
assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372"));
485+
#else
486+
assert(streq(badstr, "lnbc25m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeescqpj9q4psqqqqqqqqqqqqqqqqsgqf0nf0agw8xncpemlreh8wl0z5exhz3pky094lu7pf62nvcxq2vljzhhw69xfdftrgm0jklut3h25nlsfw5prz4c0pjy46xyer0k85hqpnathfq"));
487+
#endif
488+
483489
/* Empty set of allowed bits, ensures this fails! */
484490
fset = tal(tmpctx, struct feature_set);
485491
fset->bits[BOLT11_FEATURE] = tal_arr(fset, u8, 0);

0 commit comments

Comments
 (0)