From 301e8b497c3c25a8c75945b1a699a4f5b0ff4068 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 29 Jul 2024 11:41:56 -0600 Subject: [PATCH] zcash_client_sqlite: Add an internal newtype for transaction primary key values. --- zcash_client_sqlite/src/lib.rs | 7 +++++-- zcash_client_sqlite/src/wallet.rs | 19 ++++++++++--------- .../init/migrations/receiving_key_scopes.rs | 4 ++-- zcash_client_sqlite/src/wallet/orchard.rs | 14 +++++++------- zcash_client_sqlite/src/wallet/sapling.rs | 14 +++++++------- zcash_client_sqlite/src/wallet/transparent.rs | 5 +++-- .../src/wallet/transparent/ephemeral.rs | 9 +++++---- 7 files changed, 39 insertions(+), 33 deletions(-) diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index ec20c4b84..1655d1be3 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -177,11 +177,14 @@ impl fmt::Display for ReceivedNoteId { } } -/// A newtype wrapper for sqlite primary key values for the utxos -/// table. +/// A newtype wrapper for sqlite primary key values for the utxos table. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct UtxoId(pub i64); +/// A newtype wrapper for sqlite primary key values for the transactions table. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct TxRef(pub i64); + /// A wrapper for the SQLite connection to the wallet database. pub struct WalletDb { conn: C, diff --git a/zcash_client_sqlite/src/wallet.rs b/zcash_client_sqlite/src/wallet.rs index 9067ad324..f41ec4779 100644 --- a/zcash_client_sqlite/src/wallet.rs +++ b/zcash_client_sqlite/src/wallet.rs @@ -108,6 +108,7 @@ use zcash_primitives::{ }; use zip32::{self, DiversifierIndex, Scope}; +use crate::TxRef; use crate::{ error::SqliteClientError, wallet::commitment_tree::{get_max_checkpointed_height, SqliteShardStore}, @@ -2199,7 +2200,7 @@ pub(crate) fn put_tx_meta( conn: &rusqlite::Connection, tx: &WalletTx, height: BlockHeight, -) -> Result { +) -> Result { // It isn't there, so insert our transaction into the database. let mut stmt_upsert_tx_meta = conn.prepare_cached( "INSERT INTO transactions (txid, block, mined_height, tx_index) @@ -2219,7 +2220,7 @@ pub(crate) fn put_tx_meta( ]; stmt_upsert_tx_meta - .query_row(tx_params, |row| row.get::<_, i64>(0)) + .query_row(tx_params, |row| row.get::<_, i64>(0).map(TxRef)) .map_err(SqliteClientError::from) } @@ -2271,7 +2272,7 @@ pub(crate) fn put_tx_data( tx: &Transaction, fee: Option, created_at: Option, -) -> Result { +) -> Result { let mut stmt_upsert_tx_data = conn.prepare_cached( "INSERT INTO transactions (txid, created, expiry_height, raw, fee) VALUES (:txid, :created_at, :expiry_height, :raw, :fee) @@ -2295,7 +2296,7 @@ pub(crate) fn put_tx_data( ]; stmt_upsert_tx_data - .query_row(tx_params, |row| row.get::<_, i64>(0)) + .query_row(tx_params, |row| row.get::<_, i64>(0).map(TxRef)) .map_err(SqliteClientError::from) } @@ -2332,7 +2333,7 @@ fn recipient_params( pub(crate) fn insert_sent_output( conn: &rusqlite::Connection, params: &P, - tx_ref: i64, + tx_ref: TxRef, from_account: AccountId, output: &SentTransactionOutput, ) -> Result<(), SqliteClientError> { @@ -2347,7 +2348,7 @@ pub(crate) fn insert_sent_output( let (to_address, to_account_id, pool_type) = recipient_params(params, output.recipient()); let sql_args = named_params![ - ":tx": &tx_ref, + ":tx": tx_ref.0, ":output_pool": &pool_code(pool_type), ":output_index": &i64::try_from(output.output_index()).unwrap(), ":from_account_id": from_account.0, @@ -2378,7 +2379,7 @@ pub(crate) fn put_sent_output( conn: &rusqlite::Connection, params: &P, from_account: AccountId, - tx_ref: i64, + tx_ref: TxRef, output_index: usize, recipient: &Recipient, value: NonNegativeAmount, @@ -2401,7 +2402,7 @@ pub(crate) fn put_sent_output( let (to_address, to_account_id, pool_type) = recipient_params(params, recipient); let sql_args = named_params![ - ":tx": &tx_ref, + ":tx": tx_ref.0, ":output_pool": &pool_code(pool_type), ":output_index": &i64::try_from(output_index).unwrap(), ":from_account_id": from_account.0, @@ -2515,7 +2516,7 @@ pub(crate) fn query_nullifier_map>( conn: &rusqlite::Transaction<'_>, spend_pool: ShieldedProtocol, nf: &N, -) -> Result, SqliteClientError> { +) -> Result, SqliteClientError> { let mut stmt_select_locator = conn.prepare_cached( "SELECT block_height, tx_index, txid FROM nullifier_map diff --git a/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs b/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs index 722c609bb..3389af518 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs @@ -516,7 +516,7 @@ mod tests { // Don't need to bother with sent outputs for this test. if output.transfer_type() != TransferType::Outgoing { put_received_note_before_migration( - wdb.conn.0, output, tx_ref, None, + wdb.conn.0, output, tx_ref.0, None, ) .unwrap(); } @@ -529,7 +529,7 @@ mod tests { } } - put_received_note_before_migration(wdb.conn.0, output, tx_ref, None) + put_received_note_before_migration(wdb.conn.0, output, tx_ref.0, None) .unwrap(); } } diff --git a/zcash_client_sqlite/src/wallet/orchard.rs b/zcash_client_sqlite/src/wallet/orchard.rs index 88e7f66f7..cbd8b23b4 100644 --- a/zcash_client_sqlite/src/wallet/orchard.rs +++ b/zcash_client_sqlite/src/wallet/orchard.rs @@ -21,7 +21,7 @@ use zcash_protocol::{ }; use zip32::Scope; -use crate::{error::SqliteClientError, AccountId, ReceivedNoteId}; +use crate::{error::SqliteClientError, AccountId, ReceivedNoteId, TxRef}; use super::{memo_repr, parse_scope, scope_code}; @@ -227,8 +227,8 @@ pub(crate) fn select_spendable_orchard_notes( pub(crate) fn put_received_note( conn: &Transaction, output: &T, - tx_ref: i64, - spent_in: Option, + tx_ref: TxRef, + spent_in: Option, ) -> Result<(), SqliteClientError> { let mut stmt_upsert_received_note = conn.prepare_cached( "INSERT INTO orchard_received_notes @@ -263,7 +263,7 @@ pub(crate) fn put_received_note( let diversifier = to.diversifier(); let sql_args = named_params![ - ":tx": &tx_ref, + ":tx": tx_ref.0, ":action_index": i64::try_from(output.index()).expect("output indices are representable as i64"), ":account_id": output.account_id().0, ":diversifier": diversifier.as_array(), @@ -288,7 +288,7 @@ pub(crate) fn put_received_note( ON CONFLICT (orchard_received_note_id, transaction_id) DO NOTHING", named_params![ ":orchard_received_note_id": received_note_id, - ":transaction_id": spent_in + ":transaction_id": spent_in.0 ], )?; } @@ -366,7 +366,7 @@ pub(crate) fn detect_spending_accounts<'a>( /// spending transaction has been mined. pub(crate) fn mark_orchard_note_spent( conn: &Connection, - tx_ref: i64, + tx_ref: TxRef, nf: &Nullifier, ) -> Result { let mut stmt_mark_orchard_note_spent = conn.prepare_cached( @@ -377,7 +377,7 @@ pub(crate) fn mark_orchard_note_spent( match stmt_mark_orchard_note_spent.execute(named_params![ ":nf": nf.to_bytes(), - ":transaction_id": tx_ref + ":transaction_id": tx_ref.0 ])? { 0 => Ok(false), 1 => Ok(true), diff --git a/zcash_client_sqlite/src/wallet/sapling.rs b/zcash_client_sqlite/src/wallet/sapling.rs index b43ce4a90..1e51df25c 100644 --- a/zcash_client_sqlite/src/wallet/sapling.rs +++ b/zcash_client_sqlite/src/wallet/sapling.rs @@ -20,7 +20,7 @@ use zcash_protocol::{ }; use zip32::Scope; -use crate::{error::SqliteClientError, AccountId, ReceivedNoteId}; +use crate::{error::SqliteClientError, AccountId, ReceivedNoteId, TxRef}; use super::{memo_repr, parse_scope, scope_code}; @@ -300,7 +300,7 @@ pub(crate) fn detect_spending_accounts<'a>( /// spending transaction has been mined. pub(crate) fn mark_sapling_note_spent( conn: &Connection, - tx_ref: i64, + tx_ref: TxRef, nf: &sapling::Nullifier, ) -> Result { let mut stmt_mark_sapling_note_spent = conn.prepare_cached( @@ -311,7 +311,7 @@ pub(crate) fn mark_sapling_note_spent( match stmt_mark_sapling_note_spent.execute(named_params![ ":nf": &nf.0[..], - ":transaction_id": tx_ref + ":transaction_id": tx_ref.0 ])? { 0 => Ok(false), 1 => Ok(true), @@ -327,8 +327,8 @@ pub(crate) fn mark_sapling_note_spent( pub(crate) fn put_received_note( conn: &Transaction, output: &T, - tx_ref: i64, - spent_in: Option, + tx_ref: TxRef, + spent_in: Option, ) -> Result<(), SqliteClientError> { let mut stmt_upsert_received_note = conn.prepare_cached( "INSERT INTO sapling_received_notes @@ -366,7 +366,7 @@ pub(crate) fn put_received_note( let diversifier = to.diversifier(); let sql_args = named_params![ - ":tx": &tx_ref, + ":tx": tx_ref.0, ":output_index": i64::try_from(output.index()).expect("output indices are representable as i64"), ":account_id": output.account_id().0, ":diversifier": &diversifier.0.as_ref(), @@ -390,7 +390,7 @@ pub(crate) fn put_received_note( ON CONFLICT (sapling_received_note_id, transaction_id) DO NOTHING", named_params![ ":sapling_received_note_id": received_note_id, - ":transaction_id": spent_in + ":transaction_id": spent_in.0 ], )?; } diff --git a/zcash_client_sqlite/src/wallet/transparent.rs b/zcash_client_sqlite/src/wallet/transparent.rs index 0db0fca04..4f0d95b9b 100644 --- a/zcash_client_sqlite/src/wallet/transparent.rs +++ b/zcash_client_sqlite/src/wallet/transparent.rs @@ -20,6 +20,7 @@ use zcash_primitives::{ }; use zcash_protocol::consensus::{self, BlockHeight}; +use crate::TxRef; use crate::{error::SqliteClientError, AccountId, UtxoId}; use super::{chain_tip_height, get_account_ids}; @@ -429,7 +430,7 @@ pub(crate) fn add_transparent_account_balances( /// Marks the given UTXO as having been spent. pub(crate) fn mark_transparent_utxo_spent( conn: &rusqlite::Connection, - tx_ref: i64, + tx_ref: TxRef, outpoint: &OutPoint, ) -> Result<(), SqliteClientError> { let mut stmt_mark_transparent_utxo_spent = conn.prepare_cached( @@ -443,7 +444,7 @@ pub(crate) fn mark_transparent_utxo_spent( )?; let sql_args = named_params![ - ":spent_in_tx": &tx_ref, + ":spent_in_tx": tx_ref.0, ":prevout_txid": &outpoint.hash().to_vec(), ":prevout_idx": &outpoint.n(), ]; diff --git a/zcash_client_sqlite/src/wallet/transparent/ephemeral.rs b/zcash_client_sqlite/src/wallet/transparent/ephemeral.rs index 017ad002f..f796d931a 100644 --- a/zcash_client_sqlite/src/wallet/transparent/ephemeral.rs +++ b/zcash_client_sqlite/src/wallet/transparent/ephemeral.rs @@ -15,6 +15,7 @@ use zcash_primitives::{ }; use zcash_protocol::consensus; +use crate::TxRef; use crate::{ error::SqliteClientError, wallet::{get_account, GAP_LIMIT}, @@ -360,7 +361,7 @@ fn ephemeral_address_reuse_check( pub(crate) fn mark_ephemeral_address_as_used( wdb: &mut WalletDb, P>, ephemeral_address: &TransparentAddress, - tx_ref: i64, + tx_ref: TxRef, ) -> Result<(), SqliteClientError> { let address_str = ephemeral_address.encode(&wdb.params); ephemeral_address_reuse_check(wdb, &address_str)?; @@ -377,7 +378,7 @@ pub(crate) fn mark_ephemeral_address_as_used( SET used_in_tx = :tx_ref, seen_in_tx = :tx_ref WHERE address = :address RETURNING account_id, address_index", - named_params![":tx_ref": &tx_ref, ":address": address_str], + named_params![":tx_ref": tx_ref.0, ":address": address_str], |row| Ok((AccountId(row.get::<_, u32>(0)?), row.get::<_, u32>(1)?)), ) .optional()?; @@ -398,7 +399,7 @@ pub(crate) fn mark_ephemeral_address_as_used( pub(crate) fn mark_ephemeral_address_as_seen( wdb: &mut WalletDb, P>, address: &TransparentAddress, - tx_ref: i64, + tx_ref: TxRef, ) -> Result<(), SqliteClientError> { let address_str = address.encode(&wdb.params); @@ -419,7 +420,7 @@ pub(crate) fn mark_ephemeral_address_as_seen( tx_index ASC NULLS LAST, e.seen_in_tx ASC NULLS LAST LIMIT 1", - named_params![":tx_ref": &tx_ref, ":address": address_str], + named_params![":tx_ref": tx_ref.0, ":address": address_str], |row| row.get::<_, i64>(0), )?;