Skip to content

Commit

Permalink
zcash_client_backend: Return decoding errors from `BatchRunners::add_…
Browse files Browse the repository at this point in the history
…block`
  • Loading branch information
nuttycom committed Feb 26, 2024
1 parent 9d2bd3a commit d98e09d
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 23 deletions.
2 changes: 1 addition & 1 deletion zcash_client_backend/src/data_api/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ where
Some(from_height),
Some(limit),
|block: CompactBlock| {
runners.add_block(params, block);
runners.add_block(params, block)?;

Ok(())
},
Expand Down
91 changes: 69 additions & 22 deletions zcash_client_backend/src/scanning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,14 @@ impl ScanningKeys<(AccountId, Scope)> {
/// Errors that may occur in chain scanning
#[derive(Clone, Debug)]
pub enum ScanError {
/// The encoding of a compact Sapling output or compact Orchard action was invalid.
EncodingInvalid {
at_height: BlockHeight,
txid: TxId,
pool_type: ShieldedProtocol,
index: usize,
},

/// The hash of the parent block given by a proposed new chain tip does not match the hash of
/// the current chain tip.
PrevHashMismatch { at_height: BlockHeight },
Expand Down Expand Up @@ -335,6 +343,7 @@ impl ScanError {
pub fn is_continuity_error(&self) -> bool {
use ScanError::*;
match self {
EncodingInvalid { .. } => false,
PrevHashMismatch { .. } => true,
BlockHeightDiscontinuity { .. } => true,
TreeSizeMismatch { .. } => true,
Expand All @@ -347,6 +356,7 @@ impl ScanError {
pub fn at_height(&self) -> BlockHeight {
use ScanError::*;
match self {
EncodingInvalid { at_height, .. } => *at_height,
PrevHashMismatch { at_height } => *at_height,
BlockHeightDiscontinuity { new_height, .. } => *new_height,
TreeSizeMismatch { at_height, .. } => *at_height,
Expand All @@ -360,6 +370,11 @@ impl fmt::Display for ScanError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ScanError::*;
match &self {
EncodingInvalid { txid, pool_type, index, .. } => write!(
f,
"{:?} output {} of transaction {} was improperly encoded.",
pool_type, index, txid
),
PrevHashMismatch { at_height } => write!(
f,
"The parent hash of proposed block does not correspond to the block hash at height {}.",
Expand Down Expand Up @@ -491,7 +506,7 @@ impl<KeyId: Clone + Send + 'static, TS: SaplingTasks<KeyId>, TO: OrchardTasks<Ke
}

#[tracing::instrument(skip_all, fields(height = block.height))]
pub(crate) fn add_block<P>(&mut self, params: &P, block: CompactBlock)
pub(crate) fn add_block<P>(&mut self, params: &P, block: CompactBlock) -> Result<(), ScanError>
where
P: consensus::Parameters + Send + 'static,
KeyId: Copy + Send + 'static,
Expand All @@ -509,11 +524,18 @@ impl<KeyId: Clone + Send + 'static, TS: SaplingTasks<KeyId>, TO: OrchardTasks<Ke
|_| SaplingDomain::new(zip212_enforcement),
&tx.outputs
.iter()
.map(|output| {
CompactOutputDescription::try_from(output)
.expect("Invalid output found in compact block decoding.")
.enumerate()
.map(|(i, output)| {
CompactOutputDescription::try_from(output).map_err(|_| {
ScanError::EncodingInvalid {
at_height: block_height,
txid,
pool_type: ShieldedProtocol::Sapling,
index: i,
}
})
})
.collect::<Vec<_>>(),
.collect::<Result<Vec<_>, _>>()?,
);

#[cfg(feature = "orchard")]
Expand All @@ -523,13 +545,20 @@ impl<KeyId: Clone + Send + 'static, TS: SaplingTasks<KeyId>, TO: OrchardTasks<Ke
|action| OrchardDomain::for_nullifier(action.nullifier()),
&tx.actions
.iter()
.map(|action| {
CompactAction::try_from(action)
.expect("Invalid action found in compact block decoding.")
.enumerate()
.map(|(i, action)| {
CompactAction::try_from(action).map_err(|_| ScanError::EncodingInvalid {
at_height: block_height,
txid,
pool_type: ShieldedProtocol::Sapling,
index: i,
})
})
.collect::<Vec<_>>(),
.collect::<Result<Vec<_>, _>>()?,
);
}

Ok(())
}
}

Expand Down Expand Up @@ -731,14 +760,21 @@ pub(crate) fn scan_block_with_runners<
&spent_from_accounts,
&tx.outputs
.iter()
.map(|output| {
(
.enumerate()
.map(|(i, output)| {
Ok((
SaplingDomain::new(zip212_enforcement),
CompactOutputDescription::try_from(output)
.expect("Invalid output found in compact block decoding."),
)
CompactOutputDescription::try_from(output).map_err(|_| {
ScanError::EncodingInvalid {
at_height: cur_height,
txid,
pool_type: ShieldedProtocol::Sapling,
index: i,
}
})?,
))
})
.collect::<Vec<_>>(),
.collect::<Result<Vec<_>, _>>()?,
batch_runners
.as_mut()
.map(|runners| |txid| runners.sapling.collect_results(cur_hash, txid)),
Expand Down Expand Up @@ -769,12 +805,19 @@ pub(crate) fn scan_block_with_runners<
&spent_from_accounts,
&tx.actions
.iter()
.map(|action| {
let action = CompactAction::try_from(action)
.expect("Invalid output found in compact block decoding.");
(OrchardDomain::for_nullifier(action.nullifier()), action)
.enumerate()
.map(|(i, action)| {
let action = CompactAction::try_from(action).map_err(|_| {
ScanError::EncodingInvalid {
at_height: cur_height,
txid,
pool_type: ShieldedProtocol::Orchard,
index: i,
}
})?;
Ok((OrchardDomain::for_nullifier(action.nullifier()), action))
})
.collect::<Vec<_>>(),
.collect::<Result<Vec<_>, _>>()?,
batch_runners
.as_mut()
.map(|runners| |txid| runners.orchard.collect_results(cur_hash, txid)),
Expand Down Expand Up @@ -1204,7 +1247,9 @@ mod tests {

let mut batch_runners = if scan_multithreaded {
let mut runners = BatchRunners::<_, (), ()>::for_keys(10, &scanning_keys);
runners.add_block(&Network::TestNetwork, cb.clone());
runners
.add_block(&Network::TestNetwork, cb.clone())
.unwrap();
runners.flush();

Some(runners)
Expand Down Expand Up @@ -1289,7 +1334,9 @@ mod tests {

let mut batch_runners = if scan_multithreaded {
let mut runners = BatchRunners::<_, (), ()>::for_keys(10, &scanning_keys);
runners.add_block(&Network::TestNetwork, cb.clone());
runners
.add_block(&Network::TestNetwork, cb.clone())
.unwrap();
runners.flush();

Some(runners)
Expand Down

0 comments on commit d98e09d

Please sign in to comment.