This commit is contained in:
Kris Nuttycombe 2021-01-12 21:10:34 -07:00
parent db9eb29eba
commit ce06db197a
12 changed files with 81 additions and 97 deletions

View File

@ -6,7 +6,7 @@ use std::fmt::Debug;
use zcash_primitives::{
block::BlockHash,
consensus::{BlockHeight},
consensus::BlockHeight,
merkle_tree::{CommitmentTree, IncrementalWitness},
note_encryption::Memo,
primitives::{Note, Nullifier, PaymentAddress},
@ -97,17 +97,14 @@ pub trait WalletRead {
/// Returns the payment address for the specified account, if the account
/// identifier specified refers to a valid account for this wallet.
fn get_address(
&self,
account: AccountId,
) -> Result<Option<PaymentAddress>, Self::Error>;
fn get_address(&self, account: AccountId) -> Result<Option<PaymentAddress>, Self::Error>;
/// Returns all extended full viewing keys known about by this wallet
fn get_extended_full_viewing_keys(
&self,
) -> Result<HashMap<AccountId, ExtendedFullViewingKey>, Self::Error>;
/// Checks whether the specified extended full viewing key is
/// Checks whether the specified extended full viewing key is
/// associated with the account.
fn is_valid_account_extfvk(
&self,
@ -173,7 +170,7 @@ pub trait WalletRead {
) -> Result<Vec<SpendableNote>, Self::Error>;
/// Returns a list of spendable notes sufficient to cover the specified
/// target value, if possible.
/// target value, if possible.
fn select_spendable_notes(
&self,
account: AccountId,
@ -208,10 +205,7 @@ pub trait WalletWrite: WalletRead {
/// a chain reorg might invalidate some stored state, this method must be
/// implemented in order to allow users of this API to "reset" the data store
/// to correctly represent chainstate as of a specified block height.
fn rewind_to_height(
&mut self,
block_height: BlockHeight,
) -> Result<(), Self::Error>;
fn rewind_to_height(&mut self, block_height: BlockHeight) -> Result<(), Self::Error>;
/// Add wallet-relevant metadata for a specific transaction to the data
/// store.
@ -231,7 +225,7 @@ pub trait WalletWrite: WalletRead {
/// Mark the specified transaction as spent and record the nullifier.
fn mark_spent(&mut self, tx_ref: Self::TxRef, nf: &Nullifier) -> Result<(), Self::Error>;
/// Record a note as having been received, along with its nullifier and the transaction
/// Record a note as having been received, along with its nullifier and the transaction
/// within which the note was created.
fn put_received_note<T: ShieldedOutput>(
&mut self,
@ -298,9 +292,9 @@ pub trait BlockSource {
F: FnMut(CompactBlock) -> Result<(), Self::Error>;
}
/// This trait provides a generalization over shielded output representations
/// This trait provides a generalization over shielded output representations
/// that allows a wallet to avoid coupling to a specific one.
// TODO: it'd probably be better not to unify the definitions of
// TODO: it'd probably be better not to unify the definitions of
// `WalletShieldedOutput` and `DecryptedOutput` via a compositional
// approach, if possible.
pub trait ShieldedOutput {
@ -372,16 +366,13 @@ pub mod testing {
use crate::{
address::RecipientAddress,
decrypt::DecryptedOutput,
wallet::{AccountId, SpendableNote, WalletTx},
proto::compact_formats::CompactBlock,
wallet::{AccountId, SpendableNote, WalletTx},
};
use super::{
error::Error,
BlockSource, WalletRead, WalletWrite, ShieldedOutput
};
use super::{error::Error, BlockSource, ShieldedOutput, WalletRead, WalletWrite};
pub struct MockBlockSource { }
pub struct MockBlockSource {}
impl BlockSource for MockBlockSource {
type Error = Error<(), u32>;
@ -393,13 +384,13 @@ pub mod testing {
_with_row: F,
) -> Result<(), Self::Error>
where
F: FnMut(CompactBlock) -> Result<(), Self::Error> {
F: FnMut(CompactBlock) -> Result<(), Self::Error>,
{
Ok(())
}
}
pub struct MockWalletDB {
}
pub struct MockWalletDB {}
impl WalletRead for MockWalletDB {
type Error = Error<(), u32>;
@ -410,7 +401,10 @@ pub mod testing {
Ok(None)
}
fn get_block_hash(&self, _block_height: BlockHeight) -> Result<Option<BlockHash>, Self::Error> {
fn get_block_hash(
&self,
_block_height: BlockHeight,
) -> Result<Option<BlockHash>, Self::Error> {
Ok(None)
}
@ -418,15 +412,12 @@ pub mod testing {
Ok(None)
}
fn get_address(
&self,
_account: AccountId,
) -> Result<Option<PaymentAddress>, Self::Error> {
fn get_address(&self, _account: AccountId) -> Result<Option<PaymentAddress>, Self::Error> {
Ok(None)
}
fn get_extended_full_viewing_keys(
&self
&self,
) -> Result<HashMap<AccountId, ExtendedFullViewingKey>, Self::Error> {
Ok(HashMap::new())
}
@ -447,11 +438,17 @@ pub mod testing {
Ok(Amount::zero())
}
fn get_received_memo_as_utf8(&self, _id_note: Self::NoteRef) -> Result<Option<String>, Self::Error> {
fn get_received_memo_as_utf8(
&self,
_id_note: Self::NoteRef,
) -> Result<Option<String>, Self::Error> {
Ok(None)
}
fn get_sent_memo_as_utf8(&self, _id_note: Self::NoteRef) -> Result<Option<String>, Self::Error> {
fn get_sent_memo_as_utf8(
&self,
_id_note: Self::NoteRef,
) -> Result<Option<String>, Self::Error> {
Ok(None)
}
@ -486,7 +483,8 @@ pub mod testing {
impl WalletWrite for MockWalletDB {
fn transactionally<F, A>(&mut self, f: F) -> Result<A, Self::Error>
where
F: FnOnce(&mut Self) -> Result<A, Self::Error> {
F: FnOnce(&mut Self) -> Result<A, Self::Error>,
{
f(self)
}
@ -500,10 +498,7 @@ pub mod testing {
Ok(())
}
fn rewind_to_height(
&mut self,
_block_height: BlockHeight,
) -> Result<(), Self::Error> {
fn rewind_to_height(&mut self, _block_height: BlockHeight) -> Result<(), Self::Error> {
Ok(())
}

View File

@ -236,10 +236,9 @@ where
for output in tx.shielded_outputs {
match &extfvks.get(&output.account) {
Some(extfvk) => {
let nf = output.note.nf(
&extfvk.fvk.vk,
output.witness.position() as u64,
);
let nf = output
.note
.nf(&extfvk.fvk.vk, output.witness.position() as u64);
let note_id = up.put_received_note(&output, &Some(nf), tx_row)?;
@ -249,7 +248,7 @@ where
// Cache nullifier for note (to detect subsequent spends in this scan).
nullifiers.push((nf, output.account));
}
None => ()
None => (),
}
}
}

View File

@ -15,7 +15,7 @@ pub enum ChainInvalid {
/// The hash of the parent block given by a proposed new chain tip does
/// not match the hash of the current chain tip.
PrevHashMismatch,
/// The block height field of the proposed new chain tip is not equal
/// The block height field of the proposed new chain tip is not equal
/// to the height of the previous chain tip + 1. This variant stores
/// a copy of the incorrect height value for reporting purposes.
BlockHeightDiscontinuity(BlockHeight),
@ -29,10 +29,10 @@ pub enum Error<DbError, NoteId> {
InvalidChain(BlockHeight, ChainInvalid),
/// A provided extfvk is not associated with the specified account.
InvalidExtSK(AccountId),
/// The root of an output's witness tree in a newly arrived transaction does not correspond to
/// The root of an output's witness tree in a newly arrived transaction does not correspond to
/// root of the stored commitment tree at the recorded height.
InvalidNewWitnessAnchor(usize, TxId, BlockHeight, Node),
/// The root of an output's witness tree in a previously stored transaction does not correspond to
/// The root of an output's witness tree in a previously stored transaction does not correspond to
/// root of the current commitment tree.
InvalidWitnessAnchor(NoteId, BlockHeight),
/// The wallet must first perform a scan of the blockchain before other

View File

@ -208,8 +208,7 @@ where
let merkle_path = selected.witness.path().expect("the tree is not empty");
builder
.add_sapling_spend(extsk.clone(), selected.diversifier, note, merkle_path)?
builder.add_sapling_spend(extsk.clone(), selected.diversifier, note, merkle_path)?
}
match to {
@ -246,14 +245,7 @@ where
up.mark_spent(tx_ref, &spend.nullifier)?;
}
up.insert_sent_note(
tx_ref,
output_index as usize,
account,
to,
value,
memo,
)?;
up.insert_sent_note(tx_ref, output_index as usize, account, to, value, memo)?;
// Return the row number of the transaction, so the caller can fetch it for sending.
Ok(tx_ref)

View File

@ -206,8 +206,8 @@ mod tests {
};
use super::scan_block;
use crate::wallet::AccountId;
use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx};
use crate::wallet::AccountId;
fn random_compact_tx(mut rng: impl RngCore) -> CompactTx {
let fake_nf = {

View File

@ -79,13 +79,16 @@
//! ```
use protobuf::parse_from_bytes;
use rusqlite::{params};
use rusqlite::params;
use zcash_primitives::consensus::BlockHeight;
use zcash_client_backend::{data_api::error::Error, proto::compact_formats::CompactBlock};
use crate::{error::{SqliteClientError, db_error}, BlockDB, NoteId};
use crate::{
error::{db_error, SqliteClientError},
BlockDB, NoteId,
};
pub mod init;
@ -104,30 +107,31 @@ where
F: FnMut(CompactBlock) -> Result<(), Error<SqliteClientError, NoteId>>,
{
// Fetch the CompactBlocks we need to scan
let mut stmt_blocks = cache.0.prepare(
"SELECT height, data FROM compactblocks WHERE height > ? ORDER BY height ASC LIMIT ?",
).map_err(db_error)?;
let mut stmt_blocks = cache
.0
.prepare(
"SELECT height, data FROM compactblocks WHERE height > ? ORDER BY height ASC LIMIT ?",
)
.map_err(db_error)?;
let rows = stmt_blocks.query_map(
params![
u32::from(from_height),
limit.unwrap_or(u32::max_value()),
],
|row| {
Ok(CompactBlockRow {
height: BlockHeight::from_u32(row.get(0)?),
data: row.get(1)?,
})
},
).map_err(db_error)?;
let rows = stmt_blocks
.query_map(
params![u32::from(from_height), limit.unwrap_or(u32::max_value()),],
|row| {
Ok(CompactBlockRow {
height: BlockHeight::from_u32(row.get(0)?),
data: row.get(1)?,
})
},
)
.map_err(db_error)?;
for row_result in rows {
let cbr = row_result.map_err(db_error)?;
let block: CompactBlock = parse_from_bytes(&cbr.data).map_err(Error::from)?;
if block.height() != cbr.height {
return Err(
Error::Database(SqliteClientError::CorruptedData(format!(
return Err(Error::Database(SqliteClientError::CorruptedData(format!(
"Block height {} did not match row's height field value {}",
block.height(),
cbr.height
@ -388,8 +392,7 @@ mod tests {
&tests::network(),
&db_cache,
(&db_data).get_max_height_hash().unwrap(),
)
{
) {
Err(Error::InvalidChain(upper_bound, _)) => {
assert_eq!(upper_bound, sapling_activation_height() + 3)
}

View File

@ -238,8 +238,7 @@ impl<P: consensus::Parameters> WalletRead for WalletDB<P> {
account: AccountId,
anchor_height: BlockHeight,
) -> Result<Vec<SpendableNote>, Self::Error> {
wallet::transact::get_spendable_notes(self, account, anchor_height)
.map_err(Error::Database)
wallet::transact::get_spendable_notes(self, account, anchor_height).map_err(Error::Database)
}
fn select_spendable_notes(
@ -531,7 +530,7 @@ mod tests {
use group::GroupEncoding;
use protobuf::Message;
use rand_core::{OsRng, RngCore};
use rusqlite::{params};
use rusqlite::params;
use zcash_client_backend::proto::compact_formats::{
CompactBlock, CompactOutput, CompactSpend, CompactTx,

View File

@ -22,8 +22,8 @@ use zcash_client_backend::{
decode_extended_full_viewing_key, decode_payment_address, encode_extended_full_viewing_key,
encode_payment_address,
},
DecryptedOutput,
wallet::{AccountId, WalletTx},
DecryptedOutput,
};
use crate::{
@ -458,13 +458,12 @@ pub fn insert_block<'a, P>(
let mut encoded_tree = Vec::new();
commitment_tree.write(&mut encoded_tree).unwrap();
stmts.stmt_insert_block
.execute(params![
u32::from(block_height),
&block_hash.0[..],
block_time,
encoded_tree
])?;
stmts.stmt_insert_block.execute(params![
u32::from(block_height),
&block_hash.0[..],
block_time,
encoded_tree
])?;
Ok(())
}

View File

@ -8,7 +8,7 @@ use zcash_primitives::{
zip32::ExtendedFullViewingKey,
};
use zcash_client_backend::{encoding::encode_extended_full_viewing_key};
use zcash_client_backend::encoding::encode_extended_full_viewing_key;
use crate::{address_from_extfvk, error::SqliteClientError, WalletDB};

View File

@ -12,9 +12,7 @@ use zcash_primitives::{
transaction::components::Amount,
};
use zcash_client_backend::{
wallet::{AccountId, SpendableNote},
};
use zcash_client_backend::wallet::{AccountId, SpendableNote};
use crate::{error::SqliteClientError, WalletDB};
@ -74,7 +72,7 @@ pub fn get_spendable_notes<P>(
WHERE account = :account
AND spent IS NULL
AND transactions.block <= :anchor_height
AND sapling_witnesses.block = :anchor_height"
AND sapling_witnesses.block = :anchor_height",
)?;
// Select notes
@ -83,7 +81,7 @@ pub fn get_spendable_notes<P>(
":account": &i64::from(account.0),
":anchor_height": &u32::from(anchor_height),
],
to_spendable_note
to_spendable_note,
)?;
notes.collect::<Result<_, _>>()
@ -142,7 +140,7 @@ pub fn select_spendable_notes<P>(
":anchor_height": &u32::from(anchor_height),
":target_value": &i64::from(target_value),
],
to_spendable_note
to_spendable_note,
)?;
notes.collect::<Result<_, _>>()
@ -253,7 +251,7 @@ mod tests {
let mut db_write = db_data.get_update_ops().unwrap();
match create_spend_to_address(
&mut db_write,
&tests::network(),
&tests::network(),
test_prover(),
AccountId(0),
&extsk,

View File

@ -45,7 +45,6 @@ use crate::transaction::components::OutPoint;
#[cfg(any(test, feature = "test-dependencies"))]
use crate::prover::mock::MockTxProver;
const DEFAULT_TX_EXPIRY_DELTA: u32 = 20;
/// If there are any shielded inputs, always have at least two shielded outputs, padding

View File

@ -11,8 +11,8 @@ use std::io::{self, Read, Write};
use std::convert::TryFrom;
use crate::{
primitives::Nullifier,
legacy::Script,
primitives::Nullifier,
redjubjub::{PublicKey, Signature},
};