From f49e936b6b3c9ee5c761edb3d2d67a6976b282b5 Mon Sep 17 00:00:00 2001 From: Marek Date: Tue, 28 Nov 2023 21:19:59 +0100 Subject: [PATCH] Move code from `tests.rs` to `scan.rs` --- zebra-scan/Cargo.toml | 6 +- zebra-scan/src/scan.rs | 138 ++++++++++++++++++++++++++++++++++++++- zebra-scan/src/tests.rs | 141 ++-------------------------------------- 3 files changed, 146 insertions(+), 139 deletions(-) diff --git a/zebra-scan/Cargo.toml b/zebra-scan/Cargo.toml index 4293f3c427c..47709df1a0d 100644 --- a/zebra-scan/Cargo.toml +++ b/zebra-scan/Cargo.toml @@ -22,6 +22,9 @@ categories = ["cryptography::cryptocurrencies"] zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.31" } zebra-state = { path = "../zebra-state", version = "1.0.0-beta.31" } +zcash_primitives = "0.13.0-rc.1" +zcash_client_backend = "0.10.0-rc.1" + color-eyre = "0.6.2" indexmap = { version = "2.0.1", features = ["serde"] } serde = { version = "1.0.193", features = ["serde_derive"] } @@ -30,9 +33,6 @@ tower = "0.4.13" tracing = "0.1.39" [dev-dependencies] - -zcash_client_backend = "0.10.0-rc.1" -zcash_primitives = "0.13.0-rc.1" zcash_note_encryption = "0.4.0" rand = "0.8.5" diff --git a/zebra-scan/src/scan.rs b/zebra-scan/src/scan.rs index 9563fbd734a..9b284eedcb1 100644 --- a/zebra-scan/src/scan.rs +++ b/zebra-scan/src/scan.rs @@ -1,10 +1,21 @@ //! The scan task. -use std::time::Duration; +use std::{sync::Arc, time::Duration}; use color_eyre::{eyre::eyre, Report}; use tower::{buffer::Buffer, util::BoxService, Service, ServiceExt}; use tracing::info; +use zcash_client_backend::{ + data_api::ScannedBlock, + proto::compact_formats::{ + ChainMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx, + }, + scanning::{ScanError, ScanningKey}, +}; +use zcash_primitives::zip32::AccountId; +use zebra_chain::{ + block::Block, parameters::Network, serialization::ZcashSerialize, transaction::Transaction, +}; use crate::storage::Storage; @@ -56,3 +67,128 @@ pub async fn start(mut state: State, storage: Storage) -> Result<(), Report> { tokio::time::sleep(CHECK_INTERVAL).await; } } + +/// Returns transactions belonging to any of the given [`ScanningKey`]s. +/// +/// TODO: +/// - Remove the `sapling_tree_size` parameter or turn it into an `Option` once we have access to +/// Zebra's state, and we can retrieve the tree size ourselves. +/// - Add prior block metadata once we have access to Zebra's state. +pub fn scan_block( + network: Network, + block: Arc, + sapling_tree_size: u32, + scanning_keys: &[&K], +) -> Result, ScanError> { + // TODO: Implement a check that returns early when the block height is below the Sapling + // activation height. + + let network: zcash_primitives::consensus::Network = network.into(); + + let chain_metadata = ChainMetadata { + sapling_commitment_tree_size: sapling_tree_size, + // Orchard is not supported at the moment so the tree size can be 0. + orchard_commitment_tree_size: 0, + }; + + // 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(); + + zcash_client_backend::scanning::scan_block( + &network, + block_to_compact(block, chain_metadata), + &scanning_keys, + // Ignore whether notes are change from a viewer's own spends for now. + &[], + // Ignore previous blocks for now. + None, + ) +} + +/// Converts a zebra block and meta data into a compact block. +pub fn block_to_compact(block: Arc, chain_metadata: ChainMetadata) -> CompactBlock { + CompactBlock { + height: block + .coinbase_height() + .expect("verified block should have a valid height") + .0 + .into(), + hash: block.hash().bytes_in_display_order().to_vec(), + prev_hash: block + .header + .previous_block_hash + .bytes_in_display_order() + .to_vec(), + time: block + .header + .time + .timestamp() + .try_into() + .expect("unsigned 32-bit times should work until 2105"), + header: block + .header + .zcash_serialize_to_vec() + .expect("verified block should serialize"), + vtx: block + .transactions + .iter() + .cloned() + .enumerate() + .map(transaction_to_compact) + .collect(), + chain_metadata: Some(chain_metadata), + + // The protocol version is used for the gRPC wire format, so it isn't needed here. + proto_version: 0, + } +} + +/// Converts a zebra transaction into a compact transaction. +fn transaction_to_compact((index, tx): (usize, Arc)) -> CompactTx { + CompactTx { + index: index + .try_into() + .expect("tx index in block should fit in u64"), + hash: tx.hash().bytes_in_display_order().to_vec(), + + // `fee` is not checked by the `scan_block` function. It is allowed to be unset. + // + fee: 0, + + spends: tx + .sapling_nullifiers() + .map(|nf| CompactSaplingSpend { + nf: <[u8; 32]>::from(*nf).to_vec(), + }) + .collect(), + + // > output encodes the cmu field, ephemeralKey field, and a 52-byte prefix of the encCiphertext field of a Sapling Output + // + // + outputs: tx + .sapling_outputs() + .map(|output| CompactSaplingOutput { + cmu: output.cm_u.to_bytes().to_vec(), + ephemeral_key: output + .ephemeral_key + .zcash_serialize_to_vec() + .expect("verified output should serialize successfully"), + ciphertext: output + .enc_ciphertext + .zcash_serialize_to_vec() + .expect("verified output should serialize successfully") + .into_iter() + .take(52) + .collect(), + }) + .collect(), + + // `actions` is not checked by the `scan_block` function. + actions: vec![], + } +} diff --git a/zebra-scan/src/tests.rs b/zebra-scan/src/tests.rs index dffc77d8ce7..fe3be0a6e2c 100644 --- a/zebra-scan/src/tests.rs +++ b/zebra-scan/src/tests.rs @@ -6,13 +6,10 @@ use std::sync::Arc; use zcash_client_backend::{ - data_api::ScannedBlock, encoding::decode_extended_full_viewing_key, proto::compact_formats::{ - self as compact, ChainMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend, - CompactTx, + ChainMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx, }, - scanning::{ScanError, ScanningKey}, }; use zcash_note_encryption::Domain; use zcash_primitives::{ @@ -37,13 +34,12 @@ use ff::{Field, PrimeField}; use group::GroupEncoding; use zebra_chain::{ - block::Block, - chain_tip::ChainTip, - parameters::Network, - serialization::{ZcashDeserializeInto, ZcashSerialize}, - transaction::{Hash, Transaction}, + block::Block, chain_tip::ChainTip, parameters::Network, 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 @@ -301,89 +297,6 @@ async fn scanning_fake_blocks_store_key_and_results() -> Result<()> { Ok(()) } -/// Convert a zebra block and meta data into a compact block. -fn block_to_compact(block: Arc, chain_metadata: ChainMetadata) -> CompactBlock { - CompactBlock { - height: block - .coinbase_height() - .expect("verified block should have a valid height") - .0 - .into(), - hash: block.hash().bytes_in_display_order().to_vec(), - prev_hash: block - .header - .previous_block_hash - .bytes_in_display_order() - .to_vec(), - time: block - .header - .time - .timestamp() - .try_into() - .expect("unsigned 32-bit times should work until 2105"), - header: block - .header - .zcash_serialize_to_vec() - .expect("verified block should serialize"), - vtx: block - .transactions - .iter() - .cloned() - .enumerate() - .map(transaction_to_compact) - .collect(), - chain_metadata: Some(chain_metadata), - - // The protocol version is used for the gRPC wire format, so it isn't needed here. - proto_version: 0, - } -} - -/// Convert a zebra transaction into a compact transaction. -fn transaction_to_compact((index, tx): (usize, Arc)) -> CompactTx { - CompactTx { - index: index - .try_into() - .expect("tx index in block should fit in u64"), - hash: tx.hash().bytes_in_display_order().to_vec(), - - // `fee` is not checked by the `scan_block` function. It is allowed to be unset. - // - fee: 0, - - spends: tx - .sapling_nullifiers() - .map(|nf| CompactSaplingSpend { - nf: <[u8; 32]>::from(*nf).to_vec(), - }) - .collect(), - - // > output encodes the cmu field, ephemeralKey field, and a 52-byte prefix of the encCiphertext field of a Sapling Output - // - // - outputs: tx - .sapling_outputs() - .map(|output| CompactSaplingOutput { - cmu: output.cm_u.to_bytes().to_vec(), - ephemeral_key: output - .ephemeral_key - .zcash_serialize_to_vec() - .expect("verified output should serialize successfully"), - ciphertext: output - .enc_ciphertext - .zcash_serialize_to_vec() - .expect("verified output should serialize successfully") - .into_iter() - .take(52) - .collect(), - }) - .collect(), - - // `actions` is not checked by the `scan_block` function. - actions: vec![], - } -} - /// Create a fake compact block with provided fake account data. // This is a copy of zcash_primitives `fake_compact_block` where the `value` argument was changed to // be a number for easier conversion: @@ -462,7 +375,7 @@ fn fake_compact_block( cb.vtx.push(tx); } - cb.chain_metadata = initial_sapling_tree_size.map(|s| compact::ChainMetadata { + cb.chain_metadata = initial_sapling_tree_size.map(|s| ChainMetadata { sapling_commitment_tree_size: s + cb .vtx .iter() @@ -509,45 +422,3 @@ fn random_compact_tx(mut rng: impl RngCore) -> CompactTx { ctx.outputs.push(cout); ctx } - -/// Returns transactions belonging to any of the given [`ScanningKey`]s. -/// -/// TODO: -/// - Remove the `sapling_tree_size` parameter or turn it into an `Option` once we have access to -/// Zebra's state, and we can retrieve the tree size ourselves. -/// - Add prior block metadata once we have access to Zebra's state. -fn scan_block( - network: Network, - block: Arc, - sapling_tree_size: u32, - scanning_keys: &[&K], -) -> Result, ScanError> { - // TODO: Implement a check that returns early when the block height is below the Sapling - // activation height. - - let network: zcash_primitives::consensus::Network = network.into(); - - let chain_metadata = ChainMetadata { - sapling_commitment_tree_size: sapling_tree_size, - // Orchard is not supported at the moment so the tree size can be 0. - orchard_commitment_tree_size: 0, - }; - - // 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(); - - zcash_client_backend::scanning::scan_block( - &network, - block_to_compact(block, chain_metadata), - &scanning_keys, - // Ignore whether notes are change from a viewer's own spends for now. - &[], - // Ignore previous blocks for now. - None, - ) -}