From 7f44d691ea14cf3bdb9b4efc2f8f2bb0b0156c15 Mon Sep 17 00:00:00 2001 From: panos-xyz Date: Tue, 16 Jun 2026 08:18:14 +0800 Subject: [PATCH 1/2] fix(consensus): mark future timestamps as transient --- crates/consensus/src/validation.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/consensus/src/validation.rs b/crates/consensus/src/validation.rs index eab4883..3b32297 100644 --- a/crates/consensus/src/validation.rs +++ b/crates/consensus/src/validation.rs @@ -328,6 +328,10 @@ impl Consensus for MorphConsensus { Ok(()) } + + fn is_transient_error(&self, error: &ConsensusError) -> bool { + matches!(error, ConsensusError::TimestampIsInFuture { .. }) + } } // ============================================================================ @@ -1131,6 +1135,18 @@ mod tests { )); } + #[test] + fn test_timestamp_in_future_is_transient_error() { + let chain_spec = create_test_chainspec(); + let consensus = MorphConsensus::new(chain_spec); + let error = ConsensusError::TimestampIsInFuture { + timestamp: 2, + present_timestamp: 1, + }; + + assert!(Consensus::::is_transient_error(&consensus, &error)); + } + #[test] fn test_validate_header_gas_limit_exceeds_max() { let chain_spec = create_test_chainspec(); From cc0c65db878a4feaf4551673bc440bcc00c0708d Mon Sep 17 00:00:00 2001 From: panos-xyz Date: Tue, 16 Jun 2026 08:51:09 +0800 Subject: [PATCH 2/2] fix(engine-api): pass through rpc errors --- crates/engine-api/src/rpc.rs | 44 +++++++++++++----------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/crates/engine-api/src/rpc.rs b/crates/engine-api/src/rpc.rs index 9273ca9..0f1bbd1 100644 --- a/crates/engine-api/src/rpc.rs +++ b/crates/engine-api/src/rpc.rs @@ -118,10 +118,10 @@ where ) -> RpcResult { tracing::debug!(target: "morph::engine", block_number = params.number, "assembling L2 block"); - self.inner.assemble_l2_block(params).await.map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to assemble L2 block"); - e.into() - }) + self.inner + .assemble_l2_block(params) + .await + .map_err(|e| e.into()) } async fn assemble_l2_block_v2( @@ -138,10 +138,7 @@ where self.inner .assemble_l2_block_v2(params) .await - .map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to assemble L2 block (v2)"); - e.into() - }) + .map_err(|e| e.into()) } async fn validate_l2_block(&self, data: ExecutableL2Data) -> RpcResult { @@ -152,10 +149,10 @@ where "validating L2 block" ); - self.inner.validate_l2_block(data).await.map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to validate L2 block"); - e.into() - }) + self.inner + .validate_l2_block(data) + .await + .map_err(|e| e.into()) } async fn new_l2_block(&self, data: ExecutableL2Data) -> RpcResult<()> { @@ -166,10 +163,7 @@ where "RPC newL2Block called" ); - self.inner.new_l2_block(data).await.map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to import L2 block"); - e.into() - }) + self.inner.new_l2_block(data).await.map_err(|e| e.into()) } async fn new_l2_block_v2(&self, data: ExecutableL2Data) -> RpcResult { @@ -180,10 +174,7 @@ where "RPC newL2BlockV2 called" ); - self.inner.new_l2_block_v2(data).await.map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to import L2 block (v2)"); - e.into() - }) + self.inner.new_l2_block_v2(data).await.map_err(|e| e.into()) } async fn new_safe_l2_block(&self, data: SafeL2Data) -> RpcResult { @@ -193,10 +184,10 @@ where "RPC newSafeL2Block called" ); - self.inner.new_safe_l2_block(data).await.map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to import safe L2 block"); - e.into() - }) + self.inner + .new_safe_l2_block(data) + .await + .map_err(|e| e.into()) } async fn set_block_tags( @@ -214,10 +205,7 @@ where self.inner .set_block_tags(safe_block_hash, finalized_block_hash) .await - .map_err(|e| { - tracing::error!(target: "morph::engine", error = %e, "failed to set block tags"); - e.into() - }) + .map_err(|e| e.into()) } }