Skip to content

Commit

Permalink
zcash_client_backend: Rework scanning key identifiers.
Browse files Browse the repository at this point in the history
In the process of making the internals of `scan_block_with_runner`
reusable across Sapling and Orchard, it became evident that key
identifier abstraction along the lines of zcash#1175 is needed more
generally. This commit refactors the use of ZIP 32 account identifiers
and key scopes to better separate scanning concerns from ZIP 32 key
derivation. In the process, this removes a fair amount of unnecessary
polymorphism from `zcash_client_backend::wallet::WalletTx` and related
types.
  • Loading branch information
nuttycom committed Feb 23, 2024
1 parent b5c40f1 commit c3b8471
Show file tree
Hide file tree
Showing 9 changed files with 364 additions and 364 deletions.
24 changes: 9 additions & 15 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use zcash_primitives::{
components::amount::{Amount, BalanceError, NonNegativeAmount},
Transaction, TxId,
},
zip32::{AccountId, Scope},
zip32::AccountId,
};

use crate::{
Expand Down Expand Up @@ -700,23 +700,23 @@ pub struct ScannedBlockCommitments {
/// decrypted and extracted from a [`CompactBlock`].
///
/// [`CompactBlock`]: crate::proto::compact_formats::CompactBlock
pub struct ScannedBlock<Nf, S> {
pub struct ScannedBlock {
block_height: BlockHeight,
block_hash: BlockHash,
block_time: u32,
transactions: Vec<WalletTx<Nf, S>>,
transactions: Vec<WalletTx>,
sapling: ScannedBundles<sapling::Node, sapling::Nullifier>,
#[cfg(feature = "orchard")]
orchard: ScannedBundles<orchard::note::NoteCommitment, orchard::note::Nullifier>,
}

impl<Nf, S> ScannedBlock<Nf, S> {
impl ScannedBlock {
/// Constructs a new `ScannedBlock`
pub(crate) fn from_parts(
block_height: BlockHeight,
block_hash: BlockHash,
block_time: u32,
transactions: Vec<WalletTx<Nf, S>>,
transactions: Vec<WalletTx>,
sapling: ScannedBundles<sapling::Node, sapling::Nullifier>,
#[cfg(feature = "orchard")] orchard: ScannedBundles<
orchard::note::NoteCommitment,
Expand Down Expand Up @@ -750,7 +750,7 @@ impl<Nf, S> ScannedBlock<Nf, S> {
}

/// Returns the list of transactions from this block that are relevant to the wallet.
pub fn transactions(&self) -> &[WalletTx<Nf, S>] {
pub fn transactions(&self) -> &[WalletTx] {
&self.transactions
}

Expand Down Expand Up @@ -1042,10 +1042,7 @@ pub trait WalletWrite: WalletRead {
/// pertaining to this wallet.
///
/// `blocks` must be sequential, in order of increasing block height
fn put_blocks(
&mut self,
blocks: Vec<ScannedBlock<sapling::Nullifier, Scope>>,
) -> Result<(), Self::Error>;
fn put_blocks(&mut self, blocks: Vec<ScannedBlock>) -> Result<(), Self::Error>;

/// Updates the wallet's view of the blockchain.
///
Expand Down Expand Up @@ -1167,7 +1164,7 @@ pub mod testing {
consensus::{BlockHeight, Network},
memo::Memo,
transaction::{components::Amount, Transaction, TxId},
zip32::{AccountId, Scope},
zip32::AccountId,
};

use crate::{
Expand Down Expand Up @@ -1396,10 +1393,7 @@ pub mod testing {
}

#[allow(clippy::type_complexity)]
fn put_blocks(
&mut self,
_blocks: Vec<ScannedBlock<sapling::Nullifier, Scope>>,
) -> Result<(), Self::Error> {
fn put_blocks(&mut self, _blocks: Vec<ScannedBlock>) -> Result<(), Self::Error> {
Ok(())
}

Expand Down
40 changes: 26 additions & 14 deletions zcash_client_backend/src/data_api/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,15 @@
//! # }
//! ```
use std::ops::Range;
use std::{collections::HashMap, ops::Range};

use sapling::note_encryption::PreparedIncomingViewingKey;
use zcash_primitives::consensus::{self, BlockHeight};

use crate::{
data_api::{NullifierQuery, WalletWrite},
proto::compact_formats::CompactBlock,
scan::BatchRunner,
scanning::{add_block_to_runner, scan_block_with_runner, ScanningKey},
scanning::{add_block_to_runner, scan_block_with_runner, SaplingScanningKey, ScanningKey},
};

pub mod error;
Expand Down Expand Up @@ -281,17 +280,24 @@ where
.map_err(Error::Wallet)?;
// TODO: Change `scan_block` to also scan Orchard.
// https://github.com/zcash/librustzcash/issues/403
let sapling_ivks: Vec<_> = ufvks
let sapling_ivks = ufvks
.iter()
.filter_map(|(account, ufvk)| ufvk.sapling().map(move |k| (account, k)))
.flat_map(|(account, dfvk)| dfvk.to_ivks().into_iter().map(move |key| (account, key)))
.collect::<Vec<_>>();
.flat_map(|(account, dfvk)| {
SaplingScanningKey::from_account_dfvk(dfvk, Some(*account)).into_iter()
})
.map(|key| {
(
key.account_scope()
.expect("Account ID is available for each key"),
key,
)
})
.collect::<HashMap<_, _>>();

let mut sapling_runner = BatchRunner::<_, _, _, _, ()>::new(
100,
sapling_ivks.iter().map(|(account, (scope, ivk, _))| {
((**account, *scope), PreparedIncomingViewingKey::new(ivk))
}),
sapling_ivks.iter().map(|(id, key)| (*id, key.prepare())),
);

block_source.with_blocks::<_, DbT::Error>(
Expand Down Expand Up @@ -342,22 +348,28 @@ where
.transactions
.iter()
.fold((0, 0), |(s, r), wtx| {
(s + wtx.sapling_spends.len(), r + wtx.sapling_outputs.len())
(
s + wtx.sapling_spends().len(),
r + wtx.sapling_outputs().len(),
)
});
spent_note_count += s;
received_note_count += r;

let spent_nf: Vec<&sapling::Nullifier> = scanned_block
.transactions
.iter()
.flat_map(|tx| tx.sapling_spends.iter().map(|spend| spend.nf()))
.flat_map(|tx| tx.sapling_spends().iter().map(|spend| spend.nf()))
.collect();

sapling_nullifiers.retain(|(_, nf)| !spent_nf.contains(&nf));
sapling_nullifiers.extend(scanned_block.transactions.iter().flat_map(|tx| {
tx.sapling_outputs
.iter()
.map(|out| (out.account(), *out.nf()))
tx.sapling_outputs().iter().flat_map(|out| {
out.recipient_key_meta()
.zip(out.nf())
.into_iter()
.map(|((account_id, _), nf)| (account_id, *nf))
})
}));

prior_block_metadata = Some(scanned_block.to_block_metadata());
Expand Down
Loading

0 comments on commit c3b8471

Please sign in to comment.