poc(scanner): add a populated state test for ZECpages viewing key (#7916)
* get started with the blockchain scanner poc * rustfmt * fix the tests * Reads blocks from db * Adds conversion functions * scans blocks and counts transactions * fix bug * split into 2 tests * add duplicated dependencies to deny.toml * upgrade zebra-scanner version * try removing ecc duplicated dependencies * try fix deny.toml * remove unintended paste from deny.toml * remove duplicated code from the other test * remove strict version of `zcash_primitives` crate * change description * remove feture * remove tokio features * change lib doc * add more documentation * change expect * do not use default in compact block creation * more docs * add more checks to test * remove zebra-consensus dependency * move all deps to dev-deps * change crate version * rename crate to zebra-scan * lock file * add test for zecpages populated state * scans all cached blocks for zecpages viewing key expecting Ok results. * use test blocks * fixes test * fix expect messages * Discard changes to Cargo.lock * Discard changes to deny.toml --------- Co-authored-by: arya2 <aryasolhi@gmail.com> Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
parent
2fad3573fd
commit
e5e89ec549
|
@ -6,6 +6,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use zcash_client_backend::{
|
||||
data_api::BlockMetadata,
|
||||
encoding::decode_extended_full_viewing_key,
|
||||
proto::compact_formats::{
|
||||
self as compact, ChainMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend,
|
||||
CompactTx,
|
||||
|
@ -16,7 +18,7 @@ use zcash_note_encryption::Domain;
|
|||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{BlockHeight, Network},
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
constants::{mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, SPENDING_KEY_GENERATOR},
|
||||
memo::MemoBytes,
|
||||
sapling::{
|
||||
note_encryption::{sapling_note_encryption, SaplingDomain},
|
||||
|
@ -168,6 +170,119 @@ async fn scanning_from_fake_generated_blocks() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Scan a populated state for the ZECpages viewing key.
|
||||
/// This test is very similar to `scanning_from_populated_zebra_state` but with the ZECpages key.
|
||||
/// There are no zechub transactions in the test data so we should get empty related transactions.
|
||||
#[tokio::test]
|
||||
async fn scanning_zecpages_from_populated_zebra_state() -> Result<()> {
|
||||
/// The extended Sapling viewing key of [ZECpages](https://zecpages.com/boardinfo)
|
||||
const ZECPAGES_VIEWING_KEY: &str = "zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz";
|
||||
|
||||
// Parse the key from ZECpages
|
||||
let efvk = decode_extended_full_viewing_key(
|
||||
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
ZECPAGES_VIEWING_KEY,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let account = AccountId::from(1);
|
||||
|
||||
// Build a vector of viewing keys `vks` to scan for.
|
||||
let fvk = efvk.fvk;
|
||||
let ivk = fvk.vk.ivk();
|
||||
let vks: Vec<(&AccountId, &SaplingIvk)> = vec![(&account, &ivk)];
|
||||
|
||||
let network = zebra_chain::parameters::Network::Mainnet;
|
||||
|
||||
// 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;
|
||||
while let Some(block) = db.block(height.into()) {
|
||||
// zcash_client_backend doesn't support scanning the genesis block, but that's ok, because
|
||||
// Sapling activates at height 419,200. So we'll never scan these blocks in production code.
|
||||
let sapling_tree_size = if height.is_min() {
|
||||
1
|
||||
} else {
|
||||
db.sapling_tree_by_hash_or_height(height.into())
|
||||
.expect("each state block must have a sapling tree")
|
||||
.count()
|
||||
};
|
||||
|
||||
let orchard_tree_size = db
|
||||
.orchard_tree_by_hash_or_height(height.into())
|
||||
.expect("each state block must have a orchard tree")
|
||||
.count();
|
||||
|
||||
let chain_metadata = ChainMetadata {
|
||||
sapling_commitment_tree_size: sapling_tree_size
|
||||
.try_into()
|
||||
.expect("sapling position is limited to u32::MAX"),
|
||||
orchard_commitment_tree_size: orchard_tree_size
|
||||
.try_into()
|
||||
.expect("orchard position is limited to u32::MAX"),
|
||||
};
|
||||
|
||||
let block_metadata = if height.is_min() {
|
||||
None
|
||||
} else {
|
||||
Some(BlockMetadata::from_parts(
|
||||
height.previous()?.0.into(),
|
||||
BlockHash(block.header.previous_block_hash.0),
|
||||
db.sapling_tree_by_hash_or_height(block.header.previous_block_hash.into())
|
||||
.expect("each state block must have a sapling tree")
|
||||
.count()
|
||||
.try_into()
|
||||
.expect("sapling position is limited to u32::MAX"),
|
||||
))
|
||||
};
|
||||
|
||||
let compact_block = block_to_compact(block, chain_metadata);
|
||||
|
||||
let res = scan_block(
|
||||
&zcash_primitives::consensus::MainNetwork,
|
||||
compact_block.clone(),
|
||||
&vks[..],
|
||||
&[],
|
||||
block_metadata.as_ref(),
|
||||
)
|
||||
.expect("scanning block for the ZECpages viewing key should work");
|
||||
|
||||
transactions_found += res.transactions().len();
|
||||
transactions_scanned += compact_block.vtx.len();
|
||||
blocks_scanned += 1;
|
||||
|
||||
// scan backwards
|
||||
if height.is_min() {
|
||||
break;
|
||||
}
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Convert a zebra block and meta data into a compact block.
|
||||
fn block_to_compact(block: Arc<Block>, chain_metadata: ChainMetadata) -> CompactBlock {
|
||||
CompactBlock {
|
||||
|
|
Loading…
Reference in New Issue