Use `NULL` to represent the empty memo.

We don't need to store a bunch of copies of the empty memo, and code
should not be depending upon the presence or absence of a memo to
distinguish between different states of transaction retrieval.
This commit is contained in:
Kris Nuttycombe 2022-09-10 09:09:35 -06:00
parent a93c9d334e
commit 3120b304c7
3 changed files with 71 additions and 42 deletions

View File

@ -89,9 +89,9 @@ impl<'a, P> DataConnStmtCache<'a, P> {
)?,
stmt_update_tx_data: wallet_db.conn.prepare(
"UPDATE transactions
SET expiry_height = :expiry_height,
raw = :raw,
fee = IFNULL(:fee, fee)
SET expiry_height = :expiry_height,
raw = :raw,
fee = IFNULL(:fee, fee)
WHERE txid = :txid",
)?,
stmt_select_tx_ref: wallet_db.conn.prepare(
@ -135,12 +135,17 @@ impl<'a, P> DataConnStmtCache<'a, P> {
)?,
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 = ?",
SET from_account = :account,
address = :address,
value = :value,
memo = IFNULL(:memo, memo)
WHERE tx = :tx
AND output_pool = :output_pool
AND output_index = :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 (?, ?, ?, ?, ?, ?, ?)",
VALUES (:tx, :output_pool, :output_index, :from_account, :address, :value, :memo)"
)?,
stmt_insert_witness: wallet_db.conn.prepare(
"INSERT INTO sapling_witnesses (note, block, witness)
@ -396,7 +401,12 @@ impl<'a, P> DataConnStmtCache<'a, P> {
(":value", &(value as i64)),
(":rcm", &rcm.as_ref()),
(":nf", &nf.as_ref().map(|nf| nf.0.as_ref())),
(":memo", &memo.map(|m| m.as_slice())),
(
":memo",
&memo
.filter(|m| *m != &MemoBytes::empty())
.map(|m| m.as_slice()),
),
(":is_change", &is_change),
];
@ -433,7 +443,12 @@ impl<'a, P> DataConnStmtCache<'a, P> {
(":value", &(value as i64)),
(":rcm", &rcm.as_ref()),
(":nf", &nf.as_ref().map(|nf| nf.0.as_ref())),
(":memo", &memo.map(|m| m.as_slice())),
(
":memo",
&memo
.filter(|m| *m != &MemoBytes::empty())
.map(|m| m.as_slice()),
),
(":is_change", &is_change),
(":tx", &tx_ref),
(":output_index", &(output_index as i64)),
@ -478,18 +493,21 @@ impl<'a, P> DataConnStmtCache<'a, P> {
value: Amount,
memo: Option<&MemoBytes>,
) -> Result<(), SqliteClientError> {
let ivalue: i64 = value.into();
self.stmt_insert_sent_note.execute(params![
tx_ref,
pool_type.typecode(),
(output_index as i64),
u32::from(account),
to_str,
ivalue,
memo.filter(|m| *m != &MemoBytes::empty())
.map(|m| m.as_slice()),
])?;
let sql_args: &[(&str, &dyn ToSql)] = &[
(":tx", &tx_ref),
(":output_pool", &pool_type.typecode()),
(":output_index", &i64::try_from(output_index).unwrap()),
(":from_account", &u32::from(account)),
(":address", &to_str),
(":value", &i64::from(value)),
(
":memo",
&memo
.filter(|m| *m != &MemoBytes::empty())
.map(|m| m.as_slice()),
),
];
self.stmt_insert_sent_note.execute_named(sql_args)?;
Ok(())
}
@ -507,17 +525,21 @@ impl<'a, P> DataConnStmtCache<'a, P> {
pool_type: PoolType,
output_index: usize,
) -> Result<bool, SqliteClientError> {
let ivalue: i64 = value.into();
match self.stmt_update_sent_note.execute(params![
u32::from(account),
to_str,
ivalue,
memo.filter(|m| *m != &MemoBytes::empty())
.map(|m| m.as_slice()),
tx_ref,
pool_type.typecode(),
output_index as i64,
])? {
let sql_args: &[(&str, &dyn ToSql)] = &[
(":account", &u32::from(account)),
(":address", &to_str),
(":value", &i64::from(value)),
(
":memo",
&memo
.filter(|m| *m != &MemoBytes::empty())
.map(|m| m.as_slice()),
),
(":tx", &tx_ref),
(":output_pool", &pool_type.typecode()),
(":output_index", &i64::try_from(output_index).unwrap()),
];
match self.stmt_update_sent_note.execute_named(sql_args)? {
0 => Ok(false),
1 => Ok(true),
_ => unreachable!("tx_output constraint is marked as UNIQUE"),

View File

@ -849,7 +849,6 @@ mod tests {
received_notes.is_change AS is_change,
CASE
WHEN received_notes.memo IS NULL THEN 0
WHEN received_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END AS memo_present
FROM transactions
@ -866,7 +865,6 @@ mod tests {
false AS is_change,
CASE
WHEN sent_notes.memo IS NULL THEN 0
WHEN sent_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END AS memo_present
FROM transactions
@ -883,7 +881,6 @@ mod tests {
SUM(
CASE
WHEN received_notes.memo IS NULL THEN 0
WHEN received_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END
) AS memo_count,
@ -906,7 +903,6 @@ mod tests {
SUM(
CASE
WHEN sent_notes.memo IS NULL THEN 0
WHEN sent_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END
) AS memo_count,

View File

@ -102,6 +102,12 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
}
}
transaction.execute_batch(
"UPDATE sent_notes SET memo = NULL
WHERE memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
UPDATE received_notes SET memo = NULL
WHERE memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';")?;
transaction.execute_batch(
"CREATE VIEW v_tx_sent AS
SELECT transactions.id_tx AS id_tx,
@ -115,7 +121,6 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
SUM(
CASE
WHEN sent_notes.memo IS NULL THEN 0
WHEN sent_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END
) AS memo_count,
@ -136,7 +141,6 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
SUM(
CASE
WHEN received_notes.memo IS NULL THEN 0
WHEN received_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END
) AS memo_count,
@ -172,7 +176,6 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
received_notes.is_change AS is_change,
CASE
WHEN received_notes.memo IS NULL THEN 0
WHEN received_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END AS memo_present
FROM transactions
@ -189,7 +192,6 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
false AS is_change,
CASE
WHEN sent_notes.memo IS NULL THEN 0
WHEN sent_notes.memo = X'F600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' THEN 0
ELSE 1
END AS memo_present
FROM transactions
@ -214,7 +216,7 @@ mod tests {
#[cfg(feature = "transparent-inputs")]
use {
crate::wallet::init::{init_wallet_db_internal, WalletMigration2},
crate::wallet::init::WalletMigration2,
rusqlite::params,
zcash_client_backend::{encoding::AddressCodec, keys::UnifiedSpendingKey},
zcash_primitives::{
@ -231,13 +233,20 @@ mod tests {
},
};
use crate::{tests, wallet::init::init_wallet_db, WalletDb};
use crate::{
tests,
wallet::init::{
init_wallet_db, init_wallet_db_internal,
migrations::addresses_table::ADDRESSES_TABLE_MIGRATION,
},
WalletDb,
};
#[test]
fn transaction_views() {
let data_file = NamedTempFile::new().unwrap();
let mut db_data = WalletDb::for_path(data_file.path(), tests::network()).unwrap();
init_wallet_db(&mut db_data, None).unwrap();
init_wallet_db_internal(&mut db_data, None, Some(ADDRESSES_TABLE_MIGRATION)).unwrap();
db_data.conn.execute_batch(
"INSERT INTO accounts (account, ufvk) VALUES (0, '');
@ -257,6 +266,8 @@ mod tests {
VALUES (0, 1, 0, '', 7, '', 'b', true, X'63');",
).unwrap();
init_wallet_db(&mut db_data, None).unwrap();
let mut q = db_data
.conn
.prepare("SELECT received_total, received_note_count, memo_count FROM v_tx_received")