zcash_client_sqlite: Generalise `wallet::scanning` tests
This commit is contained in:
parent
399ae762b7
commit
9d40588a50
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use std::{convert::Infallible, num::NonZeroU32};
|
use std::{convert::Infallible, num::NonZeroU32};
|
||||||
|
|
||||||
|
use incrementalmerkletree::Level;
|
||||||
use rusqlite::params;
|
use rusqlite::params;
|
||||||
use secrecy::Secret;
|
use secrecy::Secret;
|
||||||
use shardtree::error::ShardTreeError;
|
use shardtree::error::ShardTreeError;
|
||||||
|
@ -29,7 +30,7 @@ use zcash_client_backend::{
|
||||||
chain::CommitmentTreeRoot,
|
chain::CommitmentTreeRoot,
|
||||||
error::Error,
|
error::Error,
|
||||||
wallet::input_selection::{GreedyInputSelector, GreedyInputSelectorError},
|
wallet::input_selection::{GreedyInputSelector, GreedyInputSelectorError},
|
||||||
AccountBirthday, DecryptedTransaction, Ratio, WalletRead, WalletWrite,
|
AccountBirthday, DecryptedTransaction, Ratio, WalletRead, WalletSummary, WalletWrite,
|
||||||
},
|
},
|
||||||
decrypt_transaction,
|
decrypt_transaction,
|
||||||
fees::{fixed, standard, DustOutputPolicy},
|
fees::{fixed, standard, DustOutputPolicy},
|
||||||
|
@ -87,6 +88,7 @@ pub(crate) trait ShieldedPoolTester {
|
||||||
fn fvks_equal(a: &Self::Fvk, b: &Self::Fvk) -> bool;
|
fn fvks_equal(a: &Self::Fvk, b: &Self::Fvk) -> bool;
|
||||||
|
|
||||||
fn empty_tree_leaf() -> Self::MerkleTreeHash;
|
fn empty_tree_leaf() -> Self::MerkleTreeHash;
|
||||||
|
fn empty_tree_root(level: Level) -> Self::MerkleTreeHash;
|
||||||
|
|
||||||
fn put_subtree_roots<Cache>(
|
fn put_subtree_roots<Cache>(
|
||||||
st: &mut TestState<Cache>,
|
st: &mut TestState<Cache>,
|
||||||
|
@ -94,6 +96,8 @@ pub(crate) trait ShieldedPoolTester {
|
||||||
roots: &[CommitmentTreeRoot<Self::MerkleTreeHash>],
|
roots: &[CommitmentTreeRoot<Self::MerkleTreeHash>],
|
||||||
) -> Result<(), ShardTreeError<commitment_tree::Error>>;
|
) -> Result<(), ShardTreeError<commitment_tree::Error>>;
|
||||||
|
|
||||||
|
fn next_subtree_index(s: &WalletSummary<AccountId>) -> u64;
|
||||||
|
|
||||||
fn select_spendable_notes<Cache>(
|
fn select_spendable_notes<Cache>(
|
||||||
st: &TestState<Cache>,
|
st: &TestState<Cache>,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
|
|
|
@ -464,7 +464,7 @@ pub(crate) fn put_received_note<T: ReceivedSaplingOutput>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use incrementalmerkletree::Hashable;
|
use incrementalmerkletree::{Hashable, Level};
|
||||||
use shardtree::error::ShardTreeError;
|
use shardtree::error::ShardTreeError;
|
||||||
use zcash_proofs::prover::LocalTxProver;
|
use zcash_proofs::prover::LocalTxProver;
|
||||||
|
|
||||||
|
@ -486,7 +486,9 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
address::Address,
|
address::Address,
|
||||||
data_api::{chain::CommitmentTreeRoot, DecryptedTransaction, WalletCommitmentTrees},
|
data_api::{
|
||||||
|
chain::CommitmentTreeRoot, DecryptedTransaction, WalletCommitmentTrees, WalletSummary,
|
||||||
|
},
|
||||||
keys::UnifiedSpendingKey,
|
keys::UnifiedSpendingKey,
|
||||||
wallet::{Note, ReceivedNote},
|
wallet::{Note, ReceivedNote},
|
||||||
ShieldedProtocol,
|
ShieldedProtocol,
|
||||||
|
@ -544,6 +546,10 @@ pub(crate) mod tests {
|
||||||
sapling::Node::empty_leaf()
|
sapling::Node::empty_leaf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn empty_tree_root(level: Level) -> Self::MerkleTreeHash {
|
||||||
|
sapling::Node::empty_root(level)
|
||||||
|
}
|
||||||
|
|
||||||
fn put_subtree_roots<Cache>(
|
fn put_subtree_roots<Cache>(
|
||||||
st: &mut TestState<Cache>,
|
st: &mut TestState<Cache>,
|
||||||
start_index: u64,
|
start_index: u64,
|
||||||
|
@ -553,6 +559,10 @@ pub(crate) mod tests {
|
||||||
.put_sapling_subtree_roots(start_index, roots)
|
.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>(
|
fn select_spendable_notes<Cache>(
|
||||||
st: &TestState<Cache>,
|
st: &TestState<Cache>,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
|
|
|
@ -547,8 +547,7 @@ pub(crate) mod tests {
|
||||||
use zcash_client_backend::data_api::{
|
use zcash_client_backend::data_api::{
|
||||||
chain::CommitmentTreeRoot,
|
chain::CommitmentTreeRoot,
|
||||||
scanning::{spanning_tree::testing::scan_range, ScanPriority},
|
scanning::{spanning_tree::testing::scan_range, ScanPriority},
|
||||||
AccountBirthday, Ratio, WalletCommitmentTrees, WalletRead, WalletWrite,
|
AccountBirthday, Ratio, WalletRead, WalletWrite, SAPLING_SHARD_HEIGHT,
|
||||||
SAPLING_SHARD_HEIGHT,
|
|
||||||
};
|
};
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
block::BlockHash,
|
block::BlockHash,
|
||||||
|
@ -567,7 +566,11 @@ pub(crate) mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn scan_complete() {
|
fn sapling_scan_complete() {
|
||||||
|
scan_complete::<SaplingPoolTester>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scan_complete<T: ShieldedPoolTester>() {
|
||||||
use ScanPriority::*;
|
use ScanPriority::*;
|
||||||
|
|
||||||
let mut st = TestBuilder::new()
|
let mut st = TestBuilder::new()
|
||||||
|
@ -575,26 +578,27 @@ pub(crate) mod tests {
|
||||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let dfvk = st.test_account_sapling().unwrap();
|
let dfvk = T::test_account_fvk(&st);
|
||||||
let sapling_activation_height = st.sapling_activation_height();
|
let sapling_activation_height = st.sapling_activation_height();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
// In the following, we don't care what the root hashes are, they just need to be
|
// In the following, we don't care what the root hashes are, they just need to be
|
||||||
// distinct.
|
// distinct.
|
||||||
st.wallet_mut().put_sapling_subtree_roots(
|
T::put_subtree_roots(
|
||||||
|
&mut st,
|
||||||
0,
|
0,
|
||||||
&[
|
&[
|
||||||
CommitmentTreeRoot::from_parts(
|
CommitmentTreeRoot::from_parts(
|
||||||
sapling_activation_height + 100,
|
sapling_activation_height + 100,
|
||||||
Node::empty_root(Level::from(0))
|
T::empty_tree_root(Level::from(0))
|
||||||
),
|
),
|
||||||
CommitmentTreeRoot::from_parts(
|
CommitmentTreeRoot::from_parts(
|
||||||
sapling_activation_height + 200,
|
sapling_activation_height + 200,
|
||||||
Node::empty_root(Level::from(1))
|
T::empty_tree_root(Level::from(1))
|
||||||
),
|
),
|
||||||
CommitmentTreeRoot::from_parts(
|
CommitmentTreeRoot::from_parts(
|
||||||
sapling_activation_height + 300,
|
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()
|
st.wallet()
|
||||||
.get_wallet_summary(0)
|
.get_wallet_summary(0)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|s| s.next_sapling_subtree_index()),
|
.map(|s| T::next_subtree_index(&s)),
|
||||||
Some(2),
|
Some(2),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -725,10 +729,14 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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::*;
|
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 birthday_height = birthday.height().into();
|
||||||
|
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
|
@ -784,10 +792,14 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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::*;
|
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:
|
// Set up the following situation:
|
||||||
//
|
//
|
||||||
|
@ -815,10 +827,14 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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::*;
|
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:
|
// Set up the following situation:
|
||||||
//
|
//
|
||||||
|
@ -829,16 +845,16 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
// Set up some shard root history before the wallet birthday.
|
// Set up some shard root history before the wallet birthday.
|
||||||
let last_shard_start = birthday.height() - 1000;
|
let last_shard_start = birthday.height() - 1000;
|
||||||
st.wallet_mut()
|
T::put_subtree_roots(
|
||||||
.put_sapling_subtree_roots(
|
&mut st,
|
||||||
0,
|
0,
|
||||||
&[CommitmentTreeRoot::from_parts(
|
&[CommitmentTreeRoot::from_parts(
|
||||||
last_shard_start,
|
last_shard_start,
|
||||||
// fake a hash, the value doesn't matter
|
// fake a hash, the value doesn't matter
|
||||||
Node::empty_leaf(),
|
T::empty_tree_leaf(),
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Update the chain tip.
|
// Update the chain tip.
|
||||||
let tip_height = prior_tip_height + 500;
|
let tip_height = prior_tip_height + 500;
|
||||||
|
@ -860,11 +876,15 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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::*;
|
use ScanPriority::*;
|
||||||
|
|
||||||
// this birthday is 1234 notes into the second shard
|
// 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:
|
// Set up the following situation:
|
||||||
//
|
//
|
||||||
|
@ -876,16 +896,16 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
// Set up some shard root history before the wallet birthday.
|
// Set up some shard root history before the wallet birthday.
|
||||||
let initial_shard_end = birthday.height() - 1000;
|
let initial_shard_end = birthday.height() - 1000;
|
||||||
st.wallet_mut()
|
T::put_subtree_roots(
|
||||||
.put_sapling_subtree_roots(
|
&mut st,
|
||||||
0,
|
0,
|
||||||
&[CommitmentTreeRoot::from_parts(
|
&[CommitmentTreeRoot::from_parts(
|
||||||
initial_shard_end,
|
initial_shard_end,
|
||||||
// fake a hash, the value doesn't matter
|
// fake a hash, the value doesn't matter
|
||||||
Node::empty_leaf(),
|
T::empty_tree_leaf(),
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Set up prior chain state. This simulates us having imported a wallet
|
// Set up prior chain state. This simulates us having imported a wallet
|
||||||
// with a birthday 520 blocks below the chain tip.
|
// with a birthday 520 blocks below the chain tip.
|
||||||
|
@ -928,16 +948,16 @@ pub(crate) mod tests {
|
||||||
// Now simulate shutting down, and then restarting 90 blocks later, after a shard
|
// Now simulate shutting down, and then restarting 90 blocks later, after a shard
|
||||||
// has been completed.
|
// has been completed.
|
||||||
let last_shard_start = prior_tip + 70;
|
let last_shard_start = prior_tip + 70;
|
||||||
st.wallet_mut()
|
T::put_subtree_roots(
|
||||||
.put_sapling_subtree_roots(
|
&mut st,
|
||||||
0,
|
0,
|
||||||
&[CommitmentTreeRoot::from_parts(
|
&[CommitmentTreeRoot::from_parts(
|
||||||
last_shard_start,
|
last_shard_start,
|
||||||
// fake a hash, the value doesn't matter
|
// fake a hash, the value doesn't matter
|
||||||
Node::empty_leaf(),
|
T::empty_tree_leaf(),
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let new_tip = last_shard_start + 20;
|
let new_tip = last_shard_start + 20;
|
||||||
st.wallet_mut().update_chain_tip(new_tip).unwrap();
|
st.wallet_mut().update_chain_tip(new_tip).unwrap();
|
||||||
|
@ -972,10 +992,14 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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::*;
|
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:
|
// Set up the following situation:
|
||||||
//
|
//
|
||||||
|
@ -988,16 +1012,16 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
// Set up some shard root history before the wallet birthday.
|
// Set up some shard root history before the wallet birthday.
|
||||||
let second_to_last_shard_start = birthday.height() - 1000;
|
let second_to_last_shard_start = birthday.height() - 1000;
|
||||||
st.wallet_mut()
|
T::put_subtree_roots(
|
||||||
.put_sapling_subtree_roots(
|
&mut st,
|
||||||
0,
|
0,
|
||||||
&[CommitmentTreeRoot::from_parts(
|
&[CommitmentTreeRoot::from_parts(
|
||||||
second_to_last_shard_start,
|
second_to_last_shard_start,
|
||||||
// fake a hash, the value doesn't matter
|
// fake a hash, the value doesn't matter
|
||||||
Node::empty_leaf(),
|
T::empty_tree_leaf(),
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// We have scan ranges and a subtree, but have scanned no blocks.
|
// We have scan ranges and a subtree, but have scanned no blocks.
|
||||||
let summary = st.get_wallet_summary(1);
|
let summary = st.get_wallet_summary(1);
|
||||||
|
@ -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
|
// 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.
|
// wallet birthday but before the end of the shard.
|
||||||
let summary = st.get_wallet_summary(1);
|
let summary = st.get_wallet_summary(1);
|
||||||
assert_eq!(
|
assert_eq!(summary.as_ref().map(|s| T::next_subtree_index(s)), Some(0),);
|
||||||
summary.as_ref().map(|s| s.next_sapling_subtree_index()),
|
|
||||||
Some(0),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
summary.and_then(|s| s.scan_progress()),
|
summary.and_then(|s| s.scan_progress()),
|
||||||
Some(Ratio::new(1, 0x1 << SAPLING_SHARD_HEIGHT))
|
Some(Ratio::new(1, 0x1 << SAPLING_SHARD_HEIGHT))
|
||||||
|
@ -1044,16 +1065,16 @@ pub(crate) mod tests {
|
||||||
// Now simulate shutting down, and then restarting 70 blocks later, after a shard
|
// Now simulate shutting down, and then restarting 70 blocks later, after a shard
|
||||||
// has been completed.
|
// has been completed.
|
||||||
let last_shard_start = prior_tip + 50;
|
let last_shard_start = prior_tip + 50;
|
||||||
st.wallet_mut()
|
T::put_subtree_roots(
|
||||||
.put_sapling_subtree_roots(
|
&mut st,
|
||||||
0,
|
0,
|
||||||
&[CommitmentTreeRoot::from_parts(
|
&[CommitmentTreeRoot::from_parts(
|
||||||
last_shard_start,
|
last_shard_start,
|
||||||
// fake a hash, the value doesn't matter
|
// fake a hash, the value doesn't matter
|
||||||
Node::empty_leaf(),
|
T::empty_tree_leaf(),
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let new_tip = last_shard_start + 20;
|
let new_tip = last_shard_start + 20;
|
||||||
st.wallet_mut().update_chain_tip(new_tip).unwrap();
|
st.wallet_mut().update_chain_tip(new_tip).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue