mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-15 02:42:38 +00:00
Add getPayload v2 methods
This commit is contained in:
@@ -3,7 +3,8 @@ use crate::http::{
|
||||
ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3,
|
||||
ENGINE_FORKCHOICE_UPDATED_V4, ENGINE_GET_BLOBS_V1, ENGINE_GET_BLOBS_V2,
|
||||
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_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,
|
||||
@@ -425,10 +426,18 @@ impl<E: EthSpec> GetPayloadResponse<E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2),
|
||||
variant_attributes(derive(Clone, Debug)),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExecutionPayloadBodyV1<E: EthSpec> {
|
||||
pub struct ExecutionPayloadBody<E: EthSpec> {
|
||||
pub transactions: Transactions<E>,
|
||||
pub withdrawals: Option<Withdrawals<E>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub block_access_list: Option<VariableList<u8, E::MaxBytesPerTransaction>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
|
||||
@@ -608,6 +617,195 @@ impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadBodyV2<E> {
|
||||
pub fn to_payload(
|
||||
self,
|
||||
header: ExecutionPayloadHeader<E>,
|
||||
) -> Result<ExecutionPayload<E>, String> {
|
||||
match header {
|
||||
ExecutionPayloadHeader::Bellatrix(header) => {
|
||||
if self.withdrawals.is_some() {
|
||||
return Err(format!(
|
||||
"block {} is bellatrix but payload body has withdrawals",
|
||||
header.block_hash
|
||||
));
|
||||
}
|
||||
Ok(ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix {
|
||||
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,
|
||||
}))
|
||||
}
|
||||
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
|
||||
))
|
||||
}
|
||||
}
|
||||
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
|
||||
))
|
||||
}
|
||||
}
|
||||
ExecutionPayloadHeader::Electra(header) => {
|
||||
if let Some(withdrawals) = self.withdrawals {
|
||||
Ok(ExecutionPayload::Electra(ExecutionPayloadElectra {
|
||||
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
|
||||
))
|
||||
}
|
||||
}
|
||||
ExecutionPayloadHeader::Fulu(header) => {
|
||||
if let Some(withdrawals) = self.withdrawals {
|
||||
Ok(ExecutionPayload::Fulu(ExecutionPayloadFulu {
|
||||
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
|
||||
))
|
||||
}
|
||||
}
|
||||
ExecutionPayloadHeader::Gloas(header) => {
|
||||
if let Some(withdrawals) = self.withdrawals {
|
||||
Ok(ExecutionPayload::Gloas(ExecutionPayloadGloas {
|
||||
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,
|
||||
// V2 provides block_access_list from EL; use empty if not present
|
||||
block_access_list: self
|
||||
.block_access_list
|
||||
.unwrap_or_else(VariableList::empty),
|
||||
slot_number: header.slot_number,
|
||||
}))
|
||||
} else {
|
||||
Err(format!(
|
||||
"block {} is post capella but payload body doesn't have withdrawals",
|
||||
header.block_hash
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadBody<E> {
|
||||
pub fn to_payload(
|
||||
self,
|
||||
header: ExecutionPayloadHeader<E>,
|
||||
) -> Result<ExecutionPayload<E>, String> {
|
||||
match self {
|
||||
ExecutionPayloadBody::V1(body) => body.to_payload(header),
|
||||
ExecutionPayloadBody::V2(body) => body.to_payload(header),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct EngineCapabilities {
|
||||
pub new_payload_v1: bool,
|
||||
@@ -620,7 +818,9 @@ pub struct EngineCapabilities {
|
||||
pub forkchoice_updated_v3: bool,
|
||||
pub forkchoice_updated_v4: bool,
|
||||
pub get_payload_bodies_by_hash_v1: bool,
|
||||
pub get_payload_bodies_by_hash_v2: bool,
|
||||
pub get_payload_bodies_by_range_v1: bool,
|
||||
pub get_payload_bodies_by_range_v2: bool,
|
||||
pub get_payload_v1: bool,
|
||||
pub get_payload_v2: bool,
|
||||
pub get_payload_v3: bool,
|
||||
@@ -665,9 +865,15 @@ impl EngineCapabilities {
|
||||
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_bodies_by_range_v1 {
|
||||
response.push(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ pub const ENGINE_FORKCHOICE_UPDATED_V4: &str = "engine_forkchoiceUpdatedV4";
|
||||
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_HASH_V2: &str = "engine_getPayloadBodiesByHashV2";
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1: &str = "engine_getPayloadBodiesByRangeV1";
|
||||
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";
|
||||
@@ -90,7 +92,9 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
|
||||
ENGINE_FORKCHOICE_UPDATED_V3,
|
||||
ENGINE_FORKCHOICE_UPDATED_V4,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2,
|
||||
ENGINE_GET_CLIENT_VERSION_V1,
|
||||
ENGINE_GET_BLOBS_V1,
|
||||
ENGINE_GET_BLOBS_V2,
|
||||
@@ -1364,6 +1368,58 @@ impl HttpJsonRpc {
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_hash_v2<E: EthSpec>(
|
||||
&self,
|
||||
block_hashes: Vec<ExecutionBlockHash>,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV2<E>>>, Error> {
|
||||
let params = json!([block_hashes]);
|
||||
|
||||
let response: Vec<Option<JsonExecutionPayloadBodyV2<E>>> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_BODIES_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
response
|
||||
.into_iter()
|
||||
.map(|opt_json| {
|
||||
opt_json
|
||||
.map(|json| json.try_into().map_err(Error::from))
|
||||
.transpose()
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_range_v2<E: EthSpec>(
|
||||
&self,
|
||||
start: u64,
|
||||
count: u64,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV2<E>>>, 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<Option<JsonExecutionPayloadBodyV2<E>>> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_BODIES_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
response
|
||||
.into_iter()
|
||||
.map(|opt_json| {
|
||||
opt_json
|
||||
.map(|json| json.try_into().map_err(Error::from))
|
||||
.transpose()
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
pub async fn exchange_capabilities(&self) -> Result<EngineCapabilities, Error> {
|
||||
let params = json!([LIGHTHOUSE_CAPABILITIES]);
|
||||
|
||||
@@ -1387,8 +1443,12 @@ impl HttpJsonRpc {
|
||||
forkchoice_updated_v4: capabilities.contains(ENGINE_FORKCHOICE_UPDATED_V4),
|
||||
get_payload_bodies_by_hash_v1: capabilities
|
||||
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1),
|
||||
get_payload_bodies_by_hash_v2: capabilities
|
||||
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2),
|
||||
get_payload_bodies_by_range_v1: capabilities
|
||||
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1),
|
||||
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),
|
||||
|
||||
@@ -1020,12 +1020,24 @@ impl From<ForkchoiceUpdatedResponse> for JsonForkchoiceUpdatedV1Response {
|
||||
}
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2),
|
||||
variant_attributes(
|
||||
derive(Clone, Debug, Serialize, Deserialize),
|
||||
serde(bound = "E: EthSpec", rename_all = "camelCase")
|
||||
),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
pub struct JsonExecutionPayloadBodyV1<E: EthSpec> {
|
||||
#[serde(bound = "E: EthSpec", rename_all = "camelCase")]
|
||||
pub struct JsonExecutionPayloadBody<E: EthSpec> {
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<E>,
|
||||
pub withdrawals: Option<VariableList<JsonWithdrawal, E::MaxWithdrawalsPerPayload>>,
|
||||
#[superstruct(only(V2))]
|
||||
#[serde(with = "optional_hex_var_list")]
|
||||
pub block_access_list: Option<VariableList<u8, E::MaxBytesPerTransaction>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadBodyV1<E>> for ExecutionPayloadBodyV1<E> {
|
||||
@@ -1050,6 +1062,30 @@ impl<E: EthSpec> TryFrom<ExecutionPayloadBodyV1<E>> for JsonExecutionPayloadBody
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadBodyV2<E>> for ExecutionPayloadBodyV2<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(value: JsonExecutionPayloadBodyV2<E>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(withdrawals_from_json).transpose()?,
|
||||
block_access_list: value.block_access_list,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadBodyV2<E>> for JsonExecutionPayloadBodyV2<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(value: ExecutionPayloadBodyV2<E>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(withdrawals_to_json).transpose()?,
|
||||
block_access_list: value.block_access_list,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransitionConfigurationV1 {
|
||||
@@ -1090,6 +1126,50 @@ pub mod serde_logs_bloom {
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes an optional hex variable list field (e.g., blockAccessList in EIP-7928).
|
||||
/// JSON `null` maps to `None`, hex string maps to `Some(VariableList<u8, N>)`.
|
||||
pub mod optional_hex_var_list {
|
||||
use super::*;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S, N>(
|
||||
opt_bytes: &Option<VariableList<u8, N>>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
N: Unsigned,
|
||||
{
|
||||
match opt_bytes {
|
||||
Some(bytes) => {
|
||||
let mut hex_string: String = "0x".to_string();
|
||||
hex_string.push_str(&hex::encode(&bytes[..]));
|
||||
serializer.serialize_str(&hex_string)
|
||||
}
|
||||
None => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, N>(deserializer: D) -> Result<Option<VariableList<u8, N>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
N: Unsigned,
|
||||
{
|
||||
let opt: Option<String> = Option::deserialize(deserializer)?;
|
||||
match opt {
|
||||
Some(hex_str) => {
|
||||
let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str);
|
||||
let bytes = hex::decode(hex_str)
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid hex: {:?}", e)))?;
|
||||
VariableList::new(bytes)
|
||||
.map(Some)
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid var list: {:?}", e)))
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JsonClientVersionV1 {
|
||||
|
||||
@@ -158,6 +158,7 @@ pub enum Error {
|
||||
},
|
||||
ZeroLengthTransaction,
|
||||
PayloadBodiesByRangeNotSupported,
|
||||
PayloadBodiesByHashNotSupported,
|
||||
GetBlobsNotSupported,
|
||||
InvalidJWTSecret(String),
|
||||
InvalidForkForPayload,
|
||||
@@ -1787,32 +1788,87 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
pub async fn get_payload_bodies_by_hash(
|
||||
&self,
|
||||
hashes: Vec<ExecutionBlockHash>,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV1<E>>>, Error> {
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine.api.get_payload_bodies_by_hash_v1(hashes).await
|
||||
})
|
||||
.await
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
let capabilities = self.get_engine_capabilities(None).await?;
|
||||
|
||||
if capabilities.get_payload_bodies_by_hash_v2 {
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine.api.get_payload_bodies_by_hash_v2(hashes).await
|
||||
})
|
||||
.await
|
||||
.map(|bodies| {
|
||||
bodies
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(ExecutionPayloadBody::V2))
|
||||
.collect()
|
||||
})
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
} else if capabilities.get_payload_bodies_by_hash_v1 {
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine.api.get_payload_bodies_by_hash_v1::<E>(hashes).await
|
||||
})
|
||||
.await
|
||||
.map(|bodies| {
|
||||
bodies
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(ExecutionPayloadBody::V1))
|
||||
.collect()
|
||||
})
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
} else {
|
||||
Err(Error::PayloadBodiesByHashNotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_range(
|
||||
&self,
|
||||
start: u64,
|
||||
count: u64,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV1<E>>>, Error> {
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
let _timer = metrics::start_timer(&metrics::EXECUTION_LAYER_GET_PAYLOAD_BODIES_BY_RANGE);
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine
|
||||
.api
|
||||
.get_payload_bodies_by_range_v1(start, count)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
let capabilities = self.get_engine_capabilities(None).await?;
|
||||
|
||||
if capabilities.get_payload_bodies_by_range_v2 {
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine
|
||||
.api
|
||||
.get_payload_bodies_by_range_v2(start, count)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
.map(|bodies| {
|
||||
bodies
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(ExecutionPayloadBody::V2))
|
||||
.collect()
|
||||
})
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
} else if capabilities.get_payload_bodies_by_range_v1 {
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine
|
||||
.api
|
||||
.get_payload_bodies_by_range_v1::<E>(start, count)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
.map(|bodies| {
|
||||
bodies
|
||||
.into_iter()
|
||||
.map(|opt| opt.map(ExecutionPayloadBody::V1))
|
||||
.collect()
|
||||
})
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
} else {
|
||||
Err(Error::PayloadBodiesByRangeNotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch a full payload from the execution node.
|
||||
@@ -1845,7 +1901,9 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
|
||||
// Use efficient payload bodies by range method if supported.
|
||||
let capabilities = self.get_engine_capabilities(None).await?;
|
||||
if capabilities.get_payload_bodies_by_range_v1 {
|
||||
if capabilities.get_payload_bodies_by_range_v2
|
||||
|| capabilities.get_payload_bodies_by_range_v1
|
||||
{
|
||||
let mut payload_bodies = self.get_payload_bodies_by_range(block_number, 1).await?;
|
||||
|
||||
if payload_bodies.len() != 1 {
|
||||
|
||||
@@ -51,7 +51,9 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
|
||||
forkchoice_updated_v3: true,
|
||||
forkchoice_updated_v4: true,
|
||||
get_payload_bodies_by_hash_v1: true,
|
||||
get_payload_bodies_by_hash_v2: true,
|
||||
get_payload_bodies_by_range_v1: true,
|
||||
get_payload_bodies_by_range_v2: true,
|
||||
get_payload_v1: true,
|
||||
get_payload_v2: true,
|
||||
get_payload_v3: true,
|
||||
|
||||
Reference in New Issue
Block a user