Reuse sent note insertion for wallet/transact.
This commit is contained in:
parent
68737dd1dd
commit
e144015558
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue