diff --git a/lightningd/pay.c b/lightningd/pay.c index dc76d7b5b..1836c8e23 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -515,7 +515,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, fail ? fail->failcode : 0, fail ? &fail->erring_node : 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. */ if (report_to_gossipd) @@ -549,6 +550,7 @@ bool wait_payment(const tal_t *cxt, struct pubkey *failnode; struct short_channel_id *failchannel; u8 *failupdate; + char *faildetail; struct routing_failure *fail; payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash); @@ -588,7 +590,8 @@ bool wait_payment(const tal_t *cxt, &failcode, &failnode, &failchannel, - &failupdate); + &failupdate, + &faildetail); /* Old DB might not save failure information */ if (!failonionreply && !failnode) result = sendpay_result_simple_fail(tmpctx, @@ -596,7 +599,7 @@ bool wait_payment(const tal_t *cxt, "Payment failure reason unknown"); else if (failonionreply) { /* 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 { /* Parsed onion error, get its details */ assert(failnode); @@ -607,7 +610,7 @@ bool wait_payment(const tal_t *cxt, fail->erring_node = *failnode; fail->erring_channel = *failchannel; 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); diff --git a/lightningd/payalgo.c b/lightningd/payalgo.c index fcc34f2eb..1e51fc146 100644 --- a/lightningd/payalgo.c +++ b/lightningd/payalgo.c @@ -39,6 +39,9 @@ struct pay_failure { /* The routing failure, if TYPE_PAYMENT_REPLY, a tal * object whose parent is this struct */ 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 */ @@ -48,12 +51,12 @@ json_add_failure(struct json_result *r, char const *n, { struct routing_failure *rf; json_object_start(r, n); + json_add_string(r, "message", f->details); switch (f->type) { case FAIL_UNPARSEABLE_ONION: json_add_string(r, "type", "FAIL_UNPARSEABLE_ONION"); json_add_hex(r, "onionreply", f->onionreply, tal_len(f->onionreply)); - json_add_route(r, "route", f->route, tal_count(f->route)); break; case FAIL_PAYMENT_REPLY: @@ -68,9 +71,9 @@ json_add_failure(struct json_result *r, char const *n, json_add_hex(r, "channel_update", rf->channel_update, tal_len(rf->channel_update)); - json_add_route(r, "route", f->route, tal_count(f->route)); break; } + json_add_route(r, "route", f->route, tal_count(f->route)); json_object_end(r); } @@ -173,6 +176,7 @@ add_pay_failure(struct pay *pay, default: abort(); } + f->details = tal_strdup(f, r->details); /* Grab the route */ f->route = tal_steal(f, pay->route); pay->route = NULL; diff --git a/wallet/db.c b/wallet/db.c index 461347f3c..e5a7275d1 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -300,6 +300,12 @@ char *dbmigrations[] = { ", rawtx BLOB" ", 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, }; diff --git a/wallet/wallet.c b/wallet/wallet.c index 7d3d8131f..112595545 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -11,6 +11,7 @@ #include #include #include +#include #define SQLITE_MAX_UINT 0x7FFFFFFFFFFFFFFF #define DIRECTION_INCOMING 0 @@ -1770,7 +1771,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx, enum onion_type *failcode, struct pubkey **failnode, struct short_channel_id **failchannel, - u8 **failupdate) + u8 **failupdate, + char **faildetail) { sqlite3_stmt *stmt; int res; @@ -1781,7 +1783,7 @@ void wallet_payment_get_failinfo(const tal_t *ctx, "SELECT failonionreply, faildestperm" " , failindex, failcode" " , failnode, failchannel" - " , failupdate" + " , failupdate, faildetail" " FROM payments" " WHERE 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); 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); } @@ -1830,7 +1834,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet, enum onion_type failcode, const struct pubkey *failnode, const struct short_channel_id *failchannel, - const u8 *failupdate /*tal_arr*/) + const u8 *failupdate /*tal_arr*/, + const char *faildetail) { sqlite3_stmt *stmt; @@ -1843,6 +1848,7 @@ void wallet_payment_set_failinfo(struct wallet *wallet, " , failnode=?" " , failchannel=?" " , failupdate=?" + " , faildetail=?" " WHERE payment_hash=?;"); if (failonionreply) sqlite3_bind_blob(stmt, 1, @@ -1871,8 +1877,11 @@ void wallet_payment_set_failinfo(struct wallet *wallet, SQLITE_TRANSIENT); else 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); } diff --git a/wallet/wallet.h b/wallet/wallet.h index f60e9cdc5..0e41591f7 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -735,7 +735,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx, enum onion_type *failcode, struct pubkey **failnode, struct short_channel_id **failchannel, - u8 **failupdate); + u8 **failupdate, + char **faildetail); /** * wallet_payment_set_failinfo - Set failure information for a given * `payment_hash`. @@ -748,7 +749,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet, enum onion_type failcode, const struct pubkey *failnode, const struct short_channel_id *failchannel, - const u8 *failupdate); + const u8 *failupdate, + const char *faildetail); /** * wallet_payment_list - Retrieve a list of payments