From e1fdda4f04ed5327a9d1ab6c5c196d2274906c7c Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Wed, 26 Jun 2024 12:38:09 -0500 Subject: [PATCH 1/2] Update `engine-api` for `devnet-1` --- .../beacon_chain/src/beacon_block_streamer.rs | 4 +- beacon_node/execution_layer/src/engine_api.rs | 246 ++++++++++++------ .../execution_layer/src/engine_api/http.rs | 93 ++++++- .../src/engine_api/json_structures.rs | 85 +++--- beacon_node/execution_layer/src/lib.rs | 6 +- .../src/test_utils/handle_rpc.rs | 60 +++++ .../execution_layer/src/test_utils/mod.rs | 3 + .../types/src/execution_payload_header.rs | 9 + 8 files changed, 393 insertions(+), 113 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index f0a68b6be55..5e3ac6daa7c 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -1,5 +1,5 @@ use crate::{metrics, BeaconChain, BeaconChainError, BeaconChainTypes, BlockProcessStatus}; -use execution_layer::{ExecutionLayer, ExecutionPayloadBodyV1}; +use execution_layer::{ExecutionLayer, ExecutionPayloadBody}; use slog::{crit, debug, error, Logger}; use std::collections::HashMap; use std::sync::Arc; @@ -57,7 +57,7 @@ struct BodiesByRange { struct BlockParts { blinded_block: Box>, header: Box>, - body: Option>>, + body: Option>>, } impl BlockParts { diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 2391d8c087b..d5c00e4dbe6 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -2,7 +2,8 @@ use crate::engines::ForkchoiceState; use crate::http::{ ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3, ENGINE_GET_CLIENT_VERSION_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, - ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, + ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, + ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, }; @@ -20,7 +21,7 @@ use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use strum::IntoStaticStr; use superstruct::superstruct; -use types::execution_payload::{DepositRequests, WithdrawalRequests}; +use types::execution_payload::{ConsolidationRequests, DepositRequests, WithdrawalRequests}; pub use types::{ Address, BeaconBlockRef, ConsolidationRequest, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadHeader, ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions, @@ -547,27 +548,106 @@ impl GetPayloadResponse { } } +#[superstruct( + variants(V1, V2), + variant_attributes(derive(Clone, Debug),), + partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant") +)] #[derive(Clone, Debug)] -pub struct ExecutionPayloadBodyV1 { +pub struct ExecutionPayloadBody { pub transactions: Transactions, pub withdrawals: Option>, + #[superstruct(only(V2))] pub deposit_requests: Option>, + #[superstruct(only(V2))] pub withdrawal_requests: Option>, + #[superstruct(only(V2))] + pub consolidation_requests: Option>, } -impl ExecutionPayloadBodyV1 { +impl ExecutionPayloadBody { + #[allow(clippy::type_complexity)] + pub fn deconstruct( + self, + ) -> ( + Transactions, + Option>, + Option>, + Option>, + Option>, + ) { + match self { + ExecutionPayloadBody::V1(body) => { + (body.transactions, body.withdrawals, None, None, None) + } + ExecutionPayloadBody::V2(body) => ( + body.transactions, + body.withdrawals, + body.deposit_requests, + body.withdrawal_requests, + body.consolidation_requests, + ), + } + } pub fn to_payload( self, header: ExecutionPayloadHeader, ) -> Result, String> { - match header { - ExecutionPayloadHeader::Bellatrix(header) => { - if self.withdrawals.is_some() { + let header_fork = header.fork_name_unchecked(); + match &self { + Self::V1(_) => { + if header_fork.electra_enabled() { return Err(format!( - "block {} is merge but payload body has withdrawals", - header.block_hash + "block {} is {} but response is ExecutionPayloadBodyV1. Does the EL support {}?", + header.block_hash(), + header_fork, + ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, )); } + } + Self::V2(_) => {} + } + + let ( + transactions, + withdrawals, + deposit_requests, + withdrawal_requests, + consolidation_requests, + ) = self.deconstruct(); + if !header_fork.capella_enabled() && withdrawals.is_some() { + return Err(format!( + "block {} is {} but payload body has withdrawals", + header.block_hash(), + header_fork + )); + } + if !header_fork.electra_enabled() { + if deposit_requests.is_some() { + return Err(format!( + "block {} is {} but payload body has deposit_requests", + header.block_hash(), + header_fork + )); + } + if withdrawal_requests.is_some() { + return Err(format!( + "block {} is {} but payload body has withdrawal_requests", + header.block_hash(), + header_fork + )); + } + if consolidation_requests.is_some() { + return Err(format!( + "block {} is {} but payload body has consolidation_requests", + header.block_hash(), + header_fork + )); + } + } + + match header { + ExecutionPayloadHeader::Bellatrix(header) => { Ok(ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { parent_hash: header.parent_hash, fee_recipient: header.fee_recipient, @@ -582,75 +662,86 @@ impl ExecutionPayloadBodyV1 { extra_data: header.extra_data, base_fee_per_gas: header.base_fee_per_gas, block_hash: header.block_hash, - transactions: self.transactions, + transactions, })) } ExecutionPayloadHeader::Capella(header) => { - if let Some(withdrawals) = self.withdrawals { - Ok(ExecutionPayload::Capella(ExecutionPayloadCapella { - parent_hash: header.parent_hash, - fee_recipient: header.fee_recipient, - state_root: header.state_root, - receipts_root: header.receipts_root, - logs_bloom: header.logs_bloom, - prev_randao: header.prev_randao, - block_number: header.block_number, - gas_limit: header.gas_limit, - gas_used: header.gas_used, - timestamp: header.timestamp, - extra_data: header.extra_data, - base_fee_per_gas: header.base_fee_per_gas, - block_hash: header.block_hash, - transactions: self.transactions, - withdrawals, - })) - } else { - Err(format!( - "block {} is capella but payload body doesn't have withdrawals", - header.block_hash - )) - } + let withdrawals = withdrawals.ok_or_else(|| { + format!( + "block {} is {} but payload body has withdrawals set to null", + header.block_hash, header_fork + ) + })?; + Ok(ExecutionPayload::Capella(ExecutionPayloadCapella { + parent_hash: header.parent_hash, + fee_recipient: header.fee_recipient, + state_root: header.state_root, + receipts_root: header.receipts_root, + logs_bloom: header.logs_bloom, + prev_randao: header.prev_randao, + block_number: header.block_number, + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, + extra_data: header.extra_data, + base_fee_per_gas: header.base_fee_per_gas, + block_hash: header.block_hash, + transactions, + withdrawals, + })) } ExecutionPayloadHeader::Deneb(header) => { - if let Some(withdrawals) = self.withdrawals { - Ok(ExecutionPayload::Deneb(ExecutionPayloadDeneb { - parent_hash: header.parent_hash, - fee_recipient: header.fee_recipient, - state_root: header.state_root, - receipts_root: header.receipts_root, - logs_bloom: header.logs_bloom, - prev_randao: header.prev_randao, - block_number: header.block_number, - gas_limit: header.gas_limit, - gas_used: header.gas_used, - timestamp: header.timestamp, - extra_data: header.extra_data, - base_fee_per_gas: header.base_fee_per_gas, - block_hash: header.block_hash, - transactions: self.transactions, - withdrawals, - blob_gas_used: header.blob_gas_used, - excess_blob_gas: header.excess_blob_gas, - })) - } else { - Err(format!( - "block {} is post-capella but payload body doesn't have withdrawals", - header.block_hash - )) - } + let withdrawals = withdrawals.ok_or_else(|| { + format!( + "block {} is {} but payload body has withdrawals set to null", + header.block_hash, header_fork + ) + })?; + Ok(ExecutionPayload::Deneb(ExecutionPayloadDeneb { + parent_hash: header.parent_hash, + fee_recipient: header.fee_recipient, + state_root: header.state_root, + receipts_root: header.receipts_root, + logs_bloom: header.logs_bloom, + prev_randao: header.prev_randao, + block_number: header.block_number, + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, + extra_data: header.extra_data, + base_fee_per_gas: header.base_fee_per_gas, + block_hash: header.block_hash, + transactions, + withdrawals, + blob_gas_used: header.blob_gas_used, + excess_blob_gas: header.excess_blob_gas, + })) } ExecutionPayloadHeader::Electra(header) => { - let (Some(withdrawals), Some(deposit_requests), Some(withdrawal_requests)) = ( - self.withdrawals, - self.deposit_requests, - self.withdrawal_requests, - ) else { - return Err(format!( - "block {} is post-electra but payload body doesn't have withdrawals/deposit_requests/withdrawal_requests \ - Check that ELs are returning receipts and withdrawal_requests in getPayloadBody requests", - header.block_hash - )); - }; + let withdrawals = withdrawals.ok_or_else(|| { + format!( + "block {} is {} but payload body has withdrawals set to null", + header.block_hash, header_fork + ) + })?; + let deposit_requests = deposit_requests.ok_or_else(|| { + format!( + "block {} is {} but payload body has deposit_requests set to null", + header.block_hash, header_fork + ) + })?; + let withdrawal_requests = withdrawal_requests.ok_or_else(|| { + format!( + "block {} is {} but payload body has withdrawal_requests set to null", + header.block_hash, header_fork + ) + })?; + let consolidation_requests = consolidation_requests.ok_or_else(|| { + format!( + "block {} is {} but payload body has consolidation_requests set to null", + header.block_hash, header_fork + ) + })?; Ok(ExecutionPayload::Electra(ExecutionPayloadElectra { parent_hash: header.parent_hash, fee_recipient: header.fee_recipient, @@ -665,14 +756,13 @@ impl ExecutionPayloadBodyV1 { extra_data: header.extra_data, base_fee_per_gas: header.base_fee_per_gas, block_hash: header.block_hash, - transactions: self.transactions, + transactions, withdrawals, blob_gas_used: header.blob_gas_used, excess_blob_gas: header.excess_blob_gas, deposit_requests, withdrawal_requests, - // TODO(electra): gonna need to superstruct this thing to do it properly.. - consolidation_requests: Vec::new().into(), + consolidation_requests, })) } } @@ -690,6 +780,8 @@ pub struct EngineCapabilities { pub forkchoice_updated_v3: bool, pub get_payload_bodies_by_hash_v1: bool, pub get_payload_bodies_by_range_v1: bool, + pub get_payload_bodies_by_hash_v2: bool, + pub get_payload_bodies_by_range_v2: bool, pub get_payload_v1: bool, pub get_payload_v2: bool, pub get_payload_v3: bool, @@ -727,6 +819,12 @@ impl EngineCapabilities { if self.get_payload_bodies_by_range_v1 { response.push(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1); } + if self.get_payload_bodies_by_hash_v2 { + response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2); + } + if self.get_payload_bodies_by_range_v2 { + response.push(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2); + } if self.get_payload_v1 { response.push(ENGINE_GET_PAYLOAD_V1); } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 1c03cc81fc3..73eabf574b5 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -50,6 +50,8 @@ pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8); pub const ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1: &str = "engine_getPayloadBodiesByHashV1"; pub const ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1: &str = "engine_getPayloadBodiesByRangeV1"; +pub const ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2: &str = "engine_getPayloadBodiesByHashV2"; +pub const ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2: &str = "engine_getPayloadBodiesByRangeV2"; pub const ENGINE_GET_PAYLOAD_BODIES_TIMEOUT: Duration = Duration::from_secs(10); pub const ENGINE_EXCHANGE_CAPABILITIES: &str = "engine_exchangeCapabilities"; @@ -78,6 +80,8 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[ ENGINE_FORKCHOICE_UPDATED_V3, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, + ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, + ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2, ENGINE_GET_CLIENT_VERSION_V1, ]; @@ -1036,7 +1040,7 @@ impl HttpJsonRpc { pub async fn get_payload_bodies_by_hash_v1( &self, block_hashes: Vec, - ) -> Result>>, Error> { + ) -> Result>>, Error> { let params = json!([block_hashes]); let response: Vec>> = self @@ -1049,7 +1053,27 @@ impl HttpJsonRpc { Ok(response .into_iter() - .map(|opt_json| opt_json.map(From::from)) + .map(|opt_json| opt_json.map(|v1| JsonExecutionPayloadBody::V1(v1).into())) + .collect()) + } + + pub async fn get_payload_bodies_by_hash_v2( + &self, + block_hashes: Vec, + ) -> Result>>, Error> { + let params = json!([block_hashes]); + + let response: Vec>> = self + .rpc_request( + ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, + params, + ENGINE_GET_PAYLOAD_BODIES_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?; + + Ok(response + .into_iter() + .map(|opt_json| opt_json.map(|v2| JsonExecutionPayloadBody::V2(v2).into())) .collect()) } @@ -1057,7 +1081,7 @@ impl HttpJsonRpc { &self, start: u64, count: u64, - ) -> Result>>, Error> { + ) -> Result>>, Error> { #[derive(Serialize)] #[serde(transparent)] struct Quantity(#[serde(with = "serde_utils::u64_hex_be")] u64); @@ -1073,7 +1097,31 @@ impl HttpJsonRpc { Ok(response .into_iter() - .map(|opt_json| opt_json.map(From::from)) + .map(|opt_json| opt_json.map(|v1| JsonExecutionPayloadBody::V1(v1).into())) + .collect()) + } + + pub async fn get_payload_bodies_by_range_v2( + &self, + start: u64, + count: u64, + ) -> Result>>, Error> { + #[derive(Serialize)] + #[serde(transparent)] + struct Quantity(#[serde(with = "serde_utils::u64_hex_be")] u64); + + let params = json!([Quantity(start), Quantity(count)]); + let response: Vec>> = self + .rpc_request( + ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2, + params, + ENGINE_GET_PAYLOAD_BODIES_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?; + + Ok(response + .into_iter() + .map(|opt_json| opt_json.map(|v2| JsonExecutionPayloadBody::V1(v2).into())) .collect()) } @@ -1100,6 +1148,10 @@ impl HttpJsonRpc { .contains(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1), get_payload_bodies_by_range_v1: capabilities .contains(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1), + get_payload_bodies_by_hash_v2: capabilities + .contains(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2), + get_payload_bodies_by_range_v2: capabilities + .contains(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2), get_payload_v1: capabilities.contains(ENGINE_GET_PAYLOAD_V1), get_payload_v2: capabilities.contains(ENGINE_GET_PAYLOAD_V2), get_payload_v3: capabilities.contains(ENGINE_GET_PAYLOAD_V3), @@ -1275,6 +1327,39 @@ impl HttpJsonRpc { } } + pub async fn get_payload_bodies_by_hash( + &self, + block_hashes: Vec, + ) -> Result>>, Error> { + let engine_capabilities = self.get_engine_capabilities(None).await?; + if engine_capabilities.get_payload_bodies_by_hash_v2 { + self.get_payload_bodies_by_hash_v2(block_hashes).await + } else if engine_capabilities.get_payload_bodies_by_hash_v1 { + self.get_payload_bodies_by_hash_v1(block_hashes).await + } else { + Err(Error::RequiredMethodUnsupported( + "engine_getPayloadBodiesByHash", + )) + } + } + + pub async fn get_payload_bodies_by_range( + &self, + start: u64, + count: u64, + ) -> Result>>, Error> { + let engine_capabilities = self.get_engine_capabilities(None).await?; + if engine_capabilities.get_payload_bodies_by_range_v2 { + self.get_payload_bodies_by_range_v2(start, count).await + } else if engine_capabilities.get_payload_bodies_by_range_v1 { + self.get_payload_bodies_by_range_v1(start, count).await + } else { + Err(Error::RequiredMethodUnsupported( + "engine_getPayloadBodiesByRange", + )) + } + } + // automatically selects the latest version of // forkchoice_updated that the execution engine supports pub async fn forkchoice_updated( 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 b5f04fed19e..0f566c8061e 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -719,45 +719,70 @@ impl From for JsonForkchoiceUpdatedV1Response { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[superstruct( + variants(V1, V2), + variant_attributes(derive(Clone, Debug, Serialize, Deserialize),), + partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant") +)] +#[derive(Clone, Debug, Serialize)] #[serde(bound = "E: EthSpec")] #[serde(rename_all = "camelCase")] -pub struct JsonExecutionPayloadBodyV1 { +#[serde(untagged)] +pub struct JsonExecutionPayloadBody { #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, pub withdrawals: Option>, + #[superstruct(only(V2))] pub deposit_requests: Option>, + #[superstruct(only(V2))] pub withdrawal_requests: Option>, -} - -impl From> for ExecutionPayloadBodyV1 { - fn from(value: JsonExecutionPayloadBodyV1) -> Self { - Self { - transactions: value.transactions, - withdrawals: value.withdrawals.map(|json_withdrawals| { - Withdrawals::::from( - json_withdrawals - .into_iter() - .map(Into::into) - .collect::>(), - ) - }), - deposit_requests: value.deposit_requests.map(|json_receipts| { - DepositRequests::::from( - json_receipts - .into_iter() - .map(Into::into) - .collect::>(), - ) + #[superstruct(only(V2))] + pub consolidation_requests: + Option>, +} + +impl From> for ExecutionPayloadBody { + fn from(value: JsonExecutionPayloadBody) -> Self { + match value { + JsonExecutionPayloadBody::V1(body_v1) => Self::V1(ExecutionPayloadBodyV1 { + transactions: body_v1.transactions, + withdrawals: body_v1.withdrawals.map(|json_withdrawals| { + Withdrawals::::from( + json_withdrawals + .into_iter() + .map(Into::into) + .collect::>(), + ) + }), }), - withdrawal_requests: value.withdrawal_requests.map(|json_withdrawal_requests| { - WithdrawalRequests::::from( - json_withdrawal_requests - .into_iter() - .map(Into::into) - .collect::>(), - ) + JsonExecutionPayloadBody::V2(body_v2) => Self::V2(ExecutionPayloadBodyV2 { + transactions: body_v2.transactions, + withdrawals: body_v2.withdrawals.map(|json_withdrawals| { + Withdrawals::::from( + json_withdrawals + .into_iter() + .map(Into::into) + .collect::>(), + ) + }), + deposit_requests: body_v2.deposit_requests.map(|json_receipts| { + DepositRequests::::from( + json_receipts + .into_iter() + .map(Into::into) + .collect::>(), + ) + }), + withdrawal_requests: body_v2.withdrawal_requests.map(|json_withdrawal_requests| { + WithdrawalRequests::::from( + json_withdrawal_requests + .into_iter() + .map(Into::into) + .collect::>(), + ) + }), + consolidation_requests: body_v2.consolidation_requests, }), } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index cd41fc97a10..e40e948cc6b 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -1771,10 +1771,10 @@ impl ExecutionLayer { pub async fn get_payload_bodies_by_hash( &self, hashes: Vec, - ) -> Result>>, Error> { + ) -> Result>>, Error> { self.engine() .request(|engine: &Engine| async move { - engine.api.get_payload_bodies_by_hash_v1(hashes).await + engine.api.get_payload_bodies_by_hash(hashes).await }) .await .map_err(Box::new) @@ -1785,7 +1785,7 @@ impl ExecutionLayer { &self, start: u64, count: u64, - ) -> Result>>, Error> { + ) -> Result>>, Error> { let _timer = metrics::start_timer(&metrics::EXECUTION_LAYER_GET_PAYLOAD_BODIES_BY_RANGE); self.engine() .request(|engine: &Engine| async move { diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index 0dc7a7759c5..ca379af7108 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -589,6 +589,61 @@ pub async fn handle_rpc( .withdrawals() .ok() .map(|withdrawals| VariableList::from(withdrawals.clone())), + })); + } + None => response.push(None), + } + } + + Ok(serde_json::to_value(response).unwrap()) + } + ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2 => { + #[derive(Deserialize)] + #[serde(transparent)] + struct Quantity(#[serde(with = "serde_utils::u64_hex_be")] pub u64); + + let start = get_param::(params, 0) + .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))? + .0; + let count = get_param::(params, 1) + .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))? + .0; + + let mut response = vec![]; + for block_num in start..(start + count) { + let maybe_block = ctx + .execution_block_generator + .read() + .execution_block_with_txs_by_number(block_num); + + match maybe_block { + Some(block) => { + let transactions = Transactions::::new( + block + .transactions() + .iter() + .map(|transaction| VariableList::new(transaction.rlp().to_vec())) + .collect::>() + .map_err(|e| { + ( + format!("failed to deserialize transaction: {:?}", e), + GENERIC_ERROR_CODE, + ) + })?, + ) + .map_err(|e| { + ( + format!("failed to deserialize transactions: {:?}", e), + GENERIC_ERROR_CODE, + ) + })?; + + response.push(Some(JsonExecutionPayloadBodyV2:: { + transactions, + withdrawals: block + .withdrawals() + .ok() + .map(|withdrawals| VariableList::from(withdrawals.clone())), deposit_requests: block.deposit_requests().ok().map( |deposit_requests| VariableList::from(deposit_requests.clone()), ), @@ -597,6 +652,11 @@ pub async fn handle_rpc( VariableList::from(withdrawal_requests.clone()) }, ), + consolidation_requests: block.consolidation_requests().ok().map( + |consolidation_requests| { + VariableList::from(consolidation_requests.clone()) + }, + ), })); } None => response.push(None), diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 7b00ca9fbc3..25f9a982be9 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -48,7 +48,10 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities { forkchoice_updated_v2: true, forkchoice_updated_v3: true, get_payload_bodies_by_hash_v1: true, + // TODO(electra): make a v2 implementation for the mock EL + get_payload_bodies_by_hash_v2: false, get_payload_bodies_by_range_v1: true, + get_payload_bodies_by_range_v2: false, get_payload_v1: true, get_payload_v2: true, get_payload_v3: true, diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index 477d4f5d640..28bbfb9c048 100644 --- a/consensus/types/src/execution_payload_header.rs +++ b/consensus/types/src/execution_payload_header.rs @@ -127,6 +127,15 @@ impl ExecutionPayloadHeader { } } } + + pub fn fork_name_unchecked(&self) -> ForkName { + match self { + ExecutionPayloadHeader::Bellatrix(_) => ForkName::Bellatrix, + ExecutionPayloadHeader::Capella(_) => ForkName::Capella, + ExecutionPayloadHeader::Deneb(_) => ForkName::Deneb, + ExecutionPayloadHeader::Electra(_) => ForkName::Electra, + } + } } impl<'a, E: EthSpec> ExecutionPayloadHeaderRef<'a, E> { From 9436b40dc1e535f048133ad47136e980948d7f55 Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Wed, 26 Jun 2024 14:26:16 -0500 Subject: [PATCH 2/2] Fix Failing Tests --- beacon_node/execution_layer/src/test_utils/handle_rpc.rs | 4 ++++ beacon_node/execution_layer/src/test_utils/mod.rs | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index ca379af7108..d86b4439ad7 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -638,6 +638,10 @@ pub async fn handle_rpc( ) })?; + // TODO(electra): add testing for: + // deposit_requests + // withdrawal_requests + // consolidation_requests response.push(Some(JsonExecutionPayloadBodyV2:: { transactions, withdrawals: block diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 25f9a982be9..f883f162cdc 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -48,10 +48,9 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities { forkchoice_updated_v2: true, forkchoice_updated_v3: true, get_payload_bodies_by_hash_v1: true, - // TODO(electra): make a v2 implementation for the mock EL - get_payload_bodies_by_hash_v2: false, + get_payload_bodies_by_hash_v2: true, get_payload_bodies_by_range_v1: true, - get_payload_bodies_by_range_v2: false, + get_payload_bodies_by_range_v2: true, get_payload_v1: true, get_payload_v2: true, get_payload_v3: true,