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");