Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 4 additions & 30 deletions doc/lightning-pay.7
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: lightning-pay
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 02/19/2018
.\" Date: 02/26/2018
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-PAY" "7" "02/19/2018" "\ \&" "\ \&"
.TH "LIGHTNING\-PAY" "7" "02/26/2018" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
Expand Down Expand Up @@ -96,21 +96,6 @@ using different amount or destination\&.
.sp -1
.IP \(bu 2.3
.\}
202\&. Unparseable onion reply\&. The
\fIdata\fR
field of the error will have an
\fIonionreply\fR
field, a hex string representation of the raw onion reply\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
203\&. Permanent failure at destination\&. The
\fIdata\fR
field of the error will be routing failure object\&.
Expand All @@ -124,19 +109,6 @@ field of the error will be routing failure object\&.
.sp -1
.IP \(bu 2.3
.\}
204\&. Failure along route; retry a different route\&. The
\fIdata\fR
field of the error will be routing failure object\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
205\&. Unable to find a route\&.
.RE
.sp
Expand Down Expand Up @@ -174,6 +146,8 @@ field of the error indicates
(the invoice expiration) as UNIX epoch time in seconds\&.
.RE
.sp
Error codes 202 and 204 will only get reported at \fBsendpay\fR; in \fBpay\fR we will keep retrying if we would have gotten those errors\&.
.sp
A routing failure object has the fields below:
.sp
.RS 4
Expand Down
9 changes: 4 additions & 5 deletions doc/lightning-pay.7.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,8 @@ The following error codes may occur:
* 200. A previous *sendpay* or *pay* is in progress.
* 201. Already paid with this 'hash' using different amount or
destination.
* 202. Unparseable onion reply. The 'data' field of the error
will have an 'onionreply' field, a hex string representation
of the raw onion reply.
* 203. Permanent failure at destination. The 'data' field of
the error will be routing failure object.
* 204. Failure along route; retry a different route. The 'data'
field of the error will be routing failure object.
* 205. Unable to find a route.
* 206. Route too expensive. The 'data' field of the error will
indicate the actual 'fee' as well as the 'feepercent'
Expand All @@ -72,6 +67,10 @@ The following error codes may occur:
and 'expiry' (the invoice expiration) as UNIX epoch time in
seconds.

Error codes 202 and 204 will only get reported at *sendpay*;
in *pay* we will keep retrying if we would have gotten those
errors.

A routing failure object has the fields below:

* 'erring_index'. The index of the node along the route that
Expand Down
78 changes: 57 additions & 21 deletions lightningd/payalgo.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include <ccan/tal/str/str.h>
#include <ccan/time/time.h>
#include <common/bolt11.h>
#include <common/type_to_string.h>
#include <gossipd/gen_gossip_wire.h>
#include <gossipd/routing.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/jsonrpc_errors.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/subd.h>
#include <sodium/randombytes.h>

Expand Down Expand Up @@ -58,7 +60,7 @@ json_pay_success(struct command *cmd,
command_success(cmd, response);
}

static void json_pay_failure(struct command *cmd,
static void json_pay_failure(struct pay *pay,
const struct sendpay_result *r)
{
struct json_result *data = NULL;
Expand All @@ -67,33 +69,25 @@ static void json_pay_failure(struct command *cmd,

assert(!r->succeeded);

/* FIXME: can probably be factored out with similar code
* in lightningd/pay.c */
data = new_json_result(pay);

switch (r->errorcode) {
case PAY_IN_PROGRESS:
case PAY_RHASH_ALREADY_USED:
data = NULL;
json_object_start(data, NULL);
json_add_num(data, "getroute_tries", pay->getroute_tries);
json_add_num(data, "sendpay_tries", pay->sendpay_tries);
json_object_end(data);
msg = r->details;
break;

case PAY_UNPARSEABLE_ONION:
data = new_json_result(cmd);
json_object_start(data, NULL);
json_add_hex(data, "onionreply",
r->onionreply, tal_len(r->onionreply));
json_object_end(data);

msg = tal_fmt(cmd,
"failed: WIRE_PERMANENT_NODE_FAILURE "
"(%s)",
r->details);

/* Impossible case */
abort();
break;

case PAY_DESTINATION_PERM_FAIL:
case PAY_TRY_OTHER_ROUTE:
fail = r->routing_failure;
data = new_json_result(cmd);

json_object_start(data, NULL);
json_add_num(data, "erring_index",
Expand All @@ -111,16 +105,21 @@ static void json_pay_failure(struct command *cmd,
tal_len(fail->channel_update));
json_object_end(data);

msg = tal_fmt(cmd,
msg = tal_fmt(pay,
"failed: %s (%s)",
onion_type_name(fail->failcode),
r->details);

break;

case PAY_TRY_OTHER_ROUTE:
/* Impossible case */
abort();
break;
}

assert(msg);
command_fail_detailed(cmd, r->errorcode, data, "%s", msg);
command_fail_detailed(pay->cmd, r->errorcode, data, "%s", msg);
}

/* Start a payment attempt. */
Expand All @@ -134,6 +133,7 @@ static void json_pay_sendpay_resolve(const struct sendpay_result *r,

/* If we succeed, hurray */
if (r->succeeded) {
log_info(pay->cmd->ld->log, "pay(%p): Success", pay);
json_pay_success(pay->cmd, &r->preimage,
pay->getroute_tries, pay->sendpay_tries);
return;
Expand All @@ -143,13 +143,39 @@ static void json_pay_sendpay_resolve(const struct sendpay_result *r,
* below. If it is not, fail now. */
if (r->errorcode != PAY_UNPARSEABLE_ONION &&
r->errorcode != PAY_TRY_OTHER_ROUTE) {
json_pay_failure(pay->cmd, r);
log_info(pay->cmd->ld->log, "pay(%p): Failed, reporting to caller", pay);
json_pay_failure(pay, r);
return;
}

log_info(pay->cmd->ld->log, "pay(%p): Try another route", pay);
json_pay_try(pay);
}

/* Generates a string describing the route. Route should be a
* tal_arr */
static char const *stringify_route(const tal_t *ctx, struct route_hop *route)
{
size_t i;
char *rv = tal_strdup(ctx, "us");
for (i = 0; i < tal_count(route); ++i)
tal_append_fmt(&rv, " -> %s (%"PRIu32"msat, %"PRIu32"blk) -> %s",
type_to_string(ctx, struct short_channel_id, &route[i].channel_id),
route[i].amount, route[i].delay,
type_to_string(ctx, struct pubkey, &route[i].nodeid));
return rv;
}

static void log_route(struct pay *pay, struct route_hop *route)
{
const tal_t *tmpctx = tal_tmpctx(pay->try_parent);

log_info(pay->cmd->ld->log, "pay(%p): sendpay via route: %s",
pay, stringify_route(tmpctx, route));

tal_free(tmpctx);
}

static void json_pay_getroute_reply(struct subd *gossip UNUSED,
const u8 *reply, const int *fds UNUSED,
struct pay *pay)
Expand All @@ -164,7 +190,12 @@ static void json_pay_getroute_reply(struct subd *gossip UNUSED,
fromwire_gossip_getroute_reply(reply, reply, &route);

if (tal_count(route) == 0) {
command_fail_detailed(pay->cmd, PAY_ROUTE_NOT_FOUND, NULL,
data = new_json_result(pay);
json_object_start(data, NULL);
json_add_num(data, "getroute_tries", pay->getroute_tries);
json_add_num(data, "sendpay_tries", pay->sendpay_tries);
json_object_end(data);
command_fail_detailed(pay->cmd, PAY_ROUTE_NOT_FOUND, data,
"Could not find a route");
return;
}
Expand All @@ -188,6 +219,8 @@ static void json_pay_getroute_reply(struct subd *gossip UNUSED,
json_add_double(data, "feepercent", feepercent);
json_add_u64(data, "msatoshi", pay->msatoshi);
json_add_double(data, "maxfeepercent", pay->maxfeepercent);
json_add_num(data, "getroute_tries", pay->getroute_tries);
json_add_num(data, "sendpay_tries", pay->sendpay_tries);
json_object_end(data);

command_fail_detailed(pay->cmd, PAY_ROUTE_TOO_EXPENSIVE,
Expand All @@ -211,6 +244,7 @@ static void json_pay_getroute_reply(struct subd *gossip UNUSED,

++pay->sendpay_tries;

log_route(pay, route);
send_payment(pay->try_parent,
pay->cmd->ld, &pay->payment_hash, route,
&json_pay_sendpay_resolve, pay);
Expand All @@ -232,6 +266,8 @@ static bool json_pay_try(struct pay *pay)
json_object_start(data, NULL);
json_add_num(data, "now", now.ts.tv_sec);
json_add_num(data, "expiry", pay->expiry.ts.tv_sec);
json_add_num(data, "getroute_tries", pay->getroute_tries);
json_add_num(data, "sendpay_tries", pay->sendpay_tries);
json_object_end(data);
command_fail_detailed(cmd, PAY_INVOICE_EXPIRED, data,
"Invoice expired");
Expand Down