From e60b1f11e9d07479db261394dd024f78845f8bc5 Mon Sep 17 00:00:00 2001 From: SamAg19 Date: Wed, 7 Oct 2026 15:12:31 +0530 Subject: [PATCH] Split EngineCapabilities into JsonRpc and Ssz variants --- .../fetch_blobs/fetch_blobs_beacon_adapter.rs | 4 +- .../beacon_chain/src/graffiti_calculator.rs | 10 +- beacon_node/client/src/notifier.rs | 63 ++---- beacon_node/execution_layer/src/engine_api.rs | 185 ++++++++---------- .../execution_layer/src/engine_api/http.rs | 23 ++- .../src/engine_api/json_structures.rs | 155 +++++++++++++++ beacon_node/execution_layer/src/lib.rs | 12 +- .../execution_layer/src/test_utils/mod.rs | 20 +- .../src/test_rig.rs | 2 +- 9 files changed, 296 insertions(+), 178 deletions(-) diff --git a/beacon_node/beacon_chain/src/fetch_blobs/fetch_blobs_beacon_adapter.rs b/beacon_node/beacon_chain/src/fetch_blobs/fetch_blobs_beacon_adapter.rs index db4d956e3f7..a5cf68dbcc9 100644 --- a/beacon_node/beacon_chain/src/fetch_blobs/fetch_blobs_beacon_adapter.rs +++ b/beacon_node/beacon_chain/src/fetch_blobs/fetch_blobs_beacon_adapter.rs @@ -161,7 +161,7 @@ impl FetchBlobsBeaconAdapter { .get_engine_capabilities(None) .await .map_err(FetchEngineBlobError::RequestFailed) - .map(|caps| caps.get_blobs_v3) + .map(|caps| caps.get_blobs_v3()) } pub(crate) async fn supports_get_blobs_v4(&self) -> Result { @@ -175,6 +175,6 @@ impl FetchBlobsBeaconAdapter { .get_engine_capabilities(None) .await .map_err(FetchEngineBlobError::RequestFailed) - .map(|caps| caps.get_blobs_v4) + .map(|caps| caps.get_blobs_v4()) } } diff --git a/beacon_node/beacon_chain/src/graffiti_calculator.rs b/beacon_node/beacon_chain/src/graffiti_calculator.rs index 705121824c0..779b75dd9fe 100644 --- a/beacon_node/beacon_chain/src/graffiti_calculator.rs +++ b/beacon_node/beacon_chain/src/graffiti_calculator.rs @@ -256,8 +256,7 @@ mod tests { use crate::test_utils::{BeaconChainHarness, EphemeralHarnessType, test_spec}; use bls::Keypair; use eth2::types::GraffitiPolicy; - use execution_layer::EngineCapabilities; - use execution_layer::test_utils::{DEFAULT_CLIENT_VERSION, DEFAULT_ENGINE_CAPABILITIES}; + use execution_layer::test_utils::DEFAULT_CLIENT_VERSION; use std::sync::Arc; use std::sync::LazyLock; use std::time::Duration; @@ -293,12 +292,7 @@ mod tests { let harness = get_harness(VALIDATOR_COUNT, spec, None); // modify execution engine so it doesn't support engine_getClientVersionV1 method let mock_execution_layer = harness.mock_execution_layer.as_ref().unwrap(); - mock_execution_layer - .server - .set_engine_capabilities(EngineCapabilities { - get_client_version_v1: false, - ..DEFAULT_ENGINE_CAPABILITIES - }); + mock_execution_layer.server.disable_client_version(); // refresh capabilities cache harness .chain diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index df3d6a78051..fcf644d5e4c 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -3,14 +3,7 @@ use beacon_chain::{ BeaconChain, BeaconChainTypes, ExecutionVerdict, bellatrix_readiness::GenesisExecutionPayloadStatus, }; -use execution_layer::{ - EngineCapabilities, - http::{ - ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3, ENGINE_GET_PAYLOAD_V2, - ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_GET_PAYLOAD_V5, ENGINE_GET_PAYLOAD_V6, - ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V5, - }, -}; +use execution_layer::EngineCapabilities; use lighthouse_network::{NetworkGlobals, types::SyncState}; use logging::crit; use slot_clock::SlotClock; @@ -446,7 +439,7 @@ async fn post_bellatrix_readiness_logging( { Err(e) => Err(format!("Exchange capabilities failed: {e:?}")), Ok(capabilities) => { - let missing_methods = methods_required_for_fork(fork, capabilities); + let missing_methods = methods_required_for_fork(fork, &capabilities); if missing_methods.is_empty() { Ok(()) } else { @@ -515,9 +508,10 @@ fn find_next_fork_to_prepare( fn methods_required_for_fork( fork: ForkName, - capabilities: EngineCapabilities, + capabilities: &EngineCapabilities, ) -> Vec<&'static str> { let mut missing_methods = vec![]; + match fork { ForkName::Base | ForkName::Altair | ForkName::Bellatrix => { warn!( @@ -525,50 +519,15 @@ fn methods_required_for_fork( "Invalid methods_required_for_fork call" ); } - ForkName::Capella => { - if !capabilities.get_payload_v2 { - missing_methods.push(ENGINE_GET_PAYLOAD_V2); - } - if !capabilities.forkchoice_updated_v2 { - missing_methods.push(ENGINE_FORKCHOICE_UPDATED_V2); - } - if !capabilities.new_payload_v2 { - missing_methods.push(ENGINE_NEW_PAYLOAD_V2); - } - } - ForkName::Deneb => { - if !capabilities.get_payload_v3 { - missing_methods.push(ENGINE_GET_PAYLOAD_V3); - } - if !capabilities.forkchoice_updated_v3 { - missing_methods.push(ENGINE_FORKCHOICE_UPDATED_V3); - } - if !capabilities.new_payload_v3 { - missing_methods.push(ENGINE_NEW_PAYLOAD_V3); + fork => { + if !capabilities.get_payload(fork) { + missing_methods.push("getPayload") } - } - ForkName::Electra => { - if !capabilities.get_payload_v4 { - missing_methods.push(ENGINE_GET_PAYLOAD_V4); - } - if !capabilities.new_payload_v4 { - missing_methods.push(ENGINE_NEW_PAYLOAD_V4); - } - } - ForkName::Fulu => { - if !capabilities.get_payload_v5 { - missing_methods.push(ENGINE_GET_PAYLOAD_V5); - } - if !capabilities.new_payload_v4 { - missing_methods.push(ENGINE_NEW_PAYLOAD_V4); - } - } - ForkName::Gloas | ForkName::Heze => { - if !capabilities.get_payload_v6 { - missing_methods.push(ENGINE_GET_PAYLOAD_V6); + if !capabilities.forkchoice_updated(fork) { + missing_methods.push("forkchoice_update"); } - if !capabilities.new_payload_v5 { - missing_methods.push(ENGINE_NEW_PAYLOAD_V5); + if !capabilities.new_payload(fork) { + missing_methods.push("newPayload"); } } } diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 5afa77013c6..b1a3a1cdfd3 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -1,14 +1,6 @@ use crate::engines::ForkchoiceState; -use crate::http::{ - ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3, - ENGINE_FORKCHOICE_UPDATED_V4, ENGINE_FORKCHOICE_UPDATED_V5, ENGINE_GET_BLOBS_V2, - ENGINE_GET_BLOBS_V3, ENGINE_GET_BLOBS_V4, ENGINE_GET_CLIENT_VERSION_V1, - ENGINE_GET_INCLUSION_LIST_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, - ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, - ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_GET_PAYLOAD_V5, ENGINE_GET_PAYLOAD_V6, - ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, - ENGINE_NEW_PAYLOAD_V5, ENGINE_NEW_PAYLOAD_V6, -}; +pub use crate::json_structures::JsonRpcCapabilities; +use crate::ssz_structures::{MaxBodiesRequest, SszCapabilities}; use eth2::types::{ BlobsBundle, SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttributesV2, SsePayloadAttributesV3, @@ -19,6 +11,7 @@ use pretty_reqwest_error::PrettyReqwestError; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; +use ssz_types::typenum::Unsigned; use strum::IntoStaticStr; use superstruct::superstruct; pub use types::{ @@ -674,111 +667,103 @@ impl ExecutionPayloadBodyV1 { } } -#[derive(Clone, Copy, Debug)] -pub struct EngineCapabilities { - pub new_payload_v1: bool, - pub new_payload_v2: bool, - pub new_payload_v3: bool, - pub new_payload_v4: bool, - pub new_payload_v5: bool, - pub new_payload_v6: bool, - pub forkchoice_updated_v1: bool, - pub forkchoice_updated_v2: bool, - pub forkchoice_updated_v3: bool, - pub forkchoice_updated_v4: bool, - pub forkchoice_updated_v5: bool, - pub get_payload_bodies_by_hash_v1: bool, - pub get_payload_bodies_by_hash_v2: bool, - pub get_payload_v1: bool, - pub get_payload_v2: bool, - pub get_payload_v3: bool, - pub get_payload_v4: bool, - pub get_payload_v5: bool, - pub get_payload_v6: bool, - pub get_client_version_v1: bool, - pub get_blobs_v2: bool, - pub get_blobs_v3: bool, - pub get_blobs_v4: bool, - pub get_inclusion_list_v1: bool, +#[derive(Clone, Debug)] +pub enum EngineCapabilities { + JsonRpc(JsonRpcCapabilities), + Ssz(SszCapabilities), } impl EngineCapabilities { - pub fn to_response(&self) -> Vec<&str> { - let mut response = Vec::new(); - if self.new_payload_v1 { - response.push(ENGINE_NEW_PAYLOAD_V1); - } - if self.new_payload_v2 { - response.push(ENGINE_NEW_PAYLOAD_V2); - } - if self.new_payload_v3 { - response.push(ENGINE_NEW_PAYLOAD_V3); - } - if self.new_payload_v4 { - response.push(ENGINE_NEW_PAYLOAD_V4); - } - if self.new_payload_v5 { - response.push(ENGINE_NEW_PAYLOAD_V5); - } - if self.new_payload_v6 { - response.push(ENGINE_NEW_PAYLOAD_V6); - } - if self.forkchoice_updated_v1 { - response.push(ENGINE_FORKCHOICE_UPDATED_V1); - } - if self.forkchoice_updated_v2 { - response.push(ENGINE_FORKCHOICE_UPDATED_V2); + pub fn new_payload(&self, fork: ForkName) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.new_payload(fork), + Self::Ssz(capabilities) => capabilities.new_payload(fork), } - if self.forkchoice_updated_v3 { - response.push(ENGINE_FORKCHOICE_UPDATED_V3); - } - if self.forkchoice_updated_v4 { - response.push(ENGINE_FORKCHOICE_UPDATED_V4); - } - if self.forkchoice_updated_v5 { - response.push(ENGINE_FORKCHOICE_UPDATED_V5); - } - if self.get_payload_bodies_by_hash_v1 { - response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1); - } - if self.get_payload_bodies_by_hash_v2 { - response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2); - } - if self.get_payload_v1 { - response.push(ENGINE_GET_PAYLOAD_V1); - } - if self.get_payload_v2 { - response.push(ENGINE_GET_PAYLOAD_V2); + } + + pub fn get_payload(&self, fork: ForkName) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_payload(fork), + Self::Ssz(capabilities) => capabilities.get_payload(fork), } - if self.get_payload_v3 { - response.push(ENGINE_GET_PAYLOAD_V3); + } + + pub fn forkchoice_updated(&self, fork: ForkName) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.forkchoice_updated(fork), + Self::Ssz(capabilities) => capabilities.forkchoice_updated(fork), } - if self.get_payload_v4 { - response.push(ENGINE_GET_PAYLOAD_V4); + } + + pub fn get_payload_bodies_by_hash_v1(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_payload_bodies_by_hash_v1, + Self::Ssz(capabilities) => capabilities.bodies && self.bodies_max_count() > 0, } - if self.get_payload_v5 { - response.push(ENGINE_GET_PAYLOAD_V5); + } + + pub fn get_payload_bodies_by_hash_v2(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_payload_bodies_by_hash_v2, + Self::Ssz(capabilities) => capabilities.bodies && self.bodies_max_count() > 0, } - if self.get_payload_v6 { - response.push(ENGINE_GET_PAYLOAD_V6); + } + + pub fn bodies_max_count(&self) -> usize { + let ceiling = MaxBodiesRequest::to_usize(); + match self { + Self::JsonRpc(_) => ceiling, + Self::Ssz(capabilities) => capabilities + .limits + .bodies_max_count + .map_or(ceiling, |advertised| { + advertised.min(ceiling as u64) as usize + }), } - if self.get_client_version_v1 { - response.push(ENGINE_GET_CLIENT_VERSION_V1); + } + + pub fn get_inclusion_list_v1(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_inclusion_list_v1, + // Heze fork REST-SSZ spec does not exist yet + Self::Ssz(_) => false, } - if self.get_blobs_v2 { - response.push(ENGINE_GET_BLOBS_V2); + } + + pub fn get_blobs_v2(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_blobs_v2, + Self::Ssz(capabilities) => capabilities.get_blobs_v2(), } - if self.get_blobs_v3 { - response.push(ENGINE_GET_BLOBS_V3); + } + + pub fn get_blobs_v3(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_blobs_v3, + Self::Ssz(capabilities) => capabilities.get_blobs_v3(), } - if self.get_blobs_v4 { - response.push(ENGINE_GET_BLOBS_V4); + } + + pub fn get_blobs_v4(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_blobs_v4, + Self::Ssz(capabilities) => capabilities.get_blobs_v4(), } - if self.get_inclusion_list_v1 { - response.push(ENGINE_GET_INCLUSION_LIST_V1); + } + + pub fn get_client_version_v1(&self) -> bool { + match self { + Self::JsonRpc(capabilities) => capabilities.get_client_version_v1, + Self::Ssz(capabilities) => capabilities.get_client_version_v1(), } + } - response + pub fn to_response(&self) -> Vec<&str> { + match self { + Self::JsonRpc(capabilities) => capabilities.to_response(), + // SSZ uses the structured /engine/v1/capabilities schema, not a method-name list. + Self::Ssz(_capabilities) => vec![], + } } } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index a77fd72e0ac..b1761092f96 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -613,7 +613,7 @@ pub struct HttpJsonRpc { pub client: Client, pub url: SensitiveUrl, pub execution_timeout_multiplier: u32, - pub engine_capabilities_cache: Mutex>>, + pub engine_capabilities_cache: Mutex>>, pub engine_version_cache: Mutex>>>, auth: Option, } @@ -1317,7 +1317,7 @@ impl HttpJsonRpc { .collect::>()?) } - pub async fn exchange_capabilities(&self) -> Result { + pub async fn exchange_capabilities(&self) -> Result { let params = json!([LIGHTHOUSE_CAPABILITIES]); let capabilities: HashSet = self @@ -1328,7 +1328,7 @@ impl HttpJsonRpc { ) .await?; - Ok(EngineCapabilities { + Ok(JsonRpcCapabilities { new_payload_v1: capabilities.contains(ENGINE_NEW_PAYLOAD_V1), new_payload_v2: capabilities.contains(ENGINE_NEW_PAYLOAD_V2), new_payload_v3: capabilities.contains(ENGINE_NEW_PAYLOAD_V3), @@ -1375,6 +1375,15 @@ impl HttpJsonRpc { &self, age_limit: Option, ) -> Result { + Ok(EngineCapabilities::JsonRpc( + self.json_rpc_capabilities(age_limit).await?, + )) + } + + async fn json_rpc_capabilities( + &self, + age_limit: Option, + ) -> Result { let mut lock = self.engine_capabilities_cache.lock().await; if let Some(lock) = lock @@ -1429,7 +1438,7 @@ impl HttpJsonRpc { age_limit: Option, ) -> Result, Error> { // check engine capabilities first (avoids holding two locks at once) - let engine_capabilities = self.get_engine_capabilities(None).await?; + let engine_capabilities = self.json_rpc_capabilities(None).await?; if !engine_capabilities.get_client_version_v1 { // We choose an empty vec to denote that this method is not // supported instead of an error since this method is optional @@ -1459,7 +1468,7 @@ impl HttpJsonRpc { &self, new_payload_request: NewPayloadRequest<'_, E>, ) -> Result { - let engine_capabilities = self.get_engine_capabilities(None).await?; + let engine_capabilities = self.json_rpc_capabilities(None).await?; match new_payload_request { NewPayloadRequest::Bellatrix(_) | NewPayloadRequest::Capella(_) => { if engine_capabilities.new_payload_v2 { @@ -1518,7 +1527,7 @@ impl HttpJsonRpc { fork_name: ForkName, payload_id: PayloadId, ) -> Result, Error> { - let engine_capabilities = self.get_engine_capabilities(None).await?; + let engine_capabilities = self.json_rpc_capabilities(None).await?; match fork_name { ForkName::Bellatrix | ForkName::Capella => { if engine_capabilities.get_payload_v2 { @@ -1572,7 +1581,7 @@ impl HttpJsonRpc { maybe_payload_attributes: Option, custody_columns: Option<&[ColumnIndex]>, ) -> Result { - let engine_capabilities = self.get_engine_capabilities(None).await?; + let engine_capabilities = self.json_rpc_capabilities(None).await?; if let Some(payload_attributes) = maybe_payload_attributes.as_ref() { match payload_attributes { PayloadAttributes::V1(_) | PayloadAttributes::V2(_) => { diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index 486aa1d2e15..e594f996155 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -1,4 +1,14 @@ use super::*; +use crate::http::{ + ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3, + ENGINE_FORKCHOICE_UPDATED_V4, ENGINE_FORKCHOICE_UPDATED_V5, ENGINE_GET_BLOBS_V2, + ENGINE_GET_BLOBS_V3, ENGINE_GET_BLOBS_V4, ENGINE_GET_CLIENT_VERSION_V1, + ENGINE_GET_INCLUSION_LIST_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, + ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, + ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_GET_PAYLOAD_V5, ENGINE_GET_PAYLOAD_V6, + ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, + ENGINE_NEW_PAYLOAD_V5, ENGINE_NEW_PAYLOAD_V6, +}; use alloy_rlp::RlpEncodable; use serde::{Deserialize, Serialize}; use ssz::{Decode, TryFromIter}; @@ -2072,3 +2082,148 @@ mod payload_status_tests { ); } } + +#[derive(Clone, Copy, Debug)] +pub struct JsonRpcCapabilities { + pub new_payload_v1: bool, + pub new_payload_v2: bool, + pub new_payload_v3: bool, + pub new_payload_v4: bool, + pub new_payload_v5: bool, + pub new_payload_v6: bool, + pub forkchoice_updated_v1: bool, + pub forkchoice_updated_v2: bool, + pub forkchoice_updated_v3: bool, + pub forkchoice_updated_v4: bool, + pub forkchoice_updated_v5: bool, + pub get_payload_bodies_by_hash_v1: bool, + pub get_payload_bodies_by_hash_v2: bool, + pub get_payload_v1: bool, + pub get_payload_v2: bool, + pub get_payload_v3: bool, + pub get_payload_v4: bool, + pub get_payload_v5: bool, + pub get_payload_v6: bool, + pub get_client_version_v1: bool, + pub get_blobs_v2: bool, + pub get_blobs_v3: bool, + pub get_blobs_v4: bool, + pub get_inclusion_list_v1: bool, +} + +impl JsonRpcCapabilities { + pub fn new_payload(&self, fork: ForkName) -> bool { + match fork { + ForkName::Bellatrix => self.new_payload_v1, + ForkName::Capella => self.new_payload_v2, + ForkName::Deneb => self.new_payload_v3, + ForkName::Electra | ForkName::Fulu => self.new_payload_v4, + ForkName::Gloas => self.new_payload_v5, + ForkName::Heze => self.new_payload_v6, + ForkName::Base | ForkName::Altair => false, + } + } + + pub fn get_payload(&self, fork: ForkName) -> bool { + match fork { + ForkName::Bellatrix => self.get_payload_v1, + ForkName::Capella => self.get_payload_v2, + ForkName::Deneb => self.get_payload_v3, + ForkName::Electra => self.get_payload_v4, + ForkName::Fulu => self.get_payload_v5, + ForkName::Gloas => self.get_payload_v6, + // TODO(heze): add heze arm to appropriate get_payload version once JSON engine API spec is finalized + ForkName::Base | ForkName::Altair | ForkName::Heze => false, + } + } + + pub fn forkchoice_updated(&self, fork: ForkName) -> bool { + match fork { + ForkName::Bellatrix => self.forkchoice_updated_v1, + ForkName::Capella => self.forkchoice_updated_v2, + ForkName::Deneb | ForkName::Electra | ForkName::Fulu => self.forkchoice_updated_v3, + ForkName::Gloas => self.forkchoice_updated_v4, + ForkName::Heze => self.forkchoice_updated_v5, + // TODO(heze): add heze arm to appropriate forkchoice_updated version once JSON engine API spec is finalized + ForkName::Base | ForkName::Altair => false, + } + } + + pub fn to_response(&self) -> Vec<&str> { + let mut response = Vec::new(); + if self.new_payload_v1 { + response.push(ENGINE_NEW_PAYLOAD_V1); + } + if self.new_payload_v2 { + response.push(ENGINE_NEW_PAYLOAD_V2); + } + if self.new_payload_v3 { + response.push(ENGINE_NEW_PAYLOAD_V3); + } + if self.new_payload_v4 { + response.push(ENGINE_NEW_PAYLOAD_V4); + } + if self.new_payload_v5 { + response.push(ENGINE_NEW_PAYLOAD_V5); + } + if self.new_payload_v6 { + response.push(ENGINE_NEW_PAYLOAD_V6); + } + if self.forkchoice_updated_v1 { + response.push(ENGINE_FORKCHOICE_UPDATED_V1); + } + if self.forkchoice_updated_v2 { + response.push(ENGINE_FORKCHOICE_UPDATED_V2); + } + if self.forkchoice_updated_v3 { + response.push(ENGINE_FORKCHOICE_UPDATED_V3); + } + if self.forkchoice_updated_v4 { + response.push(ENGINE_FORKCHOICE_UPDATED_V4); + } + if self.forkchoice_updated_v5 { + response.push(ENGINE_FORKCHOICE_UPDATED_V5); + } + if self.get_payload_bodies_by_hash_v1 { + response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1); + } + if self.get_payload_bodies_by_hash_v2 { + response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2); + } + if self.get_payload_v1 { + response.push(ENGINE_GET_PAYLOAD_V1); + } + if self.get_payload_v2 { + response.push(ENGINE_GET_PAYLOAD_V2); + } + if self.get_payload_v3 { + response.push(ENGINE_GET_PAYLOAD_V3); + } + if self.get_payload_v4 { + response.push(ENGINE_GET_PAYLOAD_V4); + } + if self.get_payload_v5 { + response.push(ENGINE_GET_PAYLOAD_V5); + } + if self.get_payload_v6 { + response.push(ENGINE_GET_PAYLOAD_V6); + } + if self.get_client_version_v1 { + response.push(ENGINE_GET_CLIENT_VERSION_V1); + } + if self.get_blobs_v2 { + response.push(ENGINE_GET_BLOBS_V2); + } + if self.get_blobs_v3 { + response.push(ENGINE_GET_BLOBS_V3); + } + if self.get_blobs_v4 { + response.push(ENGINE_GET_BLOBS_V4); + } + if self.get_inclusion_list_v1 { + response.push(ENGINE_GET_INCLUSION_LIST_V1); + } + + response + } +} diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 4e30ea363cf..7e08782c0aa 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -1683,7 +1683,7 @@ impl ExecutionLayer { hashes: Vec, ) -> Result>>, Error> { let capabilities = self.get_engine_capabilities(None).await?; - if !capabilities.get_payload_bodies_by_hash_v2 { + if !capabilities.get_payload_bodies_by_hash_v2() { return Err(Error::PayloadBodiesByHashV2NotSupported); } @@ -1713,7 +1713,7 @@ impl ExecutionLayer { } let capabilities = self.get_engine_capabilities(None).await?; - if capabilities.get_payload_bodies_by_hash_v1 { + if capabilities.get_payload_bodies_by_hash_v1() { let mut payload_bodies = self .get_payload_bodies_by_hash(vec![header.block_hash()]) .await?; @@ -1740,7 +1740,7 @@ impl ExecutionLayer { ) -> Result>>, Error> { let capabilities = self.get_engine_capabilities(None).await?; - if capabilities.get_blobs_v2 { + if capabilities.get_blobs_v2() { self.engine() .request(|engine| async move { engine.api.get_blobs_v2(query).await }) .await @@ -1757,7 +1757,7 @@ impl ExecutionLayer { ) -> Result>>, Error> { let capabilities = self.get_engine_capabilities(None).await?; - if capabilities.get_blobs_v3 { + if capabilities.get_blobs_v3() { self.engine() .request(|engine| async move { engine.api.get_blobs_v3(query).await }) .await @@ -1775,7 +1775,7 @@ impl ExecutionLayer { ) -> Result>, Error> { let capabilities = self.get_engine_capabilities(None).await?; - if capabilities.get_blobs_v4 { + if capabilities.get_blobs_v4() { self.engine() .request( |engine| async move { engine.api.get_blobs_v4(query, custody_columns).await }, @@ -1791,7 +1791,7 @@ impl ExecutionLayer { pub async fn get_inclusion_list_v1(&self) -> Result { let capabilities = self.get_engine_capabilities(None).await?; - if capabilities.get_inclusion_list_v1 { + if capabilities.get_inclusion_list_v1() { self.engine() .request(|engine| async move { engine.api.get_inclusion_list_v1().await }) .await diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 1b3c5988672..1b139620281 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -25,7 +25,7 @@ use tracing::info; use types::{EthSpec, ExecutionBlockHash, Uint256}; use warp::{Filter, Rejection, http::StatusCode}; -use crate::EngineCapabilities; +use crate::{EngineCapabilities, JsonRpcCapabilities}; pub use execution_block_generator::DEFAULT_GAS_LIMIT; pub use execution_block_generator::{ Block, ExecutionBlockGenerator, generate_blobs, generate_genesis_block, @@ -38,7 +38,7 @@ pub use mock_execution_layer::MockExecutionLayer; pub const DEFAULT_JWT_SECRET: [u8; 32] = [42; 32]; pub const DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI: u128 = 10_000_000_000_000_000; pub const DEFAULT_BUILDER_PAYLOAD_VALUE_WEI: u128 = 20_000_000_000_000_000; -pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities { +pub const DEFAULT_JSON_RPC_CAPABILITIES: JsonRpcCapabilities = JsonRpcCapabilities { new_payload_v1: true, new_payload_v2: true, new_payload_v3: true, @@ -67,6 +67,9 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities { get_inclusion_list_v1: true, }; +pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = + EngineCapabilities::JsonRpc(DEFAULT_JSON_RPC_CAPABILITIES); + pub static DEFAULT_CLIENT_VERSION: LazyLock = LazyLock::new(|| JsonClientVersionV1 { code: "MC".to_string(), // "mock client" @@ -212,6 +215,19 @@ impl MockServer { *self.ctx.engine_capabilities.write() = engine_capabilities; } + pub fn disable_client_version(&self) { + match &mut *self.ctx.engine_capabilities.write() { + EngineCapabilities::JsonRpc(capabilities) => { + capabilities.get_client_version_v1 = false; + } + EngineCapabilities::Ssz(capabilities) => { + capabilities + .unscoped_endpoints + .retain(|e| e.as_str() != "identity"); + } + } + } + #[allow(clippy::too_many_arguments)] pub fn new( handle: &runtime::Handle, diff --git a/testing/execution_engine_integration/src/test_rig.rs b/testing/execution_engine_integration/src/test_rig.rs index cb64c355f0b..fe44acd9216 100644 --- a/testing/execution_engine_integration/src/test_rig.rs +++ b/testing/execution_engine_integration/src/test_rig.rs @@ -741,7 +741,7 @@ async fn check_payload_reconstruction( assert!( // if the engine doesn't have this capability, we need to update the client in our tests - capabilities.get_payload_bodies_by_hash_v1, + capabilities.get_payload_bodies_by_hash_v1(), "Testing engine does not support payload bodies by hash" );