Skip to content

Commit

Permalink
change(zebra-scan): Scan only one key per backend call (#8034)
Browse files Browse the repository at this point in the history
* scan one key per backend call

* fix docs
  • Loading branch information
oxarbitrage authored Nov 30, 2023
1 parent cb9452c commit 1708f9d
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 77 deletions.
10 changes: 4 additions & 6 deletions zebra-scan/src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub async fn start(mut state: State, storage: Storage) -> Result<(), Report> {
}
}

/// Returns transactions belonging to any of the given [`ScanningKey`]s.
/// Returns transactions belonging to the given `ScanningKey`.
///
/// TODO:
/// - Remove the `sapling_tree_size` parameter or turn it into an `Option` once we have access to
Expand All @@ -80,7 +80,7 @@ pub fn scan_block<K: ScanningKey>(
network: Network,
block: Arc<Block>,
sapling_tree_size: u32,
scanning_keys: &[&K],
scanning_key: &K,
) -> Result<ScannedBlock<K::Nf>, ScanError> {
// TODO: Implement a check that returns early when the block height is below the Sapling
// activation height.
Expand All @@ -96,10 +96,8 @@ pub fn scan_block<K: ScanningKey>(
// Use a dummy `AccountId` as we don't use accounts yet.
let dummy_account = AccountId::from(0);

let scanning_keys: Vec<_> = scanning_keys
.iter()
.map(|key| (&dummy_account, key))
.collect();
// We only support scanning one key and one block per function call for now.
let scanning_keys = vec![(&dummy_account, scanning_key)];

zcash_client_backend::scanning::scan_block(
&network,
Expand Down
73 changes: 2 additions & 71 deletions zebra-scan/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,80 +32,11 @@ use zcash_primitives::{
};

use zebra_chain::{
block::Block, chain_tip::ChainTip, parameters::Network, serialization::ZcashDeserializeInto,
transaction::Hash,
block::Block, chain_tip::ChainTip, serialization::ZcashDeserializeInto, transaction::Hash,
};

use crate::scan::{block_to_compact, scan_block};

/// Scans a continuous chain of Mainnet blocks from tip to genesis.
///
/// Also verifies that no relevant transaction is found in the chain when scanning for a fake
/// account's nullifier.
#[tokio::test]
async fn scanning_from_populated_zebra_state() -> Result<()> {
let network = Network::default();

// Create a continuous chain of mainnet blocks from genesis
let blocks: Vec<Arc<Block>> = zebra_test::vectors::CONTINUOUS_MAINNET_BLOCKS
.iter()
.map(|(_height, block_bytes)| block_bytes.zcash_deserialize_into().unwrap())
.collect();

// Create a populated state service.
let (_state_service, read_only_state_service, latest_chain_tip, _chain_tip_change) =
zebra_state::populated_state(blocks.clone(), network).await;

let db = read_only_state_service.db();

// use the tip as starting height
let mut height = latest_chain_tip.best_tip_height().unwrap();

let mut transactions_found = 0;
let mut transactions_scanned = 0;
let mut blocks_scanned = 0;
// TODO: Accessing the state database directly is ok in the tests, but not in production code.
// Use `Request::Block` if the code is copied to production.
while let Some(block) = db.block(height.into()) {
// We use a dummy size of the Sapling note commitment tree. We can't set the size to zero
// because the underlying scanning function would return
// `zcash_client_backeng::scanning::ScanError::TreeSizeUnknown`.
let sapling_commitment_tree_size = 1;

let orchard_commitment_tree_size = 0;

let chain_metadata = ChainMetadata {
sapling_commitment_tree_size,
orchard_commitment_tree_size,
};

let compact_block = block_to_compact(block.clone(), chain_metadata);

let res =
scan_block::<SaplingIvk>(network, block, sapling_commitment_tree_size, &[]).unwrap();

transactions_found += res.transactions().len();
transactions_scanned += compact_block.vtx.len();
blocks_scanned += 1;

if height.is_min() {
break;
}

// scan backwards
height = height.previous()?;
}

// make sure all blocks and transactions were scanned
assert_eq!(blocks_scanned, 11);
assert_eq!(transactions_scanned, 11);

// no relevant transactions should be found
assert_eq!(transactions_found, 0);

Ok(())
}

/// Prove that we can create fake blocks with fake notes and scan them using the
/// `zcash_client_backend::scanning::scan_block` function:
/// - Function `fake_compact_block` will generate 1 block with one pre created fake nullifier in
Expand Down Expand Up @@ -207,7 +138,7 @@ async fn scanning_zecpages_from_populated_zebra_state() -> Result<()> {

let compact_block = block_to_compact(block.clone(), chain_metadata);

let res = scan_block(network, block, sapling_commitment_tree_size, &[&ivk])
let res = scan_block(network, block, sapling_commitment_tree_size, &ivk)
.expect("scanning block for the ZECpages viewing key should work");

transactions_found += res.transactions().len();
Expand Down

0 comments on commit 1708f9d

Please sign in to comment.