diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index faab247c42..942d2fe6d0 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -551,15 +551,23 @@ where state: ForkchoiceState, attrs: Option, tx: oneshot::Sender>, - ) -> bool { + ) -> OnForkchoiceUpdateOutcome { self.metrics.forkchoice_updated_messages.increment(1); self.blockchain.on_forkchoice_update_received(&state); let on_updated = match self.forkchoice_updated(state, attrs) { Ok(response) => response, Err(error) => { + if let Error::Execution(ref err) = error { + if err.is_fatal() { + // FCU resulted in a fatal error from which we can't recover + let err = err.clone(); + let _ = tx.send(Err(error)); + return OnForkchoiceUpdateOutcome::Fatal(err.clone()) + } + } let _ = tx.send(Err(error)); - return false + return OnForkchoiceUpdateOutcome::Processed } }; @@ -583,11 +591,11 @@ where // check if we reached the maximum configured block let tip_number = self.blockchain.canonical_tip().number; if self.sync.has_reached_max_block(tip_number) { - return true + return OnForkchoiceUpdateOutcome::ReachedMaxBlock } } - false + OnForkchoiceUpdateOutcome::Processed } /// Called to resolve chain forks and ensure that the Execution layer is working with the latest @@ -1700,8 +1708,16 @@ where match this.engine_message_rx.poll_next_unpin(cx) { Poll::Ready(Some(msg)) => match msg { BeaconEngineMessage::ForkchoiceUpdated { state, payload_attrs, tx } => { - if this.on_forkchoice_updated(state, payload_attrs, tx) { - return Poll::Ready(Ok(())) + match this.on_forkchoice_updated(state, payload_attrs, tx) { + OnForkchoiceUpdateOutcome::Processed => {} + OnForkchoiceUpdateOutcome::ReachedMaxBlock => { + // reached the max block, we can terminate the future + return Poll::Ready(Ok(())) + } + OnForkchoiceUpdateOutcome::Fatal(err) => { + // fatal error, we can terminate the future + return Poll::Ready(Err(Error::Execution(err).into())) + } } } BeaconEngineMessage::NewPayload { payload, tx } => { @@ -1763,6 +1779,17 @@ where } } +/// Represents all outcomes of an applied fork choice update. +#[derive(Debug)] +enum OnForkchoiceUpdateOutcome { + /// FCU was processed successfully. + Processed, + /// FCU was processed successfully and reached max block. + ReachedMaxBlock, + /// FCU resulted in a __fatal__ block execution error from which we can't recover. + Fatal(BlockExecutionError), +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/interfaces/src/executor.rs b/crates/interfaces/src/executor.rs index cc747e29fd..f57d26fb58 100644 --- a/crates/interfaces/src/executor.rs +++ b/crates/interfaces/src/executor.rs @@ -61,6 +61,8 @@ pub enum BlockExecutionError { impl BlockExecutionError { /// Returns `true` if the error is fatal. + /// + /// This represents an unrecoverable database related error. pub fn is_fatal(&self) -> bool { matches!(self, Self::CanonicalCommit { .. } | Self::CanonicalRevert { .. }) }