From 04b1d505b283727b458f295fbbaaa931ed3ba65c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 29 Aug 2022 19:09:49 +0000 Subject: [PATCH] zcash_client_sqlite: Move `DataConnStmtCache` into submodule This removes direct access to the prepared statements, instead forcing callers to use the type-safe methods added in the previous commit. --- zcash_client_sqlite/src/lib.rs | 132 +--------------------------- zcash_client_sqlite/src/prepared.rs | 131 ++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 132 deletions(-) diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 4ea69e22a..e1b2550a8 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -36,7 +36,7 @@ use std::collections::HashMap; use std::fmt; use std::path::Path; -use rusqlite::{Connection, Statement, NO_PARAMS}; +use rusqlite::{Connection, NO_PARAMS}; use zcash_primitives::{ block::BlockHash, @@ -70,6 +70,7 @@ use { }; mod prepared; +pub use prepared::DataConnStmtCache; pub mod chain; pub mod error; @@ -243,135 +244,6 @@ impl WalletReadTransparent for WalletDb

{ } } -/// The primary type used to implement [`WalletWrite`] for the SQLite database. -/// -/// A data structure that stores the SQLite prepared statements that are -/// required for the implementation of [`WalletWrite`] against the backing -/// store. -/// -/// [`WalletWrite`]: zcash_client_backend::data_api::WalletWrite -pub struct DataConnStmtCache<'a, P> { - wallet_db: &'a WalletDb

, - stmt_insert_block: Statement<'a>, - - stmt_insert_tx_meta: Statement<'a>, - stmt_update_tx_meta: Statement<'a>, - - stmt_insert_tx_data: Statement<'a>, - stmt_update_tx_data: Statement<'a>, - stmt_select_tx_ref: Statement<'a>, - - stmt_mark_sapling_note_spent: Statement<'a>, - #[cfg(feature = "transparent-inputs")] - stmt_mark_transparent_utxo_spent: Statement<'a>, - - #[cfg(feature = "transparent-inputs")] - stmt_insert_received_transparent_utxo: Statement<'a>, - #[cfg(feature = "transparent-inputs")] - stmt_delete_utxos: Statement<'a>, - stmt_insert_received_note: Statement<'a>, - stmt_update_received_note: Statement<'a>, - stmt_select_received_note: Statement<'a>, - - stmt_insert_sent_note: Statement<'a>, - stmt_update_sent_note: Statement<'a>, - - stmt_insert_witness: Statement<'a>, - stmt_prune_witnesses: Statement<'a>, - stmt_update_expired: Statement<'a>, -} - -impl<'a, P> DataConnStmtCache<'a, P> { - fn new(wallet_db: &'a WalletDb

) -> Result { - Ok( - DataConnStmtCache { - wallet_db, - stmt_insert_block: wallet_db.conn.prepare( - "INSERT INTO blocks (height, hash, time, sapling_tree) - VALUES (?, ?, ?, ?)", - )?, - stmt_insert_tx_meta: wallet_db.conn.prepare( - "INSERT INTO transactions (txid, block, tx_index) - VALUES (?, ?, ?)", - )?, - stmt_update_tx_meta: wallet_db.conn.prepare( - "UPDATE transactions - SET block = ?, tx_index = ? WHERE txid = ?", - )?, - stmt_insert_tx_data: wallet_db.conn.prepare( - "INSERT INTO transactions (txid, created, expiry_height, raw) - VALUES (?, ?, ?, ?)", - )?, - stmt_update_tx_data: wallet_db.conn.prepare( - "UPDATE transactions - SET expiry_height = ?, raw = ? WHERE txid = ?", - )?, - stmt_select_tx_ref: wallet_db.conn.prepare( - "SELECT id_tx FROM transactions WHERE txid = ?", - )?, - stmt_mark_sapling_note_spent: wallet_db.conn.prepare( - "UPDATE received_notes SET spent = ? WHERE nf = ?" - )?, - #[cfg(feature = "transparent-inputs")] - stmt_mark_transparent_utxo_spent: wallet_db.conn.prepare( - "UPDATE utxos SET spent_in_tx = :spent_in_tx - WHERE prevout_txid = :prevout_txid - AND prevout_idx = :prevout_idx" - )?, - #[cfg(feature = "transparent-inputs")] - stmt_insert_received_transparent_utxo: wallet_db.conn.prepare( - "INSERT INTO utxos (address, prevout_txid, prevout_idx, script, value_zat, height) - VALUES (:address, :prevout_txid, :prevout_idx, :script, :value_zat, :height)" - )?, - #[cfg(feature = "transparent-inputs")] - stmt_delete_utxos: wallet_db.conn.prepare( - "DELETE FROM utxos WHERE address = :address AND height > :above_height" - )?, - stmt_insert_received_note: wallet_db.conn.prepare( - "INSERT INTO received_notes (tx, output_index, account, diversifier, value, rcm, memo, nf, is_change) - VALUES (:tx, :output_index, :account, :diversifier, :value, :rcm, :memo, :nf, :is_change)", - )?, - stmt_update_received_note: wallet_db.conn.prepare( - "UPDATE received_notes - SET account = :account, - diversifier = :diversifier, - value = :value, - rcm = :rcm, - nf = IFNULL(:nf, nf), - memo = IFNULL(:memo, memo), - is_change = IFNULL(:is_change, is_change) - WHERE tx = :tx AND output_index = :output_index", - )?, - stmt_select_received_note: wallet_db.conn.prepare( - "SELECT id_note FROM received_notes WHERE tx = ? AND output_index = ?" - )?, - stmt_update_sent_note: wallet_db.conn.prepare( - "UPDATE sent_notes - SET from_account = ?, address = ?, value = ?, memo = ? - WHERE tx = ? AND output_pool = ? AND output_index = ?", - )?, - stmt_insert_sent_note: wallet_db.conn.prepare( - "INSERT INTO sent_notes (tx, output_pool, output_index, from_account, address, value, memo) - VALUES (?, ?, ?, ?, ?, ?, ?)", - )?, - stmt_insert_witness: wallet_db.conn.prepare( - "INSERT INTO sapling_witnesses (note, block, witness) - VALUES (?, ?, ?)", - )?, - stmt_prune_witnesses: wallet_db.conn.prepare( - "DELETE FROM sapling_witnesses WHERE block < ?" - )?, - stmt_update_expired: wallet_db.conn.prepare( - "UPDATE received_notes SET spent = NULL WHERE EXISTS ( - SELECT id_tx FROM transactions - WHERE id_tx = received_notes.spent AND block IS NULL AND expiry_height < ? - )", - )?, - } - ) - } -} - impl<'a, P: consensus::Parameters> WalletRead for DataConnStmtCache<'a, P> { type Error = SqliteClientError; type NoteRef = NoteId; diff --git a/zcash_client_sqlite/src/prepared.rs b/zcash_client_sqlite/src/prepared.rs index 5cec9224e..ec8b4b6cf 100644 --- a/zcash_client_sqlite/src/prepared.rs +++ b/zcash_client_sqlite/src/prepared.rs @@ -7,7 +7,7 @@ //! - Build the statement in [`DataConnStmtCache::new`]. //! - Add a crate-private helper method to `DataConnStmtCache` for running the statement. -use rusqlite::{params, ToSql}; +use rusqlite::{params, Statement, ToSql}; use zcash_primitives::{ block::BlockHash, consensus::{self, BlockHeight}, @@ -18,7 +18,7 @@ use zcash_primitives::{ zip32::AccountId, }; -use crate::{error::SqliteClientError, wallet::PoolType, DataConnStmtCache, NoteId}; +use crate::{error::SqliteClientError, wallet::PoolType, NoteId, WalletDb}; #[cfg(feature = "transparent-inputs")] use { @@ -28,7 +28,134 @@ use { }, }; +/// The primary type used to implement [`WalletWrite`] for the SQLite database. +/// +/// A data structure that stores the SQLite prepared statements that are +/// required for the implementation of [`WalletWrite`] against the backing +/// store. +/// +/// [`WalletWrite`]: zcash_client_backend::data_api::WalletWrite +pub struct DataConnStmtCache<'a, P> { + pub(crate) wallet_db: &'a WalletDb

, + stmt_insert_block: Statement<'a>, + + stmt_insert_tx_meta: Statement<'a>, + stmt_update_tx_meta: Statement<'a>, + + stmt_insert_tx_data: Statement<'a>, + stmt_update_tx_data: Statement<'a>, + stmt_select_tx_ref: Statement<'a>, + + stmt_mark_sapling_note_spent: Statement<'a>, + #[cfg(feature = "transparent-inputs")] + stmt_mark_transparent_utxo_spent: Statement<'a>, + + #[cfg(feature = "transparent-inputs")] + stmt_insert_received_transparent_utxo: Statement<'a>, + #[cfg(feature = "transparent-inputs")] + stmt_delete_utxos: Statement<'a>, + stmt_insert_received_note: Statement<'a>, + stmt_update_received_note: Statement<'a>, + stmt_select_received_note: Statement<'a>, + + stmt_insert_sent_note: Statement<'a>, + stmt_update_sent_note: Statement<'a>, + + stmt_insert_witness: Statement<'a>, + stmt_prune_witnesses: Statement<'a>, + stmt_update_expired: Statement<'a>, +} + impl<'a, P> DataConnStmtCache<'a, P> { + pub(crate) fn new(wallet_db: &'a WalletDb

) -> Result { + Ok( + DataConnStmtCache { + wallet_db, + stmt_insert_block: wallet_db.conn.prepare( + "INSERT INTO blocks (height, hash, time, sapling_tree) + VALUES (?, ?, ?, ?)", + )?, + stmt_insert_tx_meta: wallet_db.conn.prepare( + "INSERT INTO transactions (txid, block, tx_index) + VALUES (?, ?, ?)", + )?, + stmt_update_tx_meta: wallet_db.conn.prepare( + "UPDATE transactions + SET block = ?, tx_index = ? WHERE txid = ?", + )?, + stmt_insert_tx_data: wallet_db.conn.prepare( + "INSERT INTO transactions (txid, created, expiry_height, raw) + VALUES (?, ?, ?, ?)", + )?, + stmt_update_tx_data: wallet_db.conn.prepare( + "UPDATE transactions + SET expiry_height = ?, raw = ? WHERE txid = ?", + )?, + stmt_select_tx_ref: wallet_db.conn.prepare( + "SELECT id_tx FROM transactions WHERE txid = ?", + )?, + stmt_mark_sapling_note_spent: wallet_db.conn.prepare( + "UPDATE received_notes SET spent = ? WHERE nf = ?" + )?, + #[cfg(feature = "transparent-inputs")] + stmt_mark_transparent_utxo_spent: wallet_db.conn.prepare( + "UPDATE utxos SET spent_in_tx = :spent_in_tx + WHERE prevout_txid = :prevout_txid + AND prevout_idx = :prevout_idx" + )?, + #[cfg(feature = "transparent-inputs")] + stmt_insert_received_transparent_utxo: wallet_db.conn.prepare( + "INSERT INTO utxos (address, prevout_txid, prevout_idx, script, value_zat, height) + VALUES (:address, :prevout_txid, :prevout_idx, :script, :value_zat, :height)" + )?, + #[cfg(feature = "transparent-inputs")] + stmt_delete_utxos: wallet_db.conn.prepare( + "DELETE FROM utxos WHERE address = :address AND height > :above_height" + )?, + stmt_insert_received_note: wallet_db.conn.prepare( + "INSERT INTO received_notes (tx, output_index, account, diversifier, value, rcm, memo, nf, is_change) + VALUES (:tx, :output_index, :account, :diversifier, :value, :rcm, :memo, :nf, :is_change)", + )?, + stmt_update_received_note: wallet_db.conn.prepare( + "UPDATE received_notes + SET account = :account, + diversifier = :diversifier, + value = :value, + rcm = :rcm, + nf = IFNULL(:nf, nf), + memo = IFNULL(:memo, memo), + is_change = IFNULL(:is_change, is_change) + WHERE tx = :tx AND output_index = :output_index", + )?, + stmt_select_received_note: wallet_db.conn.prepare( + "SELECT id_note FROM received_notes WHERE tx = ? AND output_index = ?" + )?, + stmt_update_sent_note: wallet_db.conn.prepare( + "UPDATE sent_notes + SET from_account = ?, address = ?, value = ?, memo = ? + WHERE tx = ? AND output_pool = ? AND output_index = ?", + )?, + stmt_insert_sent_note: wallet_db.conn.prepare( + "INSERT INTO sent_notes (tx, output_pool, output_index, from_account, address, value, memo) + VALUES (?, ?, ?, ?, ?, ?, ?)", + )?, + stmt_insert_witness: wallet_db.conn.prepare( + "INSERT INTO sapling_witnesses (note, block, witness) + VALUES (?, ?, ?)", + )?, + stmt_prune_witnesses: wallet_db.conn.prepare( + "DELETE FROM sapling_witnesses WHERE block < ?" + )?, + stmt_update_expired: wallet_db.conn.prepare( + "UPDATE received_notes SET spent = NULL WHERE EXISTS ( + SELECT id_tx FROM transactions + WHERE id_tx = received_notes.spent AND block IS NULL AND expiry_height < ? + )", + )?, + } + ) + } + /// Inserts information about a scanned block into the database. pub fn stmt_insert_block( &mut self,