Skip to content

Commit edbbc18

Browse files
committed
plugins/pay: send payment_metadata if provided in invoice.
Signed-off-by: Rusty Russell <[email protected]> Changelog-Added: Protocol: `pay` (and decode, etc) supports bolt11 payment_metadata a-la lightning/bolts#912
1 parent 01505a3 commit edbbc18

File tree

5 files changed

+48
-6
lines changed

5 files changed

+48
-6
lines changed

plugins/keysend.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
179179
p->json_toks = params;
180180
p->destination = tal_steal(p, destination);
181181
p->payment_secret = NULL;
182+
p->payment_metadata = NULL;
182183
p->amount = *msat;
183184
p->routes = tal_steal(p, hints);
184185
// 22 is the Rust-Lightning default and the highest minimum we know of.

plugins/libplugin-pay.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,7 +1581,7 @@ static struct command_result *payment_createonion_success(struct command *cmd,
15811581
/* Temporary serialization method for the tlv_payload.data until we rework the
15821582
* API that is generated from the specs to use the setter/getter interface. */
15831583
static void tlvstream_set_tlv_payload_data(struct tlv_field **stream,
1584-
struct secret *payment_secret,
1584+
const struct secret *payment_secret,
15851585
u64 total_msat)
15861586
{
15871587
u8 *ser = tal_arr(NULL, u8, 0);
@@ -1596,7 +1596,8 @@ static void payment_add_hop_onion_payload(struct payment *p,
15961596
struct route_hop *node,
15971597
struct route_hop *next,
15981598
bool final,
1599-
struct secret *payment_secret)
1599+
struct secret *payment_secret,
1600+
const u8 *payment_metadata)
16001601
{
16011602
struct createonion_request *cr = p->createonion_request;
16021603
u32 cltv = p->start_block + next->delay + 1;
@@ -1627,6 +1628,11 @@ static void payment_add_hop_onion_payload(struct payment *p,
16271628
fields, payment_secret,
16281629
root->amount.millisatoshis); /* Raw: TLV payload generation*/
16291630
}
1631+
if (payment_metadata != NULL) {
1632+
assert(final);
1633+
tlvstream_set_raw(fields, TLV_TLV_PAYLOAD_PAYMENT_METADATA,
1634+
payment_metadata, tal_bytelen(payment_metadata));
1635+
}
16301636
}
16311637

16321638
static void payment_compute_onion_payloads(struct payment *p)
@@ -1665,7 +1671,7 @@ static void payment_compute_onion_payloads(struct payment *p)
16651671
* i+1 */
16661672
payment_add_hop_onion_payload(p, &cr->hops[i], &p->route[i],
16671673
&p->route[i + 1], false,
1668-
NULL);
1674+
NULL, NULL);
16691675
tal_append_fmt(&routetxt, "%s -> ",
16701676
type_to_string(tmpctx, struct short_channel_id,
16711677
&p->route[i].scid));
@@ -1675,7 +1681,7 @@ static void payment_compute_onion_payloads(struct payment *p)
16751681
payment_add_hop_onion_payload(
16761682
p, &cr->hops[hopcount - 1], &p->route[hopcount - 1],
16771683
&p->route[hopcount - 1], true,
1678-
root->payment_secret);
1684+
root->payment_secret, root->payment_metadata);
16791685
tal_append_fmt(&routetxt, "%s",
16801686
type_to_string(tmpctx, struct short_channel_id,
16811687
&p->route[hopcount - 1].scid));

plugins/libplugin-pay.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ struct payment {
180180
/* Payment secret, from the invoice if any. */
181181
struct secret *payment_secret;
182182

183+
/* Payment metadata, from the invoice if any. */
184+
u8 *payment_metadata;
185+
183186
u64 groupid;
184187
u32 partid;
185188
u32 next_partid;

plugins/pay.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ struct pay_command {
108108
/* Payment secret, if specified by invoice. */
109109
const char *payment_secret;
110110

111+
/* Payment metadata, if specified by invoice. */
112+
const char *payment_metadata;
113+
111114
/* Description, if any. */
112115
const char *label;
113116

@@ -849,6 +852,8 @@ static struct command_result *getroute_done(struct command *cmd,
849852
json_add_string(req->js, "label", pc->label);
850853
if (pc->payment_secret)
851854
json_add_string(req->js, "payment_secret", pc->payment_secret);
855+
if (pc->payment_metadata)
856+
json_add_string(req->js, "payment_metadata", pc->payment_metadata);
852857

853858
return send_outreq(cmd->plugin, req);
854859
}
@@ -1368,6 +1373,11 @@ static struct command_result *json_pay(struct command *cmd,
13681373
sizeof(*b11->payment_secret));
13691374
else
13701375
pc->payment_secret = NULL;
1376+
if (b11->metadata)
1377+
pc->payment_metadata = tal_hex(pc, b11->metadata);
1378+
else
1379+
pc->payment_metadata = NULL;
1380+
13711381
/* We try first without using routehint */
13721382
pc->current_routehint = NULL;
13731383
pc->routehints = filter_routehints(pc, b11->routes);
@@ -2374,6 +2384,10 @@ static struct command_result *json_paymod(struct command *cmd,
23742384
p->payment_hash = tal_dup(p, struct sha256, &b11->payment_hash);
23752385
p->payment_secret =
23762386
tal_dup_or_null(p, struct secret, b11->payment_secret);
2387+
if (b11->metadata)
2388+
p->payment_metadata = tal_dup_talarr(p, u8, b11->metadata);
2389+
else
2390+
p->payment_metadata = NULL;
23772391
/* FIXME: libplugin-pay plays with this array, and there are many FIXMEs
23782392
* about it. But it looks like a leak, so we suppress it here. */
23792393
p->routes = notleak_with_children(tal_steal(p, b11->routes));
@@ -2433,6 +2447,7 @@ static struct command_result *json_paymod(struct command *cmd,
24332447
BUILD_ASSERT(sizeof(*p->payment_secret) ==
24342448
sizeof(merkle));
24352449
}
2450+
p->payment_metadata = NULL;
24362451
p->routes = NULL;
24372452
/* FIXME: paths! */
24382453
if (b12->cltv)

tests/test_pay.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5162,7 +5162,24 @@ def test_pay_manual_exclude(node_factory, bitcoind):
51625162
l2.rpc.pay(inv, exclude=[scid23])
51635163

51645164

5165+
@unittest.skipIf(TEST_NETWORK != 'regtest', "Invoice is network specific")
51655166
def test_pay_bolt11_metadata(node_factory, bitcoind):
5166-
l1 = node_factory.get_node()
5167+
l1, l2 = node_factory.line_graph(2)
5168+
5169+
# BOLT #11:
5170+
# > ### Please send 0.01 BTC with payment metadata 0x01fafaf0
5171+
# > lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc
5172+
5173+
b11 = l1.rpc.decode('lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc')
5174+
assert b11['payment_metadata'] == '01fafaf0'
5175+
5176+
# I previously hacked lightningd to add "this is metadata" to metadata.
5177+
# After CI started failing, I *also* hacked it to set expiry to BIGNUM.
5178+
inv = "lnbcrt1230n1p3yzgcxsp5q8g040f9rl9mu2unkjuj0vn262s6nyrhz5hythk3ueu2lfzahmzspp5ve584t0cv27hwmy0cx9ca8uwyqyfw9y9dm3r8vus9fv36r2l9yjsdq8v3jhxccmq6w35xjueqd9ejqmt9w3skgct5vyxqxra2q2qcqp99q2sqqqqqysgqfw6efxpzk5x5vfj8se46yg667x5cvhyttnmuqyk0q7rmhx3gs249qhtdggnek8c5adm2pztkjddlwyn2art2zg9xap2ckczzl3fzz4qqsej6mf"
5179+
# Make l2 "know" about this invoice.
5180+
l2.rpc.invoice(msatoshi='123000', label='label1', description='desc', preimage='00' * 32)
5181+
5182+
with pytest.raises(RpcError, match=r'WIRE_INVALID_ONION_PAYLOAD'):
5183+
l1.rpc.pay(inv)
51675184

5168-
l1.rpc.decode('lnbcrt10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqcqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqrk6hdutpaetmm3afjn0vfczgeyv0cy739rr939kwd4h5j3khxcskhgf59eaqy8wyq82tsnaqc5y32ed4jg34jw7rmeva9u6kfhymawgptmy5f6')
5185+
l2.daemon.wait_for_log("Unexpected payment_metadata {}".format(b'this is metadata'.hex()))

0 commit comments

Comments
 (0)