wallet: Migrate channel persistence to native sqlite3 binding

Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
Christian Decker 2017-10-20 19:04:43 +02:00 committed by Rusty Russell
parent 9c12c807d1
commit c1d364c5fb
2 changed files with 136 additions and 163 deletions

View File

@ -440,7 +440,7 @@ bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col,
bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx) bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx)
{ {
u8 *ser = linearize_tx(NULL, tx); u8 *ser = linearize_tx(NULL, tx);
sqlite3_bind_blob(stmt, col, tal_hex(ser, ser), 2*tal_len(ser), SQLITE_TRANSIENT); sqlite3_bind_blob(stmt, col, ser, tal_len(ser), SQLITE_TRANSIENT);
tal_free(ser); tal_free(ser);
return true; return true;
} }
@ -448,12 +448,10 @@ bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx)
struct bitcoin_tx *sqlite3_column_tx(const tal_t *ctx, sqlite3_stmt *stmt, struct bitcoin_tx *sqlite3_column_tx(const tal_t *ctx, sqlite3_stmt *stmt,
int col) int col)
{ {
return bitcoin_tx_from_hex( const u8 *src = sqlite3_column_blob(stmt, col);
ctx, size_t len = sqlite3_column_bytes(stmt, col);
sqlite3_column_blob(stmt, col), return pull_bitcoin_tx(ctx, &src, &len);
sqlite3_column_bytes(stmt, col));
} }
bool sqlite3_bind_signature(sqlite3_stmt *stmt, int col, bool sqlite3_bind_signature(sqlite3_stmt *stmt, int col,
const secp256k1_ecdsa_signature *sig) const secp256k1_ecdsa_signature *sig)
{ {
@ -475,18 +473,8 @@ bool sqlite3_column_signature(sqlite3_stmt *stmt, int col,
bool sqlite3_column_pubkey(sqlite3_stmt *stmt, int col, struct pubkey *dest) bool sqlite3_column_pubkey(sqlite3_stmt *stmt, int col, struct pubkey *dest)
{ {
u8 buf[PUBKEY_DER_LEN];
if (sqlite3_column_bytes(stmt, col) == 2*PUBKEY_DER_LEN) {
/* FIXME: Remove the legacy path for hex-values */
if (!sqlite3_column_hexval(stmt, col, buf, sizeof(buf)))
return false;
} else {
assert(sqlite3_column_bytes(stmt, col) == PUBKEY_DER_LEN); assert(sqlite3_column_bytes(stmt, col) == PUBKEY_DER_LEN);
memcpy(buf, sqlite3_column_blob(stmt, col), PUBKEY_DER_LEN); return pubkey_from_der(sqlite3_column_blob(stmt, col), PUBKEY_DER_LEN, dest);
}
return pubkey_from_der(buf, sizeof(buf), dest);
} }
bool sqlite3_bind_pubkey(sqlite3_stmt *stmt, int col, const struct pubkey *pk) bool sqlite3_bind_pubkey(sqlite3_stmt *stmt, int col, const struct pubkey *pk)

View File

@ -342,21 +342,6 @@ bool wallet_shachain_load(struct wallet *wallet, u64 id,
return true; return true;
} }
static bool sqlite3_column_sig(sqlite3_stmt *stmt, int col, secp256k1_ecdsa_signature *sig)
{
u8 buf[64];
if (!sqlite3_column_hexval(stmt, col, buf, sizeof(buf)))
return false;
return secp256k1_ecdsa_signature_parse_compact(secp256k1_ctx, sig, buf) == 1;
}
static u8 *sqlite3_column_varhexblob(tal_t *ctx, sqlite3_stmt *stmt, int col)
{
const u8 *source = sqlite3_column_blob(stmt, col);
size_t sourcelen = sqlite3_column_bytes(stmt, col);
return tal_hexdata(ctx, source, sourcelen);
}
static bool wallet_peer_load(struct wallet *w, const u64 id, struct peer *peer) static bool wallet_peer_load(struct wallet *w, const u64 id, struct peer *peer)
{ {
bool ok = true; bool ok = true;
@ -376,9 +361,8 @@ bool wallet_peer_by_nodeid(struct wallet *w, const struct pubkey *nodeid,
{ {
bool ok; bool ok;
tal_t *tmpctx = tal_tmpctx(w); tal_t *tmpctx = tal_tmpctx(w);
sqlite3_stmt *stmt = db_query( sqlite3_stmt *stmt = db_prepare(w->db, "SELECT id, node_id FROM peers WHERE node_id=?;");
__func__, w->db, "SELECT id, node_id FROM peers WHERE node_id='%s';", sqlite3_bind_pubkey(stmt, 1, nodeid);
pubkey_to_hexstr(tmpctx, nodeid));
ok = stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW; ok = stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW;
if (ok) { if (ok) {
@ -404,8 +388,6 @@ static bool wallet_stmt2channel(struct wallet *w, sqlite3_stmt *stmt,
bool ok = true; bool ok = true;
int col = 0; int col = 0;
struct channel_info *channel_info; struct channel_info *channel_info;
struct sha256_double temphash;
struct short_channel_id scid;
u64 remote_config_id; u64 remote_config_id;
if (!chan->peer) { if (!chan->peer) {
@ -415,11 +397,12 @@ static bool wallet_stmt2channel(struct wallet *w, sqlite3_stmt *stmt,
chan->peer->dbid = sqlite3_column_int64(stmt, col++); chan->peer->dbid = sqlite3_column_int64(stmt, col++);
wallet_peer_load(w, chan->peer->dbid, chan->peer); wallet_peer_load(w, chan->peer->dbid, chan->peer);
if (sqlite3_column_short_channel_id(stmt, col++, &scid)) { if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
chan->peer->scid = tal(chan->peer, struct short_channel_id); chan->peer->scid = tal(chan->peer, struct short_channel_id);
*chan->peer->scid = scid; sqlite3_column_short_channel_id(stmt, col++, chan->peer->scid);
} else { } else {
chan->peer->scid = NULL; chan->peer->scid = NULL;
col++;
} }
chan->peer->our_config.id = sqlite3_column_int64(stmt, col++); chan->peer->our_config.id = sqlite3_column_int64(stmt, col++);
@ -434,12 +417,14 @@ static bool wallet_stmt2channel(struct wallet *w, sqlite3_stmt *stmt,
chan->peer->next_index[REMOTE] = sqlite3_column_int64(stmt, col++); chan->peer->next_index[REMOTE] = sqlite3_column_int64(stmt, col++);
chan->peer->next_htlc_id = sqlite3_column_int64(stmt, col++); chan->peer->next_htlc_id = sqlite3_column_int64(stmt, col++);
if (sqlite3_column_hexval(stmt, col++, &temphash, sizeof(temphash))) { if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
assert(sqlite3_column_bytes(stmt, col) == 32);
chan->peer->funding_txid = tal(chan->peer, struct sha256_double); chan->peer->funding_txid = tal(chan->peer, struct sha256_double);
*chan->peer->funding_txid = temphash; memcpy(chan->peer->funding_txid, sqlite3_column_blob(stmt, col), 32);
} else { } else {
chan->peer->funding_txid = NULL; chan->peer->funding_txid = NULL;
} }
col++;
chan->peer->funding_outnum = sqlite3_column_int(stmt, col++); chan->peer->funding_outnum = sqlite3_column_int(stmt, col++);
chan->peer->funding_satoshi = sqlite3_column_int64(stmt, col++); chan->peer->funding_satoshi = sqlite3_column_int64(stmt, col++);
@ -484,7 +469,8 @@ static bool wallet_stmt2channel(struct wallet *w, sqlite3_stmt *stmt,
/* Do we have a non-null remote_shutdown_scriptpubkey? */ /* Do we have a non-null remote_shutdown_scriptpubkey? */
if (sqlite3_column_type(stmt, col) != SQLITE_NULL) { if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
chan->peer->remote_shutdown_scriptpubkey = sqlite3_column_varhexblob(chan->peer, stmt, col++); chan->peer->remote_shutdown_scriptpubkey = tal_arr(chan->peer, u8, sqlite3_column_bytes(stmt, col));
memcpy(chan->peer->remote_shutdown_scriptpubkey, sqlite3_column_blob(stmt, col), sqlite3_column_bytes(stmt, col));
chan->peer->local_shutdown_idx = sqlite3_column_int64(stmt, col++); chan->peer->local_shutdown_idx = sqlite3_column_int64(stmt, col++);
} else { } else {
chan->peer->remote_shutdown_scriptpubkey = tal_free(chan->peer->remote_shutdown_scriptpubkey); chan->peer->remote_shutdown_scriptpubkey = tal_free(chan->peer->remote_shutdown_scriptpubkey);
@ -508,7 +494,7 @@ static bool wallet_stmt2channel(struct wallet *w, sqlite3_stmt *stmt,
if (sqlite3_column_type(stmt, col) != SQLITE_NULL) { if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
chan->peer->last_tx = sqlite3_column_tx(chan->peer, stmt, col++); chan->peer->last_tx = sqlite3_column_tx(chan->peer, stmt, col++);
chan->peer->last_sig = tal(chan->peer, secp256k1_ecdsa_signature); chan->peer->last_sig = tal(chan->peer, secp256k1_ecdsa_signature);
sqlite3_column_sig(stmt, col++, chan->peer->last_sig); sqlite3_column_signature(stmt, col++, chan->peer->last_sig);
} else { } else {
chan->peer->last_tx = tal_free(chan->peer->last_tx); chan->peer->last_tx = tal_free(chan->peer->last_tx);
chan->peer->last_sig = tal_free(chan->peer->last_sig); chan->peer->last_sig = tal_free(chan->peer->last_sig);
@ -581,54 +567,34 @@ bool wallet_channels_load_active(struct wallet *w, struct list_head *peers)
return ok; return ok;
} }
static char* db_serialize_signature(const tal_t *ctx, secp256k1_ecdsa_signature* sig)
{
u8 buf[64];
if (!sig || secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, buf, sig) != 1)
return "null";
return tal_fmt(ctx, "'%s'", tal_hexstr(ctx, buf, sizeof(buf)));
}
static char* db_serialize_pubkey(const tal_t *ctx, struct pubkey *pk)
{
u8 *der;
if (!pk)
return "NULL";
der = tal_arr(ctx, u8, PUBKEY_DER_LEN);
pubkey_to_der(der, pk);
return tal_hex(ctx, der);
}
static char* db_serialize_tx(const tal_t *ctx, const struct bitcoin_tx *tx)
{
if (!tx)
return "NULL";
return tal_fmt(ctx, "'%s'", tal_hex(ctx, linearize_tx(ctx, tx)));
}
bool wallet_channel_config_save(struct wallet *w, struct channel_config *cc) bool wallet_channel_config_save(struct wallet *w, struct channel_config *cc)
{ {
bool ok = true; bool ok = true;
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) {
ok &= db_exec(__func__, w->db, stmt = db_prepare(
"INSERT INTO channel_configs DEFAULT VALUES;"); w->db,"INSERT INTO channel_configs DEFAULT VALUES;");
ok &= db_exec_prepared(w->db, stmt);
cc->id = sqlite3_last_insert_rowid(w->db->sql); cc->id = sqlite3_last_insert_rowid(w->db->sql);
} }
ok &= db_exec( stmt = db_prepare(w->db, "UPDATE channel_configs SET"
__func__, w->db, "UPDATE channel_configs SET" " dust_limit_satoshis=?,"
" dust_limit_satoshis=%" PRIu64 "," " max_htlc_value_in_flight_msat=?,"
" max_htlc_value_in_flight_msat=%" PRIu64 "," " channel_reserve_satoshis=?,"
" channel_reserve_satoshis=%" PRIu64 "," " htlc_minimum_msat=?,"
" htlc_minimum_msat=%" PRIu64 "," " to_self_delay=?,"
" to_self_delay=%d," " max_accepted_htlcs=?"
" max_accepted_htlcs=%d" " WHERE id=?;");
" WHERE id=%" PRIu64 ";", sqlite3_bind_int64(stmt, 1, cc->dust_limit_satoshis);
cc->dust_limit_satoshis, cc->max_htlc_value_in_flight_msat, sqlite3_bind_int64(stmt, 2, cc->max_htlc_value_in_flight_msat);
cc->channel_reserve_satoshis, cc->htlc_minimum_msat, sqlite3_bind_int64(stmt, 3, cc->channel_reserve_satoshis);
cc->to_self_delay, cc->max_accepted_htlcs, cc->id); sqlite3_bind_int64(stmt, 4, cc->htlc_minimum_msat);
sqlite3_bind_int(stmt, 5, cc->to_self_delay);
sqlite3_bind_int(stmt, 6, cc->max_accepted_htlcs);
sqlite3_bind_int64(stmt, 7, cc->id);
ok &= db_exec_prepared(w->db, stmt);
return ok; return ok;
} }
@ -663,20 +629,23 @@ bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
bool ok = true; bool 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;
if (p->dbid == 0) {
/* Need to store the peer first */
ok &= db_exec(__func__, w->db,
"INSERT INTO peers (node_id) VALUES ('%s');",
db_serialize_pubkey(tmpctx, &chan->peer->id));
p->dbid = sqlite3_last_insert_rowid(w->db->sql);
}
db_begin_transaction(w->db); db_begin_transaction(w->db);
if (p->dbid == 0) {
/* Need to store the peer first */
stmt = db_prepare(w->db, "INSERT INTO peers (node_id) VALUES (?);");
sqlite3_bind_pubkey(stmt, 1, &chan->peer->id);
db_exec_prepared(w->db, stmt);
p->dbid = sqlite3_last_insert_rowid(w->db->sql);
}
/* Insert a stub, that we can update, unifies INSERT and UPDATE paths */ /* Insert a stub, that we can update, unifies INSERT and UPDATE paths */
if (chan->id == 0) { if (chan->id == 0) {
ok &= db_exec(__func__, w->db, "INSERT INTO channels (peer_id) VALUES (%"PRIu64");", p->dbid); stmt = db_prepare(w->db, "INSERT INTO channels (peer_id) VALUES (?);");
sqlite3_bind_int64(stmt, 1, p->dbid);
db_exec_prepared(w->db, stmt);
chan->id = sqlite3_last_insert_rowid(w->db->sql); chan->id = sqlite3_last_insert_rowid(w->db->sql);
} }
@ -688,83 +657,99 @@ bool wallet_channel_save(struct wallet *w, struct wallet_channel *chan){
ok &= wallet_channel_config_save(w, &p->our_config); ok &= wallet_channel_config_save(w, &p->our_config);
/* Now do the real update */ /* Now do the real update */
ok &= db_exec(__func__, w->db, "UPDATE channels SET" stmt = db_prepare(w->db, tal_fmt(w, "UPDATE channels SET"
" shachain_remote_id=%"PRIu64"," " shachain_remote_id=?,"
" short_channel_id=%s," " short_channel_id=?,"
" state=%d," " state=?,"
" funder=%d," " funder=?,"
" channel_flags=%d," " channel_flags=?,"
" minimum_depth=%d," " minimum_depth=?,"
" next_index_local=%"PRIu64"," " next_index_local=?,"
" next_index_remote=%"PRIu64"," " next_index_remote=?,"
" next_htlc_id=%"PRIu64"," " next_htlc_id=?,"
" funding_tx_id=%s," " funding_tx_id=?,"
" funding_tx_outnum=%d," " funding_tx_outnum=?,"
" funding_satoshi=%"PRIu64"," " funding_satoshi=?,"
" funding_locked_remote=%d," " funding_locked_remote=?,"
" push_msatoshi=%"PRIu64"," " push_msatoshi=?,"
" msatoshi_local=%s," " msatoshi_local=?,"
" shutdown_scriptpubkey_remote='%s'," " shutdown_scriptpubkey_remote=?,"
" shutdown_keyidx_local=%"PRId64"," " shutdown_keyidx_local=?,"
" channel_config_local=%"PRIu64"," " channel_config_local=?,"
" last_tx=%s, last_sig=%s" " last_tx=?, last_sig=?"
" WHERE id=%"PRIu64, " WHERE id=?"));
p->their_shachain.id, sqlite3_bind_int64(stmt, 1, p->their_shachain.id);
p->scid?tal_fmt(tmpctx,"'%s'", short_channel_id_to_str(tmpctx, p->scid)):"null", if (p->scid)
p->state, sqlite3_bind_short_channel_id(stmt, 2, p->scid);
p->funder, sqlite3_bind_int(stmt, 3, p->state);
p->channel_flags, sqlite3_bind_int(stmt, 4, p->funder);
p->minimum_depth, sqlite3_bind_int(stmt, 5, p->channel_flags);
p->next_index[LOCAL], sqlite3_bind_int(stmt, 6, p->minimum_depth);
p->next_index[REMOTE],
p->next_htlc_id, sqlite3_bind_int64(stmt, 7, p->next_index[LOCAL]);
p->funding_txid?tal_fmt(tmpctx, "'%s'", tal_hexstr(tmpctx, p->funding_txid, sizeof(struct sha256_double))):"null", sqlite3_bind_int64(stmt, 8, p->next_index[REMOTE]);
p->funding_outnum, sqlite3_bind_int64(stmt, 9, p->next_htlc_id);
p->funding_satoshi,
p->remote_funding_locked, if (p->funding_txid)
p->push_msat, sqlite3_bind_blob(stmt, 10, p->funding_txid, sizeof(*p->funding_txid), SQLITE_TRANSIENT);
p->our_msatoshi?tal_fmt(tmpctx, "%"PRIu64, *p->our_msatoshi):"NULL",
p->remote_shutdown_scriptpubkey?tal_hex(tmpctx, p->remote_shutdown_scriptpubkey):"", sqlite3_bind_int(stmt, 11, p->funding_outnum);
p->local_shutdown_idx, sqlite3_bind_int64(stmt, 12, p->funding_satoshi);
p->our_config.id, sqlite3_bind_int(stmt, 13, p->remote_funding_locked);
db_serialize_tx(tmpctx, p->last_tx), sqlite3_bind_int64(stmt, 14, p->push_msat);
db_serialize_signature(tmpctx, p->last_sig),
chan->id); if (p->our_msatoshi)
sqlite3_bind_int64(stmt, 15, *p->our_msatoshi);
if (p->remote_shutdown_scriptpubkey)
sqlite3_bind_blob(stmt, 16, p->remote_shutdown_scriptpubkey,
tal_len(p->remote_shutdown_scriptpubkey),
SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 17, p->local_shutdown_idx);
sqlite3_bind_int64(stmt, 18, p->our_config.id);
if (p->last_tx)
sqlite3_bind_tx(stmt, 19, p->last_tx);
if (p->last_sig)
sqlite3_bind_signature(stmt, 20, p->last_sig);
sqlite3_bind_int64(stmt, 21, chan->id);
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); ok &= wallet_channel_config_save(w, &p->channel_info->their_config);
ok &= db_exec(__func__, w->db, stmt = db_prepare(w->db, "UPDATE channels SET"
"UPDATE channels SET" " fundingkey_remote=?,"
" fundingkey_remote='%s'," " revocation_basepoint_remote=?,"
" revocation_basepoint_remote='%s'," " payment_basepoint_remote=?,"
" payment_basepoint_remote='%s'," " delayed_payment_basepoint_remote=?,"
" delayed_payment_basepoint_remote='%s'," " per_commit_remote=?,"
" per_commit_remote='%s'," " old_per_commit_remote=?,"
" old_per_commit_remote='%s'," " feerate_per_kw=?,"
" feerate_per_kw=%d," " channel_config_remote=?"
" channel_config_remote=%"PRIu64 " WHERE id=?");
" WHERE id=%"PRIu64, sqlite3_bind_pubkey(stmt, 1, &p->channel_info->remote_fundingkey);
db_serialize_pubkey(tmpctx, &p->channel_info->remote_fundingkey), sqlite3_bind_pubkey(stmt, 2, &p->channel_info->theirbase.revocation);
db_serialize_pubkey(tmpctx, &p->channel_info->theirbase.revocation), sqlite3_bind_pubkey(stmt, 3, &p->channel_info->theirbase.payment);
db_serialize_pubkey(tmpctx, &p->channel_info->theirbase.payment), sqlite3_bind_pubkey(stmt, 4, &p->channel_info->theirbase.delayed_payment);
db_serialize_pubkey(tmpctx, &p->channel_info->theirbase.delayed_payment), sqlite3_bind_pubkey(stmt, 5, &p->channel_info->remote_per_commit);
db_serialize_pubkey(tmpctx, &p->channel_info->remote_per_commit), sqlite3_bind_pubkey(stmt, 6, &p->channel_info->old_remote_per_commit);
db_serialize_pubkey(tmpctx, &p->channel_info->old_remote_per_commit), sqlite3_bind_int(stmt, 7, p->channel_info->feerate_per_kw);
p->channel_info->feerate_per_kw, sqlite3_bind_int64(stmt, 8, p->channel_info->their_config.id);
p->channel_info->their_config.id, sqlite3_bind_int64(stmt, 9, chan->id);
chan->id); ok &= db_exec_prepared(w->db, stmt);
} }
/* If we have a last_sent_commit, store it */ /* If we have a last_sent_commit, store it */
if (chan->peer->last_sent_commit) { if (chan->peer->last_sent_commit) {
ok &= db_exec(__func__, w->db, stmt = db_prepare(w->db,
"UPDATE channels SET" "UPDATE channels SET"
" last_sent_commit_state=%d," " last_sent_commit_state=?,"
" last_sent_commit_id=%"PRIu64 " last_sent_commit_id=?"
" WHERE id=%"PRIu64, " WHERE id=?");
p->last_sent_commit->newstate, sqlite3_bind_int(stmt, 1, p->last_sent_commit->newstate);
p->last_sent_commit->id, sqlite3_bind_int64(stmt, 2, p->last_sent_commit->id);
chan->id); sqlite3_bind_int64(stmt, 3, chan->id);
ok &= db_exec_prepared(w->db, stmt);
} }
if (ok) if (ok)