diff --git a/zebra-consensus/src/chain.rs b/zebra-consensus/src/chain.rs index 96d0c320c..9a800a550 100644 --- a/zebra-consensus/src/chain.rs +++ b/zebra-consensus/src/chain.rs @@ -50,11 +50,15 @@ where type Future = Pin> + Send + 'static>>; - fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { - // We don't expect the verifiers to exert backpressure on our - // users, so we don't need to call the verifier's `poll_ready` here. - // (And we don't know which verifier to choose at this point, anyway.) - Poll::Ready(Ok(())) + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + match (self.checkpoint.poll_ready(cx), self.block.poll_ready(cx)) { + // First, fail if either service fails. + (Poll::Ready(Err(e)), _) | (_, Poll::Ready(Err(e))) => Poll::Ready(Err(e)), + // Second, we're unready if either service is unready. + (Poll::Pending, _) | (_, Poll::Pending) => Poll::Pending, + // Finally, we're ready if both services are ready and OK. + (Poll::Ready(Ok(())), Poll::Ready(Ok(()))) => Poll::Ready(Ok(())), + } } fn call(&mut self, block: Arc) -> Self::Future { diff --git a/zebra-consensus/src/checkpoint.rs b/zebra-consensus/src/checkpoint.rs index b2d20b800..f49833ce7 100644 --- a/zebra-consensus/src/checkpoint.rs +++ b/zebra-consensus/src/checkpoint.rs @@ -763,13 +763,15 @@ where Pin> + Send + 'static>>; fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { - match self.previous_checkpoint_height() { - FinalCheckpoint => Poll::Ready(Err("there are no checkpoints left to verify".into())), - _ => Poll::Ready(Ok(())), - } + Poll::Ready(Ok(())) } fn call(&mut self, block: Arc) -> Self::Future { + // Immediately reject all incoming blocks that arrive after we've finished. + if let FinalCheckpoint = self.previous_checkpoint_height() { + return async { Err("checkpoint request after checkpointing finished".into()) }.boxed(); + } + // Queue the block for verification, until we receive all the blocks for // the current checkpoint range. let rx = self.queue_block(block.clone());