diff --git a/doc/lightning-pay.7 b/doc/lightning-pay.7
index 39d169ba3318..b0890be57624 100644
--- a/doc/lightning-pay.7
+++ b/doc/lightning-pay.7
@@ -2,12 +2,12 @@
.\" Title: lightning-pay
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" 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
.\" -----------------------------------------------------------------
@@ -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\&.
@@ -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
@@ -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
diff --git a/doc/lightning-pay.7.txt b/doc/lightning-pay.7.txt
index 73053a94dc3c..e504c8b7abfe 100644
--- a/doc/lightning-pay.7.txt
+++ b/doc/lightning-pay.7.txt
@@ -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'
@@ -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
diff --git a/lightningd/payalgo.c b/lightningd/payalgo.c
index dc1da928eaa9..381ecd1e7106 100644
--- a/lightningd/payalgo.c
+++ b/lightningd/payalgo.c
@@ -4,11 +4,13 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
@@ -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;
@@ -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",
@@ -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. */
@@ -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;
@@ -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)
@@ -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;
}
@@ -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,
@@ -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);
@@ -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");