Add MockBlockSource and MockWalletDB
These can readily be made into an in-memory wallet implementation.
This commit is contained in:
parent
7d92150965
commit
34bc655f64
|
@ -102,7 +102,6 @@ pub trait WalletRead {
|
|||
) -> Result<Option<PaymentAddress>, Self::Error>;
|
||||
|
||||
/// Returns all extended full viewing keys known about by this wallet
|
||||
// TODO: Should this also take an AccountId as argument?
|
||||
fn get_extended_full_viewing_keys<P: consensus::Parameters>(
|
||||
&self,
|
||||
params: &P,
|
||||
|
@ -120,10 +119,16 @@ pub trait WalletRead {
|
|||
/// Returns the wallet balance for the specified account.
|
||||
///
|
||||
/// This balance amount is the raw balance of all transactions in known
|
||||
/// mined blocks, irrespective of confirmation depth.
|
||||
// TODO: Do we actually need this? You can always get the "verified"
|
||||
// balance from the current chain tip.
|
||||
fn get_balance(&self, account: AccountId) -> Result<Amount, Self::Error>;
|
||||
/// mined blocks, irrespective of confirmation depth. A default implementation
|
||||
/// is provided, but implementations of this trait may override the default
|
||||
/// implementation for efficiency.
|
||||
fn get_balance(&self, account: AccountId) -> Result<Amount, Self::Error> {
|
||||
if let Some((_, tip)) = self.block_height_extrema()? {
|
||||
self.get_verified_balance(account, tip)
|
||||
} else {
|
||||
Ok(Amount::zero())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the wallet balance for an account as of the specified block
|
||||
/// height. and
|
||||
|
@ -162,7 +167,7 @@ pub trait WalletRead {
|
|||
fn get_nullifiers(&self) -> Result<Vec<(Nullifier, AccountId)>, 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,
|
||||
|
@ -325,3 +330,233 @@ impl ShieldedOutput for DecryptedOutput {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-dependencies")]
|
||||
pub mod testing {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{self, BlockHeight},
|
||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||
note_encryption::Memo,
|
||||
primitives::{Nullifier, PaymentAddress},
|
||||
sapling::Node,
|
||||
transaction::{components::Amount, Transaction, TxId},
|
||||
zip32::ExtendedFullViewingKey,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
address::RecipientAddress,
|
||||
decrypt::DecryptedOutput,
|
||||
wallet::{AccountId, SpendableNote, WalletTx},
|
||||
proto::compact_formats::CompactBlock,
|
||||
};
|
||||
|
||||
use super::{
|
||||
error::Error,
|
||||
BlockSource, WalletRead, WalletWrite, ShieldedOutput
|
||||
};
|
||||
|
||||
pub struct MockBlockSource { }
|
||||
|
||||
impl BlockSource for MockBlockSource {
|
||||
type Error = Error<(), u32>;
|
||||
fn init_cache(&self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn with_blocks<F>(
|
||||
&self,
|
||||
_from_height: BlockHeight,
|
||||
_limit: Option<u32>,
|
||||
_with_row: F,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
F: FnMut(CompactBlock) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MockWalletDB {
|
||||
}
|
||||
|
||||
impl WalletRead for MockWalletDB {
|
||||
type Error = Error<(), u32>;
|
||||
type NoteRef = u32;
|
||||
type TxRef = TxId;
|
||||
|
||||
fn block_height_extrema(&self) -> Result<Option<(BlockHeight, BlockHeight)>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_block_hash(&self, _block_height: BlockHeight) -> Result<Option<BlockHash>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_tx_height(&self, _txid: TxId) -> Result<Option<BlockHeight>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_address<P: consensus::Parameters>(
|
||||
&self,
|
||||
_params: &P,
|
||||
_account: AccountId,
|
||||
) -> Result<Option<PaymentAddress>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_extended_full_viewing_keys<P: consensus::Parameters>(
|
||||
&self,
|
||||
_params: &P,
|
||||
) -> Result<HashMap<AccountId, ExtendedFullViewingKey>, Self::Error> {
|
||||
Ok(HashMap::new())
|
||||
}
|
||||
|
||||
fn is_valid_account_extfvk<P: consensus::Parameters>(
|
||||
&self,
|
||||
_params: &P,
|
||||
_account: AccountId,
|
||||
_extfvk: &ExtendedFullViewingKey,
|
||||
) -> Result<bool, Self::Error> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn get_verified_balance(
|
||||
&self,
|
||||
_account: AccountId,
|
||||
_anchor_height: BlockHeight,
|
||||
) -> Result<Amount, Self::Error> {
|
||||
Ok(Amount::zero())
|
||||
}
|
||||
|
||||
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> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_commitment_tree(
|
||||
&self,
|
||||
_block_height: BlockHeight,
|
||||
) -> Result<Option<CommitmentTree<Node>>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_witnesses(
|
||||
&self,
|
||||
_block_height: BlockHeight,
|
||||
) -> Result<Vec<(Self::NoteRef, IncrementalWitness<Node>)>, Self::Error> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
fn get_nullifiers(&self) -> Result<Vec<(Nullifier, AccountId)>, Self::Error> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
fn select_spendable_notes(
|
||||
&self,
|
||||
_account: AccountId,
|
||||
_target_value: Amount,
|
||||
_anchor_height: BlockHeight,
|
||||
) -> Result<Vec<SpendableNote>, Self::Error> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
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(self)
|
||||
}
|
||||
|
||||
fn insert_block(
|
||||
&mut self,
|
||||
_block_height: BlockHeight,
|
||||
_block_hash: BlockHash,
|
||||
_block_time: u32,
|
||||
_commitment_tree: &CommitmentTree<Node>,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rewind_to_height<P: consensus::Parameters>(
|
||||
&mut self,
|
||||
_parameters: &P,
|
||||
_block_height: BlockHeight,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn put_tx_meta(
|
||||
&mut self,
|
||||
_tx: &WalletTx,
|
||||
_height: BlockHeight,
|
||||
) -> Result<Self::TxRef, Self::Error> {
|
||||
Ok(TxId([0u8; 32]))
|
||||
}
|
||||
|
||||
fn put_tx_data(
|
||||
&mut self,
|
||||
_tx: &Transaction,
|
||||
_created_at: Option<time::OffsetDateTime>,
|
||||
) -> Result<Self::TxRef, Self::Error> {
|
||||
Ok(TxId([0u8; 32]))
|
||||
}
|
||||
|
||||
fn mark_spent(&mut self, _tx_ref: Self::TxRef, _nf: &Nullifier) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn put_received_note<T: ShieldedOutput>(
|
||||
&mut self,
|
||||
_output: &T,
|
||||
_nf: &Option<Nullifier>,
|
||||
_tx_ref: Self::TxRef,
|
||||
) -> Result<Self::NoteRef, Self::Error> {
|
||||
Ok(0u32)
|
||||
}
|
||||
|
||||
fn insert_witness(
|
||||
&mut self,
|
||||
_note_id: Self::NoteRef,
|
||||
_witness: &IncrementalWitness<Node>,
|
||||
_height: BlockHeight,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prune_witnesses(&mut self, _from_height: BlockHeight) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_expired_notes(&mut self, _from_height: BlockHeight) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn put_sent_note<P: consensus::Parameters>(
|
||||
&mut self,
|
||||
_params: &P,
|
||||
_output: &DecryptedOutput,
|
||||
_tx_ref: Self::TxRef,
|
||||
) -> Result<(), Self::Error> {
|
||||
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> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,3 +31,4 @@ zcash_proofs = { version = "0.4", path = "../zcash_proofs" }
|
|||
|
||||
[features]
|
||||
mainnet = []
|
||||
test-dependencies = ["zcash_client_backend/test-dependencies"]
|
||||
|
|
|
@ -10,26 +10,26 @@
|
|||
//!
|
||||
//! use zcash_client_backend::{
|
||||
//! data_api::{
|
||||
//! WalletRead,
|
||||
//! BlockSource, WalletRead, WalletWrite,
|
||||
//! chain::{
|
||||
//! validate_chain,
|
||||
//! scan_cached_blocks,
|
||||
//! },
|
||||
//! error::Error,
|
||||
//! }
|
||||
//! testing::{MockBlockSource, MockWalletDB}
|
||||
//! },
|
||||
//! };
|
||||
//!
|
||||
//! use zcash_client_sqlite::{
|
||||
//! BlockDB,
|
||||
//! WalletDB,
|
||||
//! wallet::{rewind_to_height},
|
||||
//! wallet::init::{init_data_database},
|
||||
//! };
|
||||
//!
|
||||
//! let network = Network::TestNetwork;
|
||||
//! let cache_file = NamedTempFile::new().unwrap();
|
||||
//! let db_cache = BlockDB::for_path(cache_file).unwrap();
|
||||
//! let data_file = NamedTempFile::new().unwrap();
|
||||
//! let db_data = WalletDB::for_path(data_file).unwrap();
|
||||
//! let db_cache = MockBlockSource { };
|
||||
//! let mut db_data = MockWalletDB { };
|
||||
//!
|
||||
//! // 1) Download new CompactBlocks into db_cache.
|
||||
//!
|
||||
|
@ -37,8 +37,8 @@
|
|||
//! //
|
||||
//! // Given that we assume the server always gives us correct-at-the-time blocks, any
|
||||
//! // errors are in the blocks we have previously cached or scanned.
|
||||
//! if let Err(e) = validate_chain(&network, &db_cache, (&db_data).get_max_height_hash().unwrap()) {
|
||||
//! match e.0 {
|
||||
//! if let Err(e) = validate_chain(&network, &db_cache, db_data.get_max_height_hash().unwrap()) {
|
||||
//! match e {
|
||||
//! Error::InvalidChain(upper_bound, _) => {
|
||||
//! // a) Pick a height to rewind to.
|
||||
//! //
|
||||
|
@ -48,7 +48,7 @@
|
|||
//! let rewind_height = upper_bound - 10;
|
||||
//!
|
||||
//! // b) Rewind scanned block information.
|
||||
//! rewind_to_height(&db_data, &network, rewind_height);
|
||||
//! db_data.rewind_to_height(&network, rewind_height);
|
||||
//!
|
||||
//! // c) Delete cached blocks from rewind_height onwards.
|
||||
//! //
|
||||
|
@ -71,7 +71,7 @@
|
|||
//! // At this point, the cache and scanned data are locally consistent (though not
|
||||
//! // necessarily consistent with the latest chain tip - this would be discovered the
|
||||
//! // next time this codepath is executed after new blocks are received).
|
||||
//! scan_cached_blocks(&network, &db_cache, &db_data, None);
|
||||
//! scan_cached_blocks(&network, &db_cache, &mut db_data, None).unwrap();
|
||||
//! ```
|
||||
use protobuf::parse_from_bytes;
|
||||
|
||||
|
|
Loading…
Reference in New Issue