From 693c7181602d6b63519691b76aef730d25ff4998 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj Date: Wed, 7 Mar 2018 15:41:23 +0000 Subject: [PATCH] wallet: Add DB fields for recording routing failures. --- wallet/db.c | 12 +++++ wallet/wallet.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ wallet/wallet.h | 32 +++++++++++++ 3 files changed, 165 insertions(+) diff --git a/wallet/db.c b/wallet/db.c index 9e86226fe..0cd7df38a 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -233,6 +233,18 @@ char *dbmigrations[] = { /* Assign key 0 to unassigned shutdown_keyidx_local. */ "UPDATE channels SET shutdown_keyidx_local=0 WHERE shutdown_keyidx_local = -1;", /* FIXME: We should rename shutdown_keyidx_local to final_key_index */ + /* -- Payment routing failure information -- */ + /* BLOB if failure was due to unparseable onion, NULL otherwise */ + "ALTER TABLE payments ADD failonionreply BLOB;", + /* 0 if we could theoretically retry, 1 if PERM fail at payee */ + "ALTER TABLE payments ADD faildestperm INTEGER;", + /* Contents of routing_failure (only if not unparseable onion) */ + "ALTER TABLE payments ADD failindex INTEGER;", /* erring_index */ + "ALTER TABLE payments ADD failcode INTEGER;", /* failcode */ + "ALTER TABLE payments ADD failnode BLOB;", /* erring_node */ + "ALTER TABLE payments ADD failchannel BLOB;", /* erring_channel */ + "ALTER TABLE payments ADD failupdate BLOB;", /* channel_update - can be NULL*/ + /* -- Payment routing failure information ends -- */ NULL, }; diff --git a/wallet/wallet.c b/wallet/wallet.c index 015e00208..a2fa99e7f 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1682,6 +1682,127 @@ void wallet_payment_set_status(struct wallet *wallet, } } +void wallet_payment_get_failinfo(const tal_t *ctx, + struct wallet *wallet, + const struct sha256 *payment_hash, + /* outputs */ + u8 **failonionreply, + bool *faildestperm, + int *failindex, + enum onion_type *failcode, + struct pubkey **failnode, + struct short_channel_id **failchannel, + u8 **failupdate) +{ + sqlite3_stmt *stmt; + int res; + bool resb; + size_t len; + + stmt = db_prepare(wallet->db, + "SELECT failonionreply, faildestperm" + " , failindex, failcode" + " , failnode, failchannel" + " , failupdate" + " FROM payments" + " WHERE payment_hash=?;"); + sqlite3_bind_sha256(stmt, 1, payment_hash); + res = sqlite3_step(stmt); + assert(res == SQLITE_ROW); + if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) + *failonionreply = NULL; + else { + len = sqlite3_column_bytes(stmt, 0); + *failonionreply = tal_arr(ctx, u8, len); + memcpy(*failonionreply, sqlite3_column_blob(stmt, 0), len); + } + *faildestperm = sqlite3_column_int(stmt, 1) != 0; + *failindex = sqlite3_column_int(stmt, 2); + *failcode = (enum onion_type) sqlite3_column_int(stmt, 3); + if (sqlite3_column_type(stmt, 4) == SQLITE_NULL) + *failnode = NULL; + else { + *failnode = tal(ctx, struct pubkey); + resb = sqlite3_column_pubkey(stmt, 4, *failnode); + assert(resb); + } + if (sqlite3_column_type(stmt, 5) == SQLITE_NULL) + *failchannel = NULL; + else { + *failchannel = tal(ctx, struct short_channel_id); + resb = sqlite3_column_short_channel_id(stmt, 5, *failchannel); + assert(resb); + } + if (sqlite3_column_type(stmt, 6) == SQLITE_NULL) + *failupdate = NULL; + else { + len = sqlite3_column_bytes(stmt, 6); + *failupdate = tal_arr(ctx, u8, len); + memcpy(*failupdate, sqlite3_column_blob(stmt, 6), len); + } + + sqlite3_finalize(stmt); +} + +void wallet_payment_set_failinfo(struct wallet *wallet, + const struct sha256 *payment_hash, + const u8 *failonionreply /*tal_arr*/, + bool faildestperm, + int failindex, + enum onion_type failcode, + const struct pubkey *failnode, + const struct short_channel_id *failchannel, + const u8 *failupdate /*tal_arr*/) +{ + sqlite3_stmt *stmt; + const tal_t *tmpctx = tal_tmpctx(wallet); + struct short_channel_id *scid; + + stmt = db_prepare(wallet->db, + "UPDATE payments" + " SET failonionreply=?" + " , faildestperm=?" + " , failindex=?" + " , failcode=?" + " , failnode=?" + " , failchannel=?" + " , failupdate=?" + " WHERE payment_hash=?;"); + if (failonionreply) + sqlite3_bind_blob(stmt, 1, + failonionreply, tal_count(failonionreply), + SQLITE_TRANSIENT); + else + sqlite3_bind_null(stmt, 1); + sqlite3_bind_int(stmt, 2, faildestperm ? 1 : 0); + sqlite3_bind_int(stmt, 3, failindex); + sqlite3_bind_int(stmt, 4, (int) failcode); + if (failnode) + sqlite3_bind_pubkey(stmt, 5, failnode); + else + sqlite3_bind_null(stmt, 5); + if (failchannel) { + /* sqlite3_bind_short_channel_id requires the input + * channel to be tal-allocated... */ + scid = tal(tmpctx, struct short_channel_id); + *scid = *failchannel; + sqlite3_bind_short_channel_id(stmt, 6, scid); + } else + sqlite3_bind_null(stmt, 6); + if (failupdate) + sqlite3_bind_blob(stmt, 7, + failupdate, tal_count(failupdate), + SQLITE_TRANSIENT); + else + sqlite3_bind_null(stmt, 7); + + sqlite3_bind_sha256(stmt, 8, payment_hash); + + db_exec_prepared(wallet->db, stmt); + + tal_free(tmpctx); +} + const struct wallet_payment ** wallet_payment_list(const tal_t *ctx, struct wallet *wallet, diff --git a/wallet/wallet.h b/wallet/wallet.h index 6f24ba909..f0c8efcd8 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -16,6 +16,7 @@ #include #include +enum onion_type; struct invoices; struct channel; struct lightningd; @@ -678,6 +679,37 @@ struct secret *wallet_payment_get_secrets(const tal_t *ctx, struct wallet *wallet, const struct sha256 *payment_hash); +/** + * wallet_payment_get_failinfo - Get failure information for a given + * `payment_hash`. + * + * Data is allocated as children of the given context. + */ +void wallet_payment_get_failinfo(const tal_t *ctx, + struct wallet *wallet, + const struct sha256 *payment_hash, + /* outputs */ + u8 **failonionreply, + bool *faildestperm, + int *failindex, + enum onion_type *failcode, + struct pubkey **failnode, + struct short_channel_id **failchannel, + u8 **failupdate); +/** + * wallet_payment_set_failinfo - Set failure information for a given + * `payment_hash`. + */ +void wallet_payment_set_failinfo(struct wallet *wallet, + const struct sha256 *payment_hash, + const u8 *failonionreply, + bool faildestperm, + int failindex, + enum onion_type failcode, + const struct pubkey *failnode, + const struct short_channel_id *failchannel, + const u8 *failupdate); + /** * wallet_payment_list - Retrieve a list of payments *