Browse Source

wallet: add buildtime and runtime assertions on db enums.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 6 years ago
committed by Christian Decker
parent
commit
7c856470e2
  1. 32
      wallet/wallet.c
  2. 82
      wallet/wallet.h

32
wallet/wallet.c

@ -7,7 +7,6 @@
#include <common/wireaddr.h>
#include <inttypes.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h>
#include <onchaind/gen_onchain_wire.h>
@ -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);

82
wallet/wallet.h

@ -5,6 +5,7 @@
#include "db.h"
#include <bitcoin/chainparams.h>
#include <bitcoin/tx.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/list/list.h>
#include <ccan/tal/tal.h>
@ -13,6 +14,7 @@
#include <lightningd/chaintopology.h>
#include <lightningd/htlc_end.h>
#include <lightningd/invoice.h>
#include <lightningd/log.h>
#include <onchaind/onchain_wire.h>
#include <wally_bip32.h>
@ -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 */

Loading…
Cancel
Save