zcash_client_sqlite: Generalise `wallet::scanning` tests

This commit is contained in:
Jack Grigg 2024-03-09 15:14:35 +00:00
parent 399ae762b7
commit 9d40588a50
3 changed files with 111 additions and 76 deletions

View File

@ -4,6 +4,7 @@
use std::{convert::Infallible, num::NonZeroU32};
use incrementalmerkletree::Level;
use rusqlite::params;
use secrecy::Secret;
use shardtree::error::ShardTreeError;
@ -29,7 +30,7 @@ use zcash_client_backend::{
chain::CommitmentTreeRoot,
error::Error,
wallet::input_selection::{GreedyInputSelector, GreedyInputSelectorError},
AccountBirthday, DecryptedTransaction, Ratio, WalletRead, WalletWrite,
AccountBirthday, DecryptedTransaction, Ratio, WalletRead, WalletSummary, WalletWrite,
},
decrypt_transaction,
fees::{fixed, standard, DustOutputPolicy},
@ -87,6 +88,7 @@ pub(crate) trait ShieldedPoolTester {
fn fvks_equal(a: &Self::Fvk, b: &Self::Fvk) -> bool;
fn empty_tree_leaf() -> Self::MerkleTreeHash;
fn empty_tree_root(level: Level) -> Self::MerkleTreeHash;
fn put_subtree_roots<Cache>(
st: &mut TestState<Cache>,
@ -94,6 +96,8 @@ pub(crate) trait ShieldedPoolTester {
roots: &[CommitmentTreeRoot<Self::MerkleTreeHash>],
) -> Result<(), ShardTreeError<commitment_tree::Error>>;
fn next_subtree_index(s: &WalletSummary<AccountId>) -> u64;
fn select_spendable_notes<Cache>(
st: &TestState<Cache>,
account: AccountId,

View File

@ -464,7 +464,7 @@ pub(crate) fn put_received_note<T: ReceivedSaplingOutput>(
#[cfg(test)]
pub(crate) mod tests {
use incrementalmerkletree::Hashable;
use incrementalmerkletree::{Hashable, Level};
use shardtree::error::ShardTreeError;
use zcash_proofs::prover::LocalTxProver;
@ -486,7 +486,9 @@ pub(crate) mod tests {
use zcash_client_backend::{
address::Address,
data_api::{chain::CommitmentTreeRoot, DecryptedTransaction, WalletCommitmentTrees},
data_api::{
chain::CommitmentTreeRoot, DecryptedTransaction, WalletCommitmentTrees, WalletSummary,
},
keys::UnifiedSpendingKey,
wallet::{Note, ReceivedNote},
ShieldedProtocol,
@ -544,6 +546,10 @@ pub(crate) mod tests {
sapling::Node::empty_leaf()
}
fn empty_tree_root(level: Level) -> Self::MerkleTreeHash {
sapling::Node::empty_root(level)
}
fn put_subtree_roots<Cache>(
st: &mut TestState<Cache>,
start_index: u64,
@ -553,6 +559,10 @@ pub(crate) mod tests {
.put_sapling_subtree_roots(start_index, roots)
}
fn next_subtree_index(s: &WalletSummary<AccountId>) -> u64 {
s.next_sapling_subtree_index()
}
fn select_spendable_notes<Cache>(
st: &TestState<Cache>,
account: AccountId,

View File

@ -547,8 +547,7 @@ pub(crate) mod tests {
use zcash_client_backend::data_api::{
chain::CommitmentTreeRoot,
scanning::{spanning_tree::testing::scan_range, ScanPriority},
AccountBirthday, Ratio, WalletCommitmentTrees, WalletRead, WalletWrite,
SAPLING_SHARD_HEIGHT,
AccountBirthday, Ratio, WalletRead, WalletWrite, SAPLING_SHARD_HEIGHT,
};
use zcash_primitives::{
block::BlockHash,
@ -567,7 +566,11 @@ pub(crate) mod tests {
};
#[test]
fn scan_complete() {
fn sapling_scan_complete() {
scan_complete::<SaplingPoolTester>();
}
fn scan_complete<T: ShieldedPoolTester>() {
use ScanPriority::*;
let mut st = TestBuilder::new()
@ -575,26 +578,27 @@ pub(crate) mod tests {
.with_test_account(AccountBirthday::from_sapling_activation)
.build();
let dfvk = st.test_account_sapling().unwrap();
let dfvk = T::test_account_fvk(&st);
let sapling_activation_height = st.sapling_activation_height();
assert_matches!(
// In the following, we don't care what the root hashes are, they just need to be
// distinct.
st.wallet_mut().put_sapling_subtree_roots(
T::put_subtree_roots(
&mut st,
0,
&[
CommitmentTreeRoot::from_parts(
sapling_activation_height + 100,
Node::empty_root(Level::from(0))
T::empty_tree_root(Level::from(0))
),
CommitmentTreeRoot::from_parts(
sapling_activation_height + 200,
Node::empty_root(Level::from(1))
T::empty_tree_root(Level::from(1))
),
CommitmentTreeRoot::from_parts(
sapling_activation_height + 300,
Node::empty_root(Level::from(2))
T::empty_tree_root(Level::from(2))
),
]
),
@ -687,7 +691,7 @@ pub(crate) mod tests {
st.wallet()
.get_wallet_summary(0)
.unwrap()
.map(|s| s.next_sapling_subtree_index()),
.map(|s| T::next_subtree_index(&s)),
Some(2),
);
}
@ -725,10 +729,14 @@ pub(crate) mod tests {
}
#[test]
fn create_account_creates_ignored_range() {
fn sapling_create_account_creates_ignored_range() {
create_account_creates_ignored_range::<SaplingPoolTester>();
}
fn create_account_creates_ignored_range<T: ShieldedPoolTester>() {
use ScanPriority::*;
let (st, _, birthday, sap_active) = test_with_canopy_birthday::<SaplingPoolTester>();
let (st, _, birthday, sap_active) = test_with_canopy_birthday::<T>();
let birthday_height = birthday.height().into();
let expected = vec![
@ -784,10 +792,14 @@ pub(crate) mod tests {
}
#[test]
fn update_chain_tip_with_no_subtree_roots() {
fn sapling_update_chain_tip_with_no_subtree_roots() {
update_chain_tip_with_no_subtree_roots::<SaplingPoolTester>();
}
fn update_chain_tip_with_no_subtree_roots<T: ShieldedPoolTester>() {
use ScanPriority::*;
let (mut st, _, birthday, sap_active) = test_with_canopy_birthday::<SaplingPoolTester>();
let (mut st, _, birthday, sap_active) = test_with_canopy_birthday::<T>();
// Set up the following situation:
//
@ -815,10 +827,14 @@ pub(crate) mod tests {
}
#[test]
fn update_chain_tip_when_never_scanned() {
fn sapling_update_chain_tip_when_never_scanned() {
update_chain_tip_when_never_scanned::<SaplingPoolTester>();
}
fn update_chain_tip_when_never_scanned<T: ShieldedPoolTester>() {
use ScanPriority::*;
let (mut st, _, birthday, sap_active) = test_with_canopy_birthday::<SaplingPoolTester>();
let (mut st, _, birthday, sap_active) = test_with_canopy_birthday::<T>();
// Set up the following situation:
//
@ -829,13 +845,13 @@ pub(crate) mod tests {
// Set up some shard root history before the wallet birthday.
let last_shard_start = birthday.height() - 1000;
st.wallet_mut()
.put_sapling_subtree_roots(
T::put_subtree_roots(
&mut st,
0,
&[CommitmentTreeRoot::from_parts(
last_shard_start,
// fake a hash, the value doesn't matter
Node::empty_leaf(),
T::empty_tree_leaf(),
)],
)
.unwrap();
@ -860,11 +876,15 @@ pub(crate) mod tests {
}
#[test]
fn update_chain_tip_unstable_max_scanned() {
fn sapling_update_chain_tip_unstable_max_scanned() {
update_chain_tip_unstable_max_scanned::<SaplingPoolTester>();
}
fn update_chain_tip_unstable_max_scanned<T: ShieldedPoolTester>() {
use ScanPriority::*;
// this birthday is 1234 notes into the second shard
let (mut st, dfvk, birthday, sap_active) = test_with_canopy_birthday::<SaplingPoolTester>();
let (mut st, dfvk, birthday, sap_active) = test_with_canopy_birthday::<T>();
// Set up the following situation:
//
@ -876,13 +896,13 @@ pub(crate) mod tests {
// Set up some shard root history before the wallet birthday.
let initial_shard_end = birthday.height() - 1000;
st.wallet_mut()
.put_sapling_subtree_roots(
T::put_subtree_roots(
&mut st,
0,
&[CommitmentTreeRoot::from_parts(
initial_shard_end,
// fake a hash, the value doesn't matter
Node::empty_leaf(),
T::empty_tree_leaf(),
)],
)
.unwrap();
@ -928,13 +948,13 @@ pub(crate) mod tests {
// Now simulate shutting down, and then restarting 90 blocks later, after a shard
// has been completed.
let last_shard_start = prior_tip + 70;
st.wallet_mut()
.put_sapling_subtree_roots(
T::put_subtree_roots(
&mut st,
0,
&[CommitmentTreeRoot::from_parts(
last_shard_start,
// fake a hash, the value doesn't matter
Node::empty_leaf(),
T::empty_tree_leaf(),
)],
)
.unwrap();
@ -972,10 +992,14 @@ pub(crate) mod tests {
}
#[test]
fn update_chain_tip_stable_max_scanned() {
fn sapling_update_chain_tip_stable_max_scanned() {
update_chain_tip_stable_max_scanned::<SaplingPoolTester>();
}
fn update_chain_tip_stable_max_scanned<T: ShieldedPoolTester>() {
use ScanPriority::*;
let (mut st, dfvk, birthday, sap_active) = test_with_canopy_birthday::<SaplingPoolTester>();
let (mut st, dfvk, birthday, sap_active) = test_with_canopy_birthday::<T>();
// Set up the following situation:
//
@ -988,13 +1012,13 @@ pub(crate) mod tests {
// Set up some shard root history before the wallet birthday.
let second_to_last_shard_start = birthday.height() - 1000;
st.wallet_mut()
.put_sapling_subtree_roots(
T::put_subtree_roots(
&mut st,
0,
&[CommitmentTreeRoot::from_parts(
second_to_last_shard_start,
// fake a hash, the value doesn't matter
Node::empty_leaf(),
T::empty_tree_leaf(),
)],
)
.unwrap();
@ -1032,10 +1056,7 @@ pub(crate) mod tests {
// We have scanned a block, so we now have a starting tree position, 500 blocks above the
// wallet birthday but before the end of the shard.
let summary = st.get_wallet_summary(1);
assert_eq!(
summary.as_ref().map(|s| s.next_sapling_subtree_index()),
Some(0),
);
assert_eq!(summary.as_ref().map(|s| T::next_subtree_index(s)), Some(0),);
assert_eq!(
summary.and_then(|s| s.scan_progress()),
Some(Ratio::new(1, 0x1 << SAPLING_SHARD_HEIGHT))
@ -1044,13 +1065,13 @@ pub(crate) mod tests {
// Now simulate shutting down, and then restarting 70 blocks later, after a shard
// has been completed.
let last_shard_start = prior_tip + 50;
st.wallet_mut()
.put_sapling_subtree_roots(
T::put_subtree_roots(
&mut st,
0,
&[CommitmentTreeRoot::from_parts(
last_shard_start,
// fake a hash, the value doesn't matter
Node::empty_leaf(),
T::empty_tree_leaf(),
)],
)
.unwrap();