wallet: add preimage to db.

We should be saving this, as it's our proof of payment.  Also, we return
it if they try to pay again.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2018-01-18 06:59:49 +10:30 committed by Christian Decker
parent d1b2a97146
commit 2cbe5b65c7
5 changed files with 42 additions and 7 deletions

View File

@ -68,7 +68,8 @@ void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
const struct preimage *rval)
{
assert(!hout->pay_command->rval);
wallet_payment_set_status(ld->wallet, &hout->payment_hash, PAYMENT_COMPLETE);
wallet_payment_set_status(ld->wallet, &hout->payment_hash,
PAYMENT_COMPLETE, rval);
hout->pay_command->rval = tal_dup(hout->pay_command,
struct preimage, rval);
json_pay_success(hout->pay_command->cmd, rval);
@ -82,7 +83,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
struct onionreply *reply;
enum onion_type failcode;
wallet_payment_set_status(ld->wallet, &hout->payment_hash, PAYMENT_FAILED);
wallet_payment_set_status(ld->wallet, &hout->payment_hash,
PAYMENT_FAILED, NULL);
/* This gives more details than a generic failure message */
if (localfail) {
@ -248,6 +250,7 @@ static bool send_payment(struct command *cmd,
payment->status = PAYMENT_PENDING;
payment->msatoshi = route[n_hops-1].amount;
payment->timestamp = time_now().ts.tv_sec;
payment->payment_preimage = NULL;
}
pc->cmd = cmd;
pc->rhash = *rhash;
@ -514,6 +517,10 @@ static void json_listpayments(struct command *cmd, const char *buffer,
json_add_string(response, "status", "failed");
break;
}
if (t->payment_preimage)
json_add_hex(response, "payment_preimage",
t->payment_preimage,
sizeof(*t->payment_preimage));
json_object_end(response);
}

View File

@ -173,6 +173,8 @@ char *dbmigrations[] = {
");",
"INSERT INTO payments SELECT id, timestamp, status, payment_hash, destination, msatoshi FROM temp_payments WHERE direction=1;",
"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;",
NULL,
};

View File

@ -15,6 +15,7 @@ static void db_log_(struct log *log, enum log_level level, const char *fmt, ...)
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <ccan/structeq/structeq.h>
#include <common/memleak.h>
#include <stdarg.h>
#include <stddef.h>
@ -557,6 +558,7 @@ static bool test_payment_crud(const tal_t *ctx)
t.id = 0;
t.msatoshi = 100;
t.status = PAYMENT_PENDING;
t.payment_preimage = NULL;
memset(&t.payment_hash, 1, sizeof(t.payment_hash));
db_begin_transaction(w->db);
@ -568,15 +570,20 @@ static bool test_payment_crud(const tal_t *ctx)
CHECK(t2->status == t.status);
CHECK(pubkey_cmp(&t2->destination, &t.destination) == 0);
CHECK(t2->msatoshi == t.msatoshi);
CHECK(!t2->payment_preimage);
t.status = PAYMENT_COMPLETE;
wallet_payment_set_status(w, &t.payment_hash, t.status);
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,
t.payment_preimage);
t2 = wallet_payment_by_hash(ctx, w, &t.payment_hash);
CHECK(t2 != NULL);
CHECK(t2->id == t.id);
CHECK(t2->status == t.status);
CHECK(pubkey_cmp(&t2->destination, &t.destination) == 0);
CHECK(t2->msatoshi == t.msatoshi);
CHECK(structeq(t.payment_preimage, t2->payment_preimage));
db_commit_transaction(w->db);
return true;

View File

@ -1284,6 +1284,11 @@ static struct wallet_payment *wallet_stmt2payment(const tal_t *ctx,
sqlite3_column_sha256(stmt, 4, &payment->payment_hash);
payment->timestamp = sqlite3_column_int(stmt, 5);
if (sqlite3_column_type(stmt, 6) != SQLITE_NULL) {
payment->payment_preimage = tal(payment, struct preimage);
sqlite3_column_preimage(stmt, 6, payment->payment_preimage);
} else
payment->payment_preimage = NULL;
return payment;
}
@ -1296,7 +1301,7 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
stmt = db_prepare(wallet->db,
"SELECT id, status, destination,"
"msatoshi, payment_hash, timestamp "
"msatoshi, payment_hash, timestamp, payment_preimage "
"FROM payments "
"WHERE payment_hash = ?");
@ -1310,7 +1315,8 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
void wallet_payment_set_status(struct wallet *wallet,
const struct sha256 *payment_hash,
const enum wallet_payment_status newstatus)
const enum wallet_payment_status newstatus,
const struct preimage *preimage)
{
sqlite3_stmt *stmt;
@ -1321,6 +1327,16 @@ void wallet_payment_set_status(struct wallet *wallet,
sqlite3_bind_int(stmt, 1, newstatus);
sqlite3_bind_sha256(stmt, 2, payment_hash);
db_exec_prepared(wallet->db, stmt);
if (preimage) {
stmt = db_prepare(wallet->db,
"UPDATE payments SET payment_preimage=? "
"WHERE payment_hash=?");
sqlite3_bind_preimage(stmt, 1, preimage);
sqlite3_bind_sha256(stmt, 2, payment_hash);
db_exec_prepared(wallet->db, stmt);
}
}
const struct wallet_payment **wallet_payment_list(const tal_t *ctx,
@ -1333,7 +1349,7 @@ const struct wallet_payment **wallet_payment_list(const tal_t *ctx,
stmt = db_prepare(
wallet->db,
"SELECT id, status, destination, "
"msatoshi , payment_hash, timestamp "
"msatoshi , payment_hash, timestamp, payment_preimage "
"FROM payments;");
for (int i = 0; sqlite3_step(stmt) == SQLITE_ROW; i++) {

View File

@ -88,6 +88,8 @@ struct wallet_payment {
enum wallet_payment_status status;
struct pubkey destination;
u64 msatoshi;
/* Iff PAYMENT_COMPLETE */
struct preimage *payment_preimage;
};
/**
@ -551,7 +553,8 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
*/
void wallet_payment_set_status(struct wallet *wallet,
const struct sha256 *payment_hash,
const enum wallet_payment_status newstatus);
const enum wallet_payment_status newstatus,
const struct preimage *preimage);
/**
* wallet_payment_list - Retrieve a list of payments