Reuse sent note insertion for wallet/transact.

This commit is contained in:
Kris Nuttycombe 2020-08-25 18:31:21 -06:00
parent 68737dd1dd
commit e144015558
3 changed files with 67 additions and 45 deletions

View File

@ -10,6 +10,7 @@ use zcash_primitives::{
};
use crate::{
address::RecipientAddress,
decrypt::DecryptedOutput,
proto::compact_formats::CompactBlock,
wallet::{AccountId, WalletShieldedOutput, WalletTx},
@ -114,7 +115,7 @@ pub trait DBUpdate {
fn put_tx_data(&mut self, tx: &Transaction) -> Result<Self::TxRef, Self::Error>;
fn mark_spent(&mut self, tx_ref: Self::TxRef, nf: &Vec<u8>) -> Result<(), Self::Error>;
fn mark_spent(&mut self, tx_ref: Self::TxRef, nf: &[u8]) -> Result<(), Self::Error>;
fn put_received_note<T: ShieldedOutput>(
&mut self,
@ -140,6 +141,17 @@ pub trait DBUpdate {
output: &DecryptedOutput,
tx_ref: Self::TxRef,
) -> Result<(), Self::Error>;
fn insert_sent_note<P: consensus::Parameters>(
&mut self,
params: &P,
tx_ref: Self::TxRef,
output_index: usize,
account: AccountId,
to: &RecipientAddress,
value: Amount,
memo: Option<Memo>,
) -> Result<(), Self::Error>;
}
pub trait CacheOps {

View File

@ -35,6 +35,7 @@ use zcash_primitives::{
block::BlockHash,
consensus::{self, BlockHeight},
merkle_tree::{CommitmentTree, IncrementalWitness},
note_encryption::Memo,
primitives::PaymentAddress,
sapling::Node,
transaction::{components::Amount, Transaction, TxId},
@ -42,7 +43,8 @@ use zcash_primitives::{
};
use zcash_client_backend::{
data_api::{CacheOps, DBOps, DBUpdate, ShieldedOutput},
address::RecipientAddress,
data_api::{error::Error, CacheOps, DBOps, DBUpdate, ShieldedOutput},
encoding::encode_payment_address,
proto::compact_formats::CompactBlock,
wallet::{AccountId, WalletTx},
@ -381,7 +383,7 @@ impl<'a> DBUpdate for DataConnStmtCache<'a> {
}
}
fn mark_spent(&mut self, tx_ref: Self::TxRef, nf: &Vec<u8>) -> Result<(), Self::Error> {
fn mark_spent(&mut self, tx_ref: Self::TxRef, nf: &[u8]) -> Result<(), Self::Error> {
self.stmt_mark_recived_note_spent
.execute(&[tx_ref.to_sql()?, nf.to_sql()?])?;
Ok(())
@ -487,18 +489,44 @@ impl<'a> DBUpdate for DataConnStmtCache<'a> {
])? == 0
{
// It isn't there, so insert.
self.stmt_insert_sent_note.execute(&[
tx_ref.to_sql()?,
output_index.to_sql()?,
account.to_sql()?,
to_str.to_sql()?,
value.to_sql()?,
output.memo.as_bytes().to_sql()?,
])?;
self.insert_sent_note(
params,
tx_ref,
output.index,
AccountId(output.account as u32),
&RecipientAddress::Shielded(output.to.clone()),
Amount::from_u64(output.note.value)
.map_err(|_| Error::CorruptedData("Note value invalue."))?,
Some(output.memo.clone()),
)?
}
Ok(())
}
fn insert_sent_note<P: consensus::Parameters>(
&mut self,
params: &P,
tx_ref: Self::TxRef,
output_index: usize,
account: AccountId,
to: &RecipientAddress,
value: Amount,
memo: Option<Memo>,
) -> Result<(), Self::Error> {
let to_str = to.encode(params);
let ivalue: i64 = value.into();
self.stmt_insert_sent_note.execute(&[
tx_ref.to_sql()?,
(output_index as i64).to_sql()?,
account.0.to_sql()?,
to_str.to_sql()?,
ivalue.to_sql()?,
memo.map(|m| m.as_bytes().to_vec()).to_sql()?,
])?;
Ok(())
}
}
pub struct CacheConnection(Connection);

View File

@ -21,8 +21,9 @@ use zcash_primitives::{
use zcash_client_backend::{
address::RecipientAddress,
data_api::{chain::get_target_and_anchor_heights, error::Error},
data_api::{chain::get_target_and_anchor_heights, error::Error, DBOps, DBUpdate},
encoding::encode_extended_full_viewing_key,
wallet::AccountId,
};
use crate::{error::SqliteClientError, DataConnection};
@ -303,6 +304,7 @@ pub fn create_to_address<P: consensus::Parameters>(
// Update the database atomically, to ensure the result is internally consistent.
data.0.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
let mut db_update = data.get_update_ops()?;
// Save the transaction in the database.
let mut raw_tx = vec![];
@ -317,7 +319,7 @@ pub fn create_to_address<P: consensus::Parameters>(
i64::from(tx.expiry_height).to_sql()?,
raw_tx.to_sql()?,
])?;
let id_tx = data.0.last_insert_rowid();
let tx_ref = data.0.last_insert_rowid();
// Mark notes as spent.
//
@ -327,47 +329,26 @@ pub fn create_to_address<P: consensus::Parameters>(
//
// Assumes that create_to_address() will never be called in parallel, which is a
// reasonable assumption for a light client such as a mobile phone.
let mut stmt_mark_spent_note = data
.0
.prepare("UPDATE received_notes SET spent = ? WHERE nf = ?")?;
for spend in &tx.shielded_spends {
stmt_mark_spent_note.execute(&[id_tx.to_sql()?, spend.nullifier.to_sql()?])?;
db_update.mark_spent(tx_ref, &spend.nullifier)?;
}
// Save the sent note in the database.
// TODO: Decide how to save transparent output information.
let to_str = to.encode(params);
if let Some(memo) = memo {
let mut stmt_insert_sent_note = data.0.prepare(
"INSERT INTO sent_notes (tx, output_index, from_account, address, value, memo)
VALUES (?, ?, ?, ?, ?, ?)",
)?;
stmt_insert_sent_note.execute(&[
id_tx.to_sql()?,
output_index.to_sql()?,
account.to_sql()?,
to_str.to_sql()?,
i64::from(value).to_sql()?,
memo.as_bytes().to_sql()?,
])?;
} else {
let mut stmt_insert_sent_note = data.0.prepare(
"INSERT INTO sent_notes (tx, output_index, from_account, address, value)
VALUES (?, ?, ?, ?, ?)",
)?;
stmt_insert_sent_note.execute(&[
id_tx.to_sql()?,
output_index.to_sql()?,
account.to_sql()?,
to_str.to_sql()?,
i64::from(value).to_sql()?,
])?;
}
db_update.insert_sent_note(
params,
tx_ref,
output_index as usize,
AccountId(account),
to,
value,
memo,
)?;
data.0.execute("COMMIT", NO_PARAMS)?;
// Return the row number of the transaction, so the caller can fetch it for sending.
Ok(id_tx)
Ok(tx_ref)
}
#[cfg(test)]
@ -838,6 +819,7 @@ mod tests {
|row| row.get(0),
)
.unwrap();
let output = &tx.shielded_outputs[output_index as usize];
try_sapling_output_recovery(