mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-01 17:47:30 +01:00
db: we must always be in a transaction, remove nested, call fatal()
We save location where transaction was started, in case we try to nest. There's now no error case; db_exec_mayfail() is the only one. This means the tests need to override fatal() if they want to intercept these errors. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
f4d27eefa1
commit
4fb472b7a7
8 changed files with 180 additions and 186 deletions
|
@ -287,8 +287,8 @@ static void json_delinvoice(struct command *cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wallet_invoice_remove(cmd->ld->wallet, i)) {
|
if (!wallet_invoice_remove(cmd->ld->wallet, i)) {
|
||||||
log_broken(cmd->ld->log, "Error attempting to remove invoice %"PRIu64": %s",
|
log_broken(cmd->ld->log, "Error attempting to remove invoice %"PRIu64,
|
||||||
i->id, cmd->ld->wallet->db->err);
|
i->id);
|
||||||
command_fail(cmd, "Database error");
|
command_fail(cmd, "Database error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@ int unused_main(int argc, char *argv[]);
|
||||||
/* Generated stub for crashlog_activate */
|
/* Generated stub for crashlog_activate */
|
||||||
void crashlog_activate(const char *argv0 UNNEEDED, struct log *log UNNEEDED)
|
void crashlog_activate(const char *argv0 UNNEEDED, struct log *log UNNEEDED)
|
||||||
{ fprintf(stderr, "crashlog_activate called!\n"); abort(); }
|
{ fprintf(stderr, "crashlog_activate called!\n"); abort(); }
|
||||||
/* Generated stub for db_begin_transaction */
|
/* Generated stub for db_begin_transaction_ */
|
||||||
bool db_begin_transaction(struct db *db UNNEEDED)
|
void db_begin_transaction_(struct db *db UNNEEDED, const char *location UNNEEDED)
|
||||||
{ fprintf(stderr, "db_begin_transaction called!\n"); abort(); }
|
{ fprintf(stderr, "db_begin_transaction_ called!\n"); abort(); }
|
||||||
/* Generated stub for db_commit_transaction */
|
/* Generated stub for db_commit_transaction */
|
||||||
bool db_commit_transaction(struct db *db UNNEEDED)
|
void db_commit_transaction(struct db *db UNNEEDED)
|
||||||
{ fprintf(stderr, "db_commit_transaction called!\n"); abort(); }
|
{ fprintf(stderr, "db_commit_transaction called!\n"); abort(); }
|
||||||
/* Generated stub for debug_poll */
|
/* Generated stub for debug_poll */
|
||||||
int debug_poll(struct pollfd *fds UNNEEDED, nfds_t nfds UNNEEDED, int timeout UNNEEDED)
|
int debug_poll(struct pollfd *fds UNNEEDED, nfds_t nfds UNNEEDED, int timeout UNNEEDED)
|
||||||
|
|
146
wallet/db.c
146
wallet/db.c
|
@ -122,86 +122,64 @@ char *dbmigrations[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* db_clear_error - Clear any errors from previous queries
|
|
||||||
*/
|
|
||||||
static void db_clear_error(struct db *db)
|
|
||||||
{
|
|
||||||
db->err = tal_free(db->err);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query)
|
sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
if (db->in_transaction && db->err)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
db_clear_error(db);
|
assert(db->in_transaction);
|
||||||
|
|
||||||
err = sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL);
|
err = sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL);
|
||||||
|
|
||||||
if (err != SQLITE_OK) {
|
if (err != SQLITE_OK)
|
||||||
db->err = tal_fmt(db, "%s: %s: %s", caller, query,
|
fatal("%s: %s: %s", caller, query, sqlite3_errmsg(db->sql));
|
||||||
sqlite3_errmsg(db->sql));
|
|
||||||
}
|
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt)
|
void db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt)
|
||||||
{
|
{
|
||||||
if (db->in_transaction && db->err) {
|
assert(db->in_transaction);
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
db_clear_error(db);
|
if (sqlite3_step(stmt) != SQLITE_DONE)
|
||||||
|
fatal("%s: %s", caller, sqlite3_errmsg(db->sql));
|
||||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
|
||||||
db->err =
|
|
||||||
tal_fmt(db, "%s: %s", caller, sqlite3_errmsg(db->sql));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return true;
|
|
||||||
fail:
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PRINTF_FMT(3, 4)
|
/* This one doesn't check if we're in a transaction. */
|
||||||
|
static void db_do_exec(const char *caller, struct db *db, const char *cmd)
|
||||||
|
{
|
||||||
|
char *errmsg;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = sqlite3_exec(db->sql, cmd, NULL, NULL, &errmsg);
|
||||||
|
if (err != SQLITE_OK) {
|
||||||
|
fatal("%s:%s:%s:%s", caller, sqlite3_errstr(err), cmd, errmsg);
|
||||||
|
/* Only reached in testing */
|
||||||
|
sqlite3_free(errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PRINTF_FMT(3, 4)
|
||||||
db_exec(const char *caller, struct db *db, const char *fmt, ...)
|
db_exec(const char *caller, struct db *db, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *cmd, *errmsg;
|
char *cmd;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (db->in_transaction && db->err)
|
assert(db->in_transaction);
|
||||||
return false;
|
|
||||||
|
|
||||||
db_clear_error(db);
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
cmd = tal_vfmt(db, fmt, ap);
|
cmd = tal_vfmt(db, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
err = sqlite3_exec(db->sql, cmd, NULL, NULL, &errmsg);
|
db_do_exec(caller, db, cmd);
|
||||||
if (err != SQLITE_OK) {
|
|
||||||
tal_free(db->err);
|
|
||||||
db->err = tal_fmt(db, "%s:%s:%s:%s", caller,
|
|
||||||
sqlite3_errstr(err), cmd, errmsg);
|
|
||||||
sqlite3_free(errmsg);
|
|
||||||
tal_free(cmd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
tal_free(cmd);
|
tal_free(cmd);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool db_exec_prepared_mayfail_(const char *caller, struct db *db, sqlite3_stmt *stmt)
|
bool db_exec_prepared_mayfail_(const char *caller, struct db *db, sqlite3_stmt *stmt)
|
||||||
{
|
{
|
||||||
if (db->in_transaction && db->err) {
|
assert(db->in_transaction);
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -221,10 +199,7 @@ sqlite3_stmt *PRINTF_FMT(3, 4)
|
||||||
char *query;
|
char *query;
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
if (db->in_transaction && db->err)
|
assert(db->in_transaction);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
db_clear_error(db);
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
query = tal_vfmt(db, fmt, ap);
|
query = tal_vfmt(db, fmt, ap);
|
||||||
|
@ -237,50 +212,20 @@ sqlite3_stmt *PRINTF_FMT(3, 4)
|
||||||
|
|
||||||
static void close_db(struct db *db) { sqlite3_close(db->sql); }
|
static void close_db(struct db *db) { sqlite3_close(db->sql); }
|
||||||
|
|
||||||
bool db_begin_transaction(struct db *db)
|
void db_begin_transaction_(struct db *db, const char *location)
|
||||||
{
|
{
|
||||||
if (!db->in_transaction) {
|
if (db->in_transaction)
|
||||||
/* Clear any errors from previous transactions and
|
fatal("Already in transaction from %s", db->in_transaction);
|
||||||
* non-transactional queries */
|
|
||||||
db_clear_error(db);
|
db_do_exec(location, db, "BEGIN TRANSACTION;");
|
||||||
db->in_transaction = db_exec(__func__, db, "BEGIN TRANSACTION;");
|
db->in_transaction = location;
|
||||||
assert(db->in_transaction);
|
|
||||||
return db->in_transaction;
|
|
||||||
}
|
|
||||||
db->in_transaction++;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool db_commit_transaction(struct db *db)
|
void db_commit_transaction(struct db *db)
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
assert(db->in_transaction);
|
|
||||||
if (db->err) {
|
|
||||||
char *errmsg;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* Do this manually: db_exec is a NOOP with db->err */
|
|
||||||
err = sqlite3_exec(db->sql, "ROLLBACK;", NULL, NULL, &errmsg);
|
|
||||||
if (err != SQLITE_OK) {
|
|
||||||
db->err = tal_fmt(db, "%s then ROLLBACK failed:%s:%s",
|
|
||||||
db->err, sqlite3_errstr(err), errmsg);
|
|
||||||
sqlite3_free(errmsg);
|
|
||||||
}
|
|
||||||
ret = false;
|
|
||||||
} else {
|
|
||||||
ret = db_exec(__func__, db, "COMMIT;");
|
|
||||||
}
|
|
||||||
db->in_transaction--;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool db_rollback_transaction(struct db *db)
|
|
||||||
{
|
{
|
||||||
assert(db->in_transaction);
|
assert(db->in_transaction);
|
||||||
bool ret = db_exec(__func__, db, "ROLLBACK;");
|
db_exec(__func__, db, "COMMIT;");
|
||||||
db->in_transaction--;
|
db->in_transaction = NULL;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -308,11 +253,8 @@ static struct db *db_open(const tal_t *ctx, char *filename)
|
||||||
db->filename = tal_dup_arr(db, char, filename, strlen(filename), 0);
|
db->filename = tal_dup_arr(db, char, filename, strlen(filename), 0);
|
||||||
db->sql = sql;
|
db->sql = sql;
|
||||||
tal_add_destructor(db, close_db);
|
tal_add_destructor(db, close_db);
|
||||||
db->in_transaction = false;
|
db->in_transaction = NULL;
|
||||||
db->err = NULL;
|
db_do_exec(__func__, db, "PRAGMA foreign_keys = ON;");
|
||||||
if (!db_exec(__func__, db, "PRAGMA foreign_keys = ON;")) {
|
|
||||||
fatal("Could not enable foreignkeys on database: %s", db->err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
@ -411,16 +353,14 @@ s64 db_get_intvar(struct db *db, char *varname, s64 defval)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool db_set_intvar(struct db *db, char *varname, s64 val)
|
void db_set_intvar(struct db *db, char *varname, s64 val)
|
||||||
{
|
{
|
||||||
/* Attempt to update */
|
/* Attempt to update */
|
||||||
db_exec(__func__, db,
|
db_exec(__func__, db,
|
||||||
"UPDATE vars SET val='%" PRId64 "' WHERE name='%s';", val,
|
"UPDATE vars SET val='%" PRId64 "' WHERE name='%s';", val,
|
||||||
varname);
|
varname);
|
||||||
if (sqlite3_changes(db->sql) > 0)
|
if (sqlite3_changes(db->sql) == 0)
|
||||||
return true;
|
db_exec(
|
||||||
else
|
|
||||||
return db_exec(
|
|
||||||
__func__, db,
|
__func__, db,
|
||||||
"INSERT INTO vars (name, val) VALUES ('%s', '%" PRId64
|
"INSERT INTO vars (name, val) VALUES ('%s', '%" PRId64
|
||||||
"');",
|
"');",
|
||||||
|
|
42
wallet/db.h
42
wallet/db.h
|
@ -15,8 +15,7 @@
|
||||||
|
|
||||||
struct db {
|
struct db {
|
||||||
char *filename;
|
char *filename;
|
||||||
unsigned int in_transaction;
|
const char *in_transaction;
|
||||||
const char *err;
|
|
||||||
sqlite3 *sql;
|
sqlite3 *sql;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,6 +24,7 @@ struct db {
|
||||||
*
|
*
|
||||||
* Opens the database, creating it if necessary, and applying
|
* Opens the database, creating it if necessary, and applying
|
||||||
* migrations until the schema is updated to the current state.
|
* migrations until the schema is updated to the current state.
|
||||||
|
* Calls fatal() on error.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* @ctx: the tal_t context to allocate from
|
* @ctx: the tal_t context to allocate from
|
||||||
|
@ -33,37 +33,33 @@ struct db {
|
||||||
struct db *db_setup(const tal_t *ctx);
|
struct db *db_setup(const tal_t *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* db_query - Prepare and execute a query, and return the result
|
* db_query - Prepare and execute a query, and return the result (or NULL)
|
||||||
*/
|
*/
|
||||||
sqlite3_stmt *PRINTF_FMT(3, 4)
|
sqlite3_stmt *PRINTF_FMT(3, 4)
|
||||||
db_query(const char *caller, struct db *db, const char *fmt, ...);
|
db_query(const char *caller, struct db *db, const char *fmt, ...);
|
||||||
|
|
||||||
bool PRINTF_FMT(3, 4)
|
/**
|
||||||
|
* db_exec - execute a statement, call fatal() if it fails.
|
||||||
|
*/
|
||||||
|
void PRINTF_FMT(3, 4)
|
||||||
db_exec(const char *caller, struct db *db, const char *fmt, ...);
|
db_exec(const char *caller, struct db *db, const char *fmt, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* db_begin_transaction - Begin a transaction
|
* db_begin_transaction - Begin a transaction
|
||||||
*
|
*
|
||||||
* Begin a new DB transaction if we aren't already in one. Returns
|
* Begin a new DB transaction. fatal() on database error.
|
||||||
* true if the call started a transaction, i.e., the caller MUST take
|
|
||||||
* care to either commit or rollback. If false, this is a nested
|
|
||||||
* transaction and the caller MUST not commit/rollback, since the
|
|
||||||
* transaction is handled at a higher level in the callstack.
|
|
||||||
*/
|
*/
|
||||||
bool db_begin_transaction(struct db *db);
|
#define db_begin_transaction(db) \
|
||||||
|
db_begin_transaction_((db), __FILE__ ":" stringify(__LINE__))
|
||||||
|
void db_begin_transaction_(struct db *db, const char *location);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* db_commit_transaction - Commit a running transaction
|
* db_commit_transaction - Commit a running transaction
|
||||||
*
|
*
|
||||||
* Requires that we are currently in a transaction. Returns whether
|
* Requires that we are currently in a transaction. fatal() if we
|
||||||
* the commit was successful.
|
* fail to commit.
|
||||||
*/
|
*/
|
||||||
bool db_commit_transaction(struct db *db);
|
void db_commit_transaction(struct db *db);
|
||||||
|
|
||||||
/**
|
|
||||||
* db_rollback_transaction - Whoops... undo! undo!
|
|
||||||
*/
|
|
||||||
bool db_rollback_transaction(struct db *db);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* db_set_intvar - Set an integer variable in the database
|
* db_set_intvar - Set an integer variable in the database
|
||||||
|
@ -71,7 +67,7 @@ bool db_rollback_transaction(struct db *db);
|
||||||
* Utility function to store generic integer values in the
|
* Utility function to store generic integer values in the
|
||||||
* database.
|
* database.
|
||||||
*/
|
*/
|
||||||
bool db_set_intvar(struct db *db, char *varname, s64 val);
|
void db_set_intvar(struct db *db, char *varname, s64 val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* db_get_intvar - Retrieve an integer variable from the database
|
* db_get_intvar - Retrieve an integer variable from the database
|
||||||
|
@ -102,18 +98,18 @@ sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query);
|
||||||
* After preparing a statement using `db_prepare`, and after binding
|
* After preparing a statement using `db_prepare`, and after binding
|
||||||
* all non-null variables using the `sqlite3_bind_*` functions, it can
|
* all non-null variables using the `sqlite3_bind_*` functions, it can
|
||||||
* be executed with this function. It is a small, transaction-aware,
|
* be executed with this function. It is a small, transaction-aware,
|
||||||
* wrapper around `sqlite3_step`, that also sets `db->err` if the
|
* wrapper around `sqlite3_step`, that calls fatal() if the execution
|
||||||
* execution fails. This will take ownership of `stmt` and will free
|
* fails. This will take ownership of `stmt` and will free
|
||||||
* it before returning.
|
* it before returning.
|
||||||
*
|
*
|
||||||
* @db: The database to execute on
|
* @db: The database to execute on
|
||||||
* @stmt: The prepared statement to execute
|
* @stmt: The prepared statement to execute
|
||||||
*/
|
*/
|
||||||
#define db_exec_prepared(db,stmt) db_exec_prepared_(__func__,db,stmt)
|
#define db_exec_prepared(db,stmt) db_exec_prepared_(__func__,db,stmt)
|
||||||
bool db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt);
|
void db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* db_exec_prepared_mayfail - db_exec_prepared, but don't set db->err if it fails.
|
* db_exec_prepared_mayfail - db_exec_prepared, but don't fatal() it fails.
|
||||||
*/
|
*/
|
||||||
#define db_exec_prepared_mayfail(db,stmt) \
|
#define db_exec_prepared_mayfail(db,stmt) \
|
||||||
db_exec_prepared_mayfail_(__func__,db,stmt)
|
db_exec_prepared_mayfail_(__func__,db,stmt)
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
#include <lightningd/log.h>
|
||||||
|
|
||||||
|
static void db_fatal(const char *fmt, ...);
|
||||||
|
#define fatal db_fatal
|
||||||
|
|
||||||
#include "db.c"
|
#include "db.c"
|
||||||
|
|
||||||
#include "wallet/test_utils.h"
|
#include "wallet/test_utils.h"
|
||||||
|
@ -5,6 +10,19 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static char *db_err;
|
||||||
|
static void db_fatal(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* Fail hard if we're complaining about not being in transaction */
|
||||||
|
assert(!strstarts(fmt, "No longer in transaction"));
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
db_err = tal_vfmt(NULL, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
static struct db *create_test_db(const char *testname)
|
static struct db *create_test_db(const char *testname)
|
||||||
{
|
{
|
||||||
struct db *db;
|
struct db *db;
|
||||||
|
@ -23,9 +41,13 @@ static bool test_empty_db_migrate(void)
|
||||||
{
|
{
|
||||||
struct db *db = create_test_db(__func__);
|
struct db *db = create_test_db(__func__);
|
||||||
CHECK(db);
|
CHECK(db);
|
||||||
|
db_begin_transaction(db);
|
||||||
CHECK(db_get_version(db) == -1);
|
CHECK(db_get_version(db) == -1);
|
||||||
|
db_commit_transaction(db);
|
||||||
db_migrate(db);
|
db_migrate(db);
|
||||||
|
db_begin_transaction(db);
|
||||||
CHECK(db_get_version(db) == db_migration_count());
|
CHECK(db_get_version(db) == db_migration_count());
|
||||||
|
db_commit_transaction(db);
|
||||||
|
|
||||||
tal_free(db);
|
tal_free(db);
|
||||||
return true;
|
return true;
|
||||||
|
@ -34,17 +56,22 @@ static bool test_empty_db_migrate(void)
|
||||||
static bool test_primitives(void)
|
static bool test_primitives(void)
|
||||||
{
|
{
|
||||||
struct db *db = create_test_db(__func__);
|
struct db *db = create_test_db(__func__);
|
||||||
CHECK_MSG(db_begin_transaction(db), "Starting a new transaction");
|
db_begin_transaction(db);
|
||||||
CHECK(db->in_transaction);
|
CHECK(db->in_transaction);
|
||||||
CHECK_MSG(db_commit_transaction(db), "Committing a transaction");
|
db_commit_transaction(db);
|
||||||
CHECK(!db->in_transaction);
|
CHECK(!db->in_transaction);
|
||||||
CHECK_MSG(db_begin_transaction(db), "Starting a transaction after commit");
|
db_begin_transaction(db);
|
||||||
CHECK(db_rollback_transaction(db));
|
db_commit_transaction(db);
|
||||||
|
|
||||||
CHECK_MSG(db_exec(__func__, db, "SELECT name FROM sqlite_master WHERE type='table';"), "Simple correct SQL command");
|
db_begin_transaction(db);
|
||||||
CHECK_MSG(!db_exec(__func__, db, "not a valid SQL statement"), "Failing SQL command");
|
db_exec(__func__, db, "SELECT name FROM sqlite_master WHERE type='table';");
|
||||||
|
CHECK_MSG(!db_err, "Simple correct SQL command");
|
||||||
|
|
||||||
|
db_exec(__func__, db, "not a valid SQL statement");
|
||||||
|
CHECK_MSG(db_err, "Failing SQL command");
|
||||||
|
db_err = tal_free(db_err);
|
||||||
|
db_commit_transaction(db);
|
||||||
CHECK(!db->in_transaction);
|
CHECK(!db->in_transaction);
|
||||||
CHECK_MSG(db_begin_transaction(db), "Starting a transaction after a failed transaction");
|
|
||||||
tal_free(db);
|
tal_free(db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -57,16 +84,18 @@ static bool test_vars(void)
|
||||||
CHECK(db);
|
CHECK(db);
|
||||||
db_migrate(db);
|
db_migrate(db);
|
||||||
|
|
||||||
|
db_begin_transaction(db);
|
||||||
/* Check default behavior */
|
/* Check default behavior */
|
||||||
CHECK(db_get_intvar(db, varname, 42) == 42);
|
CHECK(db_get_intvar(db, varname, 42) == 42);
|
||||||
|
|
||||||
/* Check setting and getting */
|
/* Check setting and getting */
|
||||||
CHECK(db_set_intvar(db, varname, 1));
|
db_set_intvar(db, varname, 1);
|
||||||
CHECK(db_get_intvar(db, varname, 42) == 1);
|
CHECK(db_get_intvar(db, varname, 42) == 1);
|
||||||
|
|
||||||
/* Check updating */
|
/* Check updating */
|
||||||
CHECK(db_set_intvar(db, varname, 2));
|
db_set_intvar(db, varname, 2);
|
||||||
CHECK(db_get_intvar(db, varname, 42) == 2);
|
CHECK(db_get_intvar(db, varname, 42) == 2);
|
||||||
|
db_commit_transaction(db);
|
||||||
|
|
||||||
tal_free(db);
|
tal_free(db);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -106,7 +106,7 @@ static void unreserve_utxo(struct wallet *w, const struct utxo *unres)
|
||||||
if (!wallet_update_output_status(w, &unres->txid, unres->outnum,
|
if (!wallet_update_output_status(w, &unres->txid, unres->outnum,
|
||||||
output_state_reserved,
|
output_state_reserved,
|
||||||
output_state_available)) {
|
output_state_available)) {
|
||||||
fatal("Unable to unreserve output: %s", w->db->err);
|
fatal("Unable to unreserve output");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ void wallet_confirm_utxos(struct wallet *w, const struct utxo **utxos)
|
||||||
if (!wallet_update_output_status(
|
if (!wallet_update_output_status(
|
||||||
w, &utxos[i]->txid, utxos[i]->outnum,
|
w, &utxos[i]->txid, utxos[i]->outnum,
|
||||||
output_state_reserved, output_state_spent)) {
|
output_state_reserved, output_state_spent)) {
|
||||||
fatal("Unable to mark output as spent: %s", w->db->err);
|
fatal("Unable to mark output as spent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
|
||||||
if (!wallet_update_output_status(
|
if (!wallet_update_output_status(
|
||||||
w, &available[i]->txid, available[i]->outnum,
|
w, &available[i]->txid, available[i]->outnum,
|
||||||
output_state_available, output_state_reserved))
|
output_state_available, output_state_reserved))
|
||||||
fatal("Unable to reserve output: %s", w->db->err);
|
fatal("Unable to reserve output");
|
||||||
|
|
||||||
weight += (32 + 4 + 4) * 4;
|
weight += (32 + 4 + 4) * 4;
|
||||||
if (utxos[i]->is_p2sh)
|
if (utxos[i]->is_p2sh)
|
||||||
|
@ -229,19 +229,16 @@ s64 wallet_get_newindex(struct lightningd *ld)
|
||||||
return newidx;
|
return newidx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wallet_shachain_init(struct wallet *wallet, struct wallet_shachain *chain)
|
void wallet_shachain_init(struct wallet *wallet, struct wallet_shachain *chain)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
/* Create shachain */
|
/* Create shachain */
|
||||||
shachain_init(&chain->chain);
|
shachain_init(&chain->chain);
|
||||||
stmt = db_prepare(wallet->db, "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);");
|
stmt = db_prepare(wallet->db, "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);");
|
||||||
sqlite3_bind_int64(stmt, 1, chain->chain.min_index);
|
sqlite3_bind_int64(stmt, 1, chain->chain.min_index);
|
||||||
if (!db_exec_prepared(wallet->db, stmt)) {
|
db_exec_prepared(wallet->db, stmt);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
chain->id = sqlite3_last_insert_rowid(wallet->db->sql);
|
chain->id = sqlite3_last_insert_rowid(wallet->db->sql);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO(cdecker) Stolen from shachain, move to some appropriate location */
|
/* TODO(cdecker) Stolen from shachain, move to some appropriate location */
|
||||||
|
@ -971,7 +968,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
||||||
DIRECTION_INCOMING, chan->id, SENT_REMOVE_ACK_REVOCATION);
|
DIRECTION_INCOMING, chan->id, SENT_REMOVE_ACK_REVOCATION);
|
||||||
|
|
||||||
if (!stmt) {
|
if (!stmt) {
|
||||||
log_broken(wallet->log, "Could not select htlc_ins: %s", wallet->db->err);
|
log_broken(wallet->log, "Could not select htlc_ins");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,7 +989,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
||||||
DIRECTION_OUTGOING, chan->id, RCVD_REMOVE_ACK_REVOCATION);
|
DIRECTION_OUTGOING, chan->id, RCVD_REMOVE_ACK_REVOCATION);
|
||||||
|
|
||||||
if (!stmt) {
|
if (!stmt) {
|
||||||
log_broken(wallet->log, "Could not select htlc_outs: %s", wallet->db->err);
|
log_broken(wallet->log, "Could not select htlc_outs");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,8 +1055,6 @@ void wallet_invoice_save(struct wallet *wallet, struct invoice *inv)
|
||||||
if (!inv->id) {
|
if (!inv->id) {
|
||||||
stmt = db_prepare(wallet->db,
|
stmt = db_prepare(wallet->db,
|
||||||
"INSERT INTO invoices (payment_hash, payment_key, state, msatoshi, label) VALUES (?, ?, ?, ?, ?);");
|
"INSERT INTO invoices (payment_hash, payment_key, state, msatoshi, label) VALUES (?, ?, ?, ?, ?);");
|
||||||
if (!stmt)
|
|
||||||
fatal("Could not prepare statement: %s", wallet->db->err);
|
|
||||||
|
|
||||||
sqlite3_bind_blob(stmt, 1, &inv->rhash, sizeof(inv->rhash), SQLITE_TRANSIENT);
|
sqlite3_bind_blob(stmt, 1, &inv->rhash, sizeof(inv->rhash), SQLITE_TRANSIENT);
|
||||||
sqlite3_bind_blob(stmt, 2, &inv->r, sizeof(inv->r), SQLITE_TRANSIENT);
|
sqlite3_bind_blob(stmt, 2, &inv->r, sizeof(inv->r), SQLITE_TRANSIENT);
|
||||||
|
@ -1067,21 +1062,16 @@ void wallet_invoice_save(struct wallet *wallet, struct invoice *inv)
|
||||||
sqlite3_bind_int64(stmt, 4, inv->msatoshi);
|
sqlite3_bind_int64(stmt, 4, inv->msatoshi);
|
||||||
sqlite3_bind_text(stmt, 5, inv->label, strlen(inv->label), SQLITE_TRANSIENT);
|
sqlite3_bind_text(stmt, 5, inv->label, strlen(inv->label), SQLITE_TRANSIENT);
|
||||||
|
|
||||||
if (!db_exec_prepared(wallet->db, stmt))
|
db_exec_prepared(wallet->db, stmt);
|
||||||
fatal("Could not exec prepared statement: %s", wallet->db->err);
|
|
||||||
|
|
||||||
inv->id = sqlite3_last_insert_rowid(wallet->db->sql);
|
inv->id = sqlite3_last_insert_rowid(wallet->db->sql);
|
||||||
} else {
|
} else {
|
||||||
stmt = db_prepare(wallet->db, "UPDATE invoices SET state=? WHERE id=?;");
|
stmt = db_prepare(wallet->db, "UPDATE invoices SET state=? WHERE id=?;");
|
||||||
|
|
||||||
if (!stmt)
|
|
||||||
fatal("Could not prepare statement: %s", wallet->db->err);
|
|
||||||
|
|
||||||
sqlite3_bind_int(stmt, 1, inv->state);
|
sqlite3_bind_int(stmt, 1, inv->state);
|
||||||
sqlite3_bind_int64(stmt, 2, inv->id);
|
sqlite3_bind_int64(stmt, 2, inv->id);
|
||||||
|
|
||||||
if (!db_exec_prepared(wallet->db, stmt))
|
db_exec_prepared(wallet->db, stmt);
|
||||||
fatal("Could not exec prepared statement: %s", wallet->db->err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,7 +1099,7 @@ bool wallet_invoices_load(struct wallet *wallet, struct invoices *invs)
|
||||||
"SELECT id, state, payment_key, payment_hash, "
|
"SELECT id, state, payment_key, payment_hash, "
|
||||||
"label, msatoshi FROM invoices;");
|
"label, msatoshi FROM invoices;");
|
||||||
if (!stmt) {
|
if (!stmt) {
|
||||||
log_broken(wallet->log, "Could not load invoices: %s", wallet->db->err);
|
log_broken(wallet->log, "Could not load invoices");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1131,7 +1121,8 @@ bool wallet_invoice_remove(struct wallet *wallet, struct invoice *inv)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt = db_prepare(wallet->db, "DELETE FROM invoices WHERE id=?");
|
sqlite3_stmt *stmt = db_prepare(wallet->db, "DELETE FROM invoices WHERE id=?");
|
||||||
sqlite3_bind_int64(stmt, 1, inv->id);
|
sqlite3_bind_int64(stmt, 1, inv->id);
|
||||||
return db_exec_prepared(wallet->db, stmt) && sqlite3_changes(wallet->db->sql) == 1;
|
db_exec_prepared(wallet->db, stmt);
|
||||||
|
return sqlite3_changes(wallet->db->sql) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct htlc_stub *wallet_htlc_stubs(tal_t *ctx, struct wallet *wallet,
|
struct htlc_stub *wallet_htlc_stubs(tal_t *ctx, struct wallet *wallet,
|
||||||
|
@ -1143,9 +1134,6 @@ struct htlc_stub *wallet_htlc_stubs(tal_t *ctx, struct wallet *wallet,
|
||||||
"SELECT channel_id, direction, cltv_expiry, payment_hash "
|
"SELECT channel_id, direction, cltv_expiry, payment_hash "
|
||||||
"FROM channel_htlcs WHERE channel_id = ?;");
|
"FROM channel_htlcs WHERE channel_id = ?;");
|
||||||
|
|
||||||
if (!stmt)
|
|
||||||
fatal("Error preparing select: %s", wallet->db->err);
|
|
||||||
|
|
||||||
sqlite3_bind_int64(stmt, 1, chan->id);
|
sqlite3_bind_int64(stmt, 1, chan->id);
|
||||||
|
|
||||||
stubs = tal_arr(ctx, struct htlc_stub, 0);
|
stubs = tal_arr(ctx, struct htlc_stub, 0);
|
||||||
|
|
|
@ -141,7 +141,7 @@ s64 wallet_get_newindex(struct lightningd *ld);
|
||||||
/**
|
/**
|
||||||
* wallet_shachain_init -- wallet wrapper around shachain_init
|
* wallet_shachain_init -- wallet wrapper around shachain_init
|
||||||
*/
|
*/
|
||||||
bool wallet_shachain_init(struct wallet *wallet, struct wallet_shachain *chain);
|
void wallet_shachain_init(struct wallet *wallet, struct wallet_shachain *chain);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wallet_shachain_add_hash -- wallet wrapper around shachain_add_hash
|
* wallet_shachain_add_hash -- wallet wrapper around shachain_add_hash
|
||||||
|
|
|
@ -22,13 +22,16 @@ static void wallet_fatal(const char *fmt, ...)
|
||||||
/* Fail hard if we're complaining about not being in transaction */
|
/* Fail hard if we're complaining about not being in transaction */
|
||||||
assert(!strstarts(fmt, "No longer in transaction"));
|
assert(!strstarts(fmt, "No longer in transaction"));
|
||||||
|
|
||||||
|
/* Fail hard if we're complaining about not being in transaction */
|
||||||
|
assert(!strstarts(fmt, "No longer in transaction"));
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
wallet_err = tal_vfmt(NULL, fmt, ap);
|
wallet_err = tal_vfmt(NULL, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define transaction_wrap(db, ...) \
|
#define transaction_wrap(db, ...) \
|
||||||
(db_begin_transaction(db), __VA_ARGS__, db_commit_transaction(db))
|
(db_begin_transaction(db), __VA_ARGS__, db_commit_transaction(db), wallet_err == NULL)
|
||||||
|
|
||||||
void invoice_add(struct invoices *invs,
|
void invoice_add(struct invoices *invs,
|
||||||
struct invoice *inv){}
|
struct invoice *inv){}
|
||||||
|
@ -85,6 +88,8 @@ static bool test_wallet_outputs(void)
|
||||||
|
|
||||||
memset(&u, 0, sizeof(u));
|
memset(&u, 0, sizeof(u));
|
||||||
|
|
||||||
|
db_begin_transaction(w->db);
|
||||||
|
|
||||||
/* Should work, it's the first time we add it */
|
/* Should work, it's the first time we add it */
|
||||||
CHECK_MSG(wallet_add_utxo(w, &u, p2sh_wpkh),
|
CHECK_MSG(wallet_add_utxo(w, &u, p2sh_wpkh),
|
||||||
"wallet_add_utxo failed on first add");
|
"wallet_add_utxo failed on first add");
|
||||||
|
@ -117,6 +122,7 @@ static bool test_wallet_outputs(void)
|
||||||
output_state_spent),
|
output_state_spent),
|
||||||
"could not change output state ignoring oldstate");
|
"could not change output state ignoring oldstate");
|
||||||
|
|
||||||
|
db_commit_transaction(w->db);
|
||||||
tal_free(w);
|
tal_free(w);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +149,10 @@ static bool test_shachain_crud(void)
|
||||||
memset(&b, 0, sizeof(b));
|
memset(&b, 0, sizeof(b));
|
||||||
|
|
||||||
w->db = db_open(w, filename);
|
w->db = db_open(w, filename);
|
||||||
CHECK(wallet_shachain_init(w, &a));
|
db_begin_transaction(w->db);
|
||||||
|
CHECK_MSG(!wallet_err, "db_begin_transaction failed");
|
||||||
|
wallet_shachain_init(w, &a);
|
||||||
|
CHECK(!wallet_err);
|
||||||
|
|
||||||
CHECK(a.id == 1);
|
CHECK(a.id == 1);
|
||||||
|
|
||||||
|
@ -158,6 +167,9 @@ static bool test_shachain_crud(void)
|
||||||
|
|
||||||
CHECK(wallet_shachain_load(w, a.id, &b));
|
CHECK(wallet_shachain_load(w, a.id, &b));
|
||||||
CHECK_MSG(memcmp(&a, &b, sizeof(a)) == 0, "Loading from database doesn't match");
|
CHECK_MSG(memcmp(&a, &b, sizeof(a)) == 0, "Loading from database doesn't match");
|
||||||
|
|
||||||
|
db_commit_transaction(w->db);
|
||||||
|
CHECK(!wallet_err);
|
||||||
tal_free(w);
|
tal_free(w);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -261,11 +273,16 @@ static bool test_channel_crud(const tal_t *ctx)
|
||||||
ci.remote_per_commit = pk;
|
ci.remote_per_commit = pk;
|
||||||
ci.old_remote_per_commit = pk;
|
ci.old_remote_per_commit = pk;
|
||||||
|
|
||||||
|
db_begin_transaction(w->db);
|
||||||
|
CHECK(!wallet_err);
|
||||||
|
|
||||||
/* Variant 1: insert with null for scid, funding_tx_id, channel_info, last_tx */
|
/* Variant 1: insert with null for scid, funding_tx_id, channel_info, last_tx */
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err,
|
CHECK_MSG(!wallet_err,
|
||||||
tal_fmt(w, "Insert into DB: %s", w->db->err));
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Load from DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v1)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v1)");
|
||||||
|
|
||||||
/* We just inserted them into an empty DB so this must be 1 */
|
/* We just inserted them into an empty DB so this must be 1 */
|
||||||
|
@ -277,8 +294,10 @@ static bool test_channel_crud(const tal_t *ctx)
|
||||||
c1.peer->scid = talz(w, struct short_channel_id);
|
c1.peer->scid = talz(w, struct short_channel_id);
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err,
|
CHECK_MSG(!wallet_err,
|
||||||
tal_fmt(w, "Insert into DB: %s", w->db->err));
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v2)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v2)");
|
||||||
|
|
||||||
/* Updates should not result in new ids */
|
/* Updates should not result in new ids */
|
||||||
|
@ -290,39 +309,51 @@ static bool test_channel_crud(const tal_t *ctx)
|
||||||
c1.peer->our_msatoshi = &msat;
|
c1.peer->our_msatoshi = &msat;
|
||||||
|
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
|
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v3)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v3)");
|
||||||
|
|
||||||
/* Variant 4: update with funding_tx_id */
|
/* Variant 4: update with funding_tx_id */
|
||||||
c1.peer->funding_txid = hash;
|
c1.peer->funding_txid = hash;
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
|
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v4)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v4)");
|
||||||
|
|
||||||
/* Variant 5: update with channel_info */
|
/* Variant 5: update with channel_info */
|
||||||
p.channel_info = &ci;
|
p.channel_info = &ci;
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
|
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v5)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v5)");
|
||||||
|
|
||||||
/* Variant 6: update with last_commit_sent */
|
/* Variant 6: update with last_commit_sent */
|
||||||
p.last_sent_commit = &last_commit;
|
p.last_sent_commit = &last_commit;
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
|
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v6)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v6)");
|
||||||
|
|
||||||
/* Variant 7: update with last_tx (taken from BOLT #3) */
|
/* Variant 7: update with last_tx (taken from BOLT #3) */
|
||||||
p.last_tx = bitcoin_tx_from_hex(w, "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", strlen("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"));
|
p.last_tx = bitcoin_tx_from_hex(w, "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", strlen("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"));
|
||||||
p.last_sig = sig;
|
p.last_sig = sig;
|
||||||
wallet_channel_save(w, &c1);
|
wallet_channel_save(w, &c1);
|
||||||
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
|
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
|
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB"));
|
||||||
|
CHECK_MSG(!wallet_err,
|
||||||
|
tal_fmt(w, "Insert into DB: %s", wallet_err));
|
||||||
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v7)");
|
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v7)");
|
||||||
|
|
||||||
|
db_commit_transaction(w->db);
|
||||||
|
CHECK(!wallet_err);
|
||||||
tal_free(w);
|
tal_free(w);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -346,7 +377,7 @@ static bool test_channel_config_crud(const tal_t *ctx)
|
||||||
cc1->id == 1,
|
cc1->id == 1,
|
||||||
tal_fmt(ctx, "channel_config->id != 1; got %" PRIu64, cc1->id));
|
tal_fmt(ctx, "channel_config->id != 1; got %" PRIu64, cc1->id));
|
||||||
|
|
||||||
CHECK(wallet_channel_config_load(w, cc1->id, cc2));
|
CHECK(transaction_wrap(w->db, wallet_channel_config_load(w, cc1->id, cc2)));
|
||||||
CHECK(memeq(cc1, sizeof(*cc1), cc2, sizeof(*cc2)));
|
CHECK(memeq(cc1, sizeof(*cc1), cc2, sizeof(*cc2)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +394,8 @@ static bool test_htlc_crud(const tal_t *ctx)
|
||||||
struct htlc_out_map *htlcs_out = tal(ctx, struct htlc_out_map);
|
struct htlc_out_map *htlcs_out = tal(ctx, struct htlc_out_map);
|
||||||
|
|
||||||
/* Make sure we have our references correct */
|
/* Make sure we have our references correct */
|
||||||
db_exec(__func__, w->db, "INSERT INTO channels (id) VALUES (1);");
|
CHECK(transaction_wrap(w->db,
|
||||||
|
db_exec(__func__, w->db, "INSERT INTO channels (id) VALUES (1);")));
|
||||||
chan->id = 1;
|
chan->id = 1;
|
||||||
chan->peer = peer;
|
chan->peer = peer;
|
||||||
|
|
||||||
|
@ -383,11 +415,13 @@ static bool test_htlc_crud(const tal_t *ctx)
|
||||||
|
|
||||||
/* Store the htlc_in */
|
/* Store the htlc_in */
|
||||||
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_in(w, chan, &in)),
|
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_in(w, chan, &in)),
|
||||||
tal_fmt(ctx, "Save htlc_in failed: %s", w->db->err));
|
tal_fmt(ctx, "Save htlc_in failed: %s", wallet_err));
|
||||||
CHECK_MSG(in.dbid != 0, "HTLC DB ID was not set.");
|
CHECK_MSG(in.dbid != 0, "HTLC DB ID was not set.");
|
||||||
/* Saving again should get us a collision */
|
/* Saving again should get us a collision */
|
||||||
CHECK_MSG(!transaction_wrap(w->db, wallet_htlc_save_in(w, chan, &in)),
|
CHECK_MSG(!transaction_wrap(w->db, wallet_htlc_save_in(w, chan, &in)),
|
||||||
"Saving two HTLCs with the same data must not succeed.");
|
"Saving two HTLCs with the same data must not succeed.");
|
||||||
|
CHECK(wallet_err);
|
||||||
|
wallet_err = tal_free(wallet_err);
|
||||||
|
|
||||||
/* Update */
|
/* Update */
|
||||||
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL)),
|
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL)),
|
||||||
|
@ -397,21 +431,28 @@ static bool test_htlc_crud(const tal_t *ctx)
|
||||||
"Update HTLC with payment_key failed");
|
"Update HTLC with payment_key failed");
|
||||||
|
|
||||||
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
|
CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
|
||||||
tal_fmt(ctx, "Save htlc_out failed: %s", w->db->err));
|
tal_fmt(ctx, "Save htlc_out failed: %s", wallet_err));
|
||||||
CHECK_MSG(out.dbid != 0, "HTLC DB ID was not set.");
|
CHECK_MSG(out.dbid != 0, "HTLC DB ID was not set.");
|
||||||
|
|
||||||
CHECK_MSG(!transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
|
CHECK_MSG(!transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
|
||||||
"Saving two HTLCs with the same data must not succeed.");
|
"Saving two HTLCs with the same data must not succeed.");
|
||||||
|
CHECK(wallet_err);
|
||||||
|
wallet_err = tal_free(wallet_err);
|
||||||
|
|
||||||
/* Attempt to load them from the DB again */
|
/* Attempt to load them from the DB again */
|
||||||
htlc_in_map_init(htlcs_in);
|
htlc_in_map_init(htlcs_in);
|
||||||
htlc_out_map_init(htlcs_out);
|
htlc_out_map_init(htlcs_out);
|
||||||
|
|
||||||
|
db_begin_transaction(w->db);
|
||||||
|
CHECK(!wallet_err);
|
||||||
|
|
||||||
CHECK_MSG(wallet_htlcs_load_for_channel(w, chan, htlcs_in, htlcs_out),
|
CHECK_MSG(wallet_htlcs_load_for_channel(w, chan, htlcs_in, htlcs_out),
|
||||||
"Failed loading HTLCs");
|
"Failed loading HTLCs");
|
||||||
|
|
||||||
CHECK_MSG(wallet_htlcs_reconnect(w, htlcs_in, htlcs_out),
|
CHECK_MSG(wallet_htlcs_reconnect(w, htlcs_in, htlcs_out),
|
||||||
"Unable to reconnect htlcs.");
|
"Unable to reconnect htlcs.");
|
||||||
|
db_commit_transaction(w->db);
|
||||||
|
CHECK(!wallet_err);
|
||||||
|
|
||||||
hin = htlc_in_map_get(htlcs_in, &in.key);
|
hin = htlc_in_map_get(htlcs_in, &in.key);
|
||||||
hout = htlc_out_map_get(htlcs_out, &out.key);
|
hout = htlc_out_map_get(htlcs_out, &out.key);
|
||||||
|
|
Loading…
Add table
Reference in a new issue