diff --git a/doc/lightning-sendpay.7 b/doc/lightning-sendpay.7 index b6465db6f..94e789ad3 100644 --- a/doc/lightning-sendpay.7 +++ b/doc/lightning-sendpay.7 @@ -2,12 +2,12 @@ .\" Title: lightning-sendpay .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 03/14/2018 +.\" Date: 03/22/2018 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "LIGHTNING\-SENDPAY" "7" "03/14/2018" "\ \&" "\ \&" +.TH "LIGHTNING\-SENDPAY" "7" "03/22/2018" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -31,7 +31,7 @@ lightning-sendpay \- Protocol for sending a payment via a route\&. .SH "SYNOPSIS" .sp -\fBsendpay\fR \fIroute\fR \fIhash\fR +\fBsendpay\fR \fIroute\fR \fIhash\fR [\fImsatoshi\fR] .SH "DESCRIPTION" .sp The \fBsendpay\fR RPC command attempts to send funds associated with the given \fIhash\fR, along a route to the final destination in the route\&. @@ -40,7 +40,9 @@ Generally, a client would call getroute(7) to resolve a route, then use \fBsendp .sp The response will occur when the payment is on its way to the destination\&. The \fBsendpay\fR RPC command does not wait for definite success or definite failure of the payment\&. Instead, use the \fBwaitsendpay\fR RPC command to poll or wait for definite success or definite failure\&. .sp -Once a payment has succeeded, calls to \fBsendpay\fR with the same \fIhash\fR but a different amount or destination will fail; this prevents accidental multiple payments\&. Calls to \fBsendpay\fR with the same \fIhash\fR, amount, and destination as a previous successful payment (even if a different route) will return immediately with success\&. +The \fImsatoshi\fR amount, if provided, is the amount that will be recorded as the target payment value\&. If not specified, it will be the final amount to the destination\&. If specified, then the final amount at the destination must be from the specified \fImsatoshi\fR to twice the specified \fImsatoshi\fR, inclusive\&. This is intended to obscure payments by overpaying slightly at the destination; the actual target payment is what should be specified as the \fImsatoshi\fR argument\&. +.sp +Once a payment has succeeded, calls to \fBsendpay\fR with the same \fIhash\fR but a different \fImsatoshi\fR or destination will fail; this prevents accidental multiple payments\&. Calls to \fBsendpay\fR with the same \fIhash\fR, \fImsatoshi\fR, and destination as a previous successful payment (even if a different route) will return immediately with success\&. .SH "RETURN VALUE" .sp On success, an object similar to the output of \fBlistpayments\fR will be returned\&. This object will have a \fIstatus\fR field that is typically the string \fI"pending"\fR, but may be \fI"complete"\fR if the payment was already performed successfully\&. diff --git a/doc/lightning-sendpay.7.txt b/doc/lightning-sendpay.7.txt index 9cb94230d..301d01e87 100644 --- a/doc/lightning-sendpay.7.txt +++ b/doc/lightning-sendpay.7.txt @@ -8,7 +8,7 @@ lightning-sendpay - Protocol for sending a payment via a route. SYNOPSIS -------- -*sendpay* 'route' 'hash' +*sendpay* 'route' 'hash' ['msatoshi'] DESCRIPTION ----------- @@ -27,10 +27,21 @@ definite failure of the payment. Instead, use the *waitsendpay* RPC command to poll or wait for definite success or definite failure. +The 'msatoshi' amount, if provided, is the amount that will be +recorded as the target payment value. +If not specified, it will be the final amount to the destination. +If specified, then the final amount at the destination must be +from the specified 'msatoshi' to twice the specified 'msatoshi', +inclusive. +This is intended to obscure payments by overpaying slightly at +the destination; +the actual target payment is what should be specified as the +'msatoshi' argument. + Once a payment has succeeded, calls to *sendpay* with the same 'hash' -but a different amount or destination will fail; this prevents +but a different 'msatoshi' or destination will fail; this prevents accidental multiple payments. -Calls to *sendpay* with the same 'hash', amount, and destination as a +Calls to *sendpay* with the same 'hash', 'msatoshi', and destination as a previous successful payment (even if a different route) will return immediately with success. diff --git a/lightningd/pay.c b/lightningd/pay.c index 7dd9bfb32..ebd6c4d00 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -628,6 +628,7 @@ send_payment(const tal_t *ctx, struct lightningd* ld, const struct sha256 *rhash, const struct route_hop *route, + u64 msatoshi, void (*cb)(const struct sendpay_result *, void*), void *cbarg) { @@ -685,7 +686,7 @@ send_payment(const tal_t *ctx, if (payment->status == PAYMENT_COMPLETE) { log_add(ld->log, "... succeeded"); /* Must match successful payment parameters. */ - if (payment->msatoshi != hop_data[n_hops-1].amt_forward) { + if (payment->msatoshi != msatoshi) { char *msg = tal_fmt(tmpctx, "Already succeeded " "with amount %"PRIu64, @@ -740,8 +741,8 @@ send_payment(const tal_t *ctx, sizeof(struct sha256), &path_secrets); onion = serialize_onionpacket(tmpctx, packet); - log_info(ld->log, "Sending %u over %zu hops to deliver %u", - route[0].amount, n_hops, route[n_hops-1].amount); + log_info(ld->log, "Sending %u over %zu hops to deliver %"PRIu64"", + route[0].amount, n_hops, msatoshi); failcode = send_htlc_out(channel, route[0].amount, base_expiry + route[0].delay, @@ -781,7 +782,7 @@ send_payment(const tal_t *ctx, payment->payment_hash = *rhash; payment->destination = ids[n_hops - 1]; payment->status = PAYMENT_PENDING; - payment->msatoshi = route[n_hops-1].amount; + payment->msatoshi = msatoshi; payment->msatoshi_sent = route[0].amount; payment->timestamp = time_now().ts.tv_sec; payment->payment_preimage = NULL; @@ -912,14 +913,17 @@ static void json_sendpay(struct command *cmd, const char *buffer, const jsmntok_t *params) { jsmntok_t *routetok, *rhashtok; + jsmntok_t *msatoshitok; const jsmntok_t *t, *end; size_t n_hops; struct sha256 rhash; struct route_hop *route; + u64 msatoshi; if (!json_get_params(cmd, buffer, params, "route", &routetok, "payment_hash", &rhashtok, + "?msatoshi", &msatoshitok, NULL)) { return; } @@ -994,7 +998,29 @@ static void json_sendpay(struct command *cmd, return; } - if (send_payment(cmd, cmd->ld, &rhash, route, + if (msatoshitok) { + if (!json_tok_u64(buffer, msatoshitok, &msatoshi)) { + command_fail(cmd, "'%.*s' is not a number", + msatoshitok->end - msatoshitok->start, + buffer + msatoshitok->start); + return; + } + /* The given msatoshi is the actual payment that + * the payee is requesting. The final hop amount, is + * what we actually give, which can be from the + * msatoshi to twice msatoshi. */ + /* if not: msatoshi <= finalhop.amount <= 2 * msatoshi, + * fail. */ + if (!(msatoshi <= route[n_hops-1].amount && + route[n_hops-1].amount <= 2 * msatoshi)) { + command_fail(cmd, "msatoshi %"PRIu64" out of range", + msatoshi); + return; + } + } else + msatoshi = route[n_hops-1].amount; + + if (send_payment(cmd, cmd->ld, &rhash, route, msatoshi, &json_sendpay_on_resolve, cmd)) command_still_pending(cmd); } diff --git a/lightningd/pay.h b/lightningd/pay.h index 152274f67..6895e0a1e 100644 --- a/lightningd/pay.h +++ b/lightningd/pay.h @@ -57,11 +57,14 @@ struct sendpay_result { * sendpay_result indicating an error code of PAY_IN_PROGRESS. * It will only call the callback with successful sendpay_result * if the payment has already completed with the same amount - * and destination before. */ + * and destination before. + * + * The msatoshi given is what is recorded in the payment. */ bool send_payment(const tal_t *ctx, struct lightningd* ld, const struct sha256 *rhash, const struct route_hop *route, + u64 msatoshi, void (*cb)(const struct sendpay_result *, void*), void *cbarg); /* Wait for a previous send_payment to complete in definite diff --git a/lightningd/payalgo.c b/lightningd/payalgo.c index ca34015f2..4a45af051 100644 --- a/lightningd/payalgo.c +++ b/lightningd/payalgo.c @@ -475,6 +475,7 @@ static void json_pay_getroute_reply(struct subd *gossip UNUSED, pay->in_sendpay = true; send_payment(pay->try_parent, pay->cmd->ld, &pay->payment_hash, route, + pay->msatoshi, &json_pay_sendpay_resume, pay); }