Browse Source

wallet, payalgo: Save detail of payment failures for later reporting. (#1345)

Pointless for remote failures as those are never sent by
the erring node, but for local failures we can give more
detail.
ppa-0.6.1
ZmnSCPxj, ZmnSCPxj jxPCSmnZ 7 years ago
committed by Christian Decker
parent
commit
11ca729d85
  1. 11
      lightningd/pay.c
  2. 8
      lightningd/payalgo.c
  3. 6
      wallet/db.c
  4. 17
      wallet/wallet.c
  5. 6
      wallet/wallet.h

11
lightningd/pay.c

@ -515,7 +515,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
fail ? fail->failcode : 0, fail ? fail->failcode : 0,
fail ? &fail->erring_node : NULL, fail ? &fail->erring_node : NULL,
fail ? &fail->erring_channel : NULL, fail ? &fail->erring_channel : NULL,
fail ? fail->channel_update : NULL); fail ? fail->channel_update : NULL,
failmsg);
/* Report to gossipd if we decided we should. */ /* Report to gossipd if we decided we should. */
if (report_to_gossipd) if (report_to_gossipd)
@ -549,6 +550,7 @@ bool wait_payment(const tal_t *cxt,
struct pubkey *failnode; struct pubkey *failnode;
struct short_channel_id *failchannel; struct short_channel_id *failchannel;
u8 *failupdate; u8 *failupdate;
char *faildetail;
struct routing_failure *fail; struct routing_failure *fail;
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash); payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash);
@ -588,7 +590,8 @@ bool wait_payment(const tal_t *cxt,
&failcode, &failcode,
&failnode, &failnode,
&failchannel, &failchannel,
&failupdate); &failupdate,
&faildetail);
/* Old DB might not save failure information */ /* Old DB might not save failure information */
if (!failonionreply && !failnode) if (!failonionreply && !failnode)
result = sendpay_result_simple_fail(tmpctx, result = sendpay_result_simple_fail(tmpctx,
@ -596,7 +599,7 @@ bool wait_payment(const tal_t *cxt,
"Payment failure reason unknown"); "Payment failure reason unknown");
else if (failonionreply) { else if (failonionreply) {
/* failed to parse returned onion error */ /* failed to parse returned onion error */
result = sendpay_result_route_failure(tmpctx, true, NULL, failonionreply, "reply from remote"); result = sendpay_result_route_failure(tmpctx, true, NULL, failonionreply, faildetail);
} else { } else {
/* Parsed onion error, get its details */ /* Parsed onion error, get its details */
assert(failnode); assert(failnode);
@ -607,7 +610,7 @@ bool wait_payment(const tal_t *cxt,
fail->erring_node = *failnode; fail->erring_node = *failnode;
fail->erring_channel = *failchannel; fail->erring_channel = *failchannel;
fail->channel_update = failupdate; fail->channel_update = failupdate;
result = sendpay_result_route_failure(tmpctx, !faildestperm, fail, NULL, "route failure"); result = sendpay_result_route_failure(tmpctx, !faildestperm, fail, NULL, faildetail);
} }
cb(result, cbarg); cb(result, cbarg);

8
lightningd/payalgo.c

@ -39,6 +39,9 @@ struct pay_failure {
/* The routing failure, if TYPE_PAYMENT_REPLY, a tal /* The routing failure, if TYPE_PAYMENT_REPLY, a tal
* object whose parent is this struct */ * object whose parent is this struct */
struct routing_failure *routing_failure; struct routing_failure *routing_failure;
/* The detail of the routing failure. A tal_arr
* string whose parent is this struct. */
char *details;
}; };
/* Output a pay failure */ /* Output a pay failure */
@ -48,12 +51,12 @@ json_add_failure(struct json_result *r, char const *n,
{ {
struct routing_failure *rf; struct routing_failure *rf;
json_object_start(r, n); json_object_start(r, n);
json_add_string(r, "message", f->details);
switch (f->type) { switch (f->type) {
case FAIL_UNPARSEABLE_ONION: case FAIL_UNPARSEABLE_ONION:
json_add_string(r, "type", "FAIL_UNPARSEABLE_ONION"); json_add_string(r, "type", "FAIL_UNPARSEABLE_ONION");
json_add_hex(r, "onionreply", f->onionreply, json_add_hex(r, "onionreply", f->onionreply,
tal_len(f->onionreply)); tal_len(f->onionreply));
json_add_route(r, "route", f->route, tal_count(f->route));
break; break;
case FAIL_PAYMENT_REPLY: case FAIL_PAYMENT_REPLY:
@ -68,9 +71,9 @@ json_add_failure(struct json_result *r, char const *n,
json_add_hex(r, "channel_update", json_add_hex(r, "channel_update",
rf->channel_update, rf->channel_update,
tal_len(rf->channel_update)); tal_len(rf->channel_update));
json_add_route(r, "route", f->route, tal_count(f->route));
break; break;
} }
json_add_route(r, "route", f->route, tal_count(f->route));
json_object_end(r); json_object_end(r);
} }
@ -173,6 +176,7 @@ add_pay_failure(struct pay *pay,
default: default:
abort(); abort();
} }
f->details = tal_strdup(f, r->details);
/* Grab the route */ /* Grab the route */
f->route = tal_steal(f, pay->route); f->route = tal_steal(f, pay->route);
pay->route = NULL; pay->route = NULL;

6
wallet/db.c

@ -300,6 +300,12 @@ char *dbmigrations[] = {
", rawtx BLOB" ", rawtx BLOB"
", PRIMARY KEY (id)" ", PRIMARY KEY (id)"
");", ");",
/* -- Detailed payment failure -- */
"ALTER TABLE payments ADD faildetail TEXT;",
"UPDATE payments"
" SET faildetail = 'unspecified payment failure reason'"
" WHERE status = 2;", /* PAYMENT_FAILED */
/* -- Detailed payment faiure ends -- */
NULL, NULL,
}; };

17
wallet/wallet.c

@ -11,6 +11,7 @@
#include <lightningd/log.h> #include <lightningd/log.h>
#include <lightningd/peer_control.h> #include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h> #include <lightningd/peer_htlcs.h>
#include <string.h>
#define SQLITE_MAX_UINT 0x7FFFFFFFFFFFFFFF #define SQLITE_MAX_UINT 0x7FFFFFFFFFFFFFFF
#define DIRECTION_INCOMING 0 #define DIRECTION_INCOMING 0
@ -1770,7 +1771,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
enum onion_type *failcode, enum onion_type *failcode,
struct pubkey **failnode, struct pubkey **failnode,
struct short_channel_id **failchannel, struct short_channel_id **failchannel,
u8 **failupdate) u8 **failupdate,
char **faildetail)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int res; int res;
@ -1781,7 +1783,7 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
"SELECT failonionreply, faildestperm" "SELECT failonionreply, faildestperm"
" , failindex, failcode" " , failindex, failcode"
" , failnode, failchannel" " , failnode, failchannel"
" , failupdate" " , failupdate, faildetail"
" FROM payments" " FROM payments"
" WHERE payment_hash=?;"); " WHERE payment_hash=?;");
sqlite3_bind_sha256(stmt, 1, payment_hash); sqlite3_bind_sha256(stmt, 1, payment_hash);
@ -1818,6 +1820,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
*failupdate = tal_arr(ctx, u8, len); *failupdate = tal_arr(ctx, u8, len);
memcpy(*failupdate, sqlite3_column_blob(stmt, 6), len); memcpy(*failupdate, sqlite3_column_blob(stmt, 6), len);
} }
*faildetail = tal_strndup(ctx, sqlite3_column_blob(stmt, 7),
sqlite3_column_bytes(stmt, 7));
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
@ -1830,7 +1834,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
enum onion_type failcode, enum onion_type failcode,
const struct pubkey *failnode, const struct pubkey *failnode,
const struct short_channel_id *failchannel, const struct short_channel_id *failchannel,
const u8 *failupdate /*tal_arr*/) const u8 *failupdate /*tal_arr*/,
const char *faildetail)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@ -1843,6 +1848,7 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
" , failnode=?" " , failnode=?"
" , failchannel=?" " , failchannel=?"
" , failupdate=?" " , failupdate=?"
" , faildetail=?"
" WHERE payment_hash=?;"); " WHERE payment_hash=?;");
if (failonionreply) if (failonionreply)
sqlite3_bind_blob(stmt, 1, sqlite3_bind_blob(stmt, 1,
@ -1871,8 +1877,11 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
SQLITE_TRANSIENT); SQLITE_TRANSIENT);
else else
sqlite3_bind_null(stmt, 7); sqlite3_bind_null(stmt, 7);
sqlite3_bind_blob(stmt, 8,
faildetail, strlen(faildetail),
SQLITE_TRANSIENT);
sqlite3_bind_sha256(stmt, 8, payment_hash); sqlite3_bind_sha256(stmt, 9, payment_hash);
db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
} }

6
wallet/wallet.h

@ -735,7 +735,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
enum onion_type *failcode, enum onion_type *failcode,
struct pubkey **failnode, struct pubkey **failnode,
struct short_channel_id **failchannel, struct short_channel_id **failchannel,
u8 **failupdate); u8 **failupdate,
char **faildetail);
/** /**
* wallet_payment_set_failinfo - Set failure information for a given * wallet_payment_set_failinfo - Set failure information for a given
* `payment_hash`. * `payment_hash`.
@ -748,7 +749,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
enum onion_type failcode, enum onion_type failcode,
const struct pubkey *failnode, const struct pubkey *failnode,
const struct short_channel_id *failchannel, const struct short_channel_id *failchannel,
const u8 *failupdate); const u8 *failupdate,
const char *faildetail);
/** /**
* wallet_payment_list - Retrieve a list of payments * wallet_payment_list - Retrieve a list of payments

Loading…
Cancel
Save