diff --git a/zebra-consensus/src/verify.rs b/zebra-consensus/src/verify.rs index 2a349402..88f080e9 100644 --- a/zebra-consensus/src/verify.rs +++ b/zebra-consensus/src/verify.rs @@ -88,16 +88,35 @@ where fn call(&mut self, block: Arc) -> Self::Future { // TODO(jlusby): Error = Report, handle errors from state_service. // TODO(teor): - // - handle chain reorgs, adjust state_service "unique block height" conditions - // - handle block validation errors (including errors in the block's transactions) + // - handle chain reorgs + // - adjust state_service "unique block height" conditions + // - move expensive checks into the async block + // Create an AddBlock Future, but don't run it yet. + // // `state_service.call` is OK here because we already called // `state_service.poll_ready` in our `poll_ready`. - let add_block = self - .state_service - .call(zebra_state::Request::AddBlock { block }); + // + // `tower::Buffer` expects exactly one `call` for each + // `poll_ready`. So we unconditionally create the AddBlock + // Future using `state_service.call`. If verification fails, + // we return an error, and implicitly cancel the future. + let add_block = self.state_service.call(zebra_state::Request::AddBlock { + block: block.clone(), + }); async move { + // If verification fails, return an error result. + // The AddBlock Future is implicitly cancelled by the + // error return in `?`. + + // Since errors cause an early exit, try to do the + // quick checks first. + block::node_time_check(block)?; + + // Verification was successful. + // Add the block to the state by awaiting the AddBlock + // Future, and return its result. match add_block.await? { zebra_state::Response::Added { hash } => Ok(hash), _ => Err("adding block to zebra-state failed".into()),