From 2d18c3a20966ffa64366bc8e34d6dc585ef8e92b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Dec 2019 09:46:23 +1030 Subject: [PATCH] db: add partid, total_msat fields to payment entries. This is in preparation for partial payments. For existing payments, partid is 0 (arbitrarity) and total_msat is msatoshi. Signed-off-by: Rusty Russell --- lightningd/pay.c | 57 ++++++++++++++++++---------- lightningd/pay.h | 3 +- lightningd/peer_htlcs.c | 3 +- wallet/db.c | 78 +++++++++++++++++++++++++++++++++++++++ wallet/test/run-wallet.c | 18 ++++++--- wallet/wallet.c | 80 +++++++++++++++++++++++++++++----------- wallet/wallet.h | 26 +++++++++---- 7 files changed, 211 insertions(+), 54 deletions(-) diff --git a/lightningd/pay.c b/lightningd/pay.c index 525ec955b..33608db98 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -81,6 +81,8 @@ void json_add_payment_fields(struct json_stream *response, { json_add_u64(response, "id", t->id); json_add_sha256(response, "payment_hash", &t->payment_hash); + if (t->partid) + json_add_u64(response, "partid", t->partid); if (t->destination != NULL) json_add_node_id(response, "destination", t->destination); @@ -278,9 +280,11 @@ void payment_succeeded(struct lightningd *ld, struct htlc_out *hout, struct wallet_payment *payment; wallet_payment_set_status(ld->wallet, &hout->payment_hash, + /* FIXME: Set partid! */ 0, PAYMENT_COMPLETE, rval); payment = wallet_payment_by_hash(tmpctx, ld->wallet, - &hout->payment_hash); + &hout->payment_hash, + /* FIXME: Set partid! */ 0); assert(payment); tell_waiters_success(ld, &hout->payment_hash, payment); @@ -467,14 +471,16 @@ remote_routing_failure(const tal_t *ctx, return routing_failure; } -void payment_store(struct lightningd *ld, const struct sha256 *payment_hash) +void payment_store(struct lightningd *ld, + const struct sha256 *payment_hash, u64 partid) { struct sendpay_command *pc; struct sendpay_command *next; const struct wallet_payment *payment; - wallet_payment_store(ld->wallet, payment_hash); - payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash); + wallet_payment_store(ld->wallet, payment_hash, partid); + payment = wallet_payment_by_hash(tmpctx, ld->wallet, + payment_hash, partid); assert(payment); /* Trigger any sendpay commands waiting for the store to occur. */ @@ -496,7 +502,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, int pay_errcode; payment = wallet_payment_by_hash(tmpctx, ld->wallet, - &hout->payment_hash); + &hout->payment_hash, + /* FIXME: Set partid! */0); #ifdef COMPAT_V052 /* Prior to "pay: delete HTLC when we delete payment." we would @@ -566,11 +573,11 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, } /* Save to DB */ - payment_store(ld, &hout->payment_hash); - wallet_payment_set_status(ld->wallet, &hout->payment_hash, + payment_store(ld, &hout->payment_hash, /* FIXME: Set partid! */ 0); + wallet_payment_set_status(ld->wallet, &hout->payment_hash, /* FIXME: Set partid! */ 0, PAYMENT_FAILED, NULL); wallet_payment_set_failinfo(ld->wallet, - &hout->payment_hash, + &hout->payment_hash, /* FIXME: Set partid! */ 0, fail ? NULL : hout->failuremsg, pay_errcode == PAY_DESTINATION_PERM_FAIL, fail ? fail->erring_index : -1, @@ -590,7 +597,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, * Return callback if we called already, otherwise NULL. */ static struct command_result *wait_payment(struct lightningd *ld, struct command *cmd, - const struct sha256 *payment_hash) + const struct sha256 *payment_hash, + u64 partid) { struct wallet_payment *payment; u8 *failonionreply; @@ -604,7 +612,8 @@ static struct command_result *wait_payment(struct lightningd *ld, struct routing_failure *fail; int faildirection; - payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash); + payment = wallet_payment_by_hash(tmpctx, ld->wallet, + payment_hash, partid); if (!payment) { return command_fail(cmd, PAY_NO_SUCH_PAYMENT, "Never attempted payment for '%s'", @@ -622,7 +631,9 @@ static struct command_result *wait_payment(struct lightningd *ld, case PAYMENT_FAILED: /* Get error from DB */ - wallet_payment_get_failinfo(tmpctx, ld->wallet, payment_hash, + wallet_payment_get_failinfo(tmpctx, ld->wallet, + payment_hash, + partid, &failonionreply, &faildestperm, &failindex, @@ -706,8 +717,10 @@ static struct command_result * send_payment(struct lightningd *ld, struct command *cmd, const struct sha256 *rhash, + u64 partid, const struct route_hop *route, struct amount_msat msat, + struct amount_msat total_msat, const char *label TAKES, const char *b11str TAKES, const struct secret *payment_secret) @@ -779,7 +792,7 @@ send_payment(struct lightningd *ld, sphinx_add_hop(path, &pubkey, onion); /* Now, do we already have a payment? */ - payment = wallet_payment_by_hash(tmpctx, ld->wallet, rhash); + payment = wallet_payment_by_hash(tmpctx, ld->wallet, rhash, partid); if (payment) { /* FIXME: We should really do something smarter here! */ if (payment->status == PAYMENT_PENDING) { @@ -853,18 +866,21 @@ send_payment(struct lightningd *ld, * onchain_failed_our_htlc->payment_failed with no payment. */ if (payment) { - wallet_payment_delete(ld->wallet, rhash); - wallet_local_htlc_out_delete(ld->wallet, channel, rhash); + wallet_payment_delete(ld->wallet, rhash, payment->partid); + wallet_local_htlc_out_delete(ld->wallet, channel, rhash, + payment->partid); } /* If hout fails, payment should be freed too. */ payment = tal(hout, struct wallet_payment); payment->id = 0; payment->payment_hash = *rhash; + payment->partid = partid; payment->destination = tal_dup(payment, struct node_id, &ids[n_hops - 1]); payment->status = PAYMENT_PENDING; payment->msatoshi = msat; payment->msatoshi_sent = route[0].amount; + payment->total_msat = total_msat; payment->timestamp = time_now().ts.tv_sec; payment->payment_preimage = NULL; payment->path_secrets = tal_steal(payment, path_secrets); @@ -998,7 +1014,7 @@ static struct command_result *json_sendonion(struct command *cmd, failcode); /* Now, do we already have a payment? */ - payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash); + payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash, /* FIXME: Set partid! */0); if (payment) { if (payment->status == PAYMENT_PENDING) { log_debug(ld->log, "send_payment: previous still in progress"); @@ -1028,8 +1044,8 @@ static struct command_result *json_sendonion(struct command *cmd, /* Cleanup any prior payment. We're about to retry. */ if (payment) { - wallet_payment_delete(ld->wallet, payment_hash); - wallet_local_htlc_out_delete(ld->wallet, channel, payment_hash); + wallet_payment_delete(ld->wallet, payment_hash, /* FIXME: Set partid! */0); + wallet_local_htlc_out_delete(ld->wallet, channel, payment_hash, /* FIXME: Set partid! */0); } failcode = send_onion(cmd->ld, &packet, first_hop, payment_hash, channel, @@ -1247,7 +1263,10 @@ static struct command_result *json_sendpay(struct command *cmd, } #endif - res = send_payment(cmd->ld, cmd, rhash, route, + res = send_payment(cmd->ld, cmd, rhash, /* FIXME: Set partid! */ 0, + route, + msat ? *msat : route[routetok->size-1].amount, + /* FIXME: Set total_msat! */ msat ? *msat : route[routetok->size-1].amount, label, b11str, payment_secret); if (res) @@ -1284,7 +1303,7 @@ static struct command_result *json_waitsendpay(struct command *cmd, NULL)) return command_param_failed(); - res = wait_payment(cmd->ld, cmd, rhash); + res = wait_payment(cmd->ld, cmd, rhash, /* FIXME: Set partid! */0); if (res) return res; diff --git a/lightningd/pay.h b/lightningd/pay.h index 53f0e0cdd..acfb394a4 100644 --- a/lightningd/pay.h +++ b/lightningd/pay.h @@ -18,7 +18,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, const char *localfail); /* Inform payment system to save the payment. */ -void payment_store(struct lightningd *ld, const struct sha256 *payment_hash); +void payment_store(struct lightningd *ld, + const struct sha256 *payment_hash, u64 partid); /* This json will be also used in 'sendpay_success' notifictaion. */ void json_add_payment_fields(struct json_stream *response, diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index c71e23fc9..39df3f2a9 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1274,7 +1274,8 @@ static bool update_out_htlc(struct channel *channel, /* For our own HTLCs, we commit payment to db lazily */ if (hout->origin_htlc_id == 0) payment_store(ld, - &hout->payment_hash); + &hout->payment_hash, + /* FIXME: Set partid! */ 0); } if (!htlc_out_update_state(channel, hout, newstate)) diff --git a/wallet/db.c b/wallet/db.c index 0a3d4559c..6497ee293 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -481,6 +481,84 @@ static struct migration dbmigrations[] = { {SQL("UPDATE forwarded_payments SET received_time=0 WHERE received_time IS NULL;"), NULL}, {SQL("ALTER TABLE invoices ADD COLUMN features BLOB DEFAULT '';"), NULL}, + /* We can now have multiple payments in progress for a single hash, so + * add two fields; combination of payment_hash & partid is unique. */ + {SQL("ALTER TABLE payments RENAME TO temp_payments;"), NULL}, + {SQL("CREATE TABLE payments (" + " id BIGSERIAL" + ", timestamp INTEGER" + ", status INTEGER" + ", payment_hash BLOB" + ", destination BLOB" + ", msatoshi BIGINT" + ", payment_preimage BLOB" + ", path_secrets BLOB" + ", route_nodes BLOB" + ", route_channels BLOB" + ", failonionreply BLOB" + ", faildestperm INTEGER" + ", failindex INTEGER" + ", failcode INTEGER" + ", failnode BLOB" + ", failchannel TEXT" + ", failupdate BLOB" + ", msatoshi_sent BIGINT" + ", faildetail TEXT" + ", description TEXT" + ", faildirection INTEGER" + ", bolt11 TEXT" + ", total_msat BIGINT" + ", partid BIGINT" + ", PRIMARY KEY (id)" + ", UNIQUE (payment_hash, partid))"), NULL}, + {SQL("INSERT INTO payments (" + "id" + ", timestamp" + ", status" + ", payment_hash" + ", destination" + ", msatoshi" + ", payment_preimage" + ", path_secrets" + ", route_nodes" + ", route_channels" + ", failonionreply" + ", faildestperm" + ", failindex" + ", failcode" + ", failnode" + ", failchannel" + ", failupdate" + ", msatoshi_sent" + ", faildetail" + ", description" + ", faildirection" + ", bolt11)" + "SELECT id" + ", timestamp" + ", status" + ", payment_hash" + ", destination" + ", msatoshi" + ", payment_preimage" + ", path_secrets" + ", route_nodes" + ", route_channels" + ", failonionreply" + ", faildestperm" + ", failindex" + ", failcode" + ", failnode" + ", failchannel" + ", failupdate" + ", msatoshi_sent" + ", faildetail" + ", description" + ", faildirection" + ", bolt11 FROM temp_payments;"), NULL}, + {SQL("UPDATE payments SET total_msat = msatoshi;"), NULL}, + {SQL("UPDATE payments SET partid = 0;"), NULL}, + {SQL("DROP TABLE temp_payments;"), NULL}, }; /* Leak tracking. */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 56c359e8a..4fc199d9a 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -486,7 +486,8 @@ void payment_failed(struct lightningd *ld UNNEEDED, const struct htlc_out *hout const char *localfail UNNEEDED) { fprintf(stderr, "payment_failed called!\n"); abort(); } /* Generated stub for payment_store */ -void payment_store(struct lightningd *ld UNNEEDED, const struct sha256 *payment_hash UNNEEDED) +void payment_store(struct lightningd *ld UNNEEDED, + const struct sha256 *payment_hash UNNEEDED, u64 partid UNNEEDED) { fprintf(stderr, "payment_store called!\n"); abort(); } /* Generated stub for payment_succeeded */ void payment_succeeded(struct lightningd *ld UNNEEDED, struct htlc_out *hout UNNEEDED, @@ -1254,29 +1255,36 @@ static bool test_payment_crud(struct lightningd *ld, const tal_t *ctx) t->id = 0; t->msatoshi = AMOUNT_MSAT(100); t->msatoshi_sent = AMOUNT_MSAT(101); + t->total_msat = t->msatoshi; t->status = PAYMENT_PENDING; t->payment_preimage = NULL; memset(&t->payment_hash, 1, sizeof(t->payment_hash)); + t->partid = 0; db_begin_transaction(w->db); wallet_payment_setup(w, tal_dup(NULL, struct wallet_payment, t)); - wallet_payment_store(w, &t->payment_hash); - t2 = wallet_payment_by_hash(ctx, w, &t->payment_hash); + wallet_payment_store(w, &t->payment_hash, 0); + t2 = wallet_payment_by_hash(ctx, w, &t->payment_hash, 0); CHECK(t2 != NULL); CHECK(t2->status == t->status); + CHECK(sha256_eq(&t2->payment_hash, &t->payment_hash)); + CHECK(t2->partid == t->partid); CHECK(node_id_cmp(t2->destination, t->destination) == 0); CHECK(amount_msat_eq(t2->msatoshi, t->msatoshi)); CHECK(amount_msat_eq(t2->msatoshi_sent, t->msatoshi_sent)); + CHECK(amount_msat_eq(t2->total_msat, t->total_msat)); CHECK(!t2->payment_preimage); t->status = PAYMENT_COMPLETE; t->payment_preimage = tal(w, struct preimage); memset(t->payment_preimage, 2, sizeof(*t->payment_preimage)); - wallet_payment_set_status(w, &t->payment_hash, t->status, + wallet_payment_set_status(w, &t->payment_hash, t->partid, t->status, t->payment_preimage); - t2 = wallet_payment_by_hash(ctx, w, &t->payment_hash); + t2 = wallet_payment_by_hash(ctx, w, &t->payment_hash, t->partid); CHECK(t2 != NULL); CHECK(t2->status == t->status); + CHECK(sha256_eq(&t2->payment_hash, &t->payment_hash)); + CHECK(t2->partid == t->partid); CHECK(node_id_eq(t2->destination, t->destination)); CHECK(amount_msat_eq(t2->msatoshi, t->msatoshi)); CHECK(amount_msat_eq(t2->msatoshi_sent, t->msatoshi_sent)); diff --git a/wallet/wallet.c b/wallet/wallet.c index 27a31fe18..e452a4234 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -2042,10 +2042,12 @@ struct htlc_stub *wallet_htlc_stubs(const tal_t *ctx, struct wallet *wallet, void wallet_local_htlc_out_delete(struct wallet *wallet, struct channel *chan, - const struct sha256 *payment_hash) + const struct sha256 *payment_hash, + u64 partid) { struct db_stmt *stmt; + /* FIXME: Put partid into locally-generated htlc_out, select here! */ stmt = db_prepare_v2(wallet->db, SQL("DELETE FROM channel_htlcs" " WHERE direction = ?" " AND origin_htlc = ?" @@ -2058,12 +2060,15 @@ void wallet_local_htlc_out_delete(struct wallet *wallet, } static struct wallet_payment * -find_unstored_payment(struct wallet *wallet, const struct sha256 *payment_hash) +find_unstored_payment(struct wallet *wallet, + const struct sha256 *payment_hash, + u64 partid) { struct wallet_payment *i; list_for_each(&wallet->unstored_payments, i, list) { - if (sha256_eq(payment_hash, &i->payment_hash)) + if (sha256_eq(payment_hash, &i->payment_hash) + && i->partid == partid) return i; } return NULL; @@ -2076,19 +2081,21 @@ static void destroy_unstored_payment(struct wallet_payment *payment) void wallet_payment_setup(struct wallet *wallet, struct wallet_payment *payment) { - assert(!find_unstored_payment(wallet, &payment->payment_hash)); + assert(!find_unstored_payment(wallet, &payment->payment_hash, + payment->partid)); list_add_tail(&wallet->unstored_payments, &payment->list); tal_add_destructor(payment, destroy_unstored_payment); } void wallet_payment_store(struct wallet *wallet, - const struct sha256 *payment_hash) + const struct sha256 *payment_hash, + u64 partid) { struct db_stmt *stmt; struct wallet_payment *payment; - payment = find_unstored_payment(wallet, payment_hash); + payment = find_unstored_payment(wallet, payment_hash, partid); if (!payment) { /* Already stored on-disk */ #if DEVELOPER @@ -2098,8 +2105,10 @@ void wallet_payment_store(struct wallet *wallet, bool res; stmt = db_prepare_v2(wallet->db, SQL("SELECT status FROM payments" - " WHERE payment_hash=?;")); + " WHERE payment_hash=?" + " AND partid = ?;")); db_bind_sha256(stmt, 0, payment_hash); + db_bind_u64(stmt, 1, partid); db_query_prepared(stmt); res = db_step(stmt); assert(res); @@ -2124,8 +2133,10 @@ void wallet_payment_store(struct wallet *wallet, " route_channels," " msatoshi_sent," " description," - " bolt11" - ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); + " bolt11," + " total_msat," + " partid" + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_int(stmt, 0, payment->status); db_bind_sha256(stmt, 1, &payment->payment_hash); @@ -2164,26 +2175,32 @@ void wallet_payment_store(struct wallet *wallet, else db_bind_null(stmt, 10); + db_bind_amount_msat(stmt, 11, &payment->total_msat); + db_bind_u64(stmt, 12, payment->partid); + db_exec_prepared_v2(take(stmt)); tal_free(payment); } void wallet_payment_delete(struct wallet *wallet, - const struct sha256 *payment_hash) + const struct sha256 *payment_hash, + u64 partid) { struct db_stmt *stmt; struct wallet_payment *payment; - payment = find_unstored_payment(wallet, payment_hash); + payment = find_unstored_payment(wallet, payment_hash, partid); if (payment) { tal_free(payment); return; } stmt = db_prepare_v2( - wallet->db, SQL("DELETE FROM payments WHERE payment_hash = ?")); + wallet->db, SQL("DELETE FROM payments WHERE payment_hash = ?" + " AND partid = ?")); db_bind_sha256(stmt, 0, payment_hash); + db_bind_u64(stmt, 1, partid); db_exec_prepared_v2(take(stmt)); } @@ -2251,18 +2268,21 @@ static struct wallet_payment *wallet_stmt2payment(const tal_t *ctx, else payment->failonion = NULL; + db_column_amount_msat(stmt, 14, &payment->total_msat); + payment->partid = db_column_u64(stmt, 15); return payment; } struct wallet_payment * wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, - const struct sha256 *payment_hash) + const struct sha256 *payment_hash, + u64 partid) { struct db_stmt *stmt; struct wallet_payment *payment; /* Present the illusion that it's in the db... */ - payment = find_unstored_payment(wallet, payment_hash); + payment = find_unstored_payment(wallet, payment_hash, partid); if (payment) return payment; @@ -2281,10 +2301,14 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, ", description" ", bolt11" ", failonionreply" + ", total_msat" + ", partid" " FROM payments" - " WHERE payment_hash = ?")); + " WHERE payment_hash = ?" + " AND partid = ?")); db_bind_sha256(stmt, 0, payment_hash); + db_bind_u64(stmt, 1, partid); db_query_prepared(stmt); if (db_step(stmt)) { payment = wallet_stmt2payment(ctx, stmt); @@ -2295,6 +2319,7 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, void wallet_payment_set_status(struct wallet *wallet, const struct sha256 *payment_hash, + u64 partid, const enum wallet_payment_status newstatus, const struct preimage *preimage) { @@ -2302,7 +2327,7 @@ void wallet_payment_set_status(struct wallet *wallet, struct wallet_payment *payment; /* We can only fail an unstored payment! */ - payment = find_unstored_payment(wallet, payment_hash); + payment = find_unstored_payment(wallet, payment_hash, partid); if (payment) { assert(newstatus == PAYMENT_FAILED); tal_free(payment); @@ -2311,19 +2336,21 @@ void wallet_payment_set_status(struct wallet *wallet, stmt = db_prepare_v2(wallet->db, SQL("UPDATE payments SET status=? " - "WHERE payment_hash=?")); + "WHERE payment_hash=? AND partid=?")); db_bind_int(stmt, 0, wallet_payment_status_in_db(newstatus)); db_bind_sha256(stmt, 1, payment_hash); + db_bind_u64(stmt, 2, partid); db_exec_prepared_v2(take(stmt)); if (preimage) { stmt = db_prepare_v2(wallet->db, SQL("UPDATE payments SET payment_preimage=? " - "WHERE payment_hash=?")); + "WHERE payment_hash=? AND partid=?")); db_bind_preimage(stmt, 0, preimage); db_bind_sha256(stmt, 1, payment_hash); + db_bind_u64(stmt, 2, partid); db_exec_prepared_v2(take(stmt)); } if (newstatus != PAYMENT_PENDING) { @@ -2332,8 +2359,10 @@ void wallet_payment_set_status(struct wallet *wallet, " SET path_secrets = NULL" " , route_nodes = NULL" " , route_channels = NULL" - " WHERE payment_hash = ?;")); + " WHERE payment_hash = ?" + " AND partid = ?;")); db_bind_sha256(stmt, 0, payment_hash); + db_bind_u64(stmt, 1, partid); db_exec_prepared_v2(take(stmt)); } } @@ -2341,6 +2370,7 @@ 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, + u64 partid, /* outputs */ u8 **failonionreply, bool *faildestperm, @@ -2362,8 +2392,9 @@ void wallet_payment_get_failinfo(const tal_t *ctx, ", failnode, failchannel" ", failupdate, faildetail, faildirection" " FROM payments" - " WHERE payment_hash=?;")); + " WHERE payment_hash=? AND partid=?;")); db_bind_sha256(stmt, 0, payment_hash); + db_bind_u64(stmt, 1, partid); db_query_prepared(stmt); resb = db_step(stmt); assert(resb); @@ -2412,6 +2443,7 @@ void wallet_payment_get_failinfo(const tal_t *ctx, void wallet_payment_set_failinfo(struct wallet *wallet, const struct sha256 *payment_hash, + u64 partid, const u8 *failonionreply /*tal_arr*/, bool faildestperm, int failindex, @@ -2434,7 +2466,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet, " , failupdate=?" " , faildetail=?" " , faildirection=?" - " WHERE payment_hash=?;")); + " WHERE payment_hash=?" + " AND partid=?;")); if (failonionreply) db_bind_blob(stmt, 0, failonionreply, tal_count(failonionreply)); @@ -2469,6 +2502,7 @@ void wallet_payment_set_failinfo(struct wallet *wallet, db_bind_null(stmt, 7); db_bind_sha256(stmt, 9, payment_hash); + db_bind_u64(stmt, 10, partid); db_exec_prepared_v2(take(stmt)); } @@ -2501,6 +2535,8 @@ wallet_payment_list(const tal_t *ctx, ", description" ", bolt11" ", failonionreply" + ", total_msat" + ", partid" " FROM payments" " WHERE payment_hash = ?;")); db_bind_sha256(stmt, 0, payment_hash); @@ -2520,6 +2556,8 @@ wallet_payment_list(const tal_t *ctx, ", description" ", bolt11" ", failonionreply" + ", total_msat" + ", partid" " FROM payments;")); } db_query_prepared(stmt); diff --git a/wallet/wallet.h b/wallet/wallet.h index 66a1f0e8f..927007748 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -249,13 +249,18 @@ struct wallet_payment { struct list_node list; u64 id; u32 timestamp; + + /* The combination of these two fields is unique: */ struct sha256 payment_hash; + u64 partid; + enum wallet_payment_status status; /* The destination may not be known if we used `sendonion` */ struct node_id *destination; struct amount_msat msatoshi; struct amount_msat msatoshi_sent; + struct amount_msat total_msat; /* If and only if PAYMENT_COMPLETE */ struct preimage *payment_preimage; /* Needed for recovering from routing failures. */ @@ -930,7 +935,8 @@ void wallet_payment_setup(struct wallet *wallet, struct wallet_payment *payment) * Stores the payment in the database. */ void wallet_payment_store(struct wallet *wallet, - const struct sha256 *payment_hash); + const struct sha256 *payment_hash, + u64 partid); /** * wallet_payment_delete - Remove a payment @@ -938,7 +944,8 @@ void wallet_payment_store(struct wallet *wallet, * Removes the payment from the database. */ void wallet_payment_delete(struct wallet *wallet, - const struct sha256 *payment_hash); + const struct sha256 *payment_hash, + u64 partid); /** * wallet_local_htlc_out_delete - Remove a local outgoing failed HTLC @@ -949,7 +956,8 @@ void wallet_payment_delete(struct wallet *wallet, */ void wallet_local_htlc_out_delete(struct wallet *wallet, struct channel *chan, - const struct sha256 *payment_hash); + const struct sha256 *payment_hash, + u64 partid); /** * wallet_payment_by_hash - Retrieve a specific payment @@ -958,7 +966,8 @@ void wallet_local_htlc_out_delete(struct wallet *wallet, */ struct wallet_payment * wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, - const struct sha256 *payment_hash); + const struct sha256 *payment_hash, + u64 partid); /** * wallet_payment_set_status - Update the status of the payment @@ -967,9 +976,10 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, * its state. */ void wallet_payment_set_status(struct wallet *wallet, - const struct sha256 *payment_hash, - const enum wallet_payment_status newstatus, - const struct preimage *preimage); + const struct sha256 *payment_hash, + u64 partid, + const enum wallet_payment_status newstatus, + const struct preimage *preimage); /** * wallet_payment_get_failinfo - Get failure information for a given @@ -981,6 +991,7 @@ 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, + u64 partid, /* outputs */ u8 **failonionreply, bool *faildestperm, @@ -997,6 +1008,7 @@ void wallet_payment_get_failinfo(const tal_t *ctx, */ void wallet_payment_set_failinfo(struct wallet *wallet, const struct sha256 *payment_hash, + u64 partid, const u8 *failonionreply, bool faildestperm, int failindex,