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_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)
{
int err;
@ -496,24 +526,39 @@ static void PRINTF_FMT(3, 4)
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)
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;
char *query;
char *query = tal_strdup(db, "SELECT ");
sqlite3_stmt *stmt;
assert(db->in_transaction);
va_start(ap, fmt);
query = tal_vfmt(db, fmt, ap);
tal_append_vfmt(&query, fmt, ap);
va_end(ap);
/* Sets stmt to NULL if not SQLITE_OK */
sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL);
stmt = db_query(location, db, query);
if (!stmt)
db_fatal("%s:%s:%s", location, query, sqlite3_errmsg(db->sql));
tal_free(query);
if (stmt)
dev_statement_start(stmt, location);
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)
{
int err;
u64 res = -1;
sqlite3_stmt *stmt = db_query(db, "SELECT version FROM version LIMIT 1");
int res;
sqlite3_stmt *stmt = db_query(__func__,
db, "SELECT version FROM version LIMIT 1");
if (!stmt)
return -1;
err = sqlite3_step(stmt);
if (err != SQLITE_ROW) {
db_stmt_done(stmt);
if (!db_select_step(db, stmt))
return -1;
} else {
res = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
return res;
}
res = sqlite3_column_int64(stmt, 0);
db_stmt_done(stmt);
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)
{
int err;
s64 res = defval;
sqlite3_stmt *stmt =
db_query(db,
"SELECT val FROM vars WHERE name='%s' LIMIT 1", varname);
s64 res;
sqlite3_stmt *stmt;
const char *query;
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)
return defval;
err = sqlite3_step(stmt);
if (err == SQLITE_ROW) {
if (db_select_step(db, stmt)) {
const unsigned char *stringvar = sqlite3_column_text(stmt, 0);
res = atol((const char *)stringvar);
}
db_stmt_done(stmt);
db_stmt_done(stmt);
} else
res = defval;
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);
/**
* 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)
db_query_(const char *location, struct db *db, const char *fmt, ...);
#define db_query(db, ...) \
db_query_(__FILE__ ":" stringify(__LINE__), db, __VA_ARGS__)
db_select_(const char *location, struct db *db, const char *fmt, ...);
#define db_select(db, ...) \
db_select_(__FILE__ ":" stringify(__LINE__), db, __VA_ARGS__)
/**
* 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);
/**
* 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
*

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

331
wallet/wallet.c

@ -34,15 +34,13 @@ static void outpointfilters_init(struct wallet *w)
tal_free(utxos);
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);
outnum = sqlite3_column_int(stmt, 1);
outpointfilter_add(w->utxoset_outpoints, &txid, outnum);
}
db_stmt_done(stmt);
}
struct wallet *wallet_new(struct lightningd *ld,
@ -73,17 +71,16 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo,
{
sqlite3_stmt *stmt;
stmt = db_prepare(w->db,
"SELECT * from outputs WHERE prev_out_tx=? AND prev_out_index=?");
stmt = db_select_prepare(w->db,
"* from outputs WHERE prev_out_tx=? AND prev_out_index=?");
sqlite3_bind_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, utxo->outnum);
/* 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);
return false;
}
db_stmt_done(stmt);
stmt = db_prepare(w->db, "INSERT INTO outputs ("
UTXO_FIELDS
@ -203,22 +200,19 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou
sqlite3_stmt *stmt;
if (state == output_state_any)
stmt = db_prepare(w->db, "SELECT "UTXO_FIELDS
" FROM outputs");
stmt = db_select_prepare(w->db, UTXO_FIELDS " FROM outputs");
else {
stmt = db_prepare(w->db, "SELECT "UTXO_FIELDS
" FROM outputs WHERE status=?1");
stmt = db_select_prepare(w->db, UTXO_FIELDS
" FROM outputs WHERE status=?1");
sqlite3_bind_int(stmt, 1, output_status_in_db(state));
}
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);
tal_arr_expand(&results, u);
}
db_stmt_done(stmt);
return results;
}
@ -227,16 +221,15 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, struct wa
struct utxo **results;
int i;
sqlite3_stmt *stmt = db_prepare(
w->db, "SELECT " UTXO_FIELDS
sqlite3_stmt *stmt = db_select_prepare(
w->db, UTXO_FIELDS
" FROM outputs WHERE channel_id IS NOT NULL and confirmation_height IS NULL");
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);
tal_arr_expand(&results, u);
}
db_stmt_done(stmt);
return results;
}
@ -526,36 +519,30 @@ bool wallet_shachain_add_hash(struct wallet *wallet,
bool wallet_shachain_load(struct wallet *wallet, u64 id,
struct wallet_shachain *chain)
{
int err;
sqlite3_stmt *stmt;
chain->id = id;
shachain_init(&chain->chain);
/* 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);
err = sqlite3_step(stmt);
if (err != SQLITE_ROW) {
db_stmt_done(stmt);
if (!db_select_step(wallet->db, stmt))
return false;
}
chain->chain.min_index = sqlite3_column_int64(stmt, 0);
chain->chain.num_valid = sqlite3_column_int64(stmt, 1);
db_stmt_done(stmt);
/* 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);
while (sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(wallet->db, stmt)) {
int pos = sqlite3_column_int(stmt, 2);
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));
}
db_stmt_done(stmt);
return true;
}
@ -567,13 +554,12 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid)
struct wireaddr_internal addr;
sqlite3_stmt *stmt =
db_query(w->db,
"SELECT id, node_id, address FROM peers WHERE id=%"PRIu64";", dbid);
db_select(w->db,
"id, node_id, address FROM peers WHERE id=%"PRIu64";", dbid);
if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) {
db_stmt_done(stmt);
if (!db_select_step(w->db, stmt))
return NULL;
}
if (!sqlite3_column_pubkey(stmt, 1, &id)) {
db_stmt_done(stmt);
return NULL;
@ -594,17 +580,16 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid)
static secp256k1_ecdsa_signature *
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);
sqlite3_bind_int64(stmt, 1, channelid);
while (stmt && sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(w->db, stmt)) {
secp256k1_ecdsa_signature sig;
sqlite3_column_signature(stmt, 0, &sig);
tal_arr_expand(&htlc_sigs, sig);
}
db_stmt_done(stmt);
log_debug(w->log, "Loaded %zu HTLC signatures from DB",
tal_count(htlc_sigs));
return htlc_sigs;
@ -787,16 +772,16 @@ bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w)
sqlite3_stmt *stmt;
/* We load all channels */
stmt = db_query(w->db, "SELECT %s FROM channels;",
channel_fields);
stmt = db_select(w->db, "%s FROM channels;", channel_fields);
w->max_channel_dbid = 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);
if (!c) {
ok = false;
db_stmt_done(stmt);
break;
}
if (c->dbid > w->max_channel_dbid)
@ -804,7 +789,6 @@ bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w)
count++;
}
log_debug(w->log, "Loaded %d channels from DB", count);
db_stmt_done(stmt);
return ok;
}
@ -857,11 +841,11 @@ void wallet_channel_stats_load(struct wallet *w,
{
sqlite3_stmt *stmt;
int res;
stmt = db_prepare(w->db,
"SELECT in_payments_offered, in_payments_fulfilled"
" , in_msatoshi_offered, in_msatoshi_fulfilled"
" , out_payments_offered, out_payments_fulfilled"
" , out_msatoshi_offered, out_msatoshi_fulfilled"
stmt = db_select_prepare(w->db,
" in_payments_offered, in_payments_fulfilled"
", in_msatoshi_offered, in_msatoshi_fulfilled"
", out_payments_offered, out_payments_fulfilled"
", out_msatoshi_offered, out_msatoshi_fulfilled"
" FROM channels"
" WHERE 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)
{
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 (sqlite3_step(stmt) == SQLITE_ROW && sqlite3_column_type(stmt, 0) != SQLITE_NULL) {
*min = sqlite3_column_int(stmt, 0);
*max = sqlite3_column_int(stmt, 1);
} else {
*min = def;
*max = def;
if (db_select_step(w->db, stmt)) {
if (sqlite3_column_type(stmt, 0) != SQLITE_NULL) {
*min = sqlite3_column_int(stmt, 0);
*max = sqlite3_column_int(stmt, 1);
}
db_stmt_done(stmt);
}
db_stmt_done(stmt);
}
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;
int col = 1;
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, "
"max_accepted_htlcs FROM channel_configs WHERE id=%" PRIu64 ";";
sqlite3_stmt *stmt = db_query(w->db, query, id);
if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) {
db_stmt_done(stmt);
sqlite3_stmt *stmt = db_select(w->db, query, id);
if (!db_select_step(w->db, stmt))
return false;
}
cc->id = id;
cc->dust_limit = sqlite3_column_amount_sat(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;
/* Must not have any channels still using this peer */
stmt = db_query(w->db,
"SELECT * FROM channels WHERE peer_id = %"PRIu64,
peer_dbid);
assert(sqlite3_step(stmt) == SQLITE_DONE);
db_stmt_done(stmt);
stmt = db_select(w->db,
"* FROM channels WHERE peer_id = %"PRIu64,
peer_dbid);
if (db_select_step(w->db, stmt))
fatal("We have channels using peer %"PRIu64, peer_dbid);
stmt = db_prepare(w->db, "DELETE FROM peers WHERE id=?");
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;
log_debug(wallet->log, "Loading HTLCs for channel %"PRIu64, chan->dbid);
sqlite3_stmt *stmt = db_query(
sqlite3_stmt *stmt = db_select(
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_INCOMING, chan->dbid, SENT_REMOVE_ACK_REVOCATION);
if (!stmt) {
log_broken(wallet->log, "Could not select htlc_ins");
return false;
}
while (ok && sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(wallet->db, stmt)) {
struct htlc_in *in = tal(chan, struct htlc_in);
ok &= wallet_stmt2htlc_in(chan, stmt, 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;
incount++;
}
db_stmt_done(stmt);
stmt = db_query(
stmt = db_select(
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_OUTGOING, chan->dbid, RCVD_REMOVE_ACK_REVOCATION);
if (!stmt) {
log_broken(wallet->log, "Could not select htlc_outs");
return false;
}
while (ok && sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(wallet->db, stmt)) {
struct htlc_out *out = tal(chan, struct htlc_out);
ok &= wallet_stmt2htlc_out(chan, stmt, out);
connect_htlc_out(htlcs_out, out);
@ -1538,7 +1512,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
* dependencies in yet */
outcount++;
}
db_stmt_done(stmt);
log_debug(wallet->log, "Restored %d incoming and %d outgoing HTLCS", incount, outcount);
return ok;
@ -1633,15 +1607,15 @@ struct htlc_stub *wallet_htlc_stubs(const tal_t *ctx, struct wallet *wallet,
{
struct htlc_stub *stubs;
struct sha256 payment_hash;
sqlite3_stmt *stmt = db_prepare(wallet->db,
"SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash "
sqlite3_stmt *stmt = db_select_prepare(wallet->db,
"channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash "
"FROM channel_htlcs WHERE channel_id = ?;");
sqlite3_bind_int64(stmt, 1, chan->dbid);
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;
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));
tal_arr_expand(&stubs, stub);
}
db_stmt_done(stmt);
return stubs;
}
@ -1715,13 +1688,13 @@ void wallet_payment_store(struct wallet *wallet,
/* Double-check that it is indeed stored to disk
* (catch bug, where we call this on a payment_hash
* we never paid to) */
int res;
stmt = db_prepare(wallet->db,
"SELECT status FROM payments"
" WHERE payment_hash=?;");
bool res;
stmt = db_select_prepare(wallet->db,
"status FROM payments"
" WHERE payment_hash=?;");
sqlite3_bind_sha256(stmt, 1, payment_hash);
res = sqlite3_step(stmt);
assert(res == SQLITE_ROW);
res = db_select_step(wallet->db, stmt);
assert(res);
db_stmt_done(stmt);
#endif
return;
@ -1859,14 +1832,14 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
if (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 = ?");
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);
db_stmt_done(stmt);
}
db_stmt_done(stmt);
return payment;
}
@ -1930,20 +1903,19 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
int *faildirection)
{
sqlite3_stmt *stmt;
int res;
bool resb;
size_t len;
stmt = db_prepare(wallet->db,
"SELECT failonionreply, faildestperm"
" , failindex, failcode"
" , failnode, failchannel"
" , failupdate, faildetail, faildirection"
" FROM payments"
" WHERE payment_hash=?;");
stmt = db_select_prepare(wallet->db,
"failonionreply, faildestperm"
", failindex, failcode"
", failnode, failchannel"
", failupdate, faildetail, faildirection"
" FROM payments"
" WHERE payment_hash=?;");
sqlite3_bind_sha256(stmt, 1, payment_hash);
res = sqlite3_step(stmt);
assert(res == SQLITE_ROW);
resb = db_select_step(wallet->db, stmt);
assert(resb);
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL)
*failonionreply = NULL;
else {
@ -2061,22 +2033,20 @@ wallet_payment_list(const tal_t *ctx,
payments = tal_arr(ctx, const struct wallet_payment *, 0);
if (payment_hash) {
stmt = db_prepare(wallet->db,
"SELECT " PAYMENT_FIELDS " FROM payments "
"WHERE payment_hash = ?;");
stmt = db_select_prepare(wallet->db,
PAYMENT_FIELDS " FROM payments "
"WHERE payment_hash = ?;");
sqlite3_bind_sha256(stmt, 1, payment_hash);
} else {
stmt = db_prepare(wallet->db,
"SELECT " PAYMENT_FIELDS " FROM payments;");
stmt = db_select_prepare(wallet->db,
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);
payments[i] = wallet_stmt2payment(payments, stmt);
}
db_stmt_done(stmt);
/* Now attach payments not yet in db. */
list_for_each(&wallet->unstored_payments, p, list) {
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,
const struct chainparams *chainparams)
{
sqlite3_stmt *stmt = db_query(w->db,
"SELECT val FROM vars WHERE name='genesis_hash'");
sqlite3_stmt *stmt = db_select(w->db,
"val FROM vars WHERE name='genesis_hash'");
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);
db_stmt_done(stmt);
if (!bitcoin_blkid_eq(&chainhash,
@ -2133,7 +2103,6 @@ bool wallet_network_check(struct wallet *w,
} else {
/* Still a pristine wallet, claim it for the chain
* that we are running */
db_stmt_done(stmt);
stmt = db_prepare(w->db, "INSERT INTO vars (name, val) VALUES ('genesis_hash', ?);");
sqlite3_bind_sha256_double(stmt, 1, &chainparams->genesis_blockhash.shad);
db_exec_prepared(w->db, stmt);
@ -2149,14 +2118,13 @@ static void wallet_utxoset_prune(struct wallet *w, const u32 blockheight)
sqlite3_stmt *stmt;
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);
while (sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(w->db, stmt)) {
sqlite3_column_sha256_double(stmt, 0, &txid.shad);
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 < ?");
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);
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);
assert(sqlite3_step(stmt) == SQLITE_DONE);
db_stmt_done(stmt);
assert(!db_select_step(w->db, stmt));
}
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;
sqlite3_stmt *stmt;
int res;
bool res;
if (outpointfilter_matches(w->owned_outpoints, txid, outnum)) {
stmt = db_prepare(w->db,
"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 */
stmt = db_prepare(w->db,
"SELECT blockheight, txindex "
"FROM utxoset "
"WHERE txid = ? AND outnum = ?");
stmt = db_select_prepare(w->db,
"blockheight, txindex "
"FROM utxoset "
"WHERE txid = ? AND outnum = ?");
sqlite3_bind_sha256_double(stmt, 1, &txid->shad);
sqlite3_bind_int(stmt, 2, outnum);
res = sqlite3_step(stmt);
assert(res == SQLITE_ROW);
res = db_select_step(w->db, stmt);
assert(res);
scid = tal(ctx, struct short_channel_id);
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;
struct outpoint *op;
stmt = db_prepare(w->db, "SELECT"
stmt = db_select_prepare(w->db,
" txid,"
" spendheight,"
" 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));
if (sqlite3_step(stmt) != SQLITE_ROW) {
db_stmt_done(stmt);
if (!db_select_step(w->db, stmt))
return NULL;
}
op = tal(ctx, struct outpoint);
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)
{
struct bitcoin_txid txid;
sqlite3_stmt *stmt = db_prepare(w->db, "SELECT blockheight FROM transactions WHERE id=?");
bool known;
sqlite3_stmt *stmt = db_select_prepare(w->db, "blockheight FROM transactions WHERE id=?");
bitcoin_txid(tx, &txid);
sqlite3_bind_sha256(stmt, 1, &txid.shad.sha);
known = sqlite3_step(stmt) == SQLITE_ROW;
db_stmt_done(stmt);
if (!known) {
if (!db_select_step(w->db, stmt)) {
/* This transaction is still unknown, insert */
stmt = db_prepare(w->db,
"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);
db_exec_prepared(w->db, stmt);
} else if (blockheight){
/* We know about the transaction, update */
stmt = db_prepare(w->db,
"UPDATE transactions "
"SET blockheight = ?, txindex = ? "
"WHERE id = ?");
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);
} else {
db_stmt_done(stmt);
if (blockheight) {
/* We know about the transaction, update */
stmt = db_prepare(w->db,
"UPDATE transactions "
"SET blockheight = ?, txindex = ? "
"WHERE id = ?");
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 blockheight;
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=?");
sqlite3_bind_sha256(stmt, 1, &txid->shad.sha);
if (sqlite3_step(stmt) != SQLITE_ROW) {
db_stmt_done(stmt);
if (!db_select_step(w->db, stmt))
return 0;
}
blockheight = sqlite3_column_int(stmt, 0);
db_stmt_done(stmt);
@ -2399,26 +2362,22 @@ struct txlocator *wallet_transaction_locate(const tal_t *ctx, struct wallet *w,
struct txlocator *loc;
sqlite3_stmt *stmt;
stmt = db_prepare(
w->db, "SELECT blockheight, txindex FROM transactions WHERE id=?");
stmt = db_select_prepare(
w->db, "blockheight, txindex FROM transactions WHERE id=?");
sqlite3_bind_sha256(stmt, 1, &txid->shad.sha);
if (sqlite3_step(stmt) != SQLITE_ROW) {
goto fail;
if (!db_select_step(w->db, stmt))
return NULL;
}
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL)
goto fail;
loc = tal(ctx, struct txlocator);
loc->blkheight = sqlite3_column_int(stmt, 0);
loc->index = sqlite3_column_int(stmt, 1);
loc = NULL;
else {
loc = tal(ctx, struct txlocator);
loc->blkheight = sqlite3_column_int(stmt, 0);
loc->index = sqlite3_column_int(stmt, 1);
}
db_stmt_done(stmt);
return loc;
fail:
db_stmt_done(stmt);
return NULL;
}
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;
struct bitcoin_txid *txids = tal_arr(ctx, struct bitcoin_txid, 0);
int count = 0;
stmt = db_prepare(
w->db, "SELECT id FROM transactions WHERE blockheight=?");
stmt = db_select_prepare(
w->db, "id FROM transactions WHERE blockheight=?");
sqlite3_bind_int(stmt, 1, blockheight);
while (sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(w->db, stmt)) {
count++;
tal_resize(&txids, count);
sqlite3_column_sha256(stmt, 0, &txids[count-1].shad.sha);
}
db_stmt_done(stmt);
return txids;
}
@ -2469,15 +2427,14 @@ u32 *wallet_onchaind_channels(struct wallet *w,
sqlite3_stmt *stmt;
size_t count = 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);
while (sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(w->db, stmt)) {
count++;
tal_resize(&channel_ids, count);
channel_ids[count-1] = sqlite3_column_int64(stmt, 0);
}
db_stmt_done(stmt);
return channel_ids;
}
@ -2488,8 +2445,7 @@ struct channeltx *wallet_channeltxs_get(struct wallet *w, const tal_t *ctx,
sqlite3_stmt *stmt;
size_t count = 0;
struct channeltx *res = tal_arr(ctx, struct channeltx, 0);
stmt = db_prepare(w->db,
"SELECT"
stmt = db_select_prepare(w->db,
" c.type"
", c.blockheight"
", t.rawtx"
@ -2502,7 +2458,7 @@ struct channeltx *wallet_channeltxs_get(struct wallet *w, const tal_t *ctx,
"ORDER BY c.id ASC;");
sqlite3_bind_int(stmt, 1, channel_id);
while (sqlite3_step(stmt) == SQLITE_ROW) {
while (db_select_step(w->db, stmt)) {
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);
sqlite3_column_sha256(stmt, 5, &res[count-1].txid.shad.sha);
}
db_stmt_done(stmt);
return res;
}
@ -2547,18 +2502,17 @@ struct amount_msat wallet_total_forward_fees(struct wallet *w)
{
sqlite3_stmt *stmt;
struct amount_msat total;
int res;
bool res;
stmt = db_prepare(w->db,
"SELECT"
stmt = db_select_prepare(w->db,
" SUM(in_msatoshi - out_msatoshi) "
"FROM forwarded_payments "
"WHERE state = ?;");
sqlite3_bind_int(stmt, 1, wallet_forward_status_in_db(FORWARD_SETTLED));
res = sqlite3_step(stmt);
assert(res == SQLITE_ROW);
res = db_select_step(w->db, stmt);
assert(res);
total = sqlite3_column_amount_msat(stmt, 0);
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);
size_t count = 0;
sqlite3_stmt *stmt;
stmt = db_prepare(w->db,
"SELECT"
stmt = db_select_prepare(w->db,
" f.state"
", in_msatoshi"
", out_msatoshi"
@ -2583,7 +2536,7 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w,
"FROM forwarded_payments f "
"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);
struct forwarding *cur = &results[count];
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);
}
db_stmt_done(stmt);
return results;
}

Loading…
Cancel
Save