From b32d449d0b94bf8fac8abd62e2e50f48a2465580 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sun, 10 Mar 2024 22:13:39 -0600 Subject: [PATCH] zcash_client_sqlite: Add a failing test of cross-pool transfer --- zcash_client_backend/src/data_api.rs | 23 ++++-- zcash_client_sqlite/src/lib.rs | 4 +- zcash_client_sqlite/src/testing/pool.rs | 85 ++++++++++++++++++++++- zcash_client_sqlite/src/wallet/orchard.rs | 7 ++ zcash_client_sqlite/src/wallet/sapling.rs | 8 +++ 5 files changed, 120 insertions(+), 7 deletions(-) diff --git a/zcash_client_backend/src/data_api.rs b/zcash_client_backend/src/data_api.rs index 5866d1212f..d6b6df91d8 100644 --- a/zcash_client_backend/src/data_api.rs +++ b/zcash_client_backend/src/data_api.rs @@ -92,6 +92,9 @@ use { zcash_primitives::{legacy::TransparentAddress, transaction::components::OutPoint}, }; +#[cfg(feature = "test-dependencies")] +use zcash_primitives::consensus::NetworkUpgrade; + pub mod chain; pub mod error; pub mod scanning; @@ -1172,19 +1175,31 @@ impl AccountBirthday { /// # Panics /// /// Panics if the Sapling activation height is not set. - pub fn from_sapling_activation( + pub fn from_activation( params: &P, + network_upgrade: NetworkUpgrade, ) -> AccountBirthday { - use zcash_primitives::consensus::NetworkUpgrade; - AccountBirthday::from_parts( - params.activation_height(NetworkUpgrade::Sapling).unwrap(), + params.activation_height(network_upgrade).unwrap(), Frontier::empty(), #[cfg(feature = "orchard")] Frontier::empty(), None, ) } + + #[cfg(feature = "test-dependencies")] + /// Constructs a new [`AccountBirthday`] at Sapling activation, with no + /// "recover until" height. + /// + /// # Panics + /// + /// Panics if the Sapling activation height is not set. + pub fn from_sapling_activation( + params: &P, + ) -> AccountBirthday { + Self::from_activation(params, NetworkUpgrade::Sapling) + } } /// This trait encapsulates the write capabilities required to update stored diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index a6c4560f47..df83bbd75d 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -960,9 +960,9 @@ impl WalletWrite for WalletDb )?; } } - if let Some(bundle) = sent_tx.tx().orchard_bundle() { + if let Some(_bundle) = sent_tx.tx().orchard_bundle() { #[cfg(feature = "orchard")] - for action in bundle.actions() { + for action in _bundle.actions() { wallet::orchard::mark_orchard_note_spent( wdb.conn.0, tx_ref, diff --git a/zcash_client_sqlite/src/testing/pool.rs b/zcash_client_sqlite/src/testing/pool.rs index 84884ba863..5a7846984b 100644 --- a/zcash_client_sqlite/src/testing/pool.rs +++ b/zcash_client_sqlite/src/testing/pool.rs @@ -10,7 +10,7 @@ use secrecy::Secret; use shardtree::error::ShardTreeError; use zcash_primitives::{ block::BlockHash, - consensus::BranchId, + consensus::{BranchId, NetworkUpgrade}, legacy::TransparentAddress, memo::{Memo, MemoBytes}, transaction::{ @@ -1400,6 +1400,89 @@ pub(crate) fn checkpoint_gaps() { ); } +#[cfg(feature = "orchard")] +pub(crate) fn cross_pool_exchange() { + let mut st = TestBuilder::new() + .with_block_cache() + .with_test_account(|params| AccountBirthday::from_activation(params, NetworkUpgrade::Nu5)) + .build(); + + let (account, usk, birthday) = st.test_account().unwrap(); + + let p0_fvk = P0::test_account_fvk(&st); + + let p1_fvk = P1::test_account_fvk(&st); + let p1_to = P1::fvk_default_address(&p1_fvk); + + let value = NonNegativeAmount::const_from_u64(300000); + st.generate_next_block(&p0_fvk, AddressType::DefaultExternal, value); + st.generate_next_block(&p1_fvk, AddressType::DefaultExternal, value); + st.scan_cached_blocks(birthday.height(), 2); + + let initial_balance = NonNegativeAmount::const_from_u64(600000); + assert_eq!(st.get_total_balance(account), initial_balance); + assert_eq!(st.get_spendable_balance(account, 1), initial_balance); + + let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment { + recipient_address: p1_to, + amount: NonNegativeAmount::const_from_u64(200000), + memo: None, + label: None, + message: None, + other_params: vec![], + }]) + .unwrap(); + + let fee_rule = StandardFeeRule::Zip317; + let input_selector = GreedyInputSelector::new( + standard::SingleOutputChangeStrategy::new(fee_rule, None, P1::SHIELDED_PROTOCOL), + DustOutputPolicy::default(), + ); + let proposal0 = st + .propose_transfer( + account, + &input_selector, + p0_to_p1, + NonZeroU32::new(1).unwrap(), + ) + .unwrap(); + + let _min_target_height = proposal0.min_target_height(); + let step0 = &proposal0.steps().head; + + let proposed_change = step0.balance().proposed_change(); + assert_eq!(proposed_change.len(), 1); + let change_output = proposed_change.get(0).unwrap(); + // Since this is a cross-pool transfer, change will be sent to the preferred pool. + assert_eq!( + change_output.output_pool(), + std::cmp::max(ShieldedProtocol::Sapling, ShieldedProtocol::Orchard) + ); + assert_eq!( + change_output.value(), + NonNegativeAmount::const_from_u64(80000) + ); + + let expected_fee = NonNegativeAmount::const_from_u64(20000); + assert_eq!(step0.balance().fee_required(), expected_fee); + + let create_proposed_result = + st.create_proposed_transactions::(&usk, OvkPolicy::Sender, &proposal0); + assert_matches!(&create_proposed_result, Ok(txids) if txids.len() == 1); + + let (h, _) = st.generate_next_block_including(create_proposed_result.unwrap()[0]); + st.scan_cached_blocks(h, 1); + + assert_eq!( + st.get_total_balance(account), + (initial_balance - expected_fee).unwrap() + ); + assert_eq!( + st.get_spendable_balance(account, 1), + (initial_balance - expected_fee).unwrap() + ); +} + pub(crate) fn valid_chain_states() { let mut st = TestBuilder::new() .with_block_cache() diff --git a/zcash_client_sqlite/src/wallet/orchard.rs b/zcash_client_sqlite/src/wallet/orchard.rs index 92abf830c9..a4b1f83b9f 100644 --- a/zcash_client_sqlite/src/wallet/orchard.rs +++ b/zcash_client_sqlite/src/wallet/orchard.rs @@ -599,4 +599,11 @@ pub(crate) mod tests { fn scan_cached_blocks_detects_spends_out_of_order() { testing::pool::scan_cached_blocks_detects_spends_out_of_order::() } + + #[test] + fn cross_pool_exchange() { + use crate::wallet::sapling::tests::SaplingPoolTester; + + testing::pool::cross_pool_exchange::() + } } diff --git a/zcash_client_sqlite/src/wallet/sapling.rs b/zcash_client_sqlite/src/wallet/sapling.rs index 1410d0baad..4801ca69b1 100644 --- a/zcash_client_sqlite/src/wallet/sapling.rs +++ b/zcash_client_sqlite/src/wallet/sapling.rs @@ -602,4 +602,12 @@ pub(crate) mod tests { fn scan_cached_blocks_detects_spends_out_of_order() { testing::pool::scan_cached_blocks_detects_spends_out_of_order::() } + + #[test] + #[cfg(feature = "orchard")] + fn cross_pool_exchange() { + use crate::wallet::orchard::tests::OrchardPoolTester; + + testing::pool::cross_pool_exchange::() + } }