diff --git a/zcash_client_backend/src/data_api.rs b/zcash_client_backend/src/data_api.rs index 2f361ca48..18ab2a8d6 100644 --- a/zcash_client_backend/src/data_api.rs +++ b/zcash_client_backend/src/data_api.rs @@ -1166,13 +1166,20 @@ pub trait WalletRead { /// transaction data requests, such as when it is necessary to fill in purely-transparent /// transaction history by walking the chain backwards via transparent inputs. fn transaction_data_requests(&self) -> Result, Self::Error>; +} +/// Read-only operations required for testing light wallet functions. +/// +/// These methods expose internal details or unstable interfaces, primarily to enable use +/// of the [`testing`] framework. They should not be used in production software. +#[cfg(any(test, feature = "test-dependencies"))] +#[delegatable_trait] +pub trait WalletTest: WalletRead { /// Returns a vector of transaction summaries. /// /// Currently test-only, as production use could return a very large number of results; either /// pagination or a streaming design will be necessary to stabilize this feature for production /// use. - #[cfg(any(test, feature = "test-dependencies"))] fn get_tx_history( &self, ) -> Result>, Self::Error> { @@ -1181,7 +1188,6 @@ pub trait WalletRead { /// Returns the note IDs for shielded notes sent by the wallet in a particular /// transaction. - #[cfg(any(test, feature = "test-dependencies"))] fn get_sent_note_ids( &self, _txid: &TxId, diff --git a/zcash_client_backend/src/data_api/testing.rs b/zcash_client_backend/src/data_api/testing.rs index a32e48f38..ba4f81efb 100644 --- a/zcash_client_backend/src/data_api/testing.rs +++ b/zcash_client_backend/src/data_api/testing.rs @@ -56,6 +56,7 @@ use crate::{ ShieldedProtocol, }; +use super::WalletTest; #[allow(deprecated)] use super::{ chain::{scan_cached_blocks, BlockSource, ChainState, CommitmentTreeRoot, ScanSummary}, @@ -319,14 +320,14 @@ impl Account for TestAccount { } } -pub trait Reset: WalletRead + Sized { +pub trait Reset: WalletTest + Sized { type Handle; fn reset(st: &mut TestState) -> Self::Handle; } /// The state for a `zcash_client_sqlite` test. -pub struct TestState { +pub struct TestState { cache: Cache, cached_blocks: BTreeMap, latest_block_height: Option, @@ -336,7 +337,7 @@ pub struct TestState { rng: ChaChaRng, } -impl TestState { +impl TestState { /// Exposes an immutable reference to the test's `DataStore`. pub fn wallet(&self) -> &DataStore { &self.wallet_data @@ -358,7 +359,7 @@ impl TestState } } -impl +impl TestState { /// Convenience method for obtaining the Sapling activation height for the network under test. @@ -405,7 +406,7 @@ impl impl TestState where Network: consensus::Parameters, - DataStore: WalletWrite, + DataStore: WalletTest + WalletWrite, ::Error: fmt::Debug, { /// Exposes an immutable reference to the test's [`BlockSource`]. @@ -697,7 +698,7 @@ where Cache: TestCache, ::Error: fmt::Debug, ParamsT: consensus::Parameters + Send + 'static, - DbT: InputSource + WalletWrite + WalletCommitmentTrees, + DbT: InputSource + WalletTest + WalletWrite + WalletCommitmentTrees, ::AccountId: ConditionallySelectable + Default + Send + 'static, { /// Invokes [`scan_cached_blocks`] with the given arguments, expecting success. @@ -760,6 +761,7 @@ where AccountIdT: std::cmp::Eq + std::hash::Hash, ErrT: std::fmt::Debug, DbT: InputSource + + WalletTest + WalletWrite + WalletCommitmentTrees, ::AccountId: ConditionallySelectable + Default + Send + 'static, @@ -1069,7 +1071,19 @@ where pub fn get_wallet_summary(&self, min_confirmations: u32) -> Option> { self.wallet().get_wallet_summary(min_confirmations).unwrap() } +} +impl TestState +where + ParamsT: consensus::Parameters + Send + 'static, + AccountIdT: std::cmp::Eq + std::hash::Hash, + ErrT: std::fmt::Debug, + DbT: InputSource + + WalletTest + + WalletWrite + + WalletCommitmentTrees, + ::AccountId: ConditionallySelectable + Default + Send + 'static, +{ /// Returns a transaction from the history. #[allow(dead_code)] pub fn get_tx_from_history( @@ -1149,6 +1163,7 @@ pub trait DataStoreFactory { type DsError: core::fmt::Debug; type DataStore: InputSource + WalletRead + + WalletTest + WalletWrite + WalletCommitmentTrees; diff --git a/zcash_client_backend/src/data_api/testing/orchard.rs b/zcash_client_backend/src/data_api/testing/orchard.rs index 6c8ef143d..d762ac3a2 100644 --- a/zcash_client_backend/src/data_api/testing/orchard.rs +++ b/zcash_client_backend/src/data_api/testing/orchard.rs @@ -25,7 +25,7 @@ use crate::{ data_api::{ chain::{CommitmentTreeRoot, ScanSummary}, testing::{pool::ShieldedPoolTester, TestState}, - DecryptedTransaction, InputSource, WalletCommitmentTrees, WalletRead, WalletSummary, + DecryptedTransaction, InputSource, WalletCommitmentTrees, WalletSummary, WalletTest, }, wallet::{Note, ReceivedNote}, }; @@ -40,7 +40,7 @@ impl ShieldedPoolTester for OrchardPoolTester { type MerkleTreeHash = MerkleHashOrchard; type Note = orchard::note::Note; - fn test_account_fvk( + fn test_account_fvk( st: &TestState, ) -> Self::Fvk { st.test_account_orchard().unwrap().clone() @@ -90,7 +90,7 @@ impl ShieldedPoolTester for OrchardPoolTester { MerkleHashOrchard::empty_root(level) } - fn put_subtree_roots( + fn put_subtree_roots( st: &mut TestState, start_index: u64, roots: &[CommitmentTreeRoot], @@ -103,7 +103,7 @@ impl ShieldedPoolTester for OrchardPoolTester { s.next_orchard_subtree_index() } - fn select_spendable_notes( + fn select_spendable_notes( st: &TestState, account: ::AccountId, target_value: Zatoshis, diff --git a/zcash_client_backend/src/data_api/testing/pool.rs b/zcash_client_backend/src/data_api/testing/pool.rs index fb7b83805..a7d7b4bf8 100644 --- a/zcash_client_backend/src/data_api/testing/pool.rs +++ b/zcash_client_backend/src/data_api/testing/pool.rs @@ -23,7 +23,7 @@ use crate::{ testing::{AddressType, TestBuilder}, wallet::{decrypt_and_store_transaction, input_selection::GreedyInputSelector}, Account as _, DecryptedTransaction, InputSource, WalletCommitmentTrees, WalletRead, - WalletSummary, + WalletSummary, WalletTest, }, decrypt_transaction, fees::{standard, DustOutputPolicy}, @@ -42,7 +42,7 @@ pub trait ShieldedPoolTester { type MerkleTreeHash; type Note; - fn test_account_fvk( + fn test_account_fvk( st: &TestState, ) -> Self::Fvk; fn usk_to_sk(usk: &UnifiedSpendingKey) -> &Self::Sk; @@ -68,7 +68,7 @@ pub trait ShieldedPoolTester { fn empty_tree_leaf() -> Self::MerkleTreeHash; fn empty_tree_root(level: Level) -> Self::MerkleTreeHash; - fn put_subtree_roots( + fn put_subtree_roots( st: &mut TestState, start_index: u64, roots: &[CommitmentTreeRoot], @@ -77,7 +77,7 @@ pub trait ShieldedPoolTester { fn next_subtree_index(s: &WalletSummary) -> u64; #[allow(clippy::type_complexity)] - fn select_spendable_notes( + fn select_spendable_notes( st: &TestState, account: ::AccountId, target_value: Zatoshis, diff --git a/zcash_client_backend/src/data_api/testing/sapling.rs b/zcash_client_backend/src/data_api/testing/sapling.rs index 6f9a78fb4..8686d1755 100644 --- a/zcash_client_backend/src/data_api/testing/sapling.rs +++ b/zcash_client_backend/src/data_api/testing/sapling.rs @@ -19,7 +19,7 @@ use zip32::Scope; use crate::{ data_api::{ chain::{CommitmentTreeRoot, ScanSummary}, - DecryptedTransaction, InputSource, WalletCommitmentTrees, WalletRead, WalletSummary, + DecryptedTransaction, InputSource, WalletCommitmentTrees, WalletSummary, WalletTest, }, wallet::{Note, ReceivedNote}, }; @@ -36,7 +36,7 @@ impl ShieldedPoolTester for SaplingPoolTester { type MerkleTreeHash = sapling::Node; type Note = sapling::Note; - fn test_account_fvk( + fn test_account_fvk( st: &TestState, ) -> Self::Fvk { st.test_account_sapling().unwrap().clone() @@ -74,7 +74,7 @@ impl ShieldedPoolTester for SaplingPoolTester { ::sapling::Node::empty_root(level) } - fn put_subtree_roots( + fn put_subtree_roots( st: &mut TestState, start_index: u64, roots: &[CommitmentTreeRoot], @@ -87,7 +87,7 @@ impl ShieldedPoolTester for SaplingPoolTester { s.next_sapling_subtree_index() } - fn select_spendable_notes( + fn select_spendable_notes( st: &TestState, account: ::AccountId, target_value: Zatoshis, diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index fecf44229..57415820c 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -53,7 +53,7 @@ use zcash_client_backend::{ Account, AccountBirthday, AccountPurpose, AccountSource, BlockMetadata, DecryptedTransaction, InputSource, NullifierQuery, ScannedBlock, SeedRelevance, SentTransaction, SpendableNotes, TransactionDataRequest, WalletCommitmentTrees, WalletRead, - WalletSummary, WalletWrite, SAPLING_SHARD_HEIGHT, + WalletSummary, WalletTest, WalletWrite, SAPLING_SHARD_HEIGHT, }, keys::{ AddressGenerationError, UnifiedAddressRequest, UnifiedFullViewingKey, UnifiedSpendingKey, @@ -614,13 +614,14 @@ impl, P: consensus::Parameters> WalletRead for W Ok(iter.collect()) } +} - #[cfg(any(test, feature = "test-dependencies"))] +#[cfg(any(test, feature = "test-dependencies"))] +impl, P: consensus::Parameters> WalletTest for WalletDb { fn get_tx_history(&self) -> Result>, Self::Error> { wallet::testing::get_tx_history(self.conn.borrow()) } - #[cfg(any(test, feature = "test-dependencies"))] fn get_sent_note_ids( &self, txid: &TxId, @@ -1725,7 +1726,8 @@ mod tests { use zcash_client_backend::data_api::{ chain::ChainState, testing::{TestBuilder, TestState}, - Account, AccountBirthday, AccountPurpose, AccountSource, WalletRead, WalletWrite, + Account, AccountBirthday, AccountPurpose, AccountSource, WalletRead, WalletTest, + WalletWrite, }; use zcash_keys::keys::{UnifiedFullViewingKey, UnifiedSpendingKey}; use zcash_primitives::block::BlockHash; @@ -1837,7 +1839,7 @@ mod tests { AccountSource::Derived { seed_fingerprint: _, account_index } if account_index == zip32_index_2); } - fn check_collisions( + fn check_collisions( st: &mut TestState, ufvk: &UnifiedFullViewingKey, birthday: &AccountBirthday, diff --git a/zcash_client_sqlite/src/testing/db.rs b/zcash_client_sqlite/src/testing/db.rs index e980aa6ce..f972fdfde 100644 --- a/zcash_client_sqlite/src/testing/db.rs +++ b/zcash_client_sqlite/src/testing/db.rs @@ -43,6 +43,7 @@ use { #[derive(Delegate)] #[delegate(InputSource, target = "wallet_db")] #[delegate(WalletRead, target = "wallet_db")] +#[delegate(WalletTest, target = "wallet_db")] #[delegate(WalletWrite, target = "wallet_db")] #[delegate(WalletCommitmentTrees, target = "wallet_db")] pub(crate) struct TestDb { diff --git a/zcash_client_sqlite/src/testing/pool.rs b/zcash_client_sqlite/src/testing/pool.rs index 795d49f03..aff260a28 100644 --- a/zcash_client_sqlite/src/testing/pool.rs +++ b/zcash_client_sqlite/src/testing/pool.rs @@ -100,7 +100,7 @@ pub(crate) fn send_multi_step_proposed_transfer() { use rand_core::OsRng; use zcash_client_backend::{ - data_api::{TransactionDataRequest, TransactionStatus}, + data_api::{TransactionDataRequest, TransactionStatus, WalletTest}, fees::ChangeValue, wallet::TransparentAddressMetadata, };