Browse Source

wallet: assume db errors will be fatal, don't check.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
7133a2f9b3
  1. 7
      lightningd/invoice.c
  2. 30
      lightningd/peer_control.c
  3. 30
      lightningd/peer_htlcs.c
  4. 124
      wallet/wallet.c
  5. 12
      wallet/wallet.h
  6. 43
      wallet/wallet_tests.c

7
lightningd/invoice.c

@ -168,12 +168,7 @@ static void json_invoice(struct command *cmd,
return; return;
} }
if (!wallet_invoice_save(cmd->ld->wallet, invoice)) { wallet_invoice_save(cmd->ld->wallet, invoice);
printf("Could not save the invoice to the database: %s",
cmd->ld->wallet->db->err);
command_fail(cmd, "database error");
return;
}
/* Construct bolt11 string. */ /* Construct bolt11 string. */
b11 = new_bolt11(cmd, &invoice->msatoshi); b11 = new_bolt11(cmd, &invoice->msatoshi);

30
lightningd/peer_control.c

@ -252,10 +252,7 @@ void peer_set_condition(struct peer *peer, enum peer_state old_state,
if (peer_persists(peer)) { if (peer_persists(peer)) {
assert(peer->channel != NULL); assert(peer->channel != NULL);
/* TODO(cdecker) Selectively save updated fields to DB */ /* TODO(cdecker) Selectively save updated fields to DB */
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
} }
} }
@ -447,9 +444,7 @@ static struct wallet_channel *peer_channel_new(struct wallet *w,
wallet_peer_by_nodeid(w, &peer->id, peer); wallet_peer_by_nodeid(w, &peer->id, peer);
wc->id = 0; wc->id = 0;
if (!wallet_channel_save(w, wc)) { wallet_channel_save(w, wc);
fatal("Unable to save channel to database: %s", w->db->err);
}
return wc; return wc;
} }
@ -1668,10 +1663,7 @@ static void peer_got_shutdown(struct peer *peer, const u8 *msg)
} }
/* TODO(cdecker) Selectively save updated fields to DB */ /* TODO(cdecker) Selectively save updated fields to DB */
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
} }
void peer_last_tx(struct peer *peer, struct bitcoin_tx *tx, void peer_last_tx(struct peer *peer, struct bitcoin_tx *tx,
@ -1733,11 +1725,7 @@ static void peer_received_closing_signature(struct peer *peer, const u8 *msg)
/* FIXME: Make sure signature is correct! */ /* FIXME: Make sure signature is correct! */
if (better_closing_fee(peer, tx)) { if (better_closing_fee(peer, tx)) {
/* TODO(cdecker) Selectively save updated fields to DB */ /* TODO(cdecker) Selectively save updated fields to DB */
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
peer_last_tx(peer, tx, &sig); peer_last_tx(peer, tx, &sig);
} }
@ -2313,10 +2301,7 @@ static void peer_accept_channel(struct lightningd *ld,
/* Store the channel in the database in order to get a channel /* Store the channel in the database in order to get a channel
* ID that is unique and which we can base the peer_seed on */ * ID that is unique and which we can base the peer_seed on */
peer->channel = peer_channel_new(ld->wallet, peer); peer->channel = peer_channel_new(ld->wallet, peer);
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
peer->seed = tal(peer, struct privkey); peer->seed = tal(peer, struct privkey);
derive_peer_seed(ld, peer->seed, &peer->id, peer->channel->id); derive_peer_seed(ld, peer->seed, &peer->id, peer->channel->id);
@ -2377,10 +2362,7 @@ static void peer_offer_channel(struct lightningd *ld,
/* Store the channel in the database in order to get a channel /* Store the channel in the database in order to get a channel
* ID that is unique and which we can base the peer_seed on */ * ID that is unique and which we can base the peer_seed on */
fc->peer->channel = peer_channel_new(ld->wallet, fc->peer); fc->peer->channel = peer_channel_new(ld->wallet, fc->peer);
if (!wallet_channel_save(fc->peer->ld->wallet, fc->peer->channel)) { wallet_channel_save(fc->peer->ld->wallet, fc->peer->channel);
fatal("Could not save channel to database: %s",
fc->peer->ld->wallet->db->err);
}
fc->peer->seed = tal(fc->peer, struct privkey); fc->peer->seed = tal(fc->peer, struct privkey);
derive_peer_seed(ld, fc->peer->seed, &fc->peer->id, derive_peer_seed(ld, fc->peer->seed, &fc->peer->id,
fc->peer->channel->id); fc->peer->channel->id);

30
lightningd/peer_htlcs.c

@ -56,8 +56,7 @@ static bool htlc_in_update_state(struct peer *peer,
if (!state_update_ok(peer, hin->hstate, newstate, hin->key.id, "in")) if (!state_update_ok(peer, hin->hstate, newstate, hin->key.id, "in"))
return false; return false;
if (!wallet_htlc_update(peer->ld->wallet, hin->dbid, newstate, hin->preimage)) wallet_htlc_update(peer->ld->wallet, hin->dbid, newstate, hin->preimage);
return false;
hin->hstate = newstate; hin->hstate = newstate;
htlc_in_check(hin, __func__); htlc_in_check(hin, __func__);
@ -71,8 +70,7 @@ static bool htlc_out_update_state(struct peer *peer,
if (!state_update_ok(peer, hout->hstate, newstate, hout->key.id, "out")) if (!state_update_ok(peer, hout->hstate, newstate, hout->key.id, "out"))
return false; return false;
if (!wallet_htlc_update(peer->ld->wallet, hout->dbid, newstate, NULL)) wallet_htlc_update(peer->ld->wallet, hout->dbid, newstate, NULL);
return false;
hout->hstate = newstate; hout->hstate = newstate;
htlc_out_check(hout, __func__); htlc_out_check(hout, __func__);
@ -929,12 +927,8 @@ static bool update_out_htlc(struct peer *peer, u64 id, enum htlc_state newstate)
return false; return false;
} }
if (!hout->dbid && !wallet_htlc_save_out(peer->ld->wallet, peer->channel, hout)) { if (!hout->dbid)
peer_internal_error( wallet_htlc_save_out(peer->ld->wallet, peer->channel, hout);
peer, "Unable to save the htlc_out to the database: %s",
peer->ld->wallet->db->err);
return false;
}
if (!htlc_out_update_state(peer, hout, newstate)) if (!htlc_out_update_state(peer, hout, newstate))
return false; return false;
@ -972,10 +966,7 @@ static bool peer_save_commitsig_received(struct peer *peer, u64 commitnum)
peer->next_index[LOCAL]++; peer->next_index[LOCAL]++;
/* FIXME: Save to database, with sig and HTLCs. */ /* FIXME: Save to database, with sig and HTLCs. */
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
return true; return true;
} }
@ -992,11 +983,7 @@ static bool peer_save_commitsig_sent(struct peer *peer, u64 commitnum)
peer->next_index[REMOTE]++; peer->next_index[REMOTE]++;
/* FIXME: Save to database, with sig and HTLCs. */ /* FIXME: Save to database, with sig and HTLCs. */
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
return true; return true;
} }
@ -1293,10 +1280,7 @@ void peer_got_revoke(struct peer *peer, const u8 *msg)
hin = find_htlc_in(&peer->ld->htlcs_in, peer, changed[i].id); hin = find_htlc_in(&peer->ld->htlcs_in, peer, changed[i].id);
local_fail_htlc(hin, failcodes[i]); local_fail_htlc(hin, failcodes[i]);
} }
if (!wallet_channel_save(peer->ld->wallet, peer->channel)) { wallet_channel_save(peer->ld->wallet, peer->channel);
fatal("Could not save channel to database: %s",
peer->ld->wallet->db->err);
}
} }
static void *tal_arr_append_(void **p, size_t size) static void *tal_arr_append_(void **p, size_t size)

124
wallet/wallet.c

@ -137,7 +137,6 @@ const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
u64 *fee_estimate, u64 *changesatoshi) u64 *fee_estimate, u64 *changesatoshi)
{ {
size_t i = 0; size_t i = 0;
bool should_commit;
struct utxo **available; struct utxo **available;
const struct utxo **utxos = tal_arr(ctx, const struct utxo *, 0); const struct utxo **utxos = tal_arr(ctx, const struct utxo *, 0);
*fee_estimate = 0; *fee_estimate = 0;
@ -146,8 +145,9 @@ const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
u64 satoshi_in = 0, weight = (4 + (8 + 22) * 2 + 4) * 4; u64 satoshi_in = 0, weight = (4 + (8 + 22) * 2 + 4) * 4;
tal_add_destructor2(utxos, destroy_utxos, w); tal_add_destructor2(utxos, destroy_utxos, w);
should_commit = db_begin_transaction(w->db); if (!db_begin_transaction(w->db)) {
fatal("Unable to begin transaction: %s", w->db->err);
}
available = wallet_get_utxos(ctx, w, output_state_available); available = wallet_get_utxos(ctx, w, output_state_available);
for (i = 0; i < tal_count(available); i++) { for (i = 0; i < tal_count(available); i++) {
@ -175,12 +175,10 @@ const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
if (satoshi_in < *fee_estimate + value) { if (satoshi_in < *fee_estimate + value) {
/* Could not collect enough inputs, cleanup and bail */ /* Could not collect enough inputs, cleanup and bail */
utxos = tal_free(utxos); utxos = tal_free(utxos);
if (should_commit) db_rollback_transaction(w->db);
db_rollback_transaction(w->db);
} else { } else {
/* Commit the db transaction to persist markings */ /* Commit the db transaction to persist markings */
if (should_commit) db_commit_transaction(w->db);
db_commit_transaction(w->db);
*changesatoshi = satoshi_in - value - *fee_estimate; *changesatoshi = satoshi_in - value - *fee_estimate;
} }
@ -274,21 +272,19 @@ bool wallet_shachain_add_hash(struct wallet *wallet,
const struct sha256 *hash) const struct sha256 *hash)
{ {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
bool should_commit;
bool ok = true;
u32 pos = count_trailing_zeroes(index); u32 pos = count_trailing_zeroes(index);
assert(index < SQLITE_MAX_UINT); assert(index < SQLITE_MAX_UINT);
if (!shachain_add_hash(&chain->chain, index, hash)) { if (!shachain_add_hash(&chain->chain, index, hash)) {
return false; return false;
} }
should_commit = db_begin_transaction(wallet->db); db_begin_transaction(wallet->db);
stmt = db_prepare(wallet->db, "UPDATE shachains SET num_valid=?, min_index=? WHERE id=?"); stmt = db_prepare(wallet->db, "UPDATE shachains SET num_valid=?, min_index=? WHERE id=?");
sqlite3_bind_int(stmt, 1, chain->chain.num_valid); sqlite3_bind_int(stmt, 1, chain->chain.num_valid);
sqlite3_bind_int64(stmt, 2, index); sqlite3_bind_int64(stmt, 2, index);
sqlite3_bind_int64(stmt, 3, chain->id); sqlite3_bind_int64(stmt, 3, chain->id);
ok &= db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
stmt = db_prepare( stmt = db_prepare(
wallet->db, wallet->db,
@ -297,15 +293,9 @@ bool wallet_shachain_add_hash(struct wallet *wallet,
sqlite3_bind_int(stmt, 2, pos); sqlite3_bind_int(stmt, 2, pos);
sqlite3_bind_int64(stmt, 3, index); sqlite3_bind_int64(stmt, 3, index);
sqlite3_bind_blob(stmt, 4, hash, sizeof(*hash), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, 4, hash, sizeof(*hash), SQLITE_TRANSIENT);
ok &= db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
if (should_commit) { return db_commit_transaction(wallet->db);
if (ok)
ok &= db_commit_transaction(wallet->db);
else
db_rollback_transaction(wallet->db);
}
return ok;
} }
bool wallet_shachain_load(struct wallet *wallet, u64 id, bool wallet_shachain_load(struct wallet *wallet, u64 id,
@ -569,15 +559,14 @@ bool wallet_channels_load_active(struct wallet *w, struct list_head *peers)
return ok; return ok;
} }
bool wallet_channel_config_save(struct wallet *w, struct channel_config *cc) void wallet_channel_config_save(struct wallet *w, struct channel_config *cc)
{ {
bool ok = true;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
/* Is this an update? If not insert a stub first */ /* Is this an update? If not insert a stub first */
if (!cc->id) { if (!cc->id) {
stmt = db_prepare( stmt = db_prepare(
w->db,"INSERT INTO channel_configs DEFAULT VALUES;"); w->db,"INSERT INTO channel_configs DEFAULT VALUES;");
ok &= db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
cc->id = sqlite3_last_insert_rowid(w->db->sql); cc->id = sqlite3_last_insert_rowid(w->db->sql);
} }
@ -596,9 +585,7 @@ bool wallet_channel_config_save(struct wallet *w, struct channel_config *cc)
sqlite3_bind_int(stmt, 5, cc->to_self_delay); sqlite3_bind_int(stmt, 5, cc->to_self_delay);
sqlite3_bind_int(stmt, 6, cc->max_accepted_htlcs); sqlite3_bind_int(stmt, 6, cc->max_accepted_htlcs);
sqlite3_bind_int64(stmt, 7, cc->id); sqlite3_bind_int64(stmt, 7, cc->id);
ok &= db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
return ok;
} }
bool wallet_channel_config_load(struct wallet *w, const u64 id, bool wallet_channel_config_load(struct wallet *w, const u64 id,
@ -627,13 +614,12 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id,
return ok; return ok;
} }
bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){ void wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
bool should_commit, ok = true;
struct peer *p = chan->peer; struct peer *p = chan->peer;
tal_t *tmpctx = tal_tmpctx(w); tal_t *tmpctx = tal_tmpctx(w);
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
should_commit = db_begin_transaction(w->db); db_begin_transaction(w->db);
if (p->dbid == 0) { if (p->dbid == 0) {
/* Need to store the peer first */ /* Need to store the peer first */
@ -653,10 +639,10 @@ bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
/* Need to initialize the shachain first so we get an id */ /* Need to initialize the shachain first so we get an id */
if (p->their_shachain.id == 0) { if (p->their_shachain.id == 0) {
ok &= wallet_shachain_init(w, &p->their_shachain); wallet_shachain_init(w, &p->their_shachain);
} }
ok &= wallet_channel_config_save(w, &p->our_config); wallet_channel_config_save(w, &p->our_config);
/* Now do the real update */ /* Now do the real update */
stmt = db_prepare(w->db, tal_fmt(w, "UPDATE channels SET" stmt = db_prepare(w->db, tal_fmt(w, "UPDATE channels SET"
@ -718,7 +704,7 @@ bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
if (chan->peer->channel_info) { if (chan->peer->channel_info) {
ok &= wallet_channel_config_save(w, &p->channel_info->their_config); wallet_channel_config_save(w, &p->channel_info->their_config);
stmt = db_prepare(w->db, "UPDATE channels SET" stmt = db_prepare(w->db, "UPDATE channels SET"
" fundingkey_remote=?," " fundingkey_remote=?,"
" revocation_basepoint_remote=?," " revocation_basepoint_remote=?,"
@ -738,7 +724,7 @@ bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
sqlite3_bind_int(stmt, 7, p->channel_info->feerate_per_kw); sqlite3_bind_int(stmt, 7, p->channel_info->feerate_per_kw);
sqlite3_bind_int64(stmt, 8, p->channel_info->their_config.id); sqlite3_bind_int64(stmt, 8, p->channel_info->their_config.id);
sqlite3_bind_int64(stmt, 9, chan->id); sqlite3_bind_int64(stmt, 9, chan->id);
ok &= db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
} }
/* If we have a last_sent_commit, store it */ /* If we have a last_sent_commit, store it */
@ -751,17 +737,13 @@ bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
sqlite3_bind_int(stmt, 1, p->last_sent_commit->newstate); sqlite3_bind_int(stmt, 1, p->last_sent_commit->newstate);
sqlite3_bind_int64(stmt, 2, p->last_sent_commit->id); sqlite3_bind_int64(stmt, 2, p->last_sent_commit->id);
sqlite3_bind_int64(stmt, 3, chan->id); sqlite3_bind_int64(stmt, 3, chan->id);
ok &= db_exec_prepared(w->db, stmt); db_exec_prepared(w->db, stmt);
} }
if (should_commit) { if (!db_commit_transaction(w->db))
if (ok) fatal("Could not save channel to database: %s", w->db->err);
ok &= db_commit_transaction(w->db);
else
db_rollback_transaction(w->db);
}
tal_free(tmpctx); tal_free(tmpctx);
return ok;
} }
int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx, int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx,
@ -800,10 +782,9 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx,
return num_utxos; return num_utxos;
} }
bool wallet_htlc_save_in(struct wallet *wallet, void wallet_htlc_save_in(struct wallet *wallet,
const struct wallet_channel *chan, struct htlc_in *in) const struct wallet_channel *chan, struct htlc_in *in)
{ {
bool ok = true;
tal_t *tmpctx = tal_tmpctx(wallet); tal_t *tmpctx = tal_tmpctx(wallet);
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@ -839,19 +820,15 @@ bool wallet_htlc_save_in(struct wallet *wallet,
sqlite3_bind_blob(stmt, 10, &in->onion_routing_packet, sqlite3_bind_blob(stmt, 10, &in->onion_routing_packet,
sizeof(in->onion_routing_packet), SQLITE_TRANSIENT); sizeof(in->onion_routing_packet), SQLITE_TRANSIENT);
ok = db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
in->dbid = sqlite3_last_insert_rowid(wallet->db->sql);
tal_free(tmpctx); tal_free(tmpctx);
if (ok) {
in->dbid = sqlite3_last_insert_rowid(wallet->db->sql);
}
return ok;
} }
bool wallet_htlc_save_out(struct wallet *wallet, void wallet_htlc_save_out(struct wallet *wallet,
const struct wallet_channel *chan, const struct wallet_channel *chan,
struct htlc_out *out) struct htlc_out *out)
{ {
bool ok = true;
tal_t *tmpctx = tal_tmpctx(wallet); tal_t *tmpctx = tal_tmpctx(wallet);
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@ -890,20 +867,16 @@ bool wallet_htlc_save_out(struct wallet *wallet,
sqlite3_bind_blob(stmt, 10, &out->onion_routing_packet, sqlite3_bind_blob(stmt, 10, &out->onion_routing_packet,
sizeof(out->onion_routing_packet), SQLITE_TRANSIENT); sizeof(out->onion_routing_packet), SQLITE_TRANSIENT);
ok = db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
out->dbid = sqlite3_last_insert_rowid(wallet->db->sql);
tal_free(tmpctx); tal_free(tmpctx);
if (ok) {
out->dbid = sqlite3_last_insert_rowid(wallet->db->sql);
}
return ok;
} }
bool wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid, void wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid,
const enum htlc_state new_state, const enum htlc_state new_state,
const struct preimage *payment_key) const struct preimage *payment_key)
{ {
bool ok = true;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
/* The database ID must be set by a previous call to /* The database ID must be set by a previous call to
@ -919,8 +892,7 @@ bool wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid,
if (payment_key) if (payment_key)
sqlite3_bind_preimage(stmt, 2, payment_key); sqlite3_bind_preimage(stmt, 2, payment_key);
ok = db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
return ok;
} }
static bool wallet_stmt2htlc_in(const struct wallet_channel *channel, static bool wallet_stmt2htlc_in(const struct wallet_channel *channel,
@ -1090,7 +1062,7 @@ bool wallet_htlcs_reconnect(struct wallet *wallet,
return true; return true;
} }
bool wallet_invoice_save(struct wallet *wallet, struct invoice *inv) void wallet_invoice_save(struct wallet *wallet, struct invoice *inv)
{ {
/* Need to use the lower level API of sqlite3 to bind /* Need to use the lower level API of sqlite3 to bind
* label. Otherwise we'd need to implement sanitization of * label. Otherwise we'd need to implement sanitization of
@ -1099,10 +1071,8 @@ bool wallet_invoice_save(struct wallet *wallet, struct invoice *inv)
if (!inv->id) { if (!inv->id) {
stmt = db_prepare(wallet->db, stmt = db_prepare(wallet->db,
"INSERT INTO invoices (payment_hash, payment_key, state, msatoshi, label) VALUES (?, ?, ?, ?, ?);"); "INSERT INTO invoices (payment_hash, payment_key, state, msatoshi, label) VALUES (?, ?, ?, ?, ?);");
if (!stmt) { if (!stmt)
log_broken(wallet->log, "Could not prepare statement: %s", wallet->db->err); fatal("Could not prepare statement: %s", wallet->db->err);
return false;
}
sqlite3_bind_blob(stmt, 1, &inv->rhash, sizeof(inv->rhash), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, 1, &inv->rhash, sizeof(inv->rhash), SQLITE_TRANSIENT);
sqlite3_bind_blob(stmt, 2, &inv->r, sizeof(inv->r), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, 2, &inv->r, sizeof(inv->r), SQLITE_TRANSIENT);
@ -1110,30 +1080,21 @@ bool wallet_invoice_save(struct wallet *wallet, struct invoice *inv)
sqlite3_bind_int64(stmt, 4, inv->msatoshi); sqlite3_bind_int64(stmt, 4, inv->msatoshi);
sqlite3_bind_text(stmt, 5, inv->label, strlen(inv->label), SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 5, inv->label, strlen(inv->label), SQLITE_TRANSIENT);
if (!db_exec_prepared(wallet->db, stmt)) { if (!db_exec_prepared(wallet->db, stmt))
log_broken(wallet->log, "Could not exec prepared statement: %s", wallet->db->err); fatal("Could not exec prepared statement: %s", wallet->db->err);
return false;
}
inv->id = sqlite3_last_insert_rowid(wallet->db->sql); inv->id = sqlite3_last_insert_rowid(wallet->db->sql);
return true;
} else { } else {
stmt = db_prepare(wallet->db, "UPDATE invoices SET state=? WHERE id=?;"); stmt = db_prepare(wallet->db, "UPDATE invoices SET state=? WHERE id=?;");
if (!stmt) { if (!stmt)
log_broken(wallet->log, "Could not prepare statement: %s", wallet->db->err); fatal("Could not prepare statement: %s", wallet->db->err);
return false;
}
sqlite3_bind_int(stmt, 1, inv->state); sqlite3_bind_int(stmt, 1, inv->state);
sqlite3_bind_int64(stmt, 2, inv->id); sqlite3_bind_int64(stmt, 2, inv->id);
if (!db_exec_prepared(wallet->db, stmt)) { if (!db_exec_prepared(wallet->db, stmt))
log_broken(wallet->log, "Could not exec prepared statement: %s", wallet->db->err); fatal("Could not exec prepared statement: %s", wallet->db->err);
return false;
} else {
return true;
}
} }
} }
@ -1195,10 +1156,9 @@ struct htlc_stub *wallet_htlc_stubs(tal_t *ctx, struct wallet *wallet,
"SELECT channel_id, direction, cltv_expiry, payment_hash " "SELECT channel_id, direction, cltv_expiry, payment_hash "
"FROM channel_htlcs WHERE channel_id = ?;"); "FROM channel_htlcs WHERE channel_id = ?;");
if (!stmt) { if (!stmt)
log_broken(wallet->log, "Error preparing select: %s", wallet->db->err); fatal("Error preparing select: %s", wallet->db->err);
return NULL;
}
sqlite3_bind_int64(stmt, 1, chan->id); sqlite3_bind_int64(stmt, 1, chan->id);
stubs = tal_arr(ctx, struct htlc_stub, 0); stubs = tal_arr(ctx, struct htlc_stub, 0);

12
wallet/wallet.h

@ -179,12 +179,12 @@ bool wallet_channel_load(struct wallet *w, const u64 id,
* @chan: the instance to store (not const so we can update the unique_id upon * @chan: the instance to store (not const so we can update the unique_id upon
* insert) * insert)
*/ */
bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan); void wallet_channel_save(struct wallet *w, struct wallet_channel *chan);
/** /**
* wallet_channel_config_save -- Upsert a channel_config into the database * wallet_channel_config_save -- Upsert a channel_config into the database
*/ */
bool wallet_channel_config_save(struct wallet *w, struct channel_config *cc); void wallet_channel_config_save(struct wallet *w, struct channel_config *cc);
/** /**
* wallet_channel_config_load -- Load channel_config from database into cc * wallet_channel_config_load -- Load channel_config from database into cc
@ -237,7 +237,7 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx,
* for state transitions or to set the `payment_key` for completed * for state transitions or to set the `payment_key` for completed
* HTLCs. * HTLCs.
*/ */
bool wallet_htlc_save_in(struct wallet *wallet, void wallet_htlc_save_in(struct wallet *wallet,
const struct wallet_channel *chan, struct htlc_in *in); const struct wallet_channel *chan, struct htlc_in *in);
/** /**
@ -245,7 +245,7 @@ bool wallet_htlc_save_in(struct wallet *wallet,
* *
* See comment for wallet_htlc_save_in. * See comment for wallet_htlc_save_in.
*/ */
bool wallet_htlc_save_out(struct wallet *wallet, void wallet_htlc_save_out(struct wallet *wallet,
const struct wallet_channel *chan, const struct wallet_channel *chan,
struct htlc_out *out); struct htlc_out *out);
@ -262,7 +262,7 @@ bool wallet_htlc_save_out(struct wallet *wallet,
* `struct htlc_out` and optionally set the `payment_key` should the * `struct htlc_out` and optionally set the `payment_key` should the
* HTLC have been settled. * HTLC have been settled.
*/ */
bool wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid, void wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid,
const enum htlc_state new_state, const enum htlc_state new_state,
const struct preimage *payment_key); const struct preimage *payment_key);
@ -312,7 +312,7 @@ bool wallet_htlcs_reconnect(struct wallet *wallet,
* @wallet: Wallet to store in * @wallet: Wallet to store in
* @inv: Invoice to save * @inv: Invoice to save
*/ */
bool wallet_invoice_save(struct wallet *wallet, struct invoice *inv); void wallet_invoice_save(struct wallet *wallet, struct invoice *inv);
/** /**
* wallet_invoices_load -- Load all invoices into memory * wallet_invoices_load -- Load all invoices into memory

43
wallet/wallet_tests.c

@ -27,6 +27,9 @@ static void wallet_fatal(const char *fmt, ...)
va_end(ap); va_end(ap);
} }
#define transaction_wrap(db, ...) \
(db_begin_transaction(db), __VA_ARGS__, db_commit_transaction(db))
void invoice_add(struct invoices *invs, void invoice_add(struct invoices *invs,
struct invoice *inv){} struct invoice *inv){}
@ -259,7 +262,9 @@ static bool test_channel_crud(const tal_t *ctx)
ci.old_remote_per_commit = pk; ci.old_remote_per_commit = pk;
/* Variant 1: insert with null for scid, funding_tx_id, channel_info, last_tx */ /* Variant 1: insert with null for scid, funding_tx_id, channel_info, last_tx */
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err)); wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err,
tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v1)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v1)");
@ -270,7 +275,9 @@ static bool test_channel_crud(const tal_t *ctx)
/* Variant 2: update with scid set */ /* Variant 2: update with scid set */
c1.peer->scid = talz(w, struct short_channel_id); c1.peer->scid = talz(w, struct short_channel_id);
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err)); wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err,
tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v2)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v2)");
@ -281,32 +288,38 @@ static bool test_channel_crud(const tal_t *ctx)
/* Variant 3: update with our_satoshi set */ /* Variant 3: update with our_satoshi set */
c1.peer->our_msatoshi = &msat; c1.peer->our_msatoshi = &msat;
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err));
wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v3)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v3)");
/* Variant 4: update with funding_tx_id */ /* Variant 4: update with funding_tx_id */
c1.peer->funding_txid = hash; c1.peer->funding_txid = hash;
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err)); wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v4)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v4)");
/* Variant 5: update with channel_info */ /* Variant 5: update with channel_info */
p.channel_info = &ci; p.channel_info = &ci;
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err)); wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v5)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v5)");
/* Variant 6: update with last_commit_sent */ /* Variant 6: update with last_commit_sent */
p.last_sent_commit = &last_commit; p.last_sent_commit = &last_commit;
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err)); wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v6)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v6)");
/* Variant 7: update with last_tx (taken from BOLT #3) */ /* Variant 7: update with last_tx (taken from BOLT #3) */
p.last_tx = bitcoin_tx_from_hex(w, "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", strlen("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220")); p.last_tx = bitcoin_tx_from_hex(w, "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", strlen("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"));
p.last_sig = sig; p.last_sig = sig;
CHECK_MSG(wallet_channel_save(w, &c1), tal_fmt(w, "Insert into DB: %s", w->db->err)); wallet_channel_save(w, &c1);
CHECK_MSG(!wallet_err, tal_fmt(w, "Insert into DB: %s", w->db->err));
CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err)); CHECK_MSG(wallet_channel_load(w, c1.id, c2), tal_fmt(w, "Load from DB: %s", w->db->err));
CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v7)"); CHECK_MSG(channelseq(&c1, c2), "Compare loaded with saved (v7)");
@ -328,7 +341,7 @@ static bool test_channel_config_crud(const tal_t *ctx)
cc1->to_self_delay = 5; cc1->to_self_delay = 5;
cc1->max_accepted_htlcs = 6; cc1->max_accepted_htlcs = 6;
CHECK(wallet_channel_config_save(w, cc1)); CHECK(transaction_wrap(w->db, wallet_channel_config_save(w, cc1)));
CHECK_MSG( CHECK_MSG(
cc1->id == 1, cc1->id == 1,
tal_fmt(ctx, "channel_config->id != 1; got %" PRIu64, cc1->id)); tal_fmt(ctx, "channel_config->id != 1; got %" PRIu64, cc1->id));
@ -369,23 +382,25 @@ static bool test_htlc_crud(const tal_t *ctx)
out.msatoshi = 41; out.msatoshi = 41;
/* Store the htlc_in */ /* Store the htlc_in */
CHECK_MSG(wallet_htlc_save_in(w, chan, &in), CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_in(w, chan, &in)),
tal_fmt(ctx, "Save htlc_in failed: %s", w->db->err)); tal_fmt(ctx, "Save htlc_in failed: %s", w->db->err));
CHECK_MSG(in.dbid != 0, "HTLC DB ID was not set."); CHECK_MSG(in.dbid != 0, "HTLC DB ID was not set.");
/* Saving again should get us a collision */ /* Saving again should get us a collision */
CHECK_MSG(!wallet_htlc_save_in(w, chan, &in), CHECK_MSG(!transaction_wrap(w->db, wallet_htlc_save_in(w, chan, &in)),
"Saving two HTLCs with the same data must not succeed."); "Saving two HTLCs with the same data must not succeed.");
/* Update */ /* Update */
CHECK_MSG(wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL), CHECK_MSG(transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, RCVD_ADD_HTLC, NULL)),
"Update HTLC with null payment_key failed"); "Update HTLC with null payment_key failed");
CHECK_MSG( CHECK_MSG(
wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, &payment_key), transaction_wrap(w->db, wallet_htlc_update(w, in.dbid, SENT_REMOVE_HTLC, &payment_key)),
"Update HTLC with payment_key failed"); "Update HTLC with payment_key failed");
CHECK_MSG(wallet_htlc_save_out(w, chan, &out), CHECK_MSG(transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
tal_fmt(ctx, "Save htlc_out failed: %s", w->db->err)); tal_fmt(ctx, "Save htlc_out failed: %s", w->db->err));
CHECK_MSG(out.dbid != 0, "HTLC DB ID was not set."); CHECK_MSG(out.dbid != 0, "HTLC DB ID was not set.");
CHECK_MSG(!wallet_htlc_save_out(w, chan, &out),
CHECK_MSG(!transaction_wrap(w->db, wallet_htlc_save_out(w, chan, &out)),
"Saving two HTLCs with the same data must not succeed."); "Saving two HTLCs with the same data must not succeed.");
/* Attempt to load them from the DB again */ /* Attempt to load them from the DB again */

Loading…
Cancel
Save