Skip to content

Commit

Permalink
zcash_client_backend: Resolve merge conflicts in CHANGELOG.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Oscar-Pepper committed Mar 13, 2024
2 parents e89a1ac + b3d06ba commit c62b5b2
Show file tree
Hide file tree
Showing 25 changed files with 1,786 additions and 563 deletions.
10 changes: 4 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,8 @@ zip32 = "0.1"
lto = true
panic = 'abort'
codegen-units = 1

[patch.crates-io]
orchard = { git = "https://github.com/zcash/orchard", rev = "e74879dd0ad0918f4ffe0826e03905cd819981bd" }
incrementalmerkletree = { git = "https://github.com/nuttycom/incrementalmerkletree", rev = "fa147c89c6c98a03bba745538f4e68d4eaed5146" }
shardtree = { git = "https://github.com/nuttycom/incrementalmerkletree", rev = "fa147c89c6c98a03bba745538f4e68d4eaed5146" }
9 changes: 8 additions & 1 deletion zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this library adheres to Rust's notion of
changes related to `Orchard` below are introduced under this feature
flag.
- `zcash_client_backend::data_api`:
- `Account`
- `AccountBalance::with_orchard_balance_mut`
- `AccountBirthday::orchard_frontier`
- `BlockMetadata::orchard_tree_size`
Expand Down Expand Up @@ -52,7 +53,11 @@ and this library adheres to Rust's notion of
- Arguments to `BlockMetadata::from_parts` have changed.
- Arguments to `ScannedBlock::from_parts` have changed.
- Changes to the `WalletRead` trait:
- Added `get_orchard_nullifiers`
- Added `Account` associated type.
- Added `get_orchard_nullifiers` method.
- `get_account_for_ufvk` now returns an `Self::Account` instead of a bare
`AccountId`
- Added `get_seed_account` method.
- Changes to the `InputSource` trait:
- `select_spendable_notes` now takes its `target_value` argument as a
`NonNegativeAmount`. Also, the values of the returned map are also
Expand Down Expand Up @@ -81,6 +86,8 @@ and this library adheres to Rust's notion of
- Arguments to `ChangeStrategy::compute_balance` have changed.
- `zcash_client_backend::scanning`:
- `testing::fake_compact_block` is now public.
- `ChangeError::DustInputs` now has an `orchard` field behind the `orchard`
feature flag.
- `zcash_client_backend::proto`:
- `ProposalDecodingError` has a new variant `TransparentMemo`.
- `zcash_client_backend::zip321::render::amount_str` now takes a
Expand Down
83 changes: 73 additions & 10 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,12 @@ use std::{
use incrementalmerkletree::{frontier::Frontier, Retention};
use secrecy::SecretVec;
use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};
use zcash_keys::keys::HdSeedFingerprint;

use self::{chain::CommitmentTreeRoot, scanning::ScanRange};
use self::{
chain::{ChainState, CommitmentTreeRoot},
scanning::ScanRange,
};
use crate::{
address::UnifiedAddress,
decrypt::DecryptedOutput,
Expand Down Expand Up @@ -311,6 +315,35 @@ impl AccountBalance {
}
}

/// A set of capabilities that a client account must provide.
pub trait Account<AccountId: Copy> {
/// Returns the unique identifier for the account.
fn id(&self) -> AccountId;

/// Returns the UFVK that the wallet backend has stored for the account, if any.
fn ufvk(&self) -> Option<&UnifiedFullViewingKey>;
}

impl<A: Copy> Account<A> for (A, UnifiedFullViewingKey) {
fn id(&self) -> A {
self.0
}

fn ufvk(&self) -> Option<&UnifiedFullViewingKey> {
Some(&self.1)
}
}

impl<A: Copy> Account<A> for (A, Option<UnifiedFullViewingKey>) {
fn id(&self) -> A {
self.0
}

fn ufvk(&self) -> Option<&UnifiedFullViewingKey> {
self.1.as_ref()
}
}

/// A polymorphic ratio type, usually used for rational numbers.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Ratio<T> {
Expand Down Expand Up @@ -507,6 +540,9 @@ pub trait WalletRead {
/// will be interpreted as belonging to that account.
type AccountId: Copy + Debug + Eq + Hash;

/// The concrete account type used by this wallet backend.
type Account: Account<Self::AccountId>;

/// Verifies that the given seed corresponds to the viewing key for the specified account.
///
/// Returns:
Expand Down Expand Up @@ -617,11 +653,19 @@ pub trait WalletRead {
&self,
) -> Result<HashMap<Self::AccountId, UnifiedFullViewingKey>, Self::Error>;

/// Returns the account id corresponding to a given [`UnifiedFullViewingKey`], if any.
/// Returns the account corresponding to a given [`UnifiedFullViewingKey`], if any.
fn get_account_for_ufvk(
&self,
ufvk: &UnifiedFullViewingKey,
) -> Result<Option<Self::AccountId>, Self::Error>;
) -> Result<Option<Self::Account>, Self::Error>;

/// Returns the account corresponding to a given [`HdSeedFingerprint`] and
/// [`zip32::AccountId`], if any.
fn get_seed_account(
&self,
seed: &HdSeedFingerprint,
account_id: zip32::AccountId,
) -> Result<Option<Self::Account>, Self::Error>;

/// Returns the wallet balances and sync status for an account given the specified minimum
/// number of confirmations, or `Ok(None)` if the wallet has no balance data available.
Expand Down Expand Up @@ -1259,9 +1303,15 @@ pub trait WalletWrite: WalletRead {
/// along with the note commitments that were detected when scanning the block for transactions
/// pertaining to this wallet.
///
/// `blocks` must be sequential, in order of increasing block height
fn put_blocks(&mut self, blocks: Vec<ScannedBlock<Self::AccountId>>)
-> Result<(), Self::Error>;
/// ### Arguments
/// - `from_state` must be the chain state for the block height prior to the first
/// block in `blocks`.
/// - `blocks` must be sequential, in order of increasing block height.
fn put_blocks(
&mut self,
from_state: &ChainState,
blocks: Vec<ScannedBlock<Self::AccountId>>,
) -> Result<(), Self::Error>;

/// Updates the wallet's view of the blockchain.
///
Expand Down Expand Up @@ -1384,6 +1434,7 @@ pub mod testing {
use secrecy::{ExposeSecret, SecretVec};
use shardtree::{error::ShardTreeError, store::memory::MemoryShardStore, ShardTree};
use std::{collections::HashMap, convert::Infallible, num::NonZeroU32};
use zcash_keys::keys::HdSeedFingerprint;

use zcash_primitives::{
block::BlockHash,
Expand All @@ -1400,9 +1451,11 @@ pub mod testing {
};

use super::{
chain::CommitmentTreeRoot, scanning::ScanRange, AccountBirthday, BlockMetadata,
DecryptedTransaction, InputSource, NullifierQuery, ScannedBlock, SentTransaction,
WalletCommitmentTrees, WalletRead, WalletSummary, WalletWrite, SAPLING_SHARD_HEIGHT,
chain::{ChainState, CommitmentTreeRoot},
scanning::ScanRange,
AccountBirthday, BlockMetadata, DecryptedTransaction, InputSource, NullifierQuery,
ScannedBlock, SentTransaction, WalletCommitmentTrees, WalletRead, WalletSummary,
WalletWrite, SAPLING_SHARD_HEIGHT,
};

#[cfg(feature = "transparent-inputs")]
Expand Down Expand Up @@ -1466,6 +1519,7 @@ pub mod testing {
impl WalletRead for MockWalletDb {
type Error = ();
type AccountId = u32;
type Account = (Self::AccountId, UnifiedFullViewingKey);

fn validate_seed(
&self,
Expand Down Expand Up @@ -1551,7 +1605,15 @@ pub mod testing {
fn get_account_for_ufvk(
&self,
_ufvk: &UnifiedFullViewingKey,
) -> Result<Option<Self::AccountId>, Self::Error> {
) -> Result<Option<Self::Account>, Self::Error> {
Ok(None)
}

fn get_seed_account(
&self,
_seed: &HdSeedFingerprint,
_account_id: zip32::AccountId,
) -> Result<Option<Self::Account>, Self::Error> {
Ok(None)
}

Expand Down Expand Up @@ -1633,6 +1695,7 @@ pub mod testing {
#[allow(clippy::type_complexity)]
fn put_blocks(
&mut self,
_from_state: &ChainState,
_blocks: Vec<ScannedBlock<Self::AccountId>>,
) -> Result<(), Self::Error> {
Ok(())
Expand Down
86 changes: 83 additions & 3 deletions zcash_client_backend/src/data_api/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,20 @@
//! // the first element of the vector of suggested ranges.
//! match scan_ranges.first() {
//! Some(scan_range) if scan_range.priority() == ScanPriority::Verify => {
//! // Download the chain state for the block prior to the start of the range you want
//! // to scan.
//! let chain_state = unimplemented!("get_chain_state(scan_range.block_range().start - 1)?;");
//! // Download the blocks in `scan_range` into the block source, overwriting any
//! // existing blocks in this range.
//! unimplemented!();
//! unimplemented!("cache_blocks(scan_range)?;");
//!
//! // Scan the downloaded blocks
//! let scan_result = scan_cached_blocks(
//! &network,
//! &block_source,
//! &mut wallet_db,
//! scan_range.block_range().start,
//! chain_state,
//! scan_range.len()
//! );
//!
Expand Down Expand Up @@ -118,21 +122,25 @@
//! // encountered, this process should be repeated starting at step (3).
//! let scan_ranges = wallet_db.suggest_scan_ranges().map_err(Error::Wallet)?;
//! for scan_range in scan_ranges {
//! // Download the chain state for the block prior to the start of the range you want
//! // to scan.
//! let chain_state = unimplemented!("get_chain_state(scan_range.block_range().start - 1)?;");
//! // Download the blocks in `scan_range` into the block source. While in this example this
//! // step is performed in-line, it's fine for the download of scan ranges to be asynchronous
//! // and for the scanner to process the downloaded ranges as they become available in a
//! // separate thread. The scan ranges should also be broken down into smaller chunks as
//! // appropriate, and for ranges with priority `Historic` it can be useful to download and
//! // scan the range in reverse order (to discover more recent unspent notes sooner), or from
//! // the start and end of the range inwards.
//! unimplemented!();
//! unimplemented!("cache_blocks(scan_range)?;");
//!
//! // Scan the downloaded blocks.
//! let scan_result = scan_cached_blocks(
//! &network,
//! &block_source,
//! &mut wallet_db,
//! scan_range.block_range().start,
//! chain_state,
//! scan_range.len()
//! )?;
//!
Expand All @@ -145,6 +153,7 @@
use std::ops::Range;

use incrementalmerkletree::frontier::Frontier;
use subtle::ConditionallySelectable;
use zcash_primitives::consensus::{self, BlockHeight};

Expand Down Expand Up @@ -473,19 +482,86 @@ impl ScanSummary {
}
}

/// The final note commitment tree state for each shielded pool, as of a particular block height.
#[derive(Debug, Clone)]
pub struct ChainState {
block_height: BlockHeight,
final_sapling_tree: Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
#[cfg(feature = "orchard")]
final_orchard_tree:
Frontier<orchard::tree::MerkleHashOrchard, { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 }>,
}

impl ChainState {
/// Construct a new empty chain state.
pub fn empty(block_height: BlockHeight) -> Self {
Self {
block_height,
final_sapling_tree: Frontier::empty(),
#[cfg(feature = "orchard")]
final_orchard_tree: Frontier::empty(),
}
}

/// Construct a new [`ChainState`] from its constituent parts.
pub fn new(
block_height: BlockHeight,
final_sapling_tree: Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
#[cfg(feature = "orchard")] final_orchard_tree: Frontier<
orchard::tree::MerkleHashOrchard,
{ orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 },
>,
) -> Self {
Self {
block_height,
final_sapling_tree,
#[cfg(feature = "orchard")]
final_orchard_tree,
}
}

/// Returns the block height to which this chain state applies.
pub fn block_height(&self) -> BlockHeight {
self.block_height
}

/// Returns the frontier of the Sapling note commitment tree as of the end of the block at
/// [`Self::block_height`].
pub fn final_sapling_tree(
&self,
) -> &Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }> {
&self.final_sapling_tree
}

/// Returns the frontier of the Orchard note commitment tree as of the end of the block at
/// [`Self::block_height`].
#[cfg(feature = "orchard")]
pub fn final_orchard_tree(
&self,
) -> &Frontier<orchard::tree::MerkleHashOrchard, { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 }>
{
&self.final_orchard_tree
}
}

/// Scans at most `limit` blocks from the provided block source for in order to find transactions
/// received by the accounts tracked in the provided wallet database.
///
/// This function will return after scanning at most `limit` new blocks, to enable the caller to
/// update their UI with scanning progress. Repeatedly calling this function with `from_height ==
/// None` will process sequential ranges of blocks.
///
/// ## Panics
///
/// This method will panic if `from_height != from_state.block_height() + 1`.
#[tracing::instrument(skip(params, block_source, data_db))]
#[allow(clippy::type_complexity)]
pub fn scan_cached_blocks<ParamsT, DbT, BlockSourceT>(
params: &ParamsT,
block_source: &BlockSourceT,
data_db: &mut DbT,
from_height: BlockHeight,
from_state: &ChainState,
limit: usize,
) -> Result<ScanSummary, Error<DbT::Error, BlockSourceT::Error>>
where
Expand All @@ -494,6 +570,8 @@ where
DbT: WalletWrite,
<DbT as WalletRead>::AccountId: ConditionallySelectable + Default + Send + 'static,
{
assert_eq!(from_height, from_state.block_height + 1);

// Fetch the UnifiedFullViewingKeys we are tracking
let account_ufvks = data_db
.get_unified_full_viewing_keys()
Expand Down Expand Up @@ -587,7 +665,9 @@ where
},
)?;

data_db.put_blocks(scanned_blocks).map_err(Error::Wallet)?;
data_db
.put_blocks(from_state, scanned_blocks)
.map_err(Error::Wallet)?;
Ok(scan_summary)
}

Expand Down
Loading

0 comments on commit c62b5b2

Please sign in to comment.