zcash_client_backend: Remove duplicative continuity checks.

This commit is contained in:
Kris Nuttycombe 2023-11-08 14:38:20 -07:00
parent ae4cb53c49
commit 8ce8cc8145
2 changed files with 24 additions and 101 deletions

View File

@ -147,17 +147,16 @@
use std::ops::Range;
use zcash_primitives::{
block::BlockHash,
consensus::{self, BlockHeight},
sapling::{self, note_encryption::PreparedIncomingViewingKey},
zip32::Scope,
};
use crate::{
data_api::{BlockMetadata, NullifierQuery, WalletWrite},
data_api::{NullifierQuery, WalletWrite},
proto::compact_formats::CompactBlock,
scan::BatchRunner,
scanning::{add_block_to_runner, check_continuity, scan_block_with_runner, ScanningKey},
scanning::{add_block_to_runner, scan_block_with_runner, ScanningKey},
};
pub mod error;
@ -326,60 +325,10 @@ where
None
};
let mut continuity_check_metadata = prior_block_metadata;
block_source.with_blocks::<_, DbT::Error>(
Some(from_height),
Some(limit),
|block: CompactBlock| {
// check block continuity
if let Some(scan_error) = check_continuity(&block, continuity_check_metadata.as_ref()) {
return Err(Error::Scan(scan_error));
}
if block.height() == BlockHeight::from(0) {
// We can always derive a valid `continuity_check_metadata` for the
// genesis block, even if the block source doesn't have
// `sapling_commitment_tree_size`. So briefly set it to a dummy value that
// ensures the `map` below produces the correct genesis block value.
assert!(continuity_check_metadata.is_none());
continuity_check_metadata = Some(BlockMetadata::from_parts(
BlockHeight::from(0),
BlockHash([0; 32]),
Some(0),
Some(0),
));
}
continuity_check_metadata = continuity_check_metadata.as_ref().map(|bm| {
BlockMetadata::from_parts(
block.height(),
block.hash(),
block
.chain_metadata
.as_ref()
.map(|bcm| bcm.sapling_commitment_tree_size)
.or_else(|| {
bm.sapling_tree_size().map(|s| {
s + u32::try_from(
block.vtx.iter().map(|tx| tx.outputs.len()).sum::<usize>(),
)
.expect("count of Sapling outputs in a block cannot exceed a u32")
})
}),
block
.chain_metadata
.as_ref()
.map(|bcm| bcm.orchard_commitment_tree_size)
.or_else(|| {
bm.orchard_tree_size().map(|s| {
s + u32::try_from(
block.vtx.iter().map(|tx| tx.actions.len()).sum::<usize>(),
)
.expect("count of Orchard actions in a block cannot exceed a u32")
})
}),
)
});
add_block_to_runner(params, block, &mut batch_runner);
Ok(())

View File

@ -292,7 +292,7 @@ pub(crate) fn add_block_to_runner<P, S, T>(
}
}
pub(crate) fn check_continuity(
fn check_hash_continuity(
block: &CompactBlock,
prior_block_metadata: Option<&BlockMetadata>,
) -> Option<ScanError> {
@ -309,46 +309,6 @@ pub(crate) fn check_continuity(
at_height: block.height(),
});
}
let given_sapling_tree_size = block
.chain_metadata
.as_ref()
.map(|m| m.sapling_commitment_tree_size);
let computed_sapling_tree_size = prev.sapling_tree_size().map(|s| {
s + u32::try_from(block.vtx.iter().map(|tx| tx.outputs.len()).sum::<usize>()).unwrap()
});
if let Some((given, computed)) = given_sapling_tree_size.zip(computed_sapling_tree_size) {
if given != computed {
return Some(ScanError::TreeSizeMismatch {
protocol: ShieldedProtocol::Sapling,
at_height: block.height(),
given,
computed,
});
}
}
let given_orchard_tree_size = block
.chain_metadata
.as_ref()
.map(|m| m.orchard_commitment_tree_size);
let computed_orchard_tree_size = prev.orchard_tree_size().map(|s| {
s + u32::try_from(block.vtx.iter().map(|tx| tx.actions.len()).sum::<usize>()).unwrap()
});
if let Some((given, computed)) = given_orchard_tree_size.zip(computed_orchard_tree_size) {
if given != computed {
return Some(ScanError::TreeSizeMismatch {
protocol: ShieldedProtocol::Orchard,
at_height: block.height(),
given,
computed,
});
}
}
}
None
@ -367,19 +327,13 @@ pub(crate) fn scan_block_with_runner<
prior_block_metadata: Option<&BlockMetadata>,
mut batch_runner: Option<&mut TaggedBatchRunner<P, K::Scope, T>>,
) -> Result<ScannedBlock<K::Nf>, ScanError> {
if let Some(scan_error) = check_continuity(&block, prior_block_metadata) {
if let Some(scan_error) = check_hash_continuity(&block, prior_block_metadata) {
return Err(scan_error);
}
let cur_height = block.height();
let cur_hash = block.hash();
// It's possible to make progress without a Sapling tree position if we don't have any Sapling
// notes in the block, since we only use the position for constructing nullifiers for our own
// received notes. Thus, we allow it to be optional here, and only produce an error if we try
// to use it. `block.sapling_commitment_tree_size` is expected to be correct as of the end of
// the block, and we can't have a note of ours in a block with no outputs so treating the zero
// default value from the protobuf as `None` is always correct.
let initial_sapling_tree_size = prior_block_metadata.and_then(|m| m.sapling_tree_size());
let mut sapling_commitment_tree_size = initial_sapling_tree_size
.or_else(|| {
@ -622,6 +576,26 @@ pub(crate) fn scan_block_with_runner<
orchard_commitment_tree_size += tx_actions_len;
}
if let Some(chain_meta) = block.chain_metadata {
if chain_meta.sapling_commitment_tree_size != sapling_commitment_tree_size {
return Err(ScanError::TreeSizeMismatch {
protocol: ShieldedProtocol::Sapling,
at_height: cur_height,
given: chain_meta.sapling_commitment_tree_size,
computed: sapling_commitment_tree_size,
});
}
if chain_meta.orchard_commitment_tree_size != orchard_commitment_tree_size {
return Err(ScanError::TreeSizeMismatch {
protocol: ShieldedProtocol::Orchard,
at_height: cur_height,
given: chain_meta.orchard_commitment_tree_size,
computed: orchard_commitment_tree_size,
});
}
}
Ok(ScannedBlock::from_parts(
cur_height,
cur_hash,