diff --git a/common/onion.c b/common/onion.c index 5f3f71bc4..45325e25e 100644 --- a/common/onion.c +++ b/common/onion.c @@ -71,7 +71,8 @@ u8 *onion_final_hop(const tal_t *ctx, struct amount_msat total_msat, const struct pubkey *blinding, const u8 *enctlv, - const struct secret *payment_secret) + const struct secret *payment_secret, + const u8 *payment_metadata) { struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); struct tlv_tlv_payload_payment_data tlv_pdata; @@ -102,6 +103,7 @@ u8 *onion_final_hop(const tal_t *ctx, tlv_pdata.total_msat = total_msat.millisatoshis; /* Raw: TLV convert */ tlv->payment_data = &tlv_pdata; } + tlv->payment_metadata = cast_const(u8 *, payment_metadata); #if EXPERIMENTAL_FEATURES tlv->blinding_point = cast_const(struct pubkey *, blinding); tlv->encrypted_recipient_data = cast_const(u8 *, enctlv); diff --git a/common/onion.h b/common/onion.h index 828a6735d..839fa5048 100644 --- a/common/onion.h +++ b/common/onion.h @@ -36,14 +36,15 @@ u8 *onion_nonfinal_hop(const tal_t *ctx, const struct pubkey *blinding, const u8 *enctlv); -/* Note that this can fail if we supply payment_secret and !use_tlv! */ +/* Note that this can fail if we supply payment_secret or payment_metadata and !use_tlv! */ u8 *onion_final_hop(const tal_t *ctx, struct amount_msat forward, u32 outgoing_cltv, struct amount_msat total_msat, const struct pubkey *blinding, const u8 *enctlv, - const struct secret *payment_secret); + const struct secret *payment_secret, + const u8 *payment_metadata); /** * onion_payload_length: measure payload length in decrypted onion. diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index f7567fcf5..52e5c3fe3 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1128,7 +1128,7 @@ class LightningRpc(UnixDomainSocketRpc): } return self.call("plugin", payload) - def sendpay(self, route, payment_hash, label=None, msatoshi=None, bolt11=None, payment_secret=None, partid=None, groupid=None): + def sendpay(self, route, payment_hash, label=None, msatoshi=None, bolt11=None, payment_secret=None, partid=None, groupid=None, payment_metadata=None): """ Send along {route} in return for preimage of {payment_hash}. """ @@ -1141,6 +1141,7 @@ class LightningRpc(UnixDomainSocketRpc): "payment_secret": payment_secret, "partid": partid, "groupid": groupid, + "payment_metadata": payment_metadata, } return self.call("sendpay", payload) diff --git a/devtools/onion.c b/devtools/onion.c index f750bedd4..82e5129cb 100644 --- a/devtools/onion.c +++ b/devtools/onion.c @@ -80,7 +80,7 @@ static void do_generate(int argc, char **argv, take(onion_final_hop(NULL, amt, i, amt, NULL, NULL, - NULL))); + NULL, NULL))); else sphinx_add_hop(sp, &path[i], take(onion_nonfinal_hop(NULL, diff --git a/doc/lightning-sendpay.7.md b/doc/lightning-sendpay.7.md index c8d782154..ec7aec712 100644 --- a/doc/lightning-sendpay.7.md +++ b/doc/lightning-sendpay.7.md @@ -5,7 +5,7 @@ SYNOPSIS -------- **sendpay** *route* *payment\_hash* [*label*] [*msatoshi*] -[*bolt11*] [*payment_secret*] [*partid*] +[*bolt11*] [*payment_secret*] [*partid*] [*localofferid*] [*groupid*] [*payment_metadata*] DESCRIPTION ----------- @@ -44,6 +44,16 @@ partial payments with the same *payment_hash*. The *msatoshi* amount *payment_hash* must be equal, and **sendpay** will fail if there are already *msatoshi* worth of payments pending. +The *localofferid* value indicates that this payment is being made for a local +send_invoice offer: this ensures that we only send a payment for a single-use +offer once. + +*groupid* allows you to attach a number which appears in **listsendpays** so +payments can be identified as part of a logical group. The *pay* plugin uses +this to identify one attempt at a MPP payment, for example. + +*payment_metadata* is placed in the final onion hop TLV. + Once a payment has succeeded, calls to **sendpay** with the same *payment\_hash* but a different *msatoshi* or destination will fail; this prevents accidental multiple payments. Calls to **sendpay** with @@ -94,6 +104,7 @@ The following error codes may occur: will be routing failure object. - 204: Failure along route; retry a different route. The *data* field of the error will be routing failure object. +- 212: *localofferid* refers to an invalid, or used, local offer. A routing failure object has the fields below: - *erring\_index*. The index of the node along the route that reported diff --git a/lightningd/pay.c b/lightningd/pay.c index 58463ee10..9e29f92d0 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -1122,7 +1122,8 @@ send_payment(struct lightningd *ld, const char *label TAKES, const char *invstring TAKES, const struct sha256 *local_offer_id, - const struct secret *payment_secret) + const struct secret *payment_secret, + const u8 *payment_metadata) { unsigned int base_expiry; struct onionpacket *packet; @@ -1174,7 +1175,7 @@ send_payment(struct lightningd *ld, route[i].amount, base_expiry + route[i].delay, total_msat, route[i].blinding, route[i].enctlv, - payment_secret); + payment_secret, payment_metadata); if (!onion) { return command_fail(cmd, PAY_DESTINATION_PERM_FAIL, "Destination does not support" @@ -1422,7 +1423,8 @@ static struct command_result *json_sendpay(struct command *cmd, const char *invstring, *label; u64 *partid, *group; struct secret *payment_secret; - struct sha256 *local_offer_id = NULL; + struct sha256 *local_offer_id; + u8 *payment_metadata; /* For generating help, give new-style. */ if (!param(cmd, buffer, params, @@ -1436,6 +1438,7 @@ static struct command_result *json_sendpay(struct command *cmd, p_opt_def("partid", param_u64, &partid, 0), p_opt("localofferid", param_sha256, &local_offer_id), p_opt("groupid", param_u64, &group), + p_opt("payment_metadata", param_bin_from_hex, &payment_metadata), NULL)) return command_param_failed(); @@ -1485,7 +1488,8 @@ static struct command_result *json_sendpay(struct command *cmd, route, final_amount, msat ? *msat : final_amount, - label, invstring, local_offer_id, payment_secret); + label, invstring, local_offer_id, + payment_secret, payment_metadata); } static const struct json_command sendpay_command = {