Browse Source

db: create explicit separate API for select statements.

I was tempted to create a new db_select_stmt wrapper type, but that means
a lot of boilerplate around binding, which expects to work with db_prepare
*and* db_select_prepare.

This lets us clearly differentiate between db queries (which don't need to
go to a plugin) and db changes (which do).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
pr-2587
Rusty Russell 6 years ago
parent
commit
e1e26ca69d
  1. 99
      wallet/db.c
  2. 39
      wallet/db.h
  3. 156
      wallet/invoices.c
  4. 331
      wallet/wallet.c

99
wallet/db.c

@ -440,6 +440,36 @@ void db_stmt_done(sqlite3_stmt *stmt)
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
sqlite3_stmt *db_select_prepare_(const char *location, struct db *db, const char *query)
{
int err;
sqlite3_stmt *stmt;
const char *full_query = tal_fmt(db, "SELECT %s", query);
assert(db->in_transaction);
err = sqlite3_prepare_v2(db->sql, full_query, -1, &stmt, NULL);
if (err != SQLITE_OK)
db_fatal("%s: %s: %s", location, full_query, sqlite3_errmsg(db->sql));
dev_statement_start(stmt, location);
tal_free(full_query);
return stmt;
}
bool db_select_step_(const char *location, struct db *db, struct sqlite3_stmt *stmt)
{
int ret;
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
return true;
if (ret != SQLITE_DONE)
db_fatal("%s: %s", location, sqlite3_errmsg(db->sql));
db_stmt_done(stmt);
return false;
}
sqlite3_stmt *db_prepare_(const char *location, struct db *db, const char *query) sqlite3_stmt *db_prepare_(const char *location, struct db *db, const char *query)
{ {
int err; int err;
@ -496,24 +526,39 @@ static void PRINTF_FMT(3, 4)
tal_free(cmd); tal_free(cmd);
} }
/* This one can fail: returns NULL if so */
static sqlite3_stmt *db_query(const char *location,
struct db *db, const char *query)
{
sqlite3_stmt *stmt;
assert(db->in_transaction);
/* Sets stmt to NULL if not SQLITE_OK */
sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL);
if (stmt)
dev_statement_start(stmt, location);
return stmt;
}
sqlite3_stmt *PRINTF_FMT(3, 4) sqlite3_stmt *PRINTF_FMT(3, 4)
db_query_(const char *location, struct db *db, const char *fmt, ...) db_select_(const char *location, struct db *db, const char *fmt, ...)
{ {
va_list ap; va_list ap;
char *query; char *query = tal_strdup(db, "SELECT ");
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
assert(db->in_transaction); assert(db->in_transaction);
va_start(ap, fmt); va_start(ap, fmt);
query = tal_vfmt(db, fmt, ap); tal_append_vfmt(&query, fmt, ap);
va_end(ap); va_end(ap);
/* Sets stmt to NULL if not SQLITE_OK */ stmt = db_query(location, db, query);
sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL); if (!stmt)
db_fatal("%s:%s:%s", location, query, sqlite3_errmsg(db->sql));
tal_free(query); tal_free(query);
if (stmt)
dev_statement_start(stmt, location);
return stmt; return stmt;
} }
@ -577,22 +622,19 @@ static struct db *db_open(const tal_t *ctx, char *filename)
*/ */
static int db_get_version(struct db *db) static int db_get_version(struct db *db)
{ {
int err; int res;
u64 res = -1; sqlite3_stmt *stmt = db_query(__func__,
sqlite3_stmt *stmt = db_query(db, "SELECT version FROM version LIMIT 1"); db, "SELECT version FROM version LIMIT 1");
if (!stmt) if (!stmt)
return -1; return -1;
err = sqlite3_step(stmt); if (!db_select_step(db, stmt))
if (err != SQLITE_ROW) {
db_stmt_done(stmt);
return -1; return -1;
} else {
res = sqlite3_column_int64(stmt, 0); res = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt); db_stmt_done(stmt);
return res; return res;
}
} }
/** /**
@ -670,21 +712,24 @@ void db_reopen_after_fork(struct db *db)
s64 db_get_intvar(struct db *db, char *varname, s64 defval) s64 db_get_intvar(struct db *db, char *varname, s64 defval)
{ {
int err; s64 res;
s64 res = defval; sqlite3_stmt *stmt;
sqlite3_stmt *stmt = const char *query;
db_query(db,
"SELECT val FROM vars WHERE name='%s' LIMIT 1", varname); query = tal_fmt(db, "SELECT val FROM vars WHERE name='%s' LIMIT 1", varname);
stmt = db_query(__func__, db, query);
tal_free(query);
if (!stmt) if (!stmt)
return defval; return defval;
err = sqlite3_step(stmt); if (db_select_step(db, stmt)) {
if (err == SQLITE_ROW) {
const unsigned char *stringvar = sqlite3_column_text(stmt, 0); const unsigned char *stringvar = sqlite3_column_text(stmt, 0);
res = atol((const char *)stringvar); res = atol((const char *)stringvar);
} db_stmt_done(stmt);
db_stmt_done(stmt); } else
res = defval;
return res; return res;
} }

39
wallet/db.h

@ -37,12 +37,14 @@ struct db {
struct db *db_setup(const tal_t *ctx, struct lightningd *ld, struct log *log); struct db *db_setup(const tal_t *ctx, struct lightningd *ld, struct log *log);
/** /**
* db_query - Prepare and execute a query, and return the result (or NULL) * db_select - Prepare and execute a SELECT, and return the result
*
* A simpler version of db_select_prepare.
*/ */
sqlite3_stmt *PRINTF_FMT(3, 4) sqlite3_stmt *PRINTF_FMT(3, 4)
db_query_(const char *location, struct db *db, const char *fmt, ...); db_select_(const char *location, struct db *db, const char *fmt, ...);
#define db_query(db, ...) \ #define db_select(db, ...) \
db_query_(__FILE__ ":" stringify(__LINE__), db, __VA_ARGS__) db_select_(__FILE__ ":" stringify(__LINE__), db, __VA_ARGS__)
/** /**
* db_begin_transaction - Begin a transaction * db_begin_transaction - Begin a transaction
@ -77,6 +79,35 @@ void db_set_intvar(struct db *db, char *varname, s64 val);
*/ */
s64 db_get_intvar(struct db *db, char *varname, s64 defval); s64 db_get_intvar(struct db *db, char *varname, s64 defval);
/**
* db_select_prepare -- Prepare a DB select statement (read-only!)
*
* Tiny wrapper around `sqlite3_prepare_v2` that checks and sets
* errors like `db_query` and `db_exec` do. It calls fatal if
* the stmt is not valid.
*
* Call db_select_step() until it returns false (which will also consume
* the stmt).
*
* @db: Database to query/exec
* @query: The SELECT SQL statement to compile
*/
#define db_select_prepare(db, query) \
db_select_prepare_(__FILE__ ":" stringify(__LINE__), db, query)
sqlite3_stmt *db_select_prepare_(const char *location,
struct db *db, const char *query);
/**
* db_select_step -- iterate through db results.
*
* Returns false and frees stmt if we've we've reached end, otherwise
* it means sqlite3_step has returned SQLITE_ROW.
*/
#define db_select_step(db, stmt) \
db_select_step_(__FILE__ ":" stringify(__LINE__), db, stmt)
bool db_select_step_(const char *location,
struct db *db, struct sqlite3_stmt *stmt);
/** /**
* db_prepare -- Prepare a DB query/command * db_prepare -- Prepare a DB query/command
* *

156
wallet/invoices.c

@ -185,19 +185,18 @@ static void trigger_expiration(struct invoices *invoices)
/* Acquire all expired invoices and save them in a list */ /* Acquire all expired invoices and save them in a list */
list_head_init(&idlist); list_head_init(&idlist);
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT id" "id"
" FROM invoices" " FROM invoices"
" WHERE state = ?" " WHERE state = ?"
" AND expiry_time <= ?;"); " AND expiry_time <= ?;");
sqlite3_bind_int(stmt, 1, UNPAID); sqlite3_bind_int(stmt, 1, UNPAID);
sqlite3_bind_int64(stmt, 2, now); sqlite3_bind_int64(stmt, 2, now);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(invoices->db, stmt)) {
idn = tal(tmpctx, struct invoice_id_node); idn = tal(tmpctx, struct invoice_id_node);
list_add_tail(&idlist, &idn->list); list_add_tail(&idlist, &idn->list);
idn->id = sqlite3_column_int64(stmt, 0); idn->id = sqlite3_column_int64(stmt, 0);
} }
db_stmt_done(stmt);
/* Expire all those invoices */ /* Expire all those invoices */
update_db_expirations(invoices, now); update_db_expirations(invoices, now);
@ -216,7 +215,7 @@ static void trigger_expiration(struct invoices *invoices)
static void install_expiration_timer(struct invoices *invoices) static void install_expiration_timer(struct invoices *invoices)
{ {
int res; bool res;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
struct timerel rel; struct timerel rel;
struct timeabs expiry; struct timeabs expiry;
@ -225,13 +224,13 @@ static void install_expiration_timer(struct invoices *invoices)
assert(!invoices->expiration_timer); assert(!invoices->expiration_timer);
/* Find unpaid invoice with nearest expiry time */ /* Find unpaid invoice with nearest expiry time */
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT MIN(expiry_time)" "MIN(expiry_time)"
" FROM invoices" " FROM invoices"
" WHERE state = ?;"); " WHERE state = ?;");
sqlite3_bind_int(stmt, 1, UNPAID); sqlite3_bind_int(stmt, 1, UNPAID);
res = sqlite3_step(stmt); res = db_select_step(invoices->db, stmt);
assert(res == SQLITE_ROW); assert(res);
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) { if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) {
/* Nothing to install */ /* Nothing to install */
db_stmt_done(stmt); db_stmt_done(stmt);
@ -337,19 +336,17 @@ bool invoices_find_by_label(struct invoices *invoices,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT id" "id"
" FROM invoices" " FROM invoices"
" WHERE label = ?;"); " WHERE label = ?;");
sqlite3_bind_json_escaped(stmt, 1, label); sqlite3_bind_json_escaped(stmt, 1, label);
if (sqlite3_step(stmt) == SQLITE_ROW) { if (!db_select_step(invoices->db, stmt))
pinvoice->id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return true;
} else {
db_stmt_done(stmt);
return false; return false;
}
pinvoice->id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return true;
} }
bool invoices_find_by_rhash(struct invoices *invoices, bool invoices_find_by_rhash(struct invoices *invoices,
@ -358,19 +355,17 @@ bool invoices_find_by_rhash(struct invoices *invoices,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT id" "id"
" FROM invoices" " FROM invoices"
" WHERE payment_hash = ?;"); " WHERE payment_hash = ?;");
sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT);
if (sqlite3_step(stmt) == SQLITE_ROW) { if (!db_select_step(invoices->db, stmt))
pinvoice->id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return true;
} else {
db_stmt_done(stmt);
return false; return false;
}
pinvoice->id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return true;
} }
bool invoices_find_unpaid(struct invoices *invoices, bool invoices_find_unpaid(struct invoices *invoices,
@ -379,21 +374,19 @@ bool invoices_find_unpaid(struct invoices *invoices,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT id" " id"
" FROM invoices" " FROM invoices"
" WHERE payment_hash = ?" " WHERE payment_hash = ?"
" AND state = ?;"); " AND state = ?;");
sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, UNPAID); sqlite3_bind_int(stmt, 2, UNPAID);
if (sqlite3_step(stmt) == SQLITE_ROW) { if (!db_select_step(invoices->db, stmt))
pinvoice->id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return true;
} else {
db_stmt_done(stmt);
return false; return false;
}
pinvoice->id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return true;
} }
bool invoices_delete(struct invoices *invoices, bool invoices_delete(struct invoices *invoices,
@ -468,24 +461,22 @@ bool invoices_iterate(struct invoices *invoices,
struct invoice_iterator *it) struct invoice_iterator *it)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int res;
if (!it->p) { if (!it->p) {
stmt = db_prepare(invoices->db, "SELECT " INVOICE_TBL_FIELDS stmt = db_select_prepare(invoices->db,
" FROM invoices;"); INVOICE_TBL_FIELDS
" FROM invoices;");
it->p = stmt; it->p = stmt;
} else } else
stmt = it->p; stmt = it->p;
res = sqlite3_step(stmt); if (db_select_step(invoices->db, stmt))
if (res == SQLITE_DONE) {
db_stmt_done(stmt);
it->p = NULL;
return false;
} else {
assert(res == SQLITE_ROW);
return true; return true;
}
it->p = NULL;
return false;
} }
const struct invoice_details * const struct invoice_details *
invoices_iterator_deref(const tal_t *ctx, struct invoices *invoices UNUSED, invoices_iterator_deref(const tal_t *ctx, struct invoices *invoices UNUSED,
const struct invoice_iterator *it) const struct invoice_iterator *it)
@ -573,19 +564,17 @@ void invoices_waitany(const tal_t *ctx,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
struct invoice invoice; struct invoice invoice;
int res;
/* Look for an already-paid invoice. */ /* Look for an already-paid invoice. */
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT id" "id"
" FROM invoices" " FROM invoices"
" WHERE pay_index NOT NULL" " WHERE pay_index NOT NULL"
" AND pay_index > ?" " AND pay_index > ?"
" ORDER BY pay_index ASC LIMIT 1;"); " ORDER BY pay_index ASC LIMIT 1;");
sqlite3_bind_int64(stmt, 1, lastpay_index); sqlite3_bind_int64(stmt, 1, lastpay_index);
res = sqlite3_step(stmt); if (db_select_step(invoices->db, stmt)) {
if (res == SQLITE_ROW) {
invoice.id = sqlite3_column_int64(stmt, 0); invoice.id = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt); db_stmt_done(stmt);
@ -593,8 +582,6 @@ void invoices_waitany(const tal_t *ctx,
return; return;
} }
db_stmt_done(stmt);
/* None found. */ /* None found. */
add_invoice_waiter(ctx, &invoices->waiters, add_invoice_waiter(ctx, &invoices->waiters,
true, 0, cb, cbarg); true, 0, cb, cbarg);
@ -608,16 +595,17 @@ void invoices_waitone(const tal_t *ctx,
void *cbarg) void *cbarg)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int res; bool res;
enum invoice_status state; enum invoice_status state;
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT state" "state"
" FROM invoices" " FROM invoices"
" WHERE id = ?;"); " WHERE id = ?;");
sqlite3_bind_int64(stmt, 1, invoice.id); sqlite3_bind_int64(stmt, 1, invoice.id);
res = sqlite3_step(stmt);
assert(res == SQLITE_ROW); res = db_select_step(invoices->db, stmt);
assert(res);
state = sqlite3_column_int(stmt, 0); state = sqlite3_column_int(stmt, 0);
db_stmt_done(stmt); db_stmt_done(stmt);
@ -636,16 +624,16 @@ const struct invoice_details *invoices_get_details(const tal_t *ctx,
struct invoice invoice) struct invoice invoice)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int result; bool res;
struct invoice_details *details; struct invoice_details *details;
stmt = db_prepare(invoices->db, stmt = db_select_prepare(invoices->db,
"SELECT " INVOICE_TBL_FIELDS INVOICE_TBL_FIELDS
" FROM invoices" " FROM invoices"
" WHERE id = ?;"); " WHERE id = ?;");
sqlite3_bind_int64(stmt, 1, invoice.id); sqlite3_bind_int64(stmt, 1, invoice.id);
result = sqlite3_step(stmt); res = db_select_step(invoices->db, stmt);
assert(result == SQLITE_ROW); assert(res);
details = wallet_stmt2invoice_details(ctx, stmt); details = wallet_stmt2invoice_details(ctx, stmt);
db_stmt_done(stmt); db_stmt_done(stmt);

331
wallet/wallet.c

@ -34,15 +34,13 @@ static void outpointfilters_init(struct wallet *w)
tal_free(utxos); tal_free(utxos);
w->utxoset_outpoints = outpointfilter_new(w); w->utxoset_outpoints = outpointfilter_new(w);
stmt = db_prepare(w->db, "SELECT txid, outnum FROM utxoset WHERE spendheight is NULL"); stmt = db_select_prepare(w->db, "txid, outnum FROM utxoset WHERE spendheight is NULL");
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
sqlite3_column_sha256_double(stmt, 0, &txid.shad); sqlite3_column_sha256_double(stmt, 0, &txid.shad);
outnum = sqlite3_column_int(stmt, 1); outnum = sqlite3_column_int(stmt, 1);
outpointfilter_add(w->utxoset_outpoints, &txid, outnum); outpointfilter_add(w->utxoset_outpoints, &txid, outnum);
} }
db_stmt_done(stmt);
} }
struct wallet *wallet_new(struct lightningd *ld, struct wallet *wallet_new(struct lightningd *ld,
@ -73,17 +71,16 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
stmt = db_prepare(w->db, stmt = db_select_prepare(w->db,
"SELECT * from outputs WHERE prev_out_tx=? AND prev_out_index=?"); "* from outputs WHERE prev_out_tx=? AND prev_out_index=?");
sqlite3_bind_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, utxo->outnum); sqlite3_bind_int(stmt, 2, utxo->outnum);
/* If we get a result, that means a clash. */ /* If we get a result, that means a clash. */
if (sqlite3_step(stmt) == SQLITE_ROW) { if (db_select_step(w->db, stmt)) {
db_stmt_done(stmt); db_stmt_done(stmt);
return false; return false;
} }
db_stmt_done(stmt);
stmt = db_prepare(w->db, "INSERT INTO outputs (" stmt = db_prepare(w->db, "INSERT INTO outputs ("
UTXO_FIELDS UTXO_FIELDS
@ -203,22 +200,19 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
if (state == output_state_any) if (state == output_state_any)
stmt = db_prepare(w->db, "SELECT "UTXO_FIELDS stmt = db_select_prepare(w->db, UTXO_FIELDS " FROM outputs");
" FROM outputs");
else { else {
stmt = db_prepare(w->db, "SELECT "UTXO_FIELDS stmt = db_select_prepare(w->db, UTXO_FIELDS
" FROM outputs WHERE status=?1"); " FROM outputs WHERE status=?1");
sqlite3_bind_int(stmt, 1, output_status_in_db(state)); sqlite3_bind_int(stmt, 1, output_status_in_db(state));
} }
results = tal_arr(ctx, struct utxo*, 0); results = tal_arr(ctx, struct utxo*, 0);
for (i=0; sqlite3_step(stmt) == SQLITE_ROW; i++) { for (i=0; db_select_step(w->db, stmt); i++) {
struct utxo *u = wallet_stmt2output(results, stmt); struct utxo *u = wallet_stmt2output(results, stmt);
tal_arr_expand(&results, u); tal_arr_expand(&results, u);
} }
db_stmt_done(stmt);
return results; return results;
} }
@ -227,16 +221,15 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, struct wa
struct utxo **results; struct utxo **results;
int i; int i;
sqlite3_stmt *stmt = db_prepare( sqlite3_stmt *stmt = db_select_prepare(
w->db, "SELECT " UTXO_FIELDS w->db, UTXO_FIELDS
" FROM outputs WHERE channel_id IS NOT NULL and confirmation_height IS NULL"); " FROM outputs WHERE channel_id IS NOT NULL and confirmation_height IS NULL");
results = tal_arr(ctx, struct utxo*, 0); results = tal_arr(ctx, struct utxo*, 0);
for (i=0; sqlite3_step(stmt) == SQLITE_ROW; i++) { for (i=0; db_select_step(w->db, stmt); i++) {
struct utxo *u = wallet_stmt2output(results, stmt); struct utxo *u = wallet_stmt2output(results, stmt);
tal_arr_expand(&results, u); tal_arr_expand(&results, u);
} }
db_stmt_done(stmt);
return results; return results;
} }
@ -526,36 +519,30 @@ bool wallet_shachain_add_hash(struct wallet *wallet,
bool wallet_shachain_load(struct wallet *wallet, u64 id, bool wallet_shachain_load(struct wallet *wallet, u64 id,
struct wallet_shachain *chain) struct wallet_shachain *chain)
{ {
int err;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
chain->id = id; chain->id = id;
shachain_init(&chain->chain); shachain_init(&chain->chain);
/* Load shachain metadata */ /* Load shachain metadata */
stmt = db_prepare(wallet->db, "SELECT min_index, num_valid FROM shachains WHERE id=?"); stmt = db_select_prepare(wallet->db, "min_index, num_valid FROM shachains WHERE id=?");
sqlite3_bind_int64(stmt, 1, id); sqlite3_bind_int64(stmt, 1, id);
err = sqlite3_step(stmt); if (!db_select_step(wallet->db, stmt))
if (err != SQLITE_ROW) {
db_stmt_done(stmt);
return false; return false;
}
chain->chain.min_index = sqlite3_column_int64(stmt, 0); chain->chain.min_index = sqlite3_column_int64(stmt, 0);
chain->chain.num_valid = sqlite3_column_int64(stmt, 1); chain->chain.num_valid = sqlite3_column_int64(stmt, 1);
db_stmt_done(stmt); db_stmt_done(stmt);
/* Load shachain known entries */ /* Load shachain known entries */
stmt = db_prepare(wallet->db, "SELECT idx, hash, pos FROM shachain_known WHERE shachain_id=?"); stmt = db_select_prepare(wallet->db, "idx, hash, pos FROM shachain_known WHERE shachain_id=?");
sqlite3_bind_int64(stmt, 1, id); sqlite3_bind_int64(stmt, 1, id);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(wallet->db, stmt)) {
int pos = sqlite3_column_int(stmt, 2); int pos = sqlite3_column_int(stmt, 2);
chain->chain.known[pos].index = sqlite3_column_int64(stmt, 0); chain->chain.known[pos].index = sqlite3_column_int64(stmt, 0);
memcpy(&chain->chain.known[pos].hash, sqlite3_column_blob(stmt, 1), sqlite3_column_bytes(stmt, 1)); memcpy(&chain->chain.known[pos].hash, sqlite3_column_blob(stmt, 1), sqlite3_column_bytes(stmt, 1));
} }
db_stmt_done(stmt);
return true; return true;
} }
@ -567,13 +554,12 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid)
struct wireaddr_internal addr; struct wireaddr_internal addr;
sqlite3_stmt *stmt = sqlite3_stmt *stmt =
db_query(w->db, db_select(w->db,
"SELECT id, node_id, address FROM peers WHERE id=%"PRIu64";", dbid); "id, node_id, address FROM peers WHERE id=%"PRIu64";", dbid);
if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) { if (!db_select_step(w->db, stmt))
db_stmt_done(stmt);
return NULL; return NULL;
}
if (!sqlite3_column_pubkey(stmt, 1, &id)) { if (!sqlite3_column_pubkey(stmt, 1, &id)) {
db_stmt_done(stmt); db_stmt_done(stmt);
return NULL; return NULL;
@ -594,17 +580,16 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid)
static secp256k1_ecdsa_signature * static secp256k1_ecdsa_signature *
wallet_htlc_sigs_load(const tal_t *ctx, struct wallet *w, u64 channelid) wallet_htlc_sigs_load(const tal_t *ctx, struct wallet *w, u64 channelid)
{ {
sqlite3_stmt *stmt = db_prepare(w->db, "SELECT signature FROM htlc_sigs WHERE channelid = ?"); sqlite3_stmt *stmt = db_select_prepare(w->db, "signature FROM htlc_sigs WHERE channelid = ?");
secp256k1_ecdsa_signature *htlc_sigs = tal_arr(ctx, secp256k1_ecdsa_signature, 0); secp256k1_ecdsa_signature *htlc_sigs = tal_arr(ctx, secp256k1_ecdsa_signature, 0);
sqlite3_bind_int64(stmt, 1, channelid); sqlite3_bind_int64(stmt, 1, channelid);
while (stmt && sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
secp256k1_ecdsa_signature sig; secp256k1_ecdsa_signature sig;
sqlite3_column_signature(stmt, 0, &sig); sqlite3_column_signature(stmt, 0, &sig);
tal_arr_expand(&htlc_sigs, sig); tal_arr_expand(&htlc_sigs, sig);
} }
db_stmt_done(stmt);
log_debug(w->log, "Loaded %zu HTLC signatures from DB", log_debug(w->log, "Loaded %zu HTLC signatures from DB",
tal_count(htlc_sigs)); tal_count(htlc_sigs));
return htlc_sigs; return htlc_sigs;
@ -787,16 +772,16 @@ bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w)
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
/* We load all channels */ /* We load all channels */
stmt = db_query(w->db, "SELECT %s FROM channels;", stmt = db_select(w->db, "%s FROM channels;", channel_fields);
channel_fields);
w->max_channel_dbid = 0; w->max_channel_dbid = 0;
int count = 0; int count = 0;
while (ok && stmt && sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
struct channel *c = wallet_stmt2channel(ctx, w, stmt); struct channel *c = wallet_stmt2channel(ctx, w, stmt);
if (!c) { if (!c) {
ok = false; ok = false;
db_stmt_done(stmt);
break; break;
} }
if (c->dbid > w->max_channel_dbid) if (c->dbid > w->max_channel_dbid)
@ -804,7 +789,6 @@ bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w)
count++; count++;
} }
log_debug(w->log, "Loaded %d channels from DB", count); log_debug(w->log, "Loaded %d channels from DB", count);
db_stmt_done(stmt);
return ok; return ok;
} }
@ -857,11 +841,11 @@ void wallet_channel_stats_load(struct wallet *w,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int res; int res;
stmt = db_prepare(w->db, stmt = db_select_prepare(w->db,
"SELECT in_payments_offered, in_payments_fulfilled" " in_payments_offered, in_payments_fulfilled"
" , in_msatoshi_offered, in_msatoshi_fulfilled" ", in_msatoshi_offered, in_msatoshi_fulfilled"
" , out_payments_offered, out_payments_fulfilled" ", out_payments_offered, out_payments_fulfilled"
" , out_msatoshi_offered, out_msatoshi_fulfilled" ", out_msatoshi_offered, out_msatoshi_fulfilled"
" FROM channels" " FROM channels"
" WHERE id = ?"); " WHERE id = ?");
sqlite3_bind_int64(stmt, 1, id); sqlite3_bind_int64(stmt, 1, id);
@ -885,17 +869,19 @@ void wallet_channel_stats_load(struct wallet *w,
void wallet_blocks_heights(struct wallet *w, u32 def, u32 *min, u32 *max) void wallet_blocks_heights(struct wallet *w, u32 def, u32 *min, u32 *max)
{ {
assert(min != NULL && max != NULL); assert(min != NULL && max != NULL);
sqlite3_stmt *stmt = db_prepare(w->db, "SELECT MIN(height), MAX(height) FROM blocks;"); sqlite3_stmt *stmt = db_select_prepare(w->db, "MIN(height), MAX(height) FROM blocks;");
*min = def;
*max = def;
/* If we ever processed a block we'll get the latest block in the chain */ /* If we ever processed a block we'll get the latest block in the chain */
if (sqlite3_step(stmt) == SQLITE_ROW && sqlite3_column_type(stmt, 0) != SQLITE_NULL) { if (db_select_step(w->db, stmt)) {
*min = sqlite3_column_int(stmt, 0); if (sqlite3_column_type(stmt, 0) != SQLITE_NULL) {
*max = sqlite3_column_int(stmt, 1); *min = sqlite3_column_int(stmt, 0);
} else { *max = sqlite3_column_int(stmt, 1);
*min = def; }
*max = def; db_stmt_done(stmt);
} }
db_stmt_done(stmt);
} }
static void wallet_channel_config_insert(struct wallet *w, static void wallet_channel_config_insert(struct wallet *w,
@ -940,14 +926,13 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id,
bool ok = true; bool ok = true;
int col = 1; int col = 1;
const char *query = const char *query =
"SELECT id, dust_limit_satoshis, max_htlc_value_in_flight_msat, " "id, dust_limit_satoshis, max_htlc_value_in_flight_msat, "
"channel_reserve_satoshis, htlc_minimum_msat, to_self_delay, " "channel_reserve_satoshis, htlc_minimum_msat, to_self_delay, "
"max_accepted_htlcs FROM channel_configs WHERE id=%" PRIu64 ";"; "max_accepted_htlcs FROM channel_configs WHERE id=%" PRIu64 ";";
sqlite3_stmt *stmt = db_query(w->db, query, id); sqlite3_stmt *stmt = db_select(w->db, query, id);
if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) { if (!db_select_step(w->db, stmt))
db_stmt_done(stmt);
return false; return false;
}
cc->id = id; cc->id = id;
cc->dust_limit = sqlite3_column_amount_sat(stmt, col++); cc->dust_limit = sqlite3_column_amount_sat(stmt, col++);
cc->max_htlc_value_in_flight = sqlite3_column_amount_msat(stmt, col++); cc->max_htlc_value_in_flight = sqlite3_column_amount_msat(stmt, col++);
@ -1140,11 +1125,11 @@ void wallet_peer_delete(struct wallet *w, u64 peer_dbid)
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
/* Must not have any channels still using this peer */ /* Must not have any channels still using this peer */
stmt = db_query(w->db, stmt = db_select(w->db,
"SELECT * FROM channels WHERE peer_id = %"PRIu64, "* FROM channels WHERE peer_id = %"PRIu64,
peer_dbid); peer_dbid);
assert(sqlite3_step(stmt) == SQLITE_DONE); if (db_select_step(w->db, stmt))
db_stmt_done(stmt); fatal("We have channels using peer %"PRIu64, peer_dbid);
stmt = db_prepare(w->db, "DELETE FROM peers WHERE id=?"); stmt = db_prepare(w->db, "DELETE FROM peers WHERE id=?");
sqlite3_bind_int64(stmt, 1, peer_dbid); sqlite3_bind_int64(stmt, 1, peer_dbid);
@ -1498,18 +1483,13 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
int incount = 0, outcount = 0; int incount = 0, outcount = 0;
log_debug(wallet->log, "Loading HTLCs for channel %"PRIu64, chan->dbid); log_debug(wallet->log, "Loading HTLCs for channel %"PRIu64, chan->dbid);
sqlite3_stmt *stmt = db_query( sqlite3_stmt *stmt = db_select(
wallet->db, wallet->db,
"SELECT " HTLC_FIELDS " FROM channel_htlcs WHERE " HTLC_FIELDS " FROM channel_htlcs WHERE "
"direction=%d AND channel_id=%" PRIu64 " AND hstate != %d", "direction=%d AND channel_id=%" PRIu64 " AND hstate != %d",
DIRECTION_INCOMING, chan->dbid, SENT_REMOVE_ACK_REVOCATION); DIRECTION_INCOMING, chan->dbid, SENT_REMOVE_ACK_REVOCATION);
if (!stmt) { while (db_select_step(wallet->db, stmt)) {
log_broken(wallet->log, "Could not select htlc_ins");
return false;
}
while (ok && sqlite3_step(stmt) == SQLITE_ROW) {
struct htlc_in *in = tal(chan, struct htlc_in); struct htlc_in *in = tal(chan, struct htlc_in);
ok &= wallet_stmt2htlc_in(chan, stmt, in); ok &= wallet_stmt2htlc_in(chan, stmt, in);
connect_htlc_in(htlcs_in, in); connect_htlc_in(htlcs_in, in);
@ -1517,20 +1497,14 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
ok &= htlc_in_check(in, NULL) != NULL; ok &= htlc_in_check(in, NULL) != NULL;
incount++; incount++;
} }
db_stmt_done(stmt);
stmt = db_query( stmt = db_select(
wallet->db, wallet->db,
"SELECT " HTLC_FIELDS " FROM channel_htlcs WHERE " HTLC_FIELDS " FROM channel_htlcs WHERE "
"direction=%d AND channel_id=%" PRIu64 " AND hstate != %d", "direction=%d AND channel_id=%" PRIu64 " AND hstate != %d",
DIRECTION_OUTGOING, chan->dbid, RCVD_REMOVE_ACK_REVOCATION); DIRECTION_OUTGOING, chan->dbid, RCVD_REMOVE_ACK_REVOCATION);
if (!stmt) { while (db_select_step(wallet->db, stmt)) {
log_broken(wallet->log, "Could not select htlc_outs");
return false;
}
while (ok && sqlite3_step(stmt) == SQLITE_ROW) {
struct htlc_out *out = tal(chan, struct htlc_out); struct htlc_out *out = tal(chan, struct htlc_out);
ok &= wallet_stmt2htlc_out(chan, stmt, out); ok &= wallet_stmt2htlc_out(chan, stmt, out);
connect_htlc_out(htlcs_out, out); connect_htlc_out(htlcs_out, out);
@ -1538,7 +1512,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
* dependencies in yet */ * dependencies in yet */
outcount++; outcount++;
} }
db_stmt_done(stmt);
log_debug(wallet->log, "Restored %d incoming and %d outgoing HTLCS", incount, outcount); log_debug(wallet->log, "Restored %d incoming and %d outgoing HTLCS", incount, outcount);
return ok; return ok;
@ -1633,15 +1607,15 @@ struct htlc_stub *wallet_htlc_stubs(const tal_t *ctx, struct wallet *wallet,
{ {
struct htlc_stub *stubs; struct htlc_stub *stubs;
struct sha256 payment_hash; struct sha256 payment_hash;
sqlite3_stmt *stmt = db_prepare(wallet->db, sqlite3_stmt *stmt = db_select_prepare(wallet->db,
"SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash " "channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash "
"FROM channel_htlcs WHERE channel_id = ?;"); "FROM channel_htlcs WHERE channel_id = ?;");
sqlite3_bind_int64(stmt, 1, chan->dbid); sqlite3_bind_int64(stmt, 1, chan->dbid);
stubs = tal_arr(ctx, struct htlc_stub, 0); stubs = tal_arr(ctx, struct htlc_stub, 0);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(wallet->db, stmt)) {
struct htlc_stub stub; struct htlc_stub stub;
assert(sqlite3_column_int64(stmt, 0) == chan->dbid); assert(sqlite3_column_int64(stmt, 0) == chan->dbid);
@ -1655,7 +1629,6 @@ struct htlc_stub *wallet_htlc_stubs(const tal_t *ctx, struct wallet *wallet,
ripemd160(&stub.ripemd, payment_hash.u.u8, sizeof(payment_hash.u)); ripemd160(&stub.ripemd, payment_hash.u.u8, sizeof(payment_hash.u));
tal_arr_expand(&stubs, stub); tal_arr_expand(&stubs, stub);
} }
db_stmt_done(stmt);
return stubs; return stubs;
} }
@ -1715,13 +1688,13 @@ void wallet_payment_store(struct wallet *wallet,
/* Double-check that it is indeed stored to disk /* Double-check that it is indeed stored to disk
* (catch bug, where we call this on a payment_hash * (catch bug, where we call this on a payment_hash
* we never paid to) */ * we never paid to) */
int res; bool res;
stmt = db_prepare(wallet->db, stmt = db_select_prepare(wallet->db,
"SELECT status FROM payments" "status FROM payments"
" WHERE payment_hash=?;"); " WHERE payment_hash=?;");
sqlite3_bind_sha256(stmt, 1, payment_hash); sqlite3_bind_sha256(stmt, 1, payment_hash);
res = sqlite3_step(stmt); res = db_select_step(wallet->db, stmt);
assert(res == SQLITE_ROW); assert(res);
db_stmt_done(stmt); db_stmt_done(stmt);
#endif #endif
return; return;
@ -1859,14 +1832,14 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
if (payment) if (payment)
return payment; return payment;
stmt = db_prepare(wallet->db, "SELECT " PAYMENT_FIELDS " FROM payments " stmt = db_select_prepare(wallet->db, PAYMENT_FIELDS " FROM payments "
"WHERE payment_hash = ?"); "WHERE payment_hash = ?");
sqlite3_bind_sha256(stmt, 1, payment_hash); sqlite3_bind_sha256(stmt, 1, payment_hash);
if (sqlite3_step(stmt) == SQLITE_ROW) { if (db_select_step(wallet->db, stmt)) {
payment = wallet_stmt2payment(ctx, stmt); payment = wallet_stmt2payment(ctx, stmt);
db_stmt_done(stmt);
} }
db_stmt_done(stmt);
return payment; return payment;
} }
@ -1930,20 +1903,19 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
int *faildirection) int *faildirection)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int res;
bool resb; bool resb;
size_t len; size_t len;
stmt = db_prepare(wallet->db, stmt = db_select_prepare(wallet->db,
"SELECT failonionreply, faildestperm" "failonionreply, faildestperm"
" , failindex, failcode" ", failindex, failcode"
" , failnode, failchannel" ", failnode, failchannel"
" , failupdate, faildetail, faildirection" ", failupdate, faildetail, faildirection"
" FROM payments" " FROM payments"
" WHERE payment_hash=?;"); " WHERE payment_hash=?;");
sqlite3_bind_sha256(stmt, 1, payment_hash); sqlite3_bind_sha256(stmt, 1, payment_hash);
res = sqlite3_step(stmt); resb = db_select_step(wallet->db, stmt);
assert(res == SQLITE_ROW); assert(resb);
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) if (sqlite3_column_type(stmt, 0) == SQLITE_NULL)
*failonionreply = NULL; *failonionreply = NULL;
else { else {
@ -2061,22 +2033,20 @@ wallet_payment_list(const tal_t *ctx,
payments = tal_arr(ctx, const struct wallet_payment *, 0); payments = tal_arr(ctx, const struct wallet_payment *, 0);
if (payment_hash) { if (payment_hash) {
stmt = db_prepare(wallet->db, stmt = db_select_prepare(wallet->db,
"SELECT " PAYMENT_FIELDS " FROM payments " PAYMENT_FIELDS " FROM payments "
"WHERE payment_hash = ?;"); "WHERE payment_hash = ?;");
sqlite3_bind_sha256(stmt, 1, payment_hash); sqlite3_bind_sha256(stmt, 1, payment_hash);
} else { } else {
stmt = db_prepare(wallet->db, stmt = db_select_prepare(wallet->db,
"SELECT " PAYMENT_FIELDS " FROM payments;"); PAYMENT_FIELDS " FROM payments;");
} }
for (i = 0; sqlite3_step(stmt) == SQLITE_ROW; i++) { for (i = 0; db_select_step(wallet->db, stmt); i++) {
tal_resize(&payments, i+1); tal_resize(&payments, i+1);
payments[i] = wallet_stmt2payment(payments, stmt); payments[i] = wallet_stmt2payment(payments, stmt);
} }
db_stmt_done(stmt);
/* Now attach payments not yet in db. */ /* Now attach payments not yet in db. */
list_for_each(&wallet->unstored_payments, p, list) { list_for_each(&wallet->unstored_payments, p, list) {
if (payment_hash && !sha256_eq(&p->payment_hash, payment_hash)) if (payment_hash && !sha256_eq(&p->payment_hash, payment_hash))
@ -2109,11 +2079,11 @@ void wallet_htlc_sigs_save(struct wallet *w, u64 channel_id,
bool wallet_network_check(struct wallet *w, bool wallet_network_check(struct wallet *w,
const struct chainparams *chainparams) const struct chainparams *chainparams)
{ {
sqlite3_stmt *stmt = db_query(w->db, sqlite3_stmt *stmt = db_select(w->db,
"SELECT val FROM vars WHERE name='genesis_hash'"); "val FROM vars WHERE name='genesis_hash'");
struct bitcoin_blkid chainhash; struct bitcoin_blkid chainhash;
if (stmt && sqlite3_step(stmt) == SQLITE_ROW) { if (db_select_step(w->db, stmt)) {
sqlite3_column_sha256_double(stmt, 0, &chainhash.shad); sqlite3_column_sha256_double(stmt, 0, &chainhash.shad);
db_stmt_done(stmt); db_stmt_done(stmt);
if (!bitcoin_blkid_eq(&chainhash, if (!bitcoin_blkid_eq(&chainhash,
@ -2133,7 +2103,6 @@ bool wallet_network_check(struct wallet *w,
} else { } else {
/* Still a pristine wallet, claim it for the chain /* Still a pristine wallet, claim it for the chain
* that we are running */ * that we are running */
db_stmt_done(stmt);
stmt = db_prepare(w->db, "INSERT INTO vars (name, val) VALUES ('genesis_hash', ?);"); stmt = db_prepare(w->db, "INSERT INTO vars (name, val) VALUES ('genesis_hash', ?);");
sqlite3_bind_sha256_double(stmt, 1, &chainparams->genesis_blockhash.shad); sqlite3_bind_sha256_double(stmt, 1, &chainparams->genesis_blockhash.shad);
db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
@ -2149,14 +2118,13 @@ static void wallet_utxoset_prune(struct wallet *w, const u32 blockheight)
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
struct bitcoin_txid txid; struct bitcoin_txid txid;
stmt = db_prepare(w->db, "SELECT txid, outnum FROM utxoset WHERE spendheight < ?"); stmt = db_select_prepare(w->db, "txid, outnum FROM utxoset WHERE spendheight < ?");
sqlite3_bind_int(stmt, 1, blockheight - UTXO_PRUNE_DEPTH); sqlite3_bind_int(stmt, 1, blockheight - UTXO_PRUNE_DEPTH);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
sqlite3_column_sha256_double(stmt, 0, &txid.shad); sqlite3_column_sha256_double(stmt, 0, &txid.shad);
outpointfilter_remove(w->utxoset_outpoints, &txid, sqlite3_column_int(stmt, 1)); outpointfilter_remove(w->utxoset_outpoints, &txid, sqlite3_column_int(stmt, 1));
} }
db_stmt_done(stmt);
stmt = db_prepare(w->db, "DELETE FROM utxoset WHERE spendheight < ?"); stmt = db_prepare(w->db, "DELETE FROM utxoset WHERE spendheight < ?");
sqlite3_bind_int(stmt, 1, blockheight - UTXO_PRUNE_DEPTH); sqlite3_bind_int(stmt, 1, blockheight - UTXO_PRUNE_DEPTH);
@ -2189,10 +2157,9 @@ void wallet_block_remove(struct wallet *w, struct block *b)
sqlite3_bind_sha256_double(stmt, 1, &b->blkid.shad); sqlite3_bind_sha256_double(stmt, 1, &b->blkid.shad);
db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
stmt = db_prepare(w->db, "SELECT * FROM blocks WHERE height >= ?;"); stmt = db_select_prepare(w->db, "* FROM blocks WHERE height >= ?;");
sqlite3_bind_int(stmt, 1, b->height); sqlite3_bind_int(stmt, 1, b->height);
assert(sqlite3_step(stmt) == SQLITE_DONE); assert(!db_select_step(w->db, stmt));
db_stmt_done(stmt);
} }
void wallet_blocks_rollback(struct wallet *w, u32 height) void wallet_blocks_rollback(struct wallet *w, u32 height)
@ -2209,7 +2176,7 @@ wallet_outpoint_spend(struct wallet *w, const tal_t *ctx, const u32 blockheight,
{ {
struct short_channel_id *scid; struct short_channel_id *scid;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int res; bool res;
if (outpointfilter_matches(w->owned_outpoints, txid, outnum)) { if (outpointfilter_matches(w->owned_outpoints, txid, outnum)) {
stmt = db_prepare(w->db, stmt = db_prepare(w->db,
"UPDATE outputs " "UPDATE outputs "
@ -2242,15 +2209,15 @@ wallet_outpoint_spend(struct wallet *w, const tal_t *ctx, const u32 blockheight,
} }
/* Now look for the outpoint's short_channel_id */ /* Now look for the outpoint's short_channel_id */
stmt = db_prepare(w->db, stmt = db_select_prepare(w->db,
"SELECT blockheight, txindex " "blockheight, txindex "
"FROM utxoset " "FROM utxoset "
"WHERE txid = ? AND outnum = ?"); "WHERE txid = ? AND outnum = ?");
sqlite3_bind_sha256_double(stmt, 1, &txid->shad); sqlite3_bind_sha256_double(stmt, 1, &txid->shad);
sqlite3_bind_int(stmt, 2, outnum); sqlite3_bind_int(stmt, 2, outnum);
res = sqlite3_step(stmt); res = db_select_step(w->db, stmt);
assert(res == SQLITE_ROW); assert(res);
scid = tal(ctx, struct short_channel_id); scid = tal(ctx, struct short_channel_id);
if (!mk_short_channel_id(scid, sqlite3_column_int(stmt, 0), if (!mk_short_channel_id(scid, sqlite3_column_int(stmt, 0),
@ -2299,7 +2266,7 @@ struct outpoint *wallet_outpoint_for_scid(struct wallet *w, tal_t *ctx,
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
struct outpoint *op; struct outpoint *op;
stmt = db_prepare(w->db, "SELECT" stmt = db_select_prepare(w->db,
" txid," " txid,"
" spendheight," " spendheight,"
" scriptpubkey," " scriptpubkey,"
@ -2314,10 +2281,8 @@ struct outpoint *wallet_outpoint_for_scid(struct wallet *w, tal_t *ctx,
sqlite3_bind_int(stmt, 3, short_channel_id_outnum(scid)); sqlite3_bind_int(stmt, 3, short_channel_id_outnum(scid));
if (sqlite3_step(stmt) != SQLITE_ROW) { if (!db_select_step(w->db, stmt))
db_stmt_done(stmt);
return NULL; return NULL;
}
op = tal(ctx, struct outpoint); op = tal(ctx, struct outpoint);
op->blockheight = short_channel_id_blocknum(scid); op->blockheight = short_channel_id_blocknum(scid);
@ -2337,15 +2302,11 @@ void wallet_transaction_add(struct wallet *w, const struct bitcoin_tx *tx,
const u32 blockheight, const u32 txindex) const u32 blockheight, const u32 txindex)
{ {
struct bitcoin_txid txid; struct bitcoin_txid txid;
sqlite3_stmt *stmt = db_prepare(w->db, "SELECT blockheight FROM transactions WHERE id=?"); sqlite3_stmt *stmt = db_select_prepare(w->db, "blockheight FROM transactions WHERE id=?");
bool known;
bitcoin_txid(tx, &txid); bitcoin_txid(tx, &txid);
sqlite3_bind_sha256(stmt, 1, &txid.shad.sha); sqlite3_bind_sha256(stmt, 1, &txid.shad.sha);
known = sqlite3_step(stmt) == SQLITE_ROW; if (!db_select_step(w->db, stmt)) {
db_stmt_done(stmt);
if (!known) {
/* This transaction is still unknown, insert */ /* This transaction is still unknown, insert */
stmt = db_prepare(w->db, stmt = db_prepare(w->db,
"INSERT INTO transactions (" "INSERT INTO transactions ("
@ -2363,30 +2324,32 @@ void wallet_transaction_add(struct wallet *w, const struct bitcoin_tx *tx,
} }
sqlite3_bind_tx(stmt, 4, tx); sqlite3_bind_tx(stmt, 4, tx);
db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
} else if (blockheight){ } else {
/* We know about the transaction, update */ db_stmt_done(stmt);
stmt = db_prepare(w->db,
"UPDATE transactions " if (blockheight) {
"SET blockheight = ?, txindex = ? " /* We know about the transaction, update */
"WHERE id = ?"); stmt = db_prepare(w->db,
sqlite3_bind_int(stmt, 1, blockheight); "UPDATE transactions "
sqlite3_bind_int(stmt, 2, txindex); "SET blockheight = ?, txindex = ? "
sqlite3_bind_sha256(stmt, 3, &txid.shad.sha); "WHERE id = ?");
db_exec_prepared(w->db, stmt); sqlite3_bind_int(stmt, 1, blockheight);
sqlite3_bind_int(stmt, 2, txindex);
sqlite3_bind_sha256(stmt, 3, &txid.shad.sha);
db_exec_prepared(w->db, stmt);
}
} }
} }
u32 wallet_transaction_height(struct wallet *w, const struct bitcoin_txid *txid) u32 wallet_transaction_height(struct wallet *w, const struct bitcoin_txid *txid)
{ {
u32 blockheight; u32 blockheight;
sqlite3_stmt *stmt = db_prepare( sqlite3_stmt *stmt = db_select_prepare(
w->db, "SELECT blockheight FROM transactions WHERE id=?"); w->db, "blockheight FROM transactions WHERE id=?");
sqlite3_bind_sha256(stmt, 1, &txid->shad.sha); sqlite3_bind_sha256(stmt, 1, &txid->shad.sha);
if (sqlite3_step(stmt) != SQLITE_ROW) { if (!db_select_step(w->db, stmt))
db_stmt_done(stmt);
return 0; return 0;
}
blockheight = sqlite3_column_int(stmt, 0); blockheight = sqlite3_column_int(stmt, 0);
db_stmt_done(stmt); db_stmt_done(stmt);
@ -2399,26 +2362,22 @@ struct txlocator *wallet_transaction_locate(const tal_t *ctx, struct wallet *w,
struct txlocator *loc; struct txlocator *loc;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
stmt = db_prepare( stmt = db_select_prepare(
w->db, "SELECT blockheight, txindex FROM transactions WHERE id=?"); w->db, "blockheight, txindex FROM transactions WHERE id=?");
sqlite3_bind_sha256(stmt, 1, &txid->shad.sha); sqlite3_bind_sha256(stmt, 1, &txid->shad.sha);
if (sqlite3_step(stmt) != SQLITE_ROW) { if (!db_select_step(w->db, stmt))
goto fail; return NULL;
}
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) if (sqlite3_column_type(stmt, 0) == SQLITE_NULL)
goto fail; loc = NULL;
else {
loc = tal(ctx, struct txlocator); loc = tal(ctx, struct txlocator);
loc->blkheight = sqlite3_column_int(stmt, 0); loc->blkheight = sqlite3_column_int(stmt, 0);
loc->index = sqlite3_column_int(stmt, 1); loc->index = sqlite3_column_int(stmt, 1);
}
db_stmt_done(stmt); db_stmt_done(stmt);
return loc; return loc;
fail:
db_stmt_done(stmt);
return NULL;
} }
struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx, struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx,
@ -2428,16 +2387,15 @@ struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx,
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
struct bitcoin_txid *txids = tal_arr(ctx, struct bitcoin_txid, 0); struct bitcoin_txid *txids = tal_arr(ctx, struct bitcoin_txid, 0);
int count = 0; int count = 0;
stmt = db_prepare( stmt = db_select_prepare(
w->db, "SELECT id FROM transactions WHERE blockheight=?"); w->db, "id FROM transactions WHERE blockheight=?");
sqlite3_bind_int(stmt, 1, blockheight); sqlite3_bind_int(stmt, 1, blockheight);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
count++; count++;
tal_resize(&txids, count); tal_resize(&txids, count);
sqlite3_column_sha256(stmt, 0, &txids[count-1].shad.sha); sqlite3_column_sha256(stmt, 0, &txids[count-1].shad.sha);
} }
db_stmt_done(stmt);
return txids; return txids;
} }
@ -2469,15 +2427,14 @@ u32 *wallet_onchaind_channels(struct wallet *w,
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
size_t count = 0; size_t count = 0;
u32 *channel_ids = tal_arr(ctx, u32, 0); u32 *channel_ids = tal_arr(ctx, u32, 0);
stmt = db_prepare(w->db, "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;"); stmt = db_select_prepare(w->db, "DISTINCT(channel_id) FROM channeltxs WHERE type = ?;");
sqlite3_bind_int(stmt, 1, WIRE_ONCHAIN_INIT); sqlite3_bind_int(stmt, 1, WIRE_ONCHAIN_INIT);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
count++; count++;
tal_resize(&channel_ids, count); tal_resize(&channel_ids, count);
channel_ids[count-1] = sqlite3_column_int64(stmt, 0); channel_ids[count-1] = sqlite3_column_int64(stmt, 0);
} }
db_stmt_done(stmt);
return channel_ids; return channel_ids;
} }
@ -2488,8 +2445,7 @@ struct channeltx *wallet_channeltxs_get(struct wallet *w, const tal_t *ctx,
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
size_t count = 0; size_t count = 0;
struct channeltx *res = tal_arr(ctx, struct channeltx, 0); struct channeltx *res = tal_arr(ctx, struct channeltx, 0);
stmt = db_prepare(w->db, stmt = db_select_prepare(w->db,
"SELECT"
" c.type" " c.type"
", c.blockheight" ", c.blockheight"
", t.rawtx" ", t.rawtx"
@ -2502,7 +2458,7 @@ struct channeltx *wallet_channeltxs_get(struct wallet *w, const tal_t *ctx,
"ORDER BY c.id ASC;"); "ORDER BY c.id ASC;");
sqlite3_bind_int(stmt, 1, channel_id); sqlite3_bind_int(stmt, 1, channel_id);
while (sqlite3_step(stmt) == SQLITE_ROW) { while (db_select_step(w->db, stmt)) {
count++; count++;
tal_resize(&res, count); tal_resize(&res, count);
@ -2514,7 +2470,6 @@ struct channeltx *wallet_channeltxs_get(struct wallet *w, const tal_t *ctx,
res[count-1].depth = sqlite3_column_int(stmt, 4); res[count-1].depth = sqlite3_column_int(stmt, 4);
sqlite3_column_sha256(stmt, 5, &res[count-1].txid.shad.sha); sqlite3_column_sha256(stmt, 5, &res[count-1].txid.shad.sha);
} }
db_stmt_done(stmt);
return res; return res;
} }
@ -2547,18 +2502,17 @@ struct amount_msat wallet_total_forward_fees(struct wallet *w)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
struct amount_msat total; struct amount_msat total;
int res; bool res;
stmt = db_prepare(w->db, stmt = db_select_prepare(w->db,
"SELECT"
" SUM(in_msatoshi - out_msatoshi) " " SUM(in_msatoshi - out_msatoshi) "
"FROM forwarded_payments " "FROM forwarded_payments "
"WHERE state = ?;"); "WHERE state = ?;");
sqlite3_bind_int(stmt, 1, wallet_forward_status_in_db(FORWARD_SETTLED)); sqlite3_bind_int(stmt, 1, wallet_forward_status_in_db(FORWARD_SETTLED));
res = sqlite3_step(stmt); res = db_select_step(w->db, stmt);
assert(res == SQLITE_ROW); assert(res);
total = sqlite3_column_amount_msat(stmt, 0); total = sqlite3_column_amount_msat(stmt, 0);
db_stmt_done(stmt); db_stmt_done(stmt);
@ -2572,8 +2526,7 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w,
struct forwarding *results = tal_arr(ctx, struct forwarding, 0); struct forwarding *results = tal_arr(ctx, struct forwarding, 0);
size_t count = 0; size_t count = 0;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
stmt = db_prepare(w->db, stmt = db_select_prepare(w->db,
"SELECT"
" f.state" " f.state"
", in_msatoshi" ", in_msatoshi"
", out_msatoshi" ", out_msatoshi"
@ -2583,7 +2536,7 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w,
"FROM forwarded_payments f " "FROM forwarded_payments f "
"LEFT JOIN channel_htlcs hin ON (f.in_htlc_id == hin.id)"); "LEFT JOIN channel_htlcs hin ON (f.in_htlc_id == hin.id)");
for (count=0; sqlite3_step(stmt) == SQLITE_ROW; count++) { for (count=0; db_select_step(w->db, stmt); count++) {
tal_resize(&results, count+1); tal_resize(&results, count+1);
struct forwarding *cur = &results[count]; struct forwarding *cur = &results[count];
cur->status = sqlite3_column_int(stmt, 0); cur->status = sqlite3_column_int(stmt, 0);
@ -2609,7 +2562,5 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w,
cur->channel_out.u64 = sqlite3_column_int64(stmt, 5); cur->channel_out.u64 = sqlite3_column_int64(stmt, 5);
} }
db_stmt_done(stmt);
return results; return results;
} }

Loading…
Cancel
Save