diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38597e615b..04e2567800 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: matrix.extra_flags != 'NOT_A_PUZZLE' && format(' with --features {0}', matrix.extra_flags) || '' }} runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.extra_flags != 'NOT_A_PUZZLE' }} strategy: matrix: os: [ubuntu-latest-8cores, windows-latest-8cores, macOS-latest] diff --git a/Cargo.lock b/Cargo.lock index 608ebcb122..626fb840a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3069,6 +3069,7 @@ dependencies = [ "pasta_curves", "proptest", "prost", + "rand_chacha", "rand_core", "regex", "rusqlite", @@ -3101,21 +3102,6 @@ dependencies = [ "nonempty", ] -[[package]] -name = "zcash_extensions" -version = "0.0.0" -dependencies = [ - "blake2b_simd", - "ff", - "jubjub", - "orchard", - "rand_core", - "sapling-crypto", - "zcash_address", - "zcash_primitives", - "zcash_proofs", -] - [[package]] name = "zcash_history" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 612c8f7dd8..a06d110e31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,8 @@ members = [ "components/zcash_protocol", "zcash_client_backend", "zcash_client_sqlite", - "zcash_extensions", + # Disabled until we replace the `zfutures` feature flag with a compiler flag. + # "zcash_extensions", "zcash_history", "zcash_keys", "zcash_primitives", @@ -108,6 +109,7 @@ lazy_static = "1" assert_matches = "1.5" criterion = "0.4" proptest = "1" +rand_chacha = "0.3" rand_xorshift = "0.3" # ZIP 32 diff --git a/zcash_client_sqlite/Cargo.toml b/zcash_client_sqlite/Cargo.toml index 6029c4fab7..d3a46eb323 100644 --- a/zcash_client_sqlite/Cargo.toml +++ b/zcash_client_sqlite/Cargo.toml @@ -83,6 +83,7 @@ pasta_curves.workspace = true shardtree = { workspace = true, features = ["legacy-api", "test-dependencies"] } nonempty.workspace = true proptest.workspace = true +rand_chacha.workspace = true rand_core.workspace = true regex = "1.4" tempfile = "3.5.0" @@ -90,11 +91,14 @@ zcash_keys = { workspace = true, features = ["test-dependencies"] } zcash_note_encryption.workspace = true zcash_proofs = { workspace = true, features = ["bundled-prover"] } zcash_primitives = { workspace = true, features = ["test-dependencies"] } +zcash_protocol = { workspace = true, features = ["local-consensus"] } zcash_client_backend = { workspace = true, features = ["test-dependencies", "unstable-serialization", "unstable-spanning-tree"] } zcash_address = { workspace = true, features = ["test-dependencies"] } [features] default = ["multicore"] +unstable-nu6 = ["zcash_primitives/unstable-nu6"] +zfuture = ["zcash_primitives/zfuture"] ## Enables multithreading support for creating proofs and building subtrees. multicore = ["maybe-rayon/threads", "zcash_primitives/multicore"] diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index b04ea3e5a7..8c1dae2aa0 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -111,6 +111,8 @@ pub(crate) const PRUNING_DEPTH: u32 = 100; pub(crate) const VERIFY_LOOKAHEAD: u32 = 10; pub(crate) const SAPLING_TABLES_PREFIX: &str = "sapling"; +#[cfg(feature = "orchard")] +pub(crate) const ORCHARD_TABLES_PREFIX: &str = "orchard"; #[cfg(not(feature = "transparent-inputs"))] pub(crate) const UA_TRANSPARENT: bool = false; diff --git a/zcash_client_sqlite/src/testing.rs b/zcash_client_sqlite/src/testing.rs index 0cf71a6df1..8c53b1769e 100644 --- a/zcash_client_sqlite/src/testing.rs +++ b/zcash_client_sqlite/src/testing.rs @@ -7,7 +7,8 @@ use std::fs::File; use nonempty::NonEmpty; use prost::Message; -use rand_core::{CryptoRng, OsRng, RngCore}; +use rand_chacha::ChaChaRng; +use rand_core::{CryptoRng, RngCore, SeedableRng}; use rusqlite::{params, Connection}; use secrecy::{Secret, SecretVec}; use tempfile::NamedTempFile; @@ -50,7 +51,7 @@ use zcash_client_backend::{ use zcash_note_encryption::Domain; use zcash_primitives::{ block::BlockHash, - consensus::{self, BlockHeight, Network, NetworkUpgrade, Parameters}, + consensus::{self, BlockHeight, NetworkUpgrade, Parameters}, memo::{Memo, MemoBytes}, transaction::{ components::{amount::NonNegativeAmount, sapling::zip212_enforcement}, @@ -59,6 +60,7 @@ use zcash_primitives::{ }, zip32::DiversifierIndex, }; +use zcash_protocol::local_consensus::LocalNetwork; use crate::{ chain::init::init_cache_database, @@ -98,18 +100,33 @@ pub(crate) mod pool; /// A builder for a `zcash_client_sqlite` test. pub(crate) struct TestBuilder { - network: Network, + network: LocalNetwork, cache: Cache, test_account_birthday: Option, + rng: ChaChaRng, } impl TestBuilder<()> { /// Constructs a new test. pub(crate) fn new() -> Self { TestBuilder { - network: Network::TestNetwork, + // Use a fake network where Sapling through NU5 activate at the same height. + // We pick 100,000 to be large enough to handle any hard-coded test offsets. + network: LocalNetwork { + overwinter: Some(BlockHeight::from_u32(1)), + sapling: Some(BlockHeight::from_u32(100_000)), + blossom: Some(BlockHeight::from_u32(100_000)), + heartwood: Some(BlockHeight::from_u32(100_000)), + canopy: Some(BlockHeight::from_u32(100_000)), + nu5: Some(BlockHeight::from_u32(100_000)), + #[cfg(feature = "unstable-nu6")] + nu6: None, + #[cfg(feature = "zfuture")] + z_future: None, + }, cache: (), test_account_birthday: None, + rng: ChaChaRng::seed_from_u64(0), } } @@ -119,6 +136,7 @@ impl TestBuilder<()> { network: self.network, cache: BlockCache::new(), test_account_birthday: self.test_account_birthday, + rng: self.rng, } } @@ -129,12 +147,13 @@ impl TestBuilder<()> { network: self.network, cache: FsBlockCache::new(), test_account_birthday: self.test_account_birthday, + rng: self.rng, } } } impl TestBuilder { - pub(crate) fn with_test_account AccountBirthday>( + pub(crate) fn with_test_account AccountBirthday>( mut self, birthday: F, ) -> Self { @@ -162,6 +181,7 @@ impl TestBuilder { _data_file: data_file, db_data, test_account, + rng: self.rng, } } } @@ -215,13 +235,14 @@ pub(crate) struct TestState { cache: Cache, latest_cached_block: Option, _data_file: NamedTempFile, - db_data: WalletDb, + db_data: WalletDb, test_account: Option<( SecretVec, AccountId, UnifiedSpendingKey, AccountBirthday, )>, + rng: ChaChaRng, } impl TestState @@ -291,6 +312,7 @@ where value, initial_sapling_tree_size, initial_orchard_tree_size, + &mut self.rng, ); let res = self.cache.insert(&cb); @@ -332,6 +354,7 @@ where value, cached_block.sapling_end_size, cached_block.orchard_end_size, + &mut self.rng, ); let res = self.cache.insert(&cb); @@ -383,6 +406,7 @@ where tx, cached_block.sapling_end_size, cached_block.orchard_end_size, + &mut self.rng, ); let res = self.cache.insert(&cb); @@ -460,17 +484,17 @@ where impl TestState { /// Exposes an immutable reference to the test's [`WalletDb`]. - pub(crate) fn wallet(&self) -> &WalletDb { + pub(crate) fn wallet(&self) -> &WalletDb { &self.db_data } /// Exposes a mutable reference to the test's [`WalletDb`]. - pub(crate) fn wallet_mut(&mut self) -> &mut WalletDb { + pub(crate) fn wallet_mut(&mut self) -> &mut WalletDb { &mut self.db_data } /// Exposes the network in use. - pub(crate) fn network(&self) -> Network { + pub(crate) fn network(&self) -> LocalNetwork { self.db_data.params } @@ -501,6 +525,14 @@ impl TestState { .and_then(|(_, _, usk, _)| usk.to_unified_full_viewing_key().sapling().cloned()) } + /// Exposes the test account's Sapling DFVK, if enabled via [`TestBuilder::with_test_account`]. + #[cfg(feature = "orchard")] + pub(crate) fn test_account_orchard(&self) -> Option { + self.test_account + .as_ref() + .and_then(|(_, _, usk, _)| usk.to_unified_full_viewing_key().orchard().cloned()) + } + /// Invokes [`create_spend_to_address`] with the given arguments. #[allow(deprecated)] #[allow(clippy::type_complexity)] @@ -561,7 +593,7 @@ impl TestState { >, > where - InputsT: InputSelector>, + InputsT: InputSelector>, { #![allow(deprecated)] let params = self.network(); @@ -597,7 +629,7 @@ impl TestState { >, > where - InputsT: InputSelector>, + InputsT: InputSelector>, { let params = self.network(); propose_transfer::<_, _, _, Infallible>( @@ -673,7 +705,7 @@ impl TestState { >, > where - InputsT: ShieldingSelector>, + InputsT: ShieldingSelector>, { let params = self.network(); propose_shielding::<_, _, _, Infallible>( @@ -737,7 +769,7 @@ impl TestState { >, > where - InputsT: ShieldingSelector>, + InputsT: ShieldingSelector>, { let params = self.network(); let prover = test_prover(); @@ -1128,10 +1160,8 @@ fn fake_compact_block( value: NonNegativeAmount, initial_sapling_tree_size: u32, initial_orchard_tree_size: u32, + mut rng: impl RngCore + CryptoRng, ) -> (CompactBlock, Fvk::Nullifier) { - // Create a fake Note for the account - let mut rng = OsRng; - // Create a fake CompactBlock containing the note let mut ctx = fake_compact_tx(&mut rng); let nf = fvk.add_output( @@ -1150,6 +1180,7 @@ fn fake_compact_block( prev_hash, initial_sapling_tree_size, initial_orchard_tree_size, + rng, ); (cb, nf) } @@ -1162,6 +1193,7 @@ fn fake_compact_block_from_tx( tx: &Transaction, initial_sapling_tree_size: u32, initial_orchard_tree_size: u32, + rng: impl RngCore, ) -> CompactBlock { // Create a fake CompactTx containing the transaction. let mut ctx = CompactTx { @@ -1192,6 +1224,7 @@ fn fake_compact_block_from_tx( prev_hash, initial_sapling_tree_size, initial_orchard_tree_size, + rng, ) } @@ -1208,8 +1241,8 @@ fn fake_compact_block_spending( value: NonNegativeAmount, initial_sapling_tree_size: u32, initial_orchard_tree_size: u32, + mut rng: impl RngCore + CryptoRng, ) -> CompactBlock { - let mut rng = OsRng; let mut ctx = fake_compact_tx(&mut rng); // Create a fake spend and a fake Note for the change @@ -1291,6 +1324,7 @@ fn fake_compact_block_spending( prev_hash, initial_sapling_tree_size, initial_orchard_tree_size, + rng, ) } @@ -1300,8 +1334,8 @@ fn fake_compact_block_from_compact_tx( prev_hash: BlockHash, initial_sapling_tree_size: u32, initial_orchard_tree_size: u32, + mut rng: impl RngCore, ) -> CompactBlock { - let mut rng = OsRng; let mut cb = CompactBlock { hash: { let mut hash = vec![0; 32]; @@ -1428,7 +1462,7 @@ pub(crate) fn input_selector( change_memo: Option<&str>, fallback_change_pool: ShieldedProtocol, ) -> GreedyInputSelector< - WalletDb, + WalletDb, standard::SingleOutputChangeStrategy, > { let change_memo = change_memo.map(|m| MemoBytes::from(m.parse::().unwrap())); @@ -1440,7 +1474,7 @@ pub(crate) fn input_selector( // Checks that a protobuf proposal serialized from the provided proposal value correctly parses to // the same proposal value. fn check_proposal_serialization_roundtrip( - db_data: &WalletDb, + db_data: &WalletDb, proposal: &Proposal, ) { let proposal_proto = proposal::Proposal::from_standard_proposal(&db_data.params, proposal); diff --git a/zcash_client_sqlite/src/testing/pool.rs b/zcash_client_sqlite/src/testing/pool.rs index 331250e878..25da006ef4 100644 --- a/zcash_client_sqlite/src/testing/pool.rs +++ b/zcash_client_sqlite/src/testing/pool.rs @@ -46,7 +46,8 @@ use crate::{ error::SqliteClientError, testing::{input_selector, AddressType, BlockCache, TestBuilder, TestState}, wallet::{ - block_max_scanned, commitment_tree, parse_scope, scanning::tests::test_with_canopy_birthday, + block_max_scanned, commitment_tree, parse_scope, + scanning::tests::test_with_nu5_birthday_offset, }, AccountId, NoteId, ReceivedNoteId, }; @@ -147,7 +148,7 @@ pub(crate) fn send_single_step_proposed_transfer() { h ); - let to_extsk = T::sk(&[]); + let to_extsk = T::sk(&[0xf5; 32]); let to: Address = T::sk_default_address(&to_extsk); let request = zip321::TransactionRequest::new(vec![Payment { recipient_address: to, @@ -522,7 +523,7 @@ pub(crate) fn spend_fails_on_unverified_notes() { ); // Spend fails because there are insufficient verified notes - let extsk2 = T::sk(&[]); + let extsk2 = T::sk(&[0xf5; 32]); let to = T::sk_default_address(&extsk2); assert_matches!( st.propose_standard_transfer::( @@ -643,7 +644,7 @@ pub(crate) fn spend_fails_on_locked_notes() { assert_eq!(st.get_spendable_balance(account, 1), value); // Send some of the funds to another address, but don't mine the tx. - let extsk2 = T::sk(&[]); + let extsk2 = T::sk(&[0xf5; 32]); let to = T::sk_default_address(&extsk2); let min_confirmations = NonZeroU32::new(1).unwrap(); let proposal = st @@ -774,7 +775,7 @@ pub(crate) fn ovk_policy_prevents_recovery_from_chain() { assert_eq!(st.get_total_balance(account), value); assert_eq!(st.get_spendable_balance(account, 1), value); - let extsk2 = T::sk(&[]); + let extsk2 = T::sk(&[0xf5; 32]); let addr2 = T::sk_default_address(&extsk2); // TODO: This test was originally written to use the pre-zip-313 fee rule @@ -1226,7 +1227,8 @@ pub(crate) fn shield_transparent() { } pub(crate) fn birthday_in_anchor_shard() { - let (mut st, dfvk, birthday, _) = test_with_canopy_birthday::(); + // Use a non-zero birthday offset because Sapling and NU5 are activated at the same height. + let (mut st, dfvk, birthday, _) = test_with_nu5_birthday_offset::(76); // Set up the following situation: // @@ -1267,7 +1269,7 @@ pub(crate) fn birthday_in_anchor_shard() { let initial_orchard_tree_size = 0; // Generate 9 blocks that have no value for us, starting at the birthday height. - let not_our_key = T::sk_to_fvk(&T::sk(&[])); + let not_our_key = T::sk_to_fvk(&T::sk(&[0xf5; 32])); let not_our_value = NonNegativeAmount::const_from_u64(10000); st.generate_block_at( birthday.height(), @@ -1346,7 +1348,7 @@ pub(crate) fn checkpoint_gaps() { // Create a gap of 10 blocks having no shielded outputs, then add a block that doesn't // belong to us so that we can get a checkpoint in the tree. - let not_our_key = T::sk_to_fvk(&T::sk(&[])); + let not_our_key = T::sk_to_fvk(&T::sk(&[0xf5; 32])); let not_our_value = NonNegativeAmount::const_from_u64(10000); st.generate_block_at( birthday.height() + 10, diff --git a/zcash_client_sqlite/src/wallet.rs b/zcash_client_sqlite/src/wallet.rs index 6648c7fb38..ff0c7cf6ae 100644 --- a/zcash_client_sqlite/src/wallet.rs +++ b/zcash_client_sqlite/src/wallet.rs @@ -127,6 +127,8 @@ use { pub mod commitment_tree; pub mod init; +#[cfg(feature = "orchard")] +pub(crate) mod orchard; pub(crate) mod sapling; pub(crate) mod scanning; diff --git a/zcash_client_sqlite/src/wallet/commitment_tree.rs b/zcash_client_sqlite/src/wallet/commitment_tree.rs index 28b26c7574..8dde47a535 100644 --- a/zcash_client_sqlite/src/wallet/commitment_tree.rs +++ b/zcash_client_sqlite/src/wallet/commitment_tree.rs @@ -1111,6 +1111,52 @@ mod tests { ShardTree::new(store, m) } + #[cfg(feature = "orchard")] + mod orchard { + use super::new_tree; + use crate::wallet::orchard::tests::OrchardPoolTester; + + #[test] + fn append() { + super::check_append(new_tree::); + } + + #[test] + fn root_hashes() { + super::check_root_hashes(new_tree::); + } + + #[test] + fn witnesses() { + super::check_witnesses(new_tree::); + } + + #[test] + fn witness_consistency() { + super::check_witness_consistency(new_tree::); + } + + #[test] + fn checkpoint_rewind() { + super::check_checkpoint_rewind(new_tree::); + } + + #[test] + fn remove_mark() { + super::check_remove_mark(new_tree::); + } + + #[test] + fn rewind_remove_mark() { + super::check_rewind_remove_mark(new_tree::); + } + + #[test] + fn put_shard_roots() { + super::put_shard_roots::() + } + } + #[test] fn sapling_append() { check_append(new_tree::); diff --git a/zcash_client_sqlite/src/wallet/orchard.rs b/zcash_client_sqlite/src/wallet/orchard.rs new file mode 100644 index 0000000000..e9251ef014 --- /dev/null +++ b/zcash_client_sqlite/src/wallet/orchard.rs @@ -0,0 +1,238 @@ +#[cfg(test)] +pub(crate) mod tests { + use incrementalmerkletree::{Hashable, Level}; + use orchard::{ + keys::{FullViewingKey, SpendingKey}, + note_encryption::OrchardDomain, + tree::MerkleHashOrchard, + }; + use shardtree::error::ShardTreeError; + use zcash_client_backend::{ + data_api::{ + chain::CommitmentTreeRoot, DecryptedTransaction, WalletCommitmentTrees, WalletSummary, + }, + wallet::{Note, ReceivedNote}, + }; + use zcash_keys::{ + address::{Address, UnifiedAddress}, + keys::UnifiedSpendingKey, + }; + use zcash_note_encryption::try_output_recovery_with_ovk; + use zcash_primitives::transaction::Transaction; + use zcash_protocol::{consensus::BlockHeight, memo::MemoBytes, ShieldedProtocol}; + + use crate::{ + error::SqliteClientError, + testing::{ + self, + pool::{OutputRecoveryError, ShieldedPoolTester}, + TestState, + }, + wallet::commitment_tree, + ORCHARD_TABLES_PREFIX, + }; + + pub(crate) struct OrchardPoolTester; + impl ShieldedPoolTester for OrchardPoolTester { + const SHIELDED_PROTOCOL: ShieldedProtocol = ShieldedProtocol::Orchard; + const TABLES_PREFIX: &'static str = ORCHARD_TABLES_PREFIX; + + type Sk = SpendingKey; + type Fvk = FullViewingKey; + type MerkleTreeHash = MerkleHashOrchard; + + fn test_account_fvk(st: &TestState) -> Self::Fvk { + st.test_account_orchard().unwrap() + } + + fn usk_to_sk(usk: &UnifiedSpendingKey) -> &Self::Sk { + usk.orchard() + } + + fn sk(seed: &[u8]) -> Self::Sk { + let mut account = zip32::AccountId::ZERO; + loop { + if let Ok(sk) = SpendingKey::from_zip32_seed(seed, 1, account) { + break sk; + } + account = account.next().unwrap(); + } + } + + fn sk_to_fvk(sk: &Self::Sk) -> Self::Fvk { + sk.into() + } + + fn sk_default_address(sk: &Self::Sk) -> Address { + Self::fvk_default_address(&Self::sk_to_fvk(sk)) + } + + fn fvk_default_address(fvk: &Self::Fvk) -> Address { + UnifiedAddress::from_receivers( + Some(fvk.address_at(0u32, zip32::Scope::External)), + None, + None, + ) + .unwrap() + .into() + } + + fn fvks_equal(a: &Self::Fvk, b: &Self::Fvk) -> bool { + a == b + } + + fn empty_tree_leaf() -> Self::MerkleTreeHash { + MerkleHashOrchard::empty_leaf() + } + + fn empty_tree_root(level: Level) -> Self::MerkleTreeHash { + MerkleHashOrchard::empty_root(level) + } + + fn put_subtree_roots( + st: &mut TestState, + start_index: u64, + roots: &[CommitmentTreeRoot], + ) -> Result<(), ShardTreeError> { + st.wallet_mut() + .put_orchard_subtree_roots(start_index, roots) + } + + fn next_subtree_index(s: &WalletSummary) -> u64 { + todo!() + } + + fn select_spendable_notes( + st: &TestState, + account: crate::AccountId, + target_value: zcash_protocol::value::Zatoshis, + anchor_height: BlockHeight, + exclude: &[crate::ReceivedNoteId], + ) -> Result>, SqliteClientError> { + todo!() + } + + fn decrypted_pool_outputs_count( + d_tx: &DecryptedTransaction<'_, crate::AccountId>, + ) -> usize { + d_tx.orchard_outputs().len() + } + + fn with_decrypted_pool_memos( + d_tx: &DecryptedTransaction<'_, crate::AccountId>, + mut f: impl FnMut(&MemoBytes), + ) { + for output in d_tx.orchard_outputs() { + f(output.memo()); + } + } + + fn try_output_recovery( + _: &TestState, + _: BlockHeight, + tx: &Transaction, + fvk: &Self::Fvk, + ) -> Result, OutputRecoveryError> { + for action in tx.orchard_bundle().unwrap().actions() { + // Find the output that decrypts with the external OVK + let result = try_output_recovery_with_ovk( + &OrchardDomain::for_action(action), + &fvk.to_ovk(zip32::Scope::External), + action, + action.cv_net(), + &action.encrypted_note().out_ciphertext, + ); + + if result.is_some() { + return Ok(result.map(|(note, addr, memo)| { + ( + Note::Orchard(note), + UnifiedAddress::from_receivers(Some(addr), None, None) + .unwrap() + .into(), + MemoBytes::from_bytes(&memo).expect("correct length"), + ) + })); + } + } + + Ok(None) + } + } + + #[test] + fn send_single_step_proposed_transfer() { + testing::pool::send_single_step_proposed_transfer::() + } + + #[test] + #[cfg(feature = "transparent-inputs")] + fn send_multi_step_proposed_transfer() { + testing::pool::send_multi_step_proposed_transfer::() + } + + #[test] + #[allow(deprecated)] + fn create_to_address_fails_on_incorrect_usk() { + testing::pool::create_to_address_fails_on_incorrect_usk::() + } + + #[test] + #[allow(deprecated)] + fn proposal_fails_with_no_blocks() { + testing::pool::proposal_fails_with_no_blocks::() + } + + #[test] + fn spend_fails_on_unverified_notes() { + testing::pool::spend_fails_on_unverified_notes::() + } + + #[test] + fn spend_fails_on_locked_notes() { + testing::pool::spend_fails_on_locked_notes::() + } + + #[test] + fn ovk_policy_prevents_recovery_from_chain() { + testing::pool::ovk_policy_prevents_recovery_from_chain::() + } + + #[test] + fn spend_succeeds_to_t_addr_zero_change() { + testing::pool::spend_succeeds_to_t_addr_zero_change::() + } + + #[test] + fn change_note_spends_succeed() { + testing::pool::change_note_spends_succeed::() + } + + #[test] + fn external_address_change_spends_detected_in_restore_from_seed() { + testing::pool::external_address_change_spends_detected_in_restore_from_seed::< + OrchardPoolTester, + >() + } + + #[test] + fn zip317_spend() { + testing::pool::zip317_spend::() + } + + #[test] + #[cfg(feature = "transparent-inputs")] + fn shield_transparent() { + testing::pool::shield_transparent::() + } + + #[test] + fn birthday_in_anchor_shard() { + testing::pool::birthday_in_anchor_shard::() + } + + #[test] + fn checkpoint_gaps() { + testing::pool::checkpoint_gaps::() + } +} diff --git a/zcash_client_sqlite/src/wallet/scanning.rs b/zcash_client_sqlite/src/wallet/scanning.rs index 528fbf1526..83bff86986 100644 --- a/zcash_client_sqlite/src/wallet/scanning.rs +++ b/zcash_client_sqlite/src/wallet/scanning.rs @@ -565,11 +565,20 @@ pub(crate) mod tests { VERIFY_LOOKAHEAD, }; + #[cfg(feature = "orchard")] + use crate::wallet::orchard::tests::OrchardPoolTester; + #[test] fn sapling_scan_complete() { scan_complete::(); } + #[cfg(feature = "orchard")] + #[test] + fn orchard_scan_complete() { + scan_complete::(); + } + fn scan_complete() { use ScanPriority::*; @@ -699,14 +708,16 @@ pub(crate) mod tests { ); } - pub(crate) fn test_with_canopy_birthday( + pub(crate) fn test_with_nu5_birthday_offset( + offset: u32, ) -> (TestState, T::Fvk, AccountBirthday, u32) { let st = TestBuilder::new() .with_block_cache() .with_test_account(|network| { - // We use Canopy activation as an arbitrary birthday height that's greater than Sapling - // activation. We set the Canopy Sapling frontier to be 1234 notes into the second shard. - let birthday_height = network.activation_height(NetworkUpgrade::Canopy).unwrap(); + // We set the Sapling frontier at the birthday height to be 1234 notes + // into the second shard. + let birthday_height = + network.activation_height(NetworkUpgrade::Nu5).unwrap() + offset; let sapling_frontier_position = Position::from((0x1 << 16) + 1234); let sapling_frontier = Frontier::from_parts( sapling_frontier_position, @@ -736,10 +747,17 @@ pub(crate) mod tests { create_account_creates_ignored_range::(); } + #[cfg(feature = "orchard")] + #[test] + fn orchard_create_account_creates_ignored_range() { + create_account_creates_ignored_range::(); + } + fn create_account_creates_ignored_range() { use ScanPriority::*; - let (st, _, birthday, sap_active) = test_with_canopy_birthday::(); + // Use a non-zero birthday offset because Sapling and NU5 are activated at the same height. + let (st, _, birthday, sap_active) = test_with_nu5_birthday_offset::(76); let birthday_height = birthday.height().into(); let expected = vec![ @@ -799,10 +817,17 @@ pub(crate) mod tests { update_chain_tip_with_no_subtree_roots::(); } + #[cfg(feature = "orchard")] + #[test] + fn orchard_update_chain_tip_with_no_subtree_roots() { + update_chain_tip_with_no_subtree_roots::(); + } + fn update_chain_tip_with_no_subtree_roots() { use ScanPriority::*; - let (mut st, _, birthday, sap_active) = test_with_canopy_birthday::(); + // Use a non-zero birthday offset because Sapling and NU5 are activated at the same height. + let (mut st, _, birthday, sap_active) = test_with_nu5_birthday_offset::(76); // Set up the following situation: // @@ -834,10 +859,17 @@ pub(crate) mod tests { update_chain_tip_when_never_scanned::(); } + #[cfg(feature = "orchard")] + #[test] + fn orchard_update_chain_tip_when_never_scanned() { + update_chain_tip_when_never_scanned::(); + } + fn update_chain_tip_when_never_scanned() { use ScanPriority::*; - let (mut st, _, birthday, sap_active) = test_with_canopy_birthday::(); + // Use a non-zero birthday offset because Sapling and NU5 are activated at the same height. + let (mut st, _, birthday, sap_active) = test_with_nu5_birthday_offset::(76); // Set up the following situation: // @@ -883,11 +915,18 @@ pub(crate) mod tests { update_chain_tip_unstable_max_scanned::(); } + #[cfg(feature = "orchard")] + #[test] + fn orchard_update_chain_tip_unstable_max_scanned() { + update_chain_tip_unstable_max_scanned::(); + } + fn update_chain_tip_unstable_max_scanned() { use ScanPriority::*; + // Use a non-zero birthday offset because Sapling and NU5 are activated at the same height. // this birthday is 1234 notes into the second shard - let (mut st, dfvk, birthday, sap_active) = test_with_canopy_birthday::(); + let (mut st, dfvk, birthday, sap_active) = test_with_nu5_birthday_offset::(76); // Set up the following situation: // @@ -1015,10 +1054,17 @@ pub(crate) mod tests { update_chain_tip_stable_max_scanned::(); } + #[cfg(feature = "orchard")] + #[test] + fn orchard_update_chain_tip_stable_max_scanned() { + update_chain_tip_stable_max_scanned::(); + } + fn update_chain_tip_stable_max_scanned() { use ScanPriority::*; - let (mut st, dfvk, birthday, sap_active) = test_with_canopy_birthday::(); + // Use a non-zero birthday offset because Sapling and NU5 are activated at the same height. + let (mut st, dfvk, birthday, sap_active) = test_with_nu5_birthday_offset::(76); // Set up the following situation: //