diff --git a/wallet/wallet.c b/wallet/wallet.c index 794f4df7d..214692b7e 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -83,7 +82,7 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, sqlite3_bind_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, utxo->outnum); sqlite3_bind_int64(stmt, 3, utxo->amount); - sqlite3_bind_int(stmt, 4, type); + sqlite3_bind_int(stmt, 4, wallet_output_type_in_db(type)); sqlite3_bind_int(stmt, 5, output_state_available); sqlite3_bind_int(stmt, 6, utxo->keyindex); if (utxo->close_info) { @@ -161,14 +160,14 @@ bool wallet_update_output_status(struct wallet *w, if (oldstatus != output_state_any) { stmt = db_prepare( w->db, "UPDATE outputs SET status=? WHERE status=? AND prev_out_tx=? AND prev_out_index=?"); - sqlite3_bind_int(stmt, 1, newstatus); - sqlite3_bind_int(stmt, 2, oldstatus); + sqlite3_bind_int(stmt, 1, output_status_in_db(newstatus)); + sqlite3_bind_int(stmt, 2, output_status_in_db(oldstatus)); sqlite3_bind_blob(stmt, 3, txid, sizeof(*txid), SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 4, outnum); } else { stmt = db_prepare( w->db, "UPDATE outputs SET status=? WHERE prev_out_tx=? AND prev_out_index=?"); - sqlite3_bind_int(stmt, 1, newstatus); + sqlite3_bind_int(stmt, 1, output_status_in_db(newstatus)); sqlite3_bind_blob(stmt, 2, txid, sizeof(*txid), SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 3, outnum); } @@ -176,18 +175,26 @@ bool wallet_update_output_status(struct wallet *w, return sqlite3_changes(w->db->sql) > 0; } +#define UTXO_FIELDS \ + "prev_out_tx, prev_out_index, value, type, status, keyindex, " \ + "channel_id, peer_id, commitment_point, confirmation_height, " \ + "spend_height" struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum output_status state) { struct utxo **results; int i; + sqlite3_stmt *stmt; - sqlite3_stmt *stmt = db_prepare( - w->db, "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, " - "channel_id, peer_id, commitment_point, confirmation_height, spend_height " - "FROM outputs WHERE status=?1 OR ?1=255"); - sqlite3_bind_int(stmt, 1, state); + if (state == output_state_any) + stmt = db_prepare(w->db, "SELECT "UTXO_FIELDS + " FROM outputs"); + else { + stmt = db_prepare(w->db, "SELECT "UTXO_FIELDS + " FROM outputs WHERE status=?1"); + 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++) { tal_resize(&results, i+1); results[i] = tal(results, struct utxo); @@ -1211,6 +1218,7 @@ void wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid, wallet->db, "UPDATE channel_htlcs SET hstate=?, payment_key=? WHERE id=?"); + /* FIXME: htlc_state_in_db */ sqlite3_bind_int(stmt, 1, new_state); sqlite3_bind_int64(stmt, 3, htlc_dbid); @@ -1727,7 +1735,7 @@ void wallet_payment_set_status(struct wallet *wallet, "UPDATE payments SET status=? " "WHERE payment_hash=?"); - sqlite3_bind_int(stmt, 1, newstatus); + sqlite3_bind_int(stmt, 1, wallet_payment_status_in_db(newstatus)); sqlite3_bind_sha256(stmt, 2, payment_hash); db_exec_prepared(wallet->db, stmt); diff --git a/wallet/wallet.h b/wallet/wallet.h index fda903e3e..2fa32c48e 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -5,6 +5,7 @@ #include "db.h" #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include @@ -46,6 +48,8 @@ struct wallet { /* Possible states for tracked outputs in the database. Not sure yet * whether we really want to have reservations reflected in the * database, it would simplify queries at the cost of some IO ops */ +/* /!\ This is a DB ENUM, please do not change the numbering of any + * already defined elements (adding is ok) /!\ */ enum output_status { output_state_available= 0, output_state_reserved = 1, @@ -55,10 +59,31 @@ enum output_status { output_state_any = 255 }; +static inline enum output_status output_status_in_db(enum output_status s) +{ + switch (s) { + case output_state_available: + BUILD_ASSERT(output_state_available == 0); + return s; + case output_state_reserved: + BUILD_ASSERT(output_state_reserved == 1); + return s; + case output_state_spent: + BUILD_ASSERT(output_state_spent == 2); + return s; + /* This one doesn't go into db */ + case output_state_any: + break; + } + fatal("%s: %u is invalid", __func__, s); +} + /* Enumeration of all known output types. These include all types that * could ever end up on-chain and we may need to react upon. Notice * that `to_local`, `htlc_offer`, and `htlc_recv` may need immediate * action since they are encumbered with a CSV. */ +/* /!\ This is a DB ENUM, please do not change the numbering of any + * already defined elements (adding is ok) /!\ */ enum wallet_output_type { p2sh_wpkh = 0, to_local = 1, @@ -68,6 +93,31 @@ enum wallet_output_type { p2wpkh = 6 }; +static inline enum wallet_output_type wallet_output_type_in_db(enum wallet_output_type w) +{ + switch (w) { + case p2sh_wpkh: + BUILD_ASSERT(p2sh_wpkh == 0); + return w; + case to_local: + BUILD_ASSERT(to_local == 1); + return w; + case htlc_offer: + BUILD_ASSERT(htlc_offer == 3); + return w; + case htlc_recv: + BUILD_ASSERT(htlc_recv == 4); + return w; + case our_change: + BUILD_ASSERT(our_change == 5); + return w; + case p2wpkh: + BUILD_ASSERT(p2wpkh == 6); + return w; + } + fatal("%s: %u is invalid", __func__, w); +} + /* A database backed shachain struct. The datastructure is * writethrough, reads are performed from an in-memory version, all * writes are passed through to the DB. */ @@ -89,6 +139,22 @@ enum wallet_payment_status { PAYMENT_FAILED = 2 }; +static inline enum wallet_payment_status wallet_payment_status_in_db(enum wallet_payment_status w) +{ + switch (w) { + case PAYMENT_PENDING: + BUILD_ASSERT(PAYMENT_PENDING == 0); + return w; + case PAYMENT_COMPLETE: + BUILD_ASSERT(PAYMENT_COMPLETE == 1); + return w; + case PAYMENT_FAILED: + BUILD_ASSERT(PAYMENT_FAILED == 2); + return w; + } + fatal("%s: %u is invalid", __func__, w); +} + /* Outgoing payments. A simple persisted representation * of a payment we initiated. This can be used by * a UI (alongside invoices) to display the balance history. @@ -424,6 +490,22 @@ enum invoice_status { EXPIRED, }; +static inline enum invoice_status invoice_status_in_db(enum invoice_status s) +{ + switch (s) { + case UNPAID: + BUILD_ASSERT(UNPAID == 0); + return s; + case PAID: + BUILD_ASSERT(PAID == 1); + return s; + case EXPIRED: + BUILD_ASSERT(EXPIRED == 2); + return s; + } + fatal("%s: %u is invalid", __func__, s); +} + /* The information about an invoice */ struct invoice_details { /* Current invoice state */