From 6d19c0ed8e9d3e6714292c3990effe0955aa375c Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 26 Jan 2026 13:36:49 +0100 Subject: [PATCH] fix(engine): only warn for critical capability mismatches (#21398) Co-authored-by: Amp --- crates/rpc/rpc-engine-api/src/capabilities.rs | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/crates/rpc/rpc-engine-api/src/capabilities.rs b/crates/rpc/rpc-engine-api/src/capabilities.rs index 75583c821e..cf69279870 100644 --- a/crates/rpc/rpc-engine-api/src/capabilities.rs +++ b/crates/rpc/rpc-engine-api/src/capabilities.rs @@ -3,6 +3,13 @@ use std::collections::HashSet; use tracing::warn; +/// Critical Engine API method prefixes that warrant warnings on capability mismatches. +/// +/// These are essential for block production and chain synchronization. Missing support +/// for these methods indicates a significant version mismatch that operators should address. +const CRITICAL_METHOD_PREFIXES: &[&str] = + &["engine_forkchoiceUpdated", "engine_getPayload", "engine_newPayload"]; + /// All Engine API capabilities supported by Reth (Ethereum mainnet). /// /// See for updates. @@ -72,31 +79,52 @@ impl EngineCapabilities { CapabilityMismatches { missing_in_el, missing_in_cl } } - /// Logs warnings if CL and EL capabilities don't match. + /// Logs warnings if CL and EL capabilities don't match for critical methods. /// /// Called during `engine_exchangeCapabilities` to warn operators about /// version mismatches between the consensus layer and execution layer. + /// + /// Only warns about critical methods (`engine_forkchoiceUpdated`, `engine_getPayload`, + /// `engine_newPayload`) that are essential for block production and chain synchronization. + /// Non-critical methods like `engine_getBlobs` are not warned about since not all + /// clients support them. pub fn log_capability_mismatches(&self, cl_capabilities: &[String]) { let mismatches = self.get_capability_mismatches(cl_capabilities); - if !mismatches.missing_in_el.is_empty() { + let critical_missing_in_el: Vec<_> = + mismatches.missing_in_el.iter().filter(|m| is_critical_method(m)).cloned().collect(); + + let critical_missing_in_cl: Vec<_> = + mismatches.missing_in_cl.iter().filter(|m| is_critical_method(m)).cloned().collect(); + + if !critical_missing_in_el.is_empty() { warn!( target: "rpc::engine", - missing = ?mismatches.missing_in_el, + missing = ?critical_missing_in_el, "CL supports Engine API methods that Reth doesn't. Consider upgrading Reth." ); } - if !mismatches.missing_in_cl.is_empty() { + if !critical_missing_in_cl.is_empty() { warn!( target: "rpc::engine", - missing = ?mismatches.missing_in_cl, + missing = ?critical_missing_in_cl, "Reth supports Engine API methods that CL doesn't. Consider upgrading your consensus client." ); } } } +/// Returns `true` if the method is critical for block production and chain synchronization. +fn is_critical_method(method: &str) -> bool { + CRITICAL_METHOD_PREFIXES.iter().any(|prefix| { + method.starts_with(prefix) && + method[prefix.len()..] + .strip_prefix('V') + .is_some_and(|s| s.chars().next().is_some_and(|c| c.is_ascii_digit())) + }) +} + impl Default for EngineCapabilities { fn default() -> Self { Self::new(CAPABILITIES.iter().copied()) @@ -173,4 +201,20 @@ mod tests { assert_eq!(result.missing_in_el, vec!["a_other", "z_other"]); assert_eq!(result.missing_in_cl, vec!["a_method", "z_method"]); } + + #[test] + fn test_is_critical_method() { + assert!(is_critical_method("engine_forkchoiceUpdatedV1")); + assert!(is_critical_method("engine_forkchoiceUpdatedV3")); + assert!(is_critical_method("engine_getPayloadV1")); + assert!(is_critical_method("engine_getPayloadV4")); + assert!(is_critical_method("engine_newPayloadV1")); + assert!(is_critical_method("engine_newPayloadV4")); + + assert!(!is_critical_method("engine_getBlobsV1")); + assert!(!is_critical_method("engine_getBlobsV3")); + assert!(!is_critical_method("engine_getPayloadBodiesByHashV1")); + assert!(!is_critical_method("engine_getPayloadBodiesByRangeV1")); + assert!(!is_critical_method("engine_getClientVersionV1")); + } }