From 559010f525af383d069cb8d6562829e82110bc94 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 18 Jan 2018 06:59:49 +1030 Subject: [PATCH] wallet: add path_secrets to payment table. We need these to decode any returned errors. We remove it from struct pay_command too, and load directly from db when we need it. Signed-off-by: Rusty Russell --- lightningd/pay.c | 15 ++++++++------- wallet/db.c | 4 ++++ wallet/wallet.c | 29 +++++++++++++++++++++++++++-- wallet/wallet.h | 10 ++++++++++ 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/lightningd/pay.c b/lightningd/pay.c index 84f598445..6f9d8dbfd 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -28,9 +28,6 @@ struct pay_command { /* Preimage if this succeeded. */ const struct preimage *rval; struct command *cmd; - - /* Remember all shared secrets, so we can unwrap an eventual failure */ - struct secret *path_secrets; }; static void json_pay_success(struct command *cmd, const struct preimage *rval) @@ -82,6 +79,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, struct pay_command *pc = hout->pay_command; struct onionreply *reply; enum onion_type failcode; + struct secret *path_secrets; + const tal_t *tmpctx = tal_tmpctx(ld); wallet_payment_set_status(ld->wallet, &hout->payment_hash, PAYMENT_FAILED, NULL); @@ -89,13 +88,15 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, /* This gives more details than a generic failure message */ if (localfail) { json_pay_failed(pc, NULL, hout->failcode, localfail); + tal_free(tmpctx); return; } /* Must be remote fail. */ assert(!hout->failcode); - reply = unwrap_onionreply(pc, pc->path_secrets, - tal_count(pc->path_secrets), + path_secrets = wallet_payment_get_secrets(tmpctx, ld->wallet, + &hout->payment_hash); + reply = unwrap_onionreply(pc, path_secrets, tal_count(path_secrets), hout->failuremsg); if (!reply) { log_info(hout->key.peer->log, @@ -118,6 +119,7 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, /* check_for_routing_failure(i, sender, failure_code); */ json_pay_failed(pc, NULL, failcode, "reply from remote"); + tal_free(tmpctx); } /* When JSON RPC goes away, cmd is freed: detach from any running paycommand */ @@ -237,7 +239,6 @@ static bool send_payment(struct command *cmd, if (pc) { pc->ids = tal_free(pc->ids); - pc->path_secrets = tal_free(pc->path_secrets); } else { pc = tal(cmd->ld, struct pay_command); list_add_tail(&cmd->ld->pay_commands, &pc->list); @@ -251,13 +252,13 @@ static bool send_payment(struct command *cmd, payment->msatoshi = route[n_hops-1].amount; payment->timestamp = time_now().ts.tv_sec; payment->payment_preimage = NULL; + payment->path_secrets = tal_steal(payment, path_secrets); } pc->cmd = cmd; pc->rhash = *rhash; pc->rval = NULL; pc->ids = tal_steal(pc, ids); pc->msatoshi = route[n_hops-1].amount; - pc->path_secrets = tal_steal(pc, path_secrets); pc->out = NULL; log_info(cmd->ld->log, "Sending %u over %zu hops to deliver %"PRIu64, diff --git a/wallet/db.c b/wallet/db.c index 34e17dee6..93265d88e 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -175,6 +175,8 @@ char *dbmigrations[] = { "DROP TABLE temp_payments;", /* We need to keep the preimage in case they ask to pay again. */ "ALTER TABLE payments ADD COLUMN payment_preimage BLOB;", + /* We need to keep the shared secrets to decode error returns. */ + "ALTER TABLE payments ADD COLUMN path_secrets BLOB;", NULL, }; @@ -533,6 +535,8 @@ struct secret *sqlite3_column_secrets(const tal_t *ctx, /* Must fit exactly */ assert(n * sizeof(struct secret) == sqlite3_column_bytes(stmt, col)); + if (n == 0) + return NULL; secrets = tal_arr(ctx, struct secret, n); return memcpy(secrets, sqlite3_column_blob(stmt, col), tal_len(secrets)); } diff --git a/wallet/wallet.c b/wallet/wallet.c index b8f3b377c..99b18aff7 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1289,6 +1289,9 @@ static struct wallet_payment *wallet_stmt2payment(const tal_t *ctx, sqlite3_column_preimage(stmt, 6, payment->payment_preimage); } else payment->payment_preimage = NULL; + + /* Can be NULL for old db! */ + payment->path_secrets = sqlite3_column_secrets(payment, stmt, 7); return payment; } @@ -1301,7 +1304,8 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, stmt = db_prepare(wallet->db, "SELECT id, status, destination," - "msatoshi, payment_hash, timestamp, payment_preimage " + "msatoshi, payment_hash, timestamp, payment_preimage, " + "path_secrets " "FROM payments " "WHERE payment_hash = ?"); @@ -1313,6 +1317,26 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, return payment; } +struct secret *wallet_payment_get_secrets(const tal_t *ctx, + struct wallet *wallet, + const struct sha256 *payment_hash) +{ + sqlite3_stmt *stmt; + struct secret *path_secrets = NULL; + + stmt = db_prepare(wallet->db, + "SELECT path_secrets " + "FROM payments " + "WHERE payment_hash = ?"); + + sqlite3_bind_sha256(stmt, 1, payment_hash); + if (sqlite3_step(stmt) == SQLITE_ROW) { + path_secrets = sqlite3_column_secrets(ctx, stmt, 0); + } + sqlite3_finalize(stmt); + return path_secrets; +} + void wallet_payment_set_status(struct wallet *wallet, const struct sha256 *payment_hash, const enum wallet_payment_status newstatus, @@ -1349,7 +1373,8 @@ const struct wallet_payment **wallet_payment_list(const tal_t *ctx, stmt = db_prepare( wallet->db, "SELECT id, status, destination, " - "msatoshi , payment_hash, timestamp, payment_preimage " + "msatoshi, payment_hash, timestamp, payment_preimage, " + "path_secrets " "FROM payments;"); for (int i = 0; sqlite3_step(stmt) == SQLITE_ROW; i++) { diff --git a/wallet/wallet.h b/wallet/wallet.h index 24d370e5e..c21f8948a 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -90,6 +90,7 @@ struct wallet_payment { u64 msatoshi; /* Iff PAYMENT_COMPLETE */ struct preimage *payment_preimage; + struct secret *path_secrets; }; /** @@ -556,6 +557,15 @@ void wallet_payment_set_status(struct wallet *wallet, const enum wallet_payment_status newstatus, const struct preimage *preimage); +/** + * wallet_payment_get_secrets - Get the secrets array for a given `payment_hash` + * + * Returns a tal_array: can return NULL for old dbs. + */ +struct secret *wallet_payment_get_secrets(const tal_t *ctx, + struct wallet *wallet, + const struct sha256 *payment_hash); + /** * wallet_payment_list - Retrieve a list of payments */