diff --git a/zcash_client_backend/src/data_api/chain.rs b/zcash_client_backend/src/data_api/chain.rs index bdda126d5..dd10fcf5f 100644 --- a/zcash_client_backend/src/data_api/chain.rs +++ b/zcash_client_backend/src/data_api/chain.rs @@ -320,7 +320,7 @@ where Some(from_height), Some(limit), |block: CompactBlock| { - runners.add_block(params, block); + runners.add_block(params, block)?; Ok(()) }, diff --git a/zcash_client_backend/src/scanning.rs b/zcash_client_backend/src/scanning.rs index a07ecceb0..fa2399b27 100644 --- a/zcash_client_backend/src/scanning.rs +++ b/zcash_client_backend/src/scanning.rs @@ -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 }, @@ -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, @@ -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, @@ -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 {}.", @@ -491,7 +506,7 @@ impl, TO: OrchardTasks(&mut self, params: &P, block: CompactBlock) + pub(crate) fn add_block

(&mut self, params: &P, block: CompactBlock) -> Result<(), ScanError> where P: consensus::Parameters + Send + 'static, KeyId: Copy + Send + 'static, @@ -509,11 +524,18 @@ impl, TO: OrchardTasks>(), + .collect::, _>>()?, ); #[cfg(feature = "orchard")] @@ -523,13 +545,20 @@ impl, TO: OrchardTasks>(), + .collect::, _>>()?, ); } + + Ok(()) } } @@ -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::>(), + .collect::, _>>()?, batch_runners .as_mut() .map(|runners| |txid| runners.sapling.collect_results(cur_hash, txid)), @@ -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::>(), + .collect::, _>>()?, batch_runners .as_mut() .map(|runners| |txid| runners.orchard.collect_results(cur_hash, txid)), @@ -1205,7 +1248,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) @@ -1291,7 +1336,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)