Skip to content

Commit d2b604c

Browse files
committed
bolt11: support payment_metadata.
Signed-off-by: Rusty Russell <[email protected]>
1 parent 8d103fc commit d2b604c

17 files changed

+146
-9
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ CCANDIR := ccan
2424

2525
# Where we keep the BOLT RFCs
2626
BOLTDIR := ../lightning-rfc/
27-
DEFAULT_BOLTVERSION := 93909f67f6a48ee3f155a6224c182e612dd5f187
27+
DEFAULT_BOLTVERSION := f6c4d7604150986894bcb46d67c5c88680740b12
2828
# Can be overridden on cmdline.
2929
BOLTVERSION := $(DEFAULT_BOLTVERSION)
3030

common/bolt11.c

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,33 @@ static char *decode_9(struct bolt11 *b11,
516516
return NULL;
517517
}
518518

519+
/* BOLT #11:
520+
*
521+
* `m` (27): `data_length` variable. Additional metadata to attach to
522+
* the payment. Note that the size of this field is limited by the
523+
* maximum hop payload size. Long metadata fields reduce the maximum
524+
* route length.
525+
*/
526+
static char *decode_m(struct bolt11 *b11,
527+
struct hash_u5 *hu5,
528+
u5 **data, size_t *data_len,
529+
size_t data_length,
530+
bool *have_m)
531+
{
532+
size_t mlen = (data_length * 5) / 8;
533+
534+
if (*have_m)
535+
return unknown_field(b11, hu5, data, data_len, 'm',
536+
data_length);
537+
538+
b11->metadata = tal_arr(b11, u8, mlen);
539+
pull_bits_certain(hu5, data, data_len, b11->metadata,
540+
data_length * 5, false);
541+
542+
*have_m = true;
543+
return NULL;
544+
}
545+
519546
struct bolt11 *new_bolt11(const tal_t *ctx,
520547
const struct amount_msat *msat TAKES)
521548
{
@@ -535,6 +562,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx,
535562
*/
536563
b11->min_final_cltv_expiry = 18;
537564
b11->payment_secret = NULL;
565+
b11->metadata = NULL;
538566

539567
if (msat)
540568
b11->msat = tal_dup(b11, struct amount_msat, msat);
@@ -557,7 +585,7 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str,
557585
struct bolt11 *b11 = new_bolt11(ctx, NULL);
558586
struct hash_u5 hu5;
559587
bool have_p = false, have_d = false, have_h = false,
560-
have_x = false, have_c = false, have_s = false;
588+
have_x = false, have_c = false, have_s = false, have_m = false;
561589

562590
*have_n = false;
563591
b11->routes = tal_arr(b11, struct route_info *, 0);
@@ -760,6 +788,10 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str,
760788
problem = decode_s(b11, &hu5, &data, &data_len,
761789
data_length, &have_s);
762790
break;
791+
case 'm':
792+
problem = decode_m(b11, &hu5, &data, &data_len,
793+
data_length, &have_m);
794+
break;
763795
default:
764796
unknown_field(b11, &hu5, &data, &data_len,
765797
bech32_charset[type], data_length);
@@ -936,6 +968,11 @@ static void encode_p(u5 **data, const struct sha256 *hash)
936968
push_field(data, 'p', hash, 256);
937969
}
938970

971+
static void encode_m(u5 **data, const u8 *metadata)
972+
{
973+
push_field(data, 'm', metadata, tal_bytelen(metadata) * CHAR_BIT);
974+
}
975+
939976
static void encode_d(u5 **data, const char *description)
940977
{
941978
push_field(data, 'd', description, strlen(description) * CHAR_BIT);
@@ -1011,13 +1048,20 @@ static void encode_r(u5 **data, const struct route_info *r)
10111048
tal_free(rinfo);
10121049
}
10131050

1014-
static void maybe_encode_9(u5 **data, const u8 *features)
1051+
static void maybe_encode_9(u5 **data, const u8 *features,
1052+
bool have_payment_metadata)
10151053
{
10161054
u5 *f5 = tal_arr(NULL, u5, 0);
10171055

10181056
for (size_t i = 0; i < tal_count(features) * CHAR_BIT; i++) {
10191057
if (!feature_is_set(features, i))
10201058
continue;
1059+
1060+
/* Don't set option_payment_metadata unless we acually use it */
1061+
if (!have_payment_metadata
1062+
&& COMPULSORY_FEATURE(i) == OPT_PAYMENT_METADATA)
1063+
continue;
1064+
10211065
/* We expand it out so it makes a BE 5-bit/btye bitfield */
10221066
set_feature_bit(&f5, (i / 5) * 8 + (i % 5));
10231067
}
@@ -1131,6 +1175,9 @@ char *bolt11_encode_(const tal_t *ctx,
11311175
if (b11->expiry != DEFAULT_X)
11321176
encode_x(&data, b11->expiry);
11331177

1178+
if (b11->metadata)
1179+
encode_m(&data, b11->metadata);
1180+
11341181
/* BOLT #11:
11351182
* - MUST include one `c` field (`min_final_cltv_expiry`).
11361183
*/
@@ -1145,7 +1192,7 @@ char *bolt11_encode_(const tal_t *ctx,
11451192
for (size_t i = 0; i < tal_count(b11->routes); i++)
11461193
encode_r(&data, b11->routes[i]);
11471194

1148-
maybe_encode_9(&data, b11->features);
1195+
maybe_encode_9(&data, b11->features, b11->metadata != NULL);
11491196

11501197
list_for_each(&b11->extra_fields, extra, list)
11511198
if (!encode_extra(&data, extra))

common/bolt11.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ struct bolt11 {
7676
/* Features bitmap, if any. */
7777
u8 *features;
7878

79+
/* Optional metadata to send with payment. */
80+
u8 *metadata;
81+
7982
struct list_head extra_fields;
8083
};
8184

common/bolt11_json.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ void json_add_bolt11(struct json_stream *response,
6666
b11->payment_secret);
6767
if (b11->features)
6868
json_add_hex_talarr(response, "features", b11->features);
69+
if (b11->metadata)
70+
json_add_hex_talarr(response, "payment_metadata", b11->metadata);
6971
if (tal_count(b11->fallbacks)) {
7072
json_array_start(response, "fallbacks");
7173
for (size_t i = 0; i < tal_count(b11->fallbacks); i++)

common/features.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ static const struct feature_style feature_styles[] = {
9797
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
9898
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
9999
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } },
100+
{ OPT_PAYMENT_METADATA,
101+
.copy_style = { [INIT_FEATURE] = FEATURE_DONT_REPRESENT,
102+
[NODE_ANNOUNCE_FEATURE] = FEATURE_DONT_REPRESENT,
103+
/* Note: we don't actually set this in invoices, since
104+
* we don't need to use it, but if we don't set it here
105+
* we refuse to parse it. */
106+
[BOLT11_FEATURE] = FEATURE_REPRESENT,
107+
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } },
100108
};
101109

102110
struct dependency {
@@ -416,7 +424,7 @@ const char *feature_name(const tal_t *ctx, size_t f)
416424
"option_provide_peer_backup", /* https://github.com/lightningnetwork/lightning-rfc/pull/881 */
417425
NULL,
418426
NULL,
419-
NULL,
427+
"option_payment_metadata",
420428
NULL, /* 50/51 */
421429
NULL,
422430
"option_keysend",

common/features.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,15 @@ const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits);
119119
* | 20/21 | `option_anchor_outputs` |... IN ...
120120
* | 22/23 | `option_anchors_zero_fee_htlc_tx` |... IN ...
121121
* | 26/27 | `option_shutdown_anysegwit` |... IN ...
122+
* | 48/49 | `option_payment_metadata` |... 9 ...
122123
*/
123124
#define OPT_PAYMENT_SECRET 14
124125
#define OPT_BASIC_MPP 16
125126
#define OPT_LARGE_CHANNELS 18
126127
#define OPT_ANCHOR_OUTPUTS 20
127128
#define OPT_ANCHORS_ZERO_FEE_HTLC_TX 22
128129
#define OPT_SHUTDOWN_ANYSEGWIT 26
130+
#define OPT_PAYMENT_METADATA 48
129131

130132
/* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9:
131133
* | 28/29 | `option_dual_fund` | ... IN9 ...

common/test/run-bolt11.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,52 @@ int main(int argc, char *argv[])
564564
memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret));
565565
test_b11("lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz", b11, NULL);
566566

567+
/* BOLT #11:
568+
* > ### Please send 0.01 BTC with payment metadata 0x01fafaf0
569+
* > lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc
570+
*
571+
* Breakdown:
572+
*
573+
* * `lnbc`: prefix, Lightning on Bitcoin mainnet
574+
* * `10m`: amount (10 milli-bitcoin)
575+
* * `1`: Bech32 separator
576+
* * `pvjluez`: timestamp (1496314658)
577+
* * `p`: payment hash
578+
* * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52)
579+
* * `qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq`: payment hash 0001020304050607080900010203040506070809000102030405060708090102
580+
* * `d`: short description
581+
* * `p9`: `data_length` (`p` = 1, `9` = 5; 1 * 32 + 5 == 37)
582+
* * `wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2`: 'payment metadata inside'
583+
* * `m`: metadata
584+
* * `q8`: `data_length` (`q` = 0, `8` = 7; 0 * 32 + 7 == 7)
585+
* * `q8a04uq`: 0x01fafaf0
586+
* * `s`: payment secret
587+
* * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52)
588+
* * `zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs`: 0x1111111111111111111111111111111111111111111111111111111111111111
589+
* * `9`: features
590+
* * `q2`: `data_length` (`q` = 0, `2` = 10; 0 * 32 + 10 == 10)
591+
* * `gqqqqqqsgq`: [b01000000000000000000000000000000000100000100000000] = 8 + 14 + 48
592+
* * `7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqp`: signature
593+
* * `d05wjc`: Bech32 checksum
594+
*/
595+
msatoshi = AMOUNT_MSAT(1000000000);
596+
b11 = new_bolt11(tmpctx, &msatoshi);
597+
b11->chain = chainparams_for_network("bitcoin");
598+
b11->timestamp = 1496314658;
599+
if (!hex_decode("0001020304050607080900010203040506070809000102030405060708090102",
600+
strlen("0001020304050607080900010203040506070809000102030405060708090102"),
601+
&b11->payment_hash, sizeof(b11->payment_hash)))
602+
abort();
603+
b11->receiver_id = node;
604+
b11->description = "payment metadata inside";
605+
b11->metadata = tal_hexdata(b11, "01fafaf0", strlen("01fafaf0"));
606+
set_feature_bit(&b11->features, 8);
607+
set_feature_bit(&b11->features, 14);
608+
set_feature_bit(&b11->features, 48);
609+
b11->payment_secret = tal(b11, struct secret);
610+
memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret));
611+
test_b11("lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc", b11, NULL);
612+
567613
/* BOLT #11:
568614
*
569615
* > ### Bech32 checksum is invalid.

devtools/bolt11-cli.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ int main(int argc, char *argv[])
163163
printf("\n");
164164
}
165165

166+
if (b11->metadata)
167+
printf("metadata: %s\n",
168+
tal_hex(ctx, b11->metadata));
169+
166170
list_for_each(&b11->extra_fields, extra, list) {
167171
char *data = tal_arr(ctx, char, tal_count(extra->data)+1);
168172

doc/lightning-decode.7.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ If **type** is "bolt11 invoice", and **valid** is *true*:
143143
- **description_hash** (hex, optional): the hash of the description, in place of *description* (always 64 characters)
144144
- **payment_secret** (hex, optional): the secret to hand to the payee node (always 64 characters)
145145
- **features** (hex, optional): the features bitmap for this invoice
146+
- **payment_metadata** (hex, optional): the payment_metadata to put in the payment
146147
- **fallbacks** (array of objects, optional): onchain addresses:
147148
- **type** (string): the address type (if known) (one of "P2PKH", "P2SH", "P2WPKH", "P2WSH")
148149
- **hex** (hex): Raw encoded address
@@ -180,4 +181,4 @@ RESOURCES
180181

181182
Main web site: <https://github.com/ElementsProject/lightning>
182183

183-
[comment]: # ( SHA256STAMP:d05b5fc1bf230b3bbd03e2023fb0c6bbefb700f7c3cfb43512da48dbce45f005)
184+
[comment]: # ( SHA256STAMP:6ccf1b9195e64f897f65198a81c47bbd7e16387e4bdc74d624e2ec04a24e9873)

doc/lightning-decodepay.7.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ On success, an object is returned, containing:
2929
- **description_hash** (hex, optional): the hash of the description, in place of *description* (always 64 characters)
3030
- **payment_secret** (hex, optional): the secret to hand to the payee node (always 64 characters)
3131
- **features** (hex, optional): the features bitmap for this invoice
32+
- **payment_metadata** (hex, optional): the payment_metadata to put in the payment
3233
- **fallbacks** (array of objects, optional): onchain addresses:
3334
- **type** (string): the address type (if known) (one of "P2PKH", "P2SH", "P2WPKH", "P2WSH")
3435
- **hex** (hex): Raw encoded address
@@ -69,4 +70,4 @@ RESOURCES
6970

7071
Main web site: <https://github.com/ElementsProject/lightning>
7172

72-
[comment]: # ( SHA256STAMP:d92e1197708fff40f8ad71ccec3c0d8122d8088da1803c02bb042b09dbf2ee33)
73+
[comment]: # ( SHA256STAMP:17cb6c66c75e907f3a2583d702aec2fc6e5a7b6026d05a3ed9957304799c9aef)

0 commit comments

Comments
 (0)