zcash_client_sqlite: Modify `TestState` to allow initialization with chain state.
This commit is contained in:
parent
978f838aae
commit
dc4fccf566
|
@ -71,6 +71,8 @@ and this library adheres to Rust's notion of
|
|||
- `get_transaction` now returns `Result<Option<Transaction>, _>` rather
|
||||
than returning an `Err` if the `txid` parameter does not correspond to
|
||||
a transaction in the database.
|
||||
- `WalletWrite::create_account` now takes its `AccountBirthday` argument by
|
||||
reference.
|
||||
- Changes to the `InputSource` trait:
|
||||
- `select_spendable_notes` now takes its `target_value` argument as a
|
||||
`NonNegativeAmount`. Also, it now returns a `SpendableNotes` data
|
||||
|
|
|
@ -1297,11 +1297,7 @@ impl<AccountId> SentTransactionOutput<AccountId> {
|
|||
/// note commitment tree state is recorded at that height.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AccountBirthday {
|
||||
height: BlockHeight,
|
||||
sapling_frontier: Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_frontier:
|
||||
Frontier<orchard::tree::MerkleHashOrchard, { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 }>,
|
||||
prior_chain_state: ChainState,
|
||||
recover_until: Option<BlockHeight>,
|
||||
}
|
||||
|
||||
|
@ -1326,10 +1322,9 @@ impl From<io::Error> for BirthdayError {
|
|||
impl AccountBirthday {
|
||||
/// Constructs a new [`AccountBirthday`] from its constituent parts.
|
||||
///
|
||||
/// * `height`: The birthday height of the account. This is defined as the height of the first
|
||||
/// block to be scanned in wallet recovery.
|
||||
/// * `sapling_frontier`: The Sapling note commitment tree frontier as of the end of the block
|
||||
/// prior to the birthday height.
|
||||
/// * `prior_chain_state`: The chain state prior to the birthday height of the account. The
|
||||
/// birthday height is defined as the height of the first block to be scanned in wallet
|
||||
/// recovery.
|
||||
/// * `recover_until`: An optional height at which the wallet should exit "recovery mode". In
|
||||
/// order to avoid confusing shifts in wallet balance and spendability that may temporarily be
|
||||
/// visible to a user during the process of recovering from seed, wallets may optionally set a
|
||||
|
@ -1340,20 +1335,9 @@ impl AccountBirthday {
|
|||
/// This API is intended primarily to be used in testing contexts; under normal circumstances,
|
||||
/// [`AccountBirthday::from_treestate`] should be used instead.
|
||||
#[cfg(feature = "test-dependencies")]
|
||||
pub fn from_parts(
|
||||
height: BlockHeight,
|
||||
sapling_frontier: Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
|
||||
#[cfg(feature = "orchard")] orchard_frontier: Frontier<
|
||||
orchard::tree::MerkleHashOrchard,
|
||||
{ orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 },
|
||||
>,
|
||||
recover_until: Option<BlockHeight>,
|
||||
) -> Self {
|
||||
pub fn from_parts(prior_chain_state: ChainState, recover_until: Option<BlockHeight>) -> Self {
|
||||
Self {
|
||||
height,
|
||||
sapling_frontier,
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_frontier,
|
||||
prior_chain_state,
|
||||
recover_until,
|
||||
}
|
||||
}
|
||||
|
@ -1373,10 +1357,7 @@ impl AccountBirthday {
|
|||
recover_until: Option<BlockHeight>,
|
||||
) -> Result<Self, BirthdayError> {
|
||||
Ok(Self {
|
||||
height: BlockHeight::try_from(treestate.height + 1)?,
|
||||
sapling_frontier: treestate.sapling_tree()?.to_frontier(),
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_frontier: treestate.orchard_tree()?.to_frontier(),
|
||||
prior_chain_state: treestate.to_chain_state()?,
|
||||
recover_until,
|
||||
})
|
||||
}
|
||||
|
@ -1386,7 +1367,7 @@ impl AccountBirthday {
|
|||
pub fn sapling_frontier(
|
||||
&self,
|
||||
) -> &Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }> {
|
||||
&self.sapling_frontier
|
||||
self.prior_chain_state.final_sapling_tree()
|
||||
}
|
||||
|
||||
/// Returns the Orchard note commitment tree frontier as of the end of the block at
|
||||
|
@ -1396,12 +1377,12 @@ impl AccountBirthday {
|
|||
&self,
|
||||
) -> &Frontier<orchard::tree::MerkleHashOrchard, { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 }>
|
||||
{
|
||||
&self.orchard_frontier
|
||||
self.prior_chain_state.final_orchard_tree()
|
||||
}
|
||||
|
||||
/// Returns the birthday height of the account.
|
||||
pub fn height(&self) -> BlockHeight {
|
||||
self.height
|
||||
self.prior_chain_state.block_height() + 1
|
||||
}
|
||||
|
||||
/// Returns the height at which the wallet should exit "recovery mode".
|
||||
|
@ -1409,7 +1390,7 @@ impl AccountBirthday {
|
|||
self.recover_until
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-dependencies")]
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
/// Constructs a new [`AccountBirthday`] at the given network upgrade's activation,
|
||||
/// with no "recover until" height.
|
||||
///
|
||||
|
@ -1419,17 +1400,18 @@ impl AccountBirthday {
|
|||
pub fn from_activation<P: zcash_primitives::consensus::Parameters>(
|
||||
params: &P,
|
||||
network_upgrade: NetworkUpgrade,
|
||||
prior_block_hash: BlockHash,
|
||||
) -> AccountBirthday {
|
||||
AccountBirthday::from_parts(
|
||||
params.activation_height(network_upgrade).unwrap(),
|
||||
Frontier::empty(),
|
||||
#[cfg(feature = "orchard")]
|
||||
Frontier::empty(),
|
||||
ChainState::empty(
|
||||
params.activation_height(network_upgrade).unwrap() - 1,
|
||||
prior_block_hash,
|
||||
),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-dependencies")]
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
/// Constructs a new [`AccountBirthday`] at Sapling activation, with no
|
||||
/// "recover until" height.
|
||||
///
|
||||
|
@ -1438,8 +1420,9 @@ impl AccountBirthday {
|
|||
/// Panics if the Sapling activation height is not set.
|
||||
pub fn from_sapling_activation<P: zcash_primitives::consensus::Parameters>(
|
||||
params: &P,
|
||||
prior_block_hash: BlockHash,
|
||||
) -> AccountBirthday {
|
||||
Self::from_activation(params, NetworkUpgrade::Sapling)
|
||||
Self::from_activation(params, NetworkUpgrade::Sapling, prior_block_hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1482,7 +1465,7 @@ pub trait WalletWrite: WalletRead {
|
|||
fn create_account(
|
||||
&mut self,
|
||||
seed: &SecretVec<u8>,
|
||||
birthday: AccountBirthday,
|
||||
birthday: &AccountBirthday,
|
||||
) -> Result<(Self::AccountId, UnifiedSpendingKey), Self::Error>;
|
||||
|
||||
/// Generates and persists the next available diversified address, given the current
|
||||
|
@ -1887,7 +1870,7 @@ pub mod testing {
|
|||
fn create_account(
|
||||
&mut self,
|
||||
seed: &SecretVec<u8>,
|
||||
_birthday: AccountBirthday,
|
||||
_birthday: &AccountBirthday,
|
||||
) -> Result<(Self::AccountId, UnifiedSpendingKey), Self::Error> {
|
||||
let account = zip32::AccountId::ZERO;
|
||||
UnifiedSpendingKey::from_seed(&self.network, seed.expose_secret(), account)
|
||||
|
|
|
@ -530,7 +530,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
|
|||
fn create_account(
|
||||
&mut self,
|
||||
seed: &SecretVec<u8>,
|
||||
birthday: AccountBirthday,
|
||||
birthday: &AccountBirthday,
|
||||
) -> Result<(AccountId, UnifiedSpendingKey), Self::Error> {
|
||||
self.transactionally(|wdb| {
|
||||
let seed_fingerprint =
|
||||
|
@ -1690,7 +1690,8 @@ extern crate assert_matches;
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use secrecy::SecretVec;
|
||||
use zcash_client_backend::data_api::{AccountBirthday, WalletRead, WalletWrite};
|
||||
use zcash_client_backend::data_api::{WalletRead, WalletWrite};
|
||||
use zcash_primitives::block::BlockHash;
|
||||
|
||||
use crate::{testing::TestBuilder, AccountId, DEFAULT_UA_REQUEST};
|
||||
|
||||
|
@ -1703,7 +1704,7 @@ mod tests {
|
|||
#[test]
|
||||
fn validate_seed() {
|
||||
let st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
let account = st.test_account().unwrap();
|
||||
|
||||
|
@ -1732,7 +1733,7 @@ mod tests {
|
|||
#[test]
|
||||
pub(crate) fn get_next_available_address() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
||||
|
@ -1763,7 +1764,7 @@ mod tests {
|
|||
// Add an account to the wallet.
|
||||
let st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
let account = st.test_account().unwrap();
|
||||
let ufvk = account.usk().to_unified_full_viewing_key();
|
||||
|
|
|
@ -13,7 +13,7 @@ use rand_chacha::ChaChaRng;
|
|||
use rand_core::{CryptoRng, RngCore, SeedableRng};
|
||||
use rusqlite::{params, Connection};
|
||||
use secrecy::{Secret, SecretVec};
|
||||
use shardtree::error::ShardTreeError;
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
|
@ -102,45 +102,57 @@ use crate::{
|
|||
|
||||
pub(crate) mod pool;
|
||||
|
||||
pub(crate) struct InitialChainState {
|
||||
pub(crate) chain_state: ChainState,
|
||||
pub(crate) prior_sapling_roots: Vec<CommitmentTreeRoot<sapling::Node>>,
|
||||
#[cfg(feature = "orchard")]
|
||||
pub(crate) prior_orchard_roots: Vec<CommitmentTreeRoot<MerkleHashOrchard>>,
|
||||
}
|
||||
|
||||
/// A builder for a `zcash_client_sqlite` test.
|
||||
pub(crate) struct TestBuilder<Cache> {
|
||||
rng: ChaChaRng,
|
||||
network: LocalNetwork,
|
||||
cache: Cache,
|
||||
test_account_birthday: Option<AccountBirthday>,
|
||||
rng: ChaChaRng,
|
||||
initial_chain_state: Option<InitialChainState>,
|
||||
account_birthday: Option<AccountBirthday>,
|
||||
}
|
||||
|
||||
impl TestBuilder<()> {
|
||||
pub const DEFAULT_NETWORK: LocalNetwork = 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(zcash_unstable = "nu6")]
|
||||
nu6: None,
|
||||
#[cfg(zcash_unstable = "zfuture")]
|
||||
z_future: None,
|
||||
};
|
||||
|
||||
/// Constructs a new test.
|
||||
pub(crate) fn new() -> Self {
|
||||
TestBuilder {
|
||||
rng: ChaChaRng::seed_from_u64(0),
|
||||
// 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(zcash_unstable = "nu6")]
|
||||
nu6: None,
|
||||
#[cfg(zcash_unstable = "zfuture")]
|
||||
z_future: None,
|
||||
},
|
||||
network: Self::DEFAULT_NETWORK,
|
||||
cache: (),
|
||||
test_account_birthday: None,
|
||||
rng: ChaChaRng::seed_from_u64(0),
|
||||
initial_chain_state: None,
|
||||
account_birthday: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a [`BlockDb`] cache to the test.
|
||||
pub(crate) fn with_block_cache(self) -> TestBuilder<BlockCache> {
|
||||
TestBuilder {
|
||||
rng: self.rng,
|
||||
network: self.network,
|
||||
cache: BlockCache::new(),
|
||||
test_account_birthday: self.test_account_birthday,
|
||||
rng: self.rng,
|
||||
initial_chain_state: self.initial_chain_state,
|
||||
account_birthday: self.account_birthday,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,20 +160,69 @@ impl TestBuilder<()> {
|
|||
#[cfg(feature = "unstable")]
|
||||
pub(crate) fn with_fs_block_cache(self) -> TestBuilder<FsBlockCache> {
|
||||
TestBuilder {
|
||||
rng: self.rng,
|
||||
network: self.network,
|
||||
cache: FsBlockCache::new(),
|
||||
test_account_birthday: self.test_account_birthday,
|
||||
rng: self.rng,
|
||||
initial_chain_state: self.initial_chain_state,
|
||||
account_birthday: self.account_birthday,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Cache> TestBuilder<Cache> {
|
||||
pub(crate) fn with_test_account<F: FnOnce(&LocalNetwork) -> AccountBirthday>(
|
||||
pub(crate) fn with_initial_chain_state(
|
||||
mut self,
|
||||
birthday: F,
|
||||
chain_state: impl FnOnce(&mut ChaChaRng, &LocalNetwork) -> InitialChainState,
|
||||
) -> Self {
|
||||
self.test_account_birthday = Some(birthday(&self.network));
|
||||
assert!(self.initial_chain_state.is_none());
|
||||
assert!(self.account_birthday.is_none());
|
||||
self.initial_chain_state = Some(chain_state(&mut self.rng, &self.network));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_account_birthday(
|
||||
mut self,
|
||||
birthday: impl FnOnce(
|
||||
&mut ChaChaRng,
|
||||
&LocalNetwork,
|
||||
Option<&InitialChainState>,
|
||||
) -> AccountBirthday,
|
||||
) -> Self {
|
||||
assert!(self.account_birthday.is_none());
|
||||
self.account_birthday = Some(birthday(
|
||||
&mut self.rng,
|
||||
&self.network,
|
||||
self.initial_chain_state.as_ref(),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_account_from_sapling_activation(mut self, prev_hash: BlockHash) -> Self {
|
||||
assert!(self.account_birthday.is_none());
|
||||
self.account_birthday = Some(AccountBirthday::from_parts(
|
||||
ChainState::empty(
|
||||
self.network
|
||||
.activation_height(NetworkUpgrade::Sapling)
|
||||
.unwrap()
|
||||
- 1,
|
||||
prev_hash,
|
||||
),
|
||||
None,
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_account_having_current_birthday(mut self) -> Self {
|
||||
assert!(self.account_birthday.is_none());
|
||||
assert!(self.initial_chain_state.is_some());
|
||||
self.account_birthday = Some(AccountBirthday::from_parts(
|
||||
self.initial_chain_state
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.chain_state
|
||||
.clone(),
|
||||
None,
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -171,24 +232,75 @@ impl<Cache> TestBuilder<Cache> {
|
|||
let mut db_data = WalletDb::for_path(data_file.path(), self.network).unwrap();
|
||||
init_wallet_db(&mut db_data, None).unwrap();
|
||||
|
||||
let test_account = if let Some(birthday) = self.test_account_birthday {
|
||||
let mut cached_blocks = BTreeMap::new();
|
||||
|
||||
if let Some(initial_state) = self.initial_chain_state {
|
||||
db_data
|
||||
.put_sapling_subtree_roots(0, &initial_state.prior_sapling_roots)
|
||||
.unwrap();
|
||||
db_data
|
||||
.with_sapling_tree_mut(|t| {
|
||||
t.insert_frontier(
|
||||
initial_state.chain_state.final_sapling_tree().clone(),
|
||||
Retention::Checkpoint {
|
||||
id: initial_state.chain_state.block_height(),
|
||||
is_marked: false,
|
||||
},
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
#[cfg(feature = "orchard")]
|
||||
{
|
||||
db_data
|
||||
.put_orchard_subtree_roots(0, &initial_state.prior_orchard_roots)
|
||||
.unwrap();
|
||||
db_data
|
||||
.with_orchard_tree_mut(|t| {
|
||||
t.insert_frontier(
|
||||
initial_state.chain_state.final_orchard_tree().clone(),
|
||||
Retention::Checkpoint {
|
||||
id: initial_state.chain_state.block_height(),
|
||||
is_marked: false,
|
||||
},
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let final_sapling_tree_size =
|
||||
initial_state.chain_state.final_sapling_tree().tree_size() as u32;
|
||||
let _final_orchard_tree_size = 0;
|
||||
#[cfg(feature = "orchard")]
|
||||
let _final_orchard_tree_size =
|
||||
initial_state.chain_state.final_orchard_tree().tree_size() as u32;
|
||||
|
||||
cached_blocks.insert(
|
||||
initial_state.chain_state.block_height(),
|
||||
CachedBlock {
|
||||
chain_state: initial_state.chain_state.clone(),
|
||||
sapling_end_size: final_sapling_tree_size,
|
||||
orchard_end_size: _final_orchard_tree_size,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
let test_account = self.account_birthday.map(|birthday| {
|
||||
let seed = Secret::new(vec![0u8; 32]);
|
||||
let (account_id, usk) = db_data.create_account(&seed, birthday.clone()).unwrap();
|
||||
Some((
|
||||
let (account_id, usk) = db_data.create_account(&seed, &birthday).unwrap();
|
||||
(
|
||||
seed,
|
||||
TestAccount {
|
||||
account_id,
|
||||
usk,
|
||||
birthday,
|
||||
},
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
)
|
||||
});
|
||||
|
||||
TestState {
|
||||
cache: self.cache,
|
||||
cached_blocks: BTreeMap::new(),
|
||||
cached_blocks,
|
||||
latest_block_height: None,
|
||||
_data_file: data_file,
|
||||
db_data,
|
||||
|
@ -341,67 +453,6 @@ where
|
|||
self.cache.insert(&compact_block)
|
||||
}
|
||||
|
||||
/// Ensure that the provided chain state and subtree roots exist in the wallet's note
|
||||
/// commitment tree(s). This may result in a conflict if either the provided subtree roots or
|
||||
/// the chain state conflict with existing note commitment tree data.
|
||||
pub(crate) fn establish_chain_state(
|
||||
&mut self,
|
||||
state: ChainState,
|
||||
prior_sapling_roots: &[CommitmentTreeRoot<sapling::Node>],
|
||||
#[cfg(feature = "orchard")] prior_orchard_roots: &[CommitmentTreeRoot<MerkleHashOrchard>],
|
||||
) -> Result<(), ShardTreeError<commitment_tree::Error>> {
|
||||
self.wallet_mut()
|
||||
.put_sapling_subtree_roots(0, prior_sapling_roots)?;
|
||||
#[cfg(feature = "orchard")]
|
||||
self.wallet_mut()
|
||||
.put_orchard_subtree_roots(0, prior_orchard_roots)?;
|
||||
|
||||
self.wallet_mut().with_sapling_tree_mut(|t| {
|
||||
t.insert_frontier(
|
||||
state.final_sapling_tree().clone(),
|
||||
Retention::Checkpoint {
|
||||
id: state.block_height(),
|
||||
is_marked: false,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let final_sapling_tree_size = state.final_sapling_tree().tree_size() as u32;
|
||||
|
||||
#[cfg(feature = "orchard")]
|
||||
self.wallet_mut().with_orchard_tree_mut(|t| {
|
||||
t.insert_frontier(
|
||||
state.final_orchard_tree().clone(),
|
||||
Retention::Checkpoint {
|
||||
id: state.block_height(),
|
||||
is_marked: false,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
let _final_orchard_tree_size = 0;
|
||||
#[cfg(feature = "orchard")]
|
||||
let _final_orchard_tree_size = state.final_orchard_tree().tree_size() as u32;
|
||||
|
||||
self.insert_cached_block(state, final_sapling_tree_size, _final_orchard_tree_size);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn insert_cached_block(
|
||||
&mut self,
|
||||
chain_state: ChainState,
|
||||
sapling_end_size: u32,
|
||||
orchard_end_size: u32,
|
||||
) {
|
||||
self.cached_blocks.insert(
|
||||
chain_state.block_height(),
|
||||
CachedBlock {
|
||||
chain_state,
|
||||
sapling_end_size,
|
||||
orchard_end_size,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a fake block at the expected next height containing a single output of the
|
||||
/// given value, and inserts it into the cache.
|
||||
pub(crate) fn generate_next_block<Fvk: TestFvk>(
|
||||
|
@ -692,11 +743,6 @@ impl<Cache> TestState<Cache> {
|
|||
self.db_data.params
|
||||
}
|
||||
|
||||
/// Exposes the random number source for the test state
|
||||
pub(crate) fn rng(&mut self) -> &mut ChaChaRng {
|
||||
&mut self.rng
|
||||
}
|
||||
|
||||
/// Convenience method for obtaining the Sapling activation height for the network under test.
|
||||
pub(crate) fn sapling_activation_height(&self) -> BlockHeight {
|
||||
self.db_data
|
||||
|
|
|
@ -53,9 +53,6 @@ use crate::{
|
|||
AccountId, NoteId, ReceivedNoteId,
|
||||
};
|
||||
|
||||
#[cfg(feature = "orchard")]
|
||||
use zcash_primitives::consensus::NetworkUpgrade;
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
use {
|
||||
zcash_client_backend::{
|
||||
|
@ -129,7 +126,7 @@ pub(crate) trait ShieldedPoolTester {
|
|||
pub(crate) fn send_single_step_proposed_transfer<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -287,7 +284,7 @@ pub(crate) fn send_multi_step_proposed_transfer<T: ShieldedPoolTester>() {
|
|||
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -439,7 +436,7 @@ pub(crate) fn send_multi_step_proposed_transfer<T: ShieldedPoolTester>() {
|
|||
#[allow(deprecated)]
|
||||
pub(crate) fn create_to_address_fails_on_incorrect_usk<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
let dfvk = T::test_account_fvk(&st);
|
||||
let to = T::fvk_default_address(&dfvk);
|
||||
|
@ -467,7 +464,7 @@ pub(crate) fn create_to_address_fails_on_incorrect_usk<T: ShieldedPoolTester>()
|
|||
#[allow(deprecated)]
|
||||
pub(crate) fn proposal_fails_with_no_blocks<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account_id = st.test_account().unwrap().account_id();
|
||||
|
@ -496,7 +493,7 @@ pub(crate) fn proposal_fails_with_no_blocks<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn spend_fails_on_unverified_notes<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -647,7 +644,7 @@ pub(crate) fn spend_fails_on_unverified_notes<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn spend_fails_on_locked_notes<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -785,7 +782,7 @@ pub(crate) fn spend_fails_on_locked_notes<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn ovk_policy_prevents_recovery_from_chain<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -881,7 +878,7 @@ pub(crate) fn ovk_policy_prevents_recovery_from_chain<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn spend_succeeds_to_t_addr_zero_change<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -928,7 +925,7 @@ pub(crate) fn spend_succeeds_to_t_addr_zero_change<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn change_note_spends_succeed<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -998,17 +995,11 @@ pub(crate) fn external_address_change_spends_detected_in_restore_from_seed<
|
|||
|
||||
// Add two accounts to the wallet.
|
||||
let seed = Secret::new([0u8; 32].to_vec());
|
||||
let birthday = AccountBirthday::from_sapling_activation(&st.network());
|
||||
let (account_id, usk) = st
|
||||
.wallet_mut()
|
||||
.create_account(&seed, birthday.clone())
|
||||
.unwrap();
|
||||
let birthday = AccountBirthday::from_sapling_activation(&st.network(), BlockHash([0; 32]));
|
||||
let (account_id, usk) = st.wallet_mut().create_account(&seed, &birthday).unwrap();
|
||||
let dfvk = T::sk_to_fvk(T::usk_to_sk(&usk));
|
||||
|
||||
let (account2, usk2) = st
|
||||
.wallet_mut()
|
||||
.create_account(&seed, birthday.clone())
|
||||
.unwrap();
|
||||
let (account2, usk2) = st.wallet_mut().create_account(&seed, &birthday).unwrap();
|
||||
let dfvk2 = T::sk_to_fvk(T::usk_to_sk(&usk2));
|
||||
|
||||
// Add funds to the wallet in a single note
|
||||
|
@ -1081,16 +1072,13 @@ pub(crate) fn external_address_change_spends_detected_in_restore_from_seed<
|
|||
st.reset();
|
||||
|
||||
// Account creation and DFVK derivation should be deterministic.
|
||||
let (_, restored_usk) = st
|
||||
.wallet_mut()
|
||||
.create_account(&seed, birthday.clone())
|
||||
.unwrap();
|
||||
let (_, restored_usk) = st.wallet_mut().create_account(&seed, &birthday).unwrap();
|
||||
assert!(T::fvks_equal(
|
||||
&T::sk_to_fvk(T::usk_to_sk(&restored_usk)),
|
||||
&dfvk,
|
||||
));
|
||||
|
||||
let (_, restored_usk2) = st.wallet_mut().create_account(&seed, birthday).unwrap();
|
||||
let (_, restored_usk2) = st.wallet_mut().create_account(&seed, &birthday).unwrap();
|
||||
assert!(T::fvks_equal(
|
||||
&T::sk_to_fvk(T::usk_to_sk(&restored_usk2)),
|
||||
&dfvk2,
|
||||
|
@ -1105,7 +1093,7 @@ pub(crate) fn external_address_change_spends_detected_in_restore_from_seed<
|
|||
pub(crate) fn zip317_spend<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1199,7 +1187,7 @@ pub(crate) fn zip317_spend<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn shield_transparent<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1259,7 +1247,7 @@ pub(crate) fn shield_transparent<T: ShieldedPoolTester>() {
|
|||
#[allow(dead_code)]
|
||||
pub(crate) fn birthday_in_anchor_shard<T: ShieldedPoolTester>() {
|
||||
// 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::<T>(76);
|
||||
let (mut st, dfvk, birthday, _) = test_with_nu5_birthday_offset::<T>(76, BlockHash([0; 32]));
|
||||
|
||||
// Set up the following situation:
|
||||
//
|
||||
|
@ -1364,7 +1352,7 @@ pub(crate) fn birthday_in_anchor_shard<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn checkpoint_gaps<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1433,7 +1421,8 @@ pub(crate) fn checkpoint_gaps<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn pool_crossing_required<P0: ShieldedPoolTester, P1: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(|params| AccountBirthday::from_activation(params, NetworkUpgrade::Nu5))
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32])) // TODO: Allow for Orchard
|
||||
// activation after Sapling
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1522,7 +1511,8 @@ pub(crate) fn pool_crossing_required<P0: ShieldedPoolTester, P1: ShieldedPoolTes
|
|||
pub(crate) fn fully_funded_fully_private<P0: ShieldedPoolTester, P1: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(|params| AccountBirthday::from_activation(params, NetworkUpgrade::Nu5))
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32])) // TODO: Allow for Orchard
|
||||
// activation after Sapling
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1612,7 +1602,7 @@ pub(crate) fn fully_funded_fully_private<P0: ShieldedPoolTester, P1: ShieldedPoo
|
|||
pub(crate) fn valid_chain_states<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let dfvk = T::test_account_fvk(&st);
|
||||
|
@ -1646,7 +1636,7 @@ pub(crate) fn valid_chain_states<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn invalid_chain_cache_disconnected<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let dfvk = T::test_account_fvk(&st);
|
||||
|
@ -1697,7 +1687,7 @@ pub(crate) fn invalid_chain_cache_disconnected<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn data_db_truncation<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1753,7 +1743,7 @@ pub(crate) fn data_db_truncation<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn scan_cached_blocks_allows_blocks_out_of_order<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1813,7 +1803,7 @@ pub(crate) fn scan_cached_blocks_allows_blocks_out_of_order<T: ShieldedPoolTeste
|
|||
pub(crate) fn scan_cached_blocks_finds_received_notes<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1856,7 +1846,7 @@ pub(crate) fn scan_cached_blocks_finds_received_notes<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn scan_cached_blocks_finds_change_notes<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
@ -1895,7 +1885,7 @@ pub(crate) fn scan_cached_blocks_finds_change_notes<T: ShieldedPoolTester>() {
|
|||
pub(crate) fn scan_cached_blocks_detects_spends_out_of_order<T: ShieldedPoolTester>() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
|
|
|
@ -351,7 +351,7 @@ pub(crate) fn add_account<P: consensus::Parameters>(
|
|||
params: &P,
|
||||
kind: AccountSource,
|
||||
viewing_key: ViewingKey,
|
||||
birthday: AccountBirthday,
|
||||
birthday: &AccountBirthday,
|
||||
) -> Result<AccountId, SqliteClientError> {
|
||||
let (hd_seed_fingerprint, hd_account_index) = match kind {
|
||||
AccountSource::Derived {
|
||||
|
@ -2720,7 +2720,7 @@ mod tests {
|
|||
use std::num::NonZeroU32;
|
||||
|
||||
use sapling::zip32::ExtendedSpendingKey;
|
||||
use zcash_client_backend::data_api::{AccountBirthday, AccountSource, WalletRead};
|
||||
use zcash_client_backend::data_api::{AccountSource, WalletRead};
|
||||
use zcash_primitives::{block::BlockHash, transaction::components::amount::NonNegativeAmount};
|
||||
|
||||
use crate::{
|
||||
|
@ -2749,7 +2749,7 @@ mod tests {
|
|||
#[test]
|
||||
fn empty_database_has_no_balance() {
|
||||
let st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
let account = st.test_account().unwrap();
|
||||
|
||||
|
@ -2784,7 +2784,7 @@ mod tests {
|
|||
use crate::testing::TestBuilder;
|
||||
|
||||
let mut st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account_id = st.test_account().unwrap().account_id();
|
||||
|
@ -2873,7 +2873,7 @@ mod tests {
|
|||
use crate::testing::TestBuilder;
|
||||
|
||||
let st = TestBuilder::new()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
let account_id = st.test_account().unwrap().account_id();
|
||||
let account_parameters = st.wallet().get_account(account_id).unwrap().unwrap();
|
||||
|
@ -2892,10 +2892,10 @@ mod tests {
|
|||
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let account = st.test_account().unwrap().clone();
|
||||
let account = st.test_account().cloned().unwrap();
|
||||
let uaddr = st
|
||||
.wallet()
|
||||
.get_current_address(account.account_id())
|
||||
|
@ -3043,7 +3043,7 @@ mod tests {
|
|||
fn block_fully_scanned() {
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.with_account_from_sapling_activation(BlockHash([0; 32]))
|
||||
.build();
|
||||
|
||||
let block_fully_scanned = |st: &TestState<BlockCache>| {
|
||||
|
|
|
@ -1427,6 +1427,7 @@ mod tests {
|
|||
#[cfg(feature = "transparent-inputs")]
|
||||
fn account_produces_expected_ua_sequence() {
|
||||
use zcash_client_backend::data_api::{AccountBirthday, AccountSource, WalletRead};
|
||||
use zcash_primitives::block::BlockHash;
|
||||
|
||||
let network = Network::MainNetwork;
|
||||
let data_file = NamedTempFile::new().unwrap();
|
||||
|
@ -1445,9 +1446,9 @@ mod tests {
|
|||
Ok(())
|
||||
);
|
||||
|
||||
let birthday = AccountBirthday::from_sapling_activation(&network);
|
||||
let birthday = AccountBirthday::from_sapling_activation(&network, BlockHash([0; 32]));
|
||||
let (account_id, _usk) = db_data
|
||||
.create_account(&Secret::new(seed.to_vec()), birthday)
|
||||
.create_account(&Secret::new(seed.to_vec()), &birthday)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
db_data.get_account(account_id),
|
||||
|
|
|
@ -581,9 +581,8 @@ pub(crate) fn update_chain_tip<P: consensus::Parameters>(
|
|||
pub(crate) mod tests {
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
use incrementalmerkletree::{frontier::Frontier, Hashable, Position};
|
||||
use incrementalmerkletree::{frontier::Frontier, Position};
|
||||
|
||||
use sapling::Node;
|
||||
use secrecy::SecretVec;
|
||||
use zcash_client_backend::data_api::{
|
||||
chain::{ChainState, CommitmentTreeRoot},
|
||||
|
@ -599,7 +598,10 @@ pub(crate) mod tests {
|
|||
|
||||
use crate::{
|
||||
error::SqliteClientError,
|
||||
testing::{pool::ShieldedPoolTester, AddressType, BlockCache, TestBuilder, TestState},
|
||||
testing::{
|
||||
pool::ShieldedPoolTester, AddressType, BlockCache, InitialChainState, TestBuilder,
|
||||
TestState,
|
||||
},
|
||||
wallet::{
|
||||
sapling::tests::SaplingPoolTester,
|
||||
scanning::{insert_queue_entries, replace_queue_entries, suggest_scan_ranges},
|
||||
|
@ -609,7 +611,7 @@ pub(crate) mod tests {
|
|||
|
||||
#[cfg(feature = "orchard")]
|
||||
use {
|
||||
crate::wallet::orchard::tests::OrchardPoolTester, orchard::tree::MerkleHashOrchard,
|
||||
crate::wallet::orchard::tests::OrchardPoolTester,
|
||||
zcash_client_backend::data_api::ORCHARD_SHARD_HEIGHT,
|
||||
};
|
||||
|
||||
|
@ -626,66 +628,75 @@ pub(crate) mod tests {
|
|||
|
||||
fn scan_complete<T: ShieldedPoolTester>() {
|
||||
use ScanPriority::*;
|
||||
let initial_height_offset = 310;
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(AccountBirthday::from_sapling_activation)
|
||||
.build();
|
||||
|
||||
let sapling_activation_height = st.sapling_activation_height();
|
||||
|
||||
// We'll start inserting leaf notes 5 notes after the end of the third subtree, with a gap
|
||||
// of 10 blocks. After `scan_cached_blocks`, the scan queue should have a requested scan
|
||||
// range of 300..310 with `FoundNote` priority, 310..320 with `Scanned` priority.
|
||||
// We set both Sapling and Orchard to the same initial tree size for simplicity.
|
||||
let prior_block_hash = BlockHash([0; 32]);
|
||||
let initial_sapling_tree_size: u32 = (0x1 << 16) * 3 + 5;
|
||||
let initial_orchard_tree_size: u32 = (0x1 << 16) * 3 + 5;
|
||||
let initial_height_offset = 310;
|
||||
|
||||
// Construct a fake chain state for the end of block 300
|
||||
let (prior_sapling_frontiers, sapling_initial_tree) =
|
||||
Frontier::random_with_prior_subtree_roots(
|
||||
st.rng(),
|
||||
initial_sapling_tree_size.into(),
|
||||
NonZeroU8::new(16).unwrap(),
|
||||
);
|
||||
let sapling_subtree_roots = prior_sapling_frontiers
|
||||
.into_iter()
|
||||
.zip(0u32..)
|
||||
.map(|(root, i)| {
|
||||
CommitmentTreeRoot::from_parts(sapling_activation_height + (100 * (i + 1)), root)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_initial_chain_state(|rng, network| {
|
||||
let sapling_activation_height =
|
||||
network.activation_height(NetworkUpgrade::Sapling).unwrap();
|
||||
// Construct a fake chain state for the end of block 300
|
||||
let (prior_sapling_roots, sapling_initial_tree) =
|
||||
Frontier::random_with_prior_subtree_roots(
|
||||
rng,
|
||||
initial_sapling_tree_size.into(),
|
||||
NonZeroU8::new(16).unwrap(),
|
||||
);
|
||||
let prior_sapling_roots = prior_sapling_roots
|
||||
.into_iter()
|
||||
.zip(0u32..)
|
||||
.map(|(root, i)| {
|
||||
CommitmentTreeRoot::from_parts(
|
||||
sapling_activation_height + (100 * (i + 1)),
|
||||
root,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
#[cfg(feature = "orchard")]
|
||||
let (prior_orchard_frontiers, orchard_initial_tree) =
|
||||
Frontier::random_with_prior_subtree_roots(
|
||||
st.rng(),
|
||||
initial_orchard_tree_size.into(),
|
||||
NonZeroU8::new(16).unwrap(),
|
||||
);
|
||||
#[cfg(feature = "orchard")]
|
||||
let orchard_subtree_roots = prior_orchard_frontiers
|
||||
.into_iter()
|
||||
.zip(0u32..)
|
||||
.map(|(root, i)| {
|
||||
CommitmentTreeRoot::from_parts(sapling_activation_height + (100 * (i + 1)), root)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let prior_block_hash = BlockHash([0; 32]);
|
||||
st.establish_chain_state(
|
||||
ChainState::new(
|
||||
sapling_activation_height + initial_height_offset - 1,
|
||||
prior_block_hash,
|
||||
sapling_initial_tree,
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_initial_tree,
|
||||
),
|
||||
&sapling_subtree_roots,
|
||||
#[cfg(feature = "orchard")]
|
||||
&orchard_subtree_roots,
|
||||
)
|
||||
.unwrap();
|
||||
let (prior_orchard_roots, orchard_initial_tree) =
|
||||
Frontier::random_with_prior_subtree_roots(
|
||||
rng,
|
||||
initial_orchard_tree_size.into(),
|
||||
NonZeroU8::new(16).unwrap(),
|
||||
);
|
||||
#[cfg(feature = "orchard")]
|
||||
let prior_orchard_roots = prior_orchard_roots
|
||||
.into_iter()
|
||||
.zip(0u32..)
|
||||
.map(|(root, i)| {
|
||||
CommitmentTreeRoot::from_parts(
|
||||
sapling_activation_height + (100 * (i + 1)),
|
||||
root,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
InitialChainState {
|
||||
chain_state: ChainState::new(
|
||||
sapling_activation_height + initial_height_offset - 1,
|
||||
prior_block_hash,
|
||||
sapling_initial_tree,
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_initial_tree,
|
||||
),
|
||||
prior_sapling_roots,
|
||||
#[cfg(feature = "orchard")]
|
||||
prior_orchard_roots,
|
||||
}
|
||||
})
|
||||
.with_account_from_sapling_activation(BlockHash([3; 32]))
|
||||
.build();
|
||||
|
||||
let sapling_activation_height = st.sapling_activation_height();
|
||||
|
||||
let dfvk = T::test_account_fvk(&st);
|
||||
let value = NonNegativeAmount::const_from_u64(50000);
|
||||
|
@ -776,37 +787,43 @@ pub(crate) mod tests {
|
|||
}
|
||||
|
||||
pub(crate) fn test_with_nu5_birthday_offset<T: ShieldedPoolTester>(
|
||||
offset: u32,
|
||||
birthday_offset: u32,
|
||||
prior_block_hash: BlockHash,
|
||||
) -> (TestState<BlockCache>, T::Fvk, AccountBirthday, u32) {
|
||||
let st = TestBuilder::new()
|
||||
.with_block_cache()
|
||||
.with_test_account(|network| {
|
||||
.with_account_birthday(|rng, network, initial_chain_state| {
|
||||
// We're constructing the birthday without adding any chain data.
|
||||
assert!(initial_chain_state.is_none());
|
||||
|
||||
// We set the Sapling and Orchard frontiers at the birthday height to be
|
||||
// 1234 notes into the second shard.
|
||||
let birthday_height =
|
||||
network.activation_height(NetworkUpgrade::Nu5).unwrap() + offset;
|
||||
let frontier_position = Position::from((0x1 << 16) + 1234);
|
||||
let sapling_frontier = Frontier::from_parts(
|
||||
frontier_position,
|
||||
Node::empty_leaf(),
|
||||
vec![Node::empty_leaf(); frontier_position.past_ommer_count().into()],
|
||||
)
|
||||
.unwrap();
|
||||
let birthday_height =
|
||||
network.activation_height(NetworkUpgrade::Nu5).unwrap() + birthday_offset;
|
||||
|
||||
// Construct a fake chain state for the end of the block with the given
|
||||
// birthday_offset from the Nu5 birthday.
|
||||
let (_, sapling_initial_tree) = Frontier::random_with_prior_subtree_roots(
|
||||
rng,
|
||||
(frontier_position + 1).into(),
|
||||
NonZeroU8::new(16).unwrap(),
|
||||
);
|
||||
#[cfg(feature = "orchard")]
|
||||
let orchard_frontier = Frontier::from_parts(
|
||||
frontier_position,
|
||||
MerkleHashOrchard::empty_leaf(),
|
||||
vec![
|
||||
MerkleHashOrchard::empty_leaf();
|
||||
frontier_position.past_ommer_count().into()
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
let (_, orchard_initial_tree) = Frontier::random_with_prior_subtree_roots(
|
||||
rng,
|
||||
(frontier_position + 1).into(),
|
||||
NonZeroU8::new(16).unwrap(),
|
||||
);
|
||||
|
||||
AccountBirthday::from_parts(
|
||||
birthday_height,
|
||||
sapling_frontier,
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_frontier,
|
||||
ChainState::new(
|
||||
birthday_height,
|
||||
prior_block_hash,
|
||||
sapling_initial_tree,
|
||||
#[cfg(feature = "orchard")]
|
||||
orchard_initial_tree,
|
||||
),
|
||||
None,
|
||||
)
|
||||
})
|
||||
|
@ -834,7 +851,8 @@ pub(crate) mod tests {
|
|||
use ScanPriority::*;
|
||||
|
||||
// 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::<T>(76);
|
||||
let (st, _, birthday, sap_active) =
|
||||
test_with_nu5_birthday_offset::<T>(76, BlockHash([0; 32]));
|
||||
let birthday_height = birthday.height().into();
|
||||
|
||||
let expected = vec![
|
||||
|
@ -869,11 +887,8 @@ pub(crate) mod tests {
|
|||
st.wallet_mut()
|
||||
.create_account(
|
||||
&SecretVec::new(vec![0; 32]),
|
||||
AccountBirthday::from_parts(
|
||||
wallet_birthday,
|
||||
Frontier::empty(),
|
||||
#[cfg(feature = "orchard")]
|
||||
Frontier::empty(),
|
||||
&AccountBirthday::from_parts(
|
||||
ChainState::empty(wallet_birthday - 1, BlockHash([0; 32])),
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
@ -904,7 +919,8 @@ pub(crate) mod tests {
|
|||
use ScanPriority::*;
|
||||
|
||||
// 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::<T>(76);
|
||||
let (mut st, _, birthday, sap_active) =
|
||||
test_with_nu5_birthday_offset::<T>(76, BlockHash([0; 32]));
|
||||
|
||||
// Set up the following situation:
|
||||
//
|
||||
|
@ -921,7 +937,9 @@ pub(crate) mod tests {
|
|||
|
||||
// Verify that the suggested scan ranges match what is expected.
|
||||
let expected = vec![
|
||||
// The wallet's birthday onward is marked for recovery.
|
||||
// The wallet's birthday onward is marked for recovery. Because we don't
|
||||
// yet have any chain state, it is marked with `Historic` priority rather
|
||||
// than `ChainTip`.
|
||||
scan_range(wallet_birthday..chain_end, Historic),
|
||||
// The range below the wallet's birthday height is ignored.
|
||||
scan_range(sap_active..wallet_birthday, Ignored),
|
||||
|
@ -946,7 +964,8 @@ pub(crate) mod tests {
|
|||
use ScanPriority::*;
|
||||
|
||||
// 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::<T>(76);
|
||||
let (mut st, _, birthday, sap_active) =
|
||||
test_with_nu5_birthday_offset::<T>(76, BlockHash([0; 32]));
|
||||
|
||||
// Set up the following situation:
|
||||
//
|
||||
|
@ -1007,7 +1026,8 @@ pub(crate) mod tests {
|
|||
|
||||
// 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_nu5_birthday_offset::<T>(76);
|
||||
let (mut st, dfvk, birthday, sap_active) =
|
||||
test_with_nu5_birthday_offset::<T>(76, BlockHash([0; 32]));
|
||||
|
||||
// Set up the following situation:
|
||||
//
|
||||
|
@ -1149,7 +1169,8 @@ pub(crate) mod tests {
|
|||
use ScanPriority::*;
|
||||
|
||||
// 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::<T>(76);
|
||||
let (mut st, dfvk, birthday, sap_active) =
|
||||
test_with_nu5_birthday_offset::<T>(76, BlockHash([0; 32]));
|
||||
|
||||
// Set up the following situation:
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue