mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
feat: make payload builder generic over attributes type (#5948)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
use crate::{
|
||||
metrics::EngineApiMetrics, payload::PayloadOrAttributes, EngineApiError,
|
||||
EngineApiMessageVersion, EngineApiResult,
|
||||
};
|
||||
use crate::{metrics::EngineApiMetrics, EngineApiError, EngineApiResult};
|
||||
use async_trait::async_trait;
|
||||
use jsonrpsee_core::RpcResult;
|
||||
use reth_beacon_consensus::BeaconConsensusEngineHandle;
|
||||
use reth_interfaces::consensus::ForkchoiceState;
|
||||
use reth_payload_builder::{PayloadBuilderAttributes, PayloadStore};
|
||||
use reth_node_api::{
|
||||
validate_payload_timestamp, validate_version_specific_fields, EngineApiMessageVersion,
|
||||
EngineTypes, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes,
|
||||
};
|
||||
use reth_payload_builder::PayloadStore;
|
||||
use reth_primitives::{BlockHash, BlockHashOrNumber, BlockNumber, ChainSpec, Hardfork, B256, U64};
|
||||
use reth_provider::{BlockReader, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
||||
use reth_rpc_api::EngineApiServer;
|
||||
use reth_rpc_types::engine::{
|
||||
CancunPayloadFields, ExecutionPayload, ExecutionPayloadBodiesV1, ExecutionPayloadEnvelopeV2,
|
||||
ExecutionPayloadEnvelopeV3, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3,
|
||||
ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus, TransitionConfiguration,
|
||||
CAPABILITIES,
|
||||
ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration, CAPABILITIES,
|
||||
};
|
||||
use reth_rpc_types_compat::engine::payload::{
|
||||
convert_payload_input_v2_to_payload, convert_to_payload_body_v1,
|
||||
@@ -32,35 +32,37 @@ const MAX_PAYLOAD_BODIES_LIMIT: u64 = 1024;
|
||||
|
||||
/// The Engine API implementation that grants the Consensus layer access to data and
|
||||
/// functions in the Execution layer that are crucial for the consensus process.
|
||||
pub struct EngineApi<Provider> {
|
||||
inner: Arc<EngineApiInner<Provider>>,
|
||||
pub struct EngineApi<Provider, EngineT: EngineTypes> {
|
||||
inner: Arc<EngineApiInner<Provider, EngineT>>,
|
||||
}
|
||||
|
||||
struct EngineApiInner<Provider> {
|
||||
struct EngineApiInner<Provider, EngineT: EngineTypes> {
|
||||
/// The provider to interact with the chain.
|
||||
provider: Provider,
|
||||
/// Consensus configuration
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
/// The channel to send messages to the beacon consensus engine.
|
||||
beacon_consensus: BeaconConsensusEngineHandle,
|
||||
beacon_consensus: BeaconConsensusEngineHandle<EngineT>,
|
||||
/// The type that can communicate with the payload service to retrieve payloads.
|
||||
payload_store: PayloadStore,
|
||||
payload_store: PayloadStore<EngineT>,
|
||||
/// For spawning and executing async tasks
|
||||
task_spawner: Box<dyn TaskSpawner>,
|
||||
/// The metrics for engine api calls
|
||||
metrics: EngineApiMetrics,
|
||||
}
|
||||
|
||||
impl<Provider> EngineApi<Provider>
|
||||
impl<Provider, EngineT> EngineApi<Provider, EngineT>
|
||||
where
|
||||
Provider: HeaderProvider + BlockReader + StateProviderFactory + EvmEnvProvider + 'static,
|
||||
EngineT: EngineTypes + 'static,
|
||||
EngineT::PayloadBuilderAttributes: Send,
|
||||
{
|
||||
/// Create new instance of [EngineApi].
|
||||
pub fn new(
|
||||
provider: Provider,
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
beacon_consensus: BeaconConsensusEngineHandle,
|
||||
payload_store: PayloadStore,
|
||||
beacon_consensus: BeaconConsensusEngineHandle<EngineT>,
|
||||
payload_store: PayloadStore<EngineT>,
|
||||
task_spawner: Box<dyn TaskSpawner>,
|
||||
) -> Self {
|
||||
let inner = Arc::new(EngineApiInner {
|
||||
@@ -78,7 +80,7 @@ where
|
||||
async fn get_payload_attributes(
|
||||
&self,
|
||||
payload_id: PayloadId,
|
||||
) -> EngineApiResult<PayloadBuilderAttributes> {
|
||||
) -> EngineApiResult<EngineT::PayloadBuilderAttributes> {
|
||||
Ok(self
|
||||
.inner
|
||||
.payload_store
|
||||
@@ -94,8 +96,15 @@ where
|
||||
payload: ExecutionPayloadV1,
|
||||
) -> EngineApiResult<PayloadStatus> {
|
||||
let payload = ExecutionPayload::from(payload);
|
||||
let payload_or_attrs = PayloadOrAttributes::from_execution_payload(&payload, None);
|
||||
self.validate_version_specific_fields(EngineApiMessageVersion::V1, &payload_or_attrs)?;
|
||||
let payload_or_attrs =
|
||||
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
|
||||
&payload, None,
|
||||
);
|
||||
validate_version_specific_fields(
|
||||
&self.inner.chain_spec,
|
||||
EngineApiMessageVersion::V1,
|
||||
&payload_or_attrs,
|
||||
)?;
|
||||
Ok(self.inner.beacon_consensus.new_payload(payload, None).await?)
|
||||
}
|
||||
|
||||
@@ -105,8 +114,15 @@ where
|
||||
payload: ExecutionPayloadInputV2,
|
||||
) -> EngineApiResult<PayloadStatus> {
|
||||
let payload = convert_payload_input_v2_to_payload(payload);
|
||||
let payload_or_attrs = PayloadOrAttributes::from_execution_payload(&payload, None);
|
||||
self.validate_version_specific_fields(EngineApiMessageVersion::V2, &payload_or_attrs)?;
|
||||
let payload_or_attrs =
|
||||
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
|
||||
&payload, None,
|
||||
);
|
||||
validate_version_specific_fields(
|
||||
&self.inner.chain_spec,
|
||||
EngineApiMessageVersion::V2,
|
||||
&payload_or_attrs,
|
||||
)?;
|
||||
Ok(self.inner.beacon_consensus.new_payload(payload, None).await?)
|
||||
}
|
||||
|
||||
@@ -119,8 +135,15 @@ where
|
||||
) -> EngineApiResult<PayloadStatus> {
|
||||
let payload = ExecutionPayload::from(payload);
|
||||
let payload_or_attrs =
|
||||
PayloadOrAttributes::from_execution_payload(&payload, Some(parent_beacon_block_root));
|
||||
self.validate_version_specific_fields(EngineApiMessageVersion::V3, &payload_or_attrs)?;
|
||||
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
|
||||
&payload,
|
||||
Some(parent_beacon_block_root),
|
||||
);
|
||||
validate_version_specific_fields(
|
||||
&self.inner.chain_spec,
|
||||
EngineApiMessageVersion::V3,
|
||||
&payload_or_attrs,
|
||||
)?;
|
||||
|
||||
let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root };
|
||||
|
||||
@@ -136,7 +159,7 @@ where
|
||||
pub async fn fork_choice_updated_v1(
|
||||
&self,
|
||||
state: ForkchoiceState,
|
||||
payload_attrs: Option<PayloadAttributes>,
|
||||
payload_attrs: Option<EngineT::PayloadAttributes>,
|
||||
) -> EngineApiResult<ForkchoiceUpdated> {
|
||||
self.validate_and_execute_forkchoice(EngineApiMessageVersion::V1, state, payload_attrs)
|
||||
.await
|
||||
@@ -149,7 +172,7 @@ where
|
||||
pub async fn fork_choice_updated_v2(
|
||||
&self,
|
||||
state: ForkchoiceState,
|
||||
payload_attrs: Option<PayloadAttributes>,
|
||||
payload_attrs: Option<EngineT::PayloadAttributes>,
|
||||
) -> EngineApiResult<ForkchoiceUpdated> {
|
||||
self.validate_and_execute_forkchoice(EngineApiMessageVersion::V2, state, payload_attrs)
|
||||
.await
|
||||
@@ -162,7 +185,7 @@ where
|
||||
pub async fn fork_choice_updated_v3(
|
||||
&self,
|
||||
state: ForkchoiceState,
|
||||
payload_attrs: Option<PayloadAttributes>,
|
||||
payload_attrs: Option<EngineT::PayloadAttributes>,
|
||||
) -> EngineApiResult<ForkchoiceUpdated> {
|
||||
self.validate_and_execute_forkchoice(EngineApiMessageVersion::V3, state, payload_attrs)
|
||||
.await
|
||||
@@ -205,7 +228,11 @@ where
|
||||
let attributes = self.get_payload_attributes(payload_id).await?;
|
||||
|
||||
// validate timestamp according to engine rules
|
||||
self.validate_payload_timestamp(EngineApiMessageVersion::V2, attributes.timestamp)?;
|
||||
validate_payload_timestamp(
|
||||
&self.inner.chain_spec,
|
||||
EngineApiMessageVersion::V2,
|
||||
attributes.timestamp(),
|
||||
)?;
|
||||
|
||||
// Now resolve the payload
|
||||
Ok(self
|
||||
@@ -232,7 +259,11 @@ where
|
||||
let attributes = self.get_payload_attributes(payload_id).await?;
|
||||
|
||||
// validate timestamp according to engine rules
|
||||
self.validate_payload_timestamp(EngineApiMessageVersion::V3, attributes.timestamp)?;
|
||||
validate_payload_timestamp(
|
||||
&self.inner.chain_spec,
|
||||
EngineApiMessageVersion::V3,
|
||||
attributes.timestamp(),
|
||||
)?;
|
||||
|
||||
// Now resolve the payload
|
||||
Ok(self
|
||||
@@ -385,159 +416,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates the timestamp depending on the version called:
|
||||
///
|
||||
/// * If V2, this ensure that the payload timestamp is pre-Cancun.
|
||||
/// * If V3, this ensures that the payload timestamp is within the Cancun timestamp.
|
||||
///
|
||||
/// Otherwise, this will return [EngineApiError::UnsupportedFork].
|
||||
fn validate_payload_timestamp(
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
timestamp: u64,
|
||||
) -> EngineApiResult<()> {
|
||||
let is_cancun = self.inner.chain_spec.is_cancun_active_at_timestamp(timestamp);
|
||||
if version == EngineApiMessageVersion::V2 && is_cancun {
|
||||
// From the Engine API spec:
|
||||
//
|
||||
// ### Update the methods of previous forks
|
||||
//
|
||||
// This document defines how Cancun payload should be handled by the [`Shanghai
|
||||
// API`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md).
|
||||
//
|
||||
// For the following methods:
|
||||
//
|
||||
// - [`engine_forkchoiceUpdatedV2`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md#engine_forkchoiceupdatedv2)
|
||||
// - [`engine_newPayloadV2`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md#engine_newpayloadV2)
|
||||
// - [`engine_getPayloadV2`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md#engine_getpayloadv2)
|
||||
//
|
||||
// a validation **MUST** be added:
|
||||
//
|
||||
// 1. Client software **MUST** return `-38005: Unsupported fork` error if the
|
||||
// `timestamp` of payload or payloadAttributes greater or equal to the Cancun
|
||||
// activation timestamp.
|
||||
return Err(EngineApiError::UnsupportedFork)
|
||||
}
|
||||
|
||||
if version == EngineApiMessageVersion::V3 && !is_cancun {
|
||||
// From the Engine API spec:
|
||||
// <https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/cancun.md#specification-2>
|
||||
//
|
||||
// 1. Client software **MUST** return `-38005: Unsupported fork` error if the
|
||||
// `timestamp` of the built payload does not fall within the time frame of the Cancun
|
||||
// fork.
|
||||
return Err(EngineApiError::UnsupportedFork)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates the presence of the `withdrawals` field according to the payload timestamp.
|
||||
/// After Shanghai, withdrawals field must be [Some].
|
||||
/// Before Shanghai, withdrawals field must be [None];
|
||||
fn validate_withdrawals_presence(
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
timestamp: u64,
|
||||
has_withdrawals: bool,
|
||||
) -> EngineApiResult<()> {
|
||||
let is_shanghai =
|
||||
self.inner.chain_spec.fork(Hardfork::Shanghai).active_at_timestamp(timestamp);
|
||||
|
||||
match version {
|
||||
EngineApiMessageVersion::V1 => {
|
||||
if has_withdrawals {
|
||||
return Err(EngineApiError::WithdrawalsNotSupportedInV1)
|
||||
}
|
||||
if is_shanghai {
|
||||
return Err(EngineApiError::NoWithdrawalsPostShanghai)
|
||||
}
|
||||
}
|
||||
EngineApiMessageVersion::V2 | EngineApiMessageVersion::V3 => {
|
||||
if is_shanghai && !has_withdrawals {
|
||||
return Err(EngineApiError::NoWithdrawalsPostShanghai)
|
||||
}
|
||||
if !is_shanghai && has_withdrawals {
|
||||
return Err(EngineApiError::HasWithdrawalsPreShanghai)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate the presence of the `parentBeaconBlockRoot` field according to the payload
|
||||
/// timestamp.
|
||||
///
|
||||
/// After Cancun, `parentBeaconBlockRoot` field must be [Some].
|
||||
/// Before Cancun, `parentBeaconBlockRoot` field must be [None].
|
||||
///
|
||||
/// If the engine API message version is V1 or V2, and the payload attribute's timestamp is
|
||||
/// post-Cancun, then this will return [EngineApiError::UnsupportedFork].
|
||||
///
|
||||
/// If the payload attribute's timestamp is before the Cancun fork and the engine API message
|
||||
/// version is V3, then this will return [EngineApiError::UnsupportedFork].
|
||||
///
|
||||
/// If the engine API message version is V3, but the `parentBeaconBlockRoot` is [None], then
|
||||
/// this will return [EngineApiError::NoParentBeaconBlockRootPostCancun].
|
||||
///
|
||||
/// This implements the following Engine API spec rules:
|
||||
///
|
||||
/// 1. Client software **MUST** check that provided set of parameters and their fields strictly
|
||||
/// matches the expected one and return `-32602: Invalid params` error if this check fails.
|
||||
/// Any field having `null` value **MUST** be considered as not provided.
|
||||
///
|
||||
/// 2. Client software **MUST** return `-38005: Unsupported fork` error if the
|
||||
/// `payloadAttributes` is set and the `payloadAttributes.timestamp` does not fall within the
|
||||
/// time frame of the Cancun fork.
|
||||
fn validate_parent_beacon_block_root_presence(
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
timestamp: u64,
|
||||
has_parent_beacon_block_root: bool,
|
||||
) -> EngineApiResult<()> {
|
||||
// 1. Client software **MUST** check that provided set of parameters and their fields
|
||||
// strictly matches the expected one and return `-32602: Invalid params` error if this
|
||||
// check fails. Any field having `null` value **MUST** be considered as not provided.
|
||||
match version {
|
||||
EngineApiMessageVersion::V1 | EngineApiMessageVersion::V2 => {
|
||||
if has_parent_beacon_block_root {
|
||||
return Err(EngineApiError::ParentBeaconBlockRootNotSupportedBeforeV3)
|
||||
}
|
||||
}
|
||||
EngineApiMessageVersion::V3 => {
|
||||
if !has_parent_beacon_block_root {
|
||||
return Err(EngineApiError::NoParentBeaconBlockRootPostCancun)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 2. Client software **MUST** return `-38005: Unsupported fork` error if the
|
||||
// `payloadAttributes` is set and the `payloadAttributes.timestamp` does not fall within
|
||||
// the time frame of the Cancun fork.
|
||||
self.validate_payload_timestamp(version, timestamp)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates the presence or exclusion of fork-specific fields based on the payload attributes
|
||||
/// and the message version.
|
||||
fn validate_version_specific_fields(
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
payload_or_attrs: &PayloadOrAttributes<'_>,
|
||||
) -> EngineApiResult<()> {
|
||||
self.validate_withdrawals_presence(
|
||||
version,
|
||||
payload_or_attrs.timestamp(),
|
||||
payload_or_attrs.withdrawals().is_some(),
|
||||
)?;
|
||||
self.validate_parent_beacon_block_root_presence(
|
||||
version,
|
||||
payload_or_attrs.timestamp(),
|
||||
payload_or_attrs.parent_beacon_block_root().is_some(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Validates the `engine_forkchoiceUpdated` payload attributes and executes the forkchoice
|
||||
/// update.
|
||||
///
|
||||
@@ -555,17 +433,11 @@ where
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
state: ForkchoiceState,
|
||||
payload_attrs: Option<PayloadAttributes>,
|
||||
payload_attrs: Option<EngineT::PayloadAttributes>,
|
||||
) -> EngineApiResult<ForkchoiceUpdated> {
|
||||
if let Some(ref attrs) = payload_attrs {
|
||||
let attr_validation_res = self.validate_version_specific_fields(version, &attrs.into());
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
if attrs.optimism_payload_attributes.gas_limit.is_none() &&
|
||||
self.inner.chain_spec.is_optimism()
|
||||
{
|
||||
return Err(EngineApiError::MissingGasLimitInPayloadAttributes)
|
||||
}
|
||||
let attr_validation_res =
|
||||
attrs.ensure_well_formed_attributes(&self.inner.chain_spec, version);
|
||||
|
||||
// From the engine API spec:
|
||||
//
|
||||
@@ -587,7 +459,7 @@ where
|
||||
if fcu_res.is_invalid() {
|
||||
return Ok(fcu_res)
|
||||
}
|
||||
return Err(err)
|
||||
return Err(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,9 +468,12 @@ where
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Provider> EngineApiServer for EngineApi<Provider>
|
||||
impl<Provider, EngineT> EngineApiServer<EngineT> for EngineApi<Provider, EngineT>
|
||||
where
|
||||
Provider: HeaderProvider + BlockReader + StateProviderFactory + EvmEnvProvider + 'static,
|
||||
EngineT: EngineTypes + 'static + Send,
|
||||
EngineT::PayloadAttributes: Send,
|
||||
EngineT::PayloadBuilderAttributes: Send,
|
||||
{
|
||||
/// Handler for `engine_newPayloadV1`
|
||||
/// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/paris.md#engine_newpayloadv1>
|
||||
@@ -645,7 +520,7 @@ where
|
||||
async fn fork_choice_updated_v1(
|
||||
&self,
|
||||
fork_choice_state: ForkchoiceState,
|
||||
payload_attributes: Option<PayloadAttributes>,
|
||||
payload_attributes: Option<EngineT::PayloadAttributes>,
|
||||
) -> RpcResult<ForkchoiceUpdated> {
|
||||
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedV1");
|
||||
let start = Instant::now();
|
||||
@@ -660,7 +535,7 @@ where
|
||||
async fn fork_choice_updated_v2(
|
||||
&self,
|
||||
fork_choice_state: ForkchoiceState,
|
||||
payload_attributes: Option<PayloadAttributes>,
|
||||
payload_attributes: Option<EngineT::PayloadAttributes>,
|
||||
) -> RpcResult<ForkchoiceUpdated> {
|
||||
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedV2");
|
||||
let start = Instant::now();
|
||||
@@ -676,7 +551,7 @@ where
|
||||
async fn fork_choice_updated_v3(
|
||||
&self,
|
||||
fork_choice_state: ForkchoiceState,
|
||||
payload_attributes: Option<PayloadAttributes>,
|
||||
payload_attributes: Option<EngineT::PayloadAttributes>,
|
||||
) -> RpcResult<ForkchoiceUpdated> {
|
||||
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedV3");
|
||||
let start = Instant::now();
|
||||
@@ -800,7 +675,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider> std::fmt::Debug for EngineApi<Provider> {
|
||||
impl<Provider, EngineT> std::fmt::Debug for EngineApi<Provider, EngineT>
|
||||
where
|
||||
EngineT: EngineTypes,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EngineApi").finish_non_exhaustive()
|
||||
}
|
||||
@@ -812,6 +690,7 @@ mod tests {
|
||||
use assert_matches::assert_matches;
|
||||
use reth_beacon_consensus::BeaconEngineMessage;
|
||||
use reth_interfaces::test_utils::generators::random_block;
|
||||
use reth_node_builder::EthEngineTypes;
|
||||
use reth_payload_builder::test_utils::spawn_test_payload_service;
|
||||
use reth_primitives::{SealedBlock, B256, MAINNET};
|
||||
use reth_provider::test_utils::MockEthProvider;
|
||||
@@ -820,7 +699,8 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
||||
|
||||
fn setup_engine_api() -> (EngineApiTestHandle, EngineApi<Arc<MockEthProvider>>) {
|
||||
fn setup_engine_api() -> (EngineApiTestHandle, EngineApi<Arc<MockEthProvider>, EthEngineTypes>)
|
||||
{
|
||||
let chain_spec: Arc<ChainSpec> = MAINNET.clone();
|
||||
let provider = Arc::new(MockEthProvider::default());
|
||||
let payload_store = spawn_test_payload_service();
|
||||
@@ -840,7 +720,7 @@ mod tests {
|
||||
struct EngineApiTestHandle {
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
provider: Arc<MockEthProvider>,
|
||||
from_api: UnboundedReceiver<BeaconEngineMessage>,
|
||||
from_api: UnboundedReceiver<BeaconEngineMessage<EthEngineTypes>>,
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -2,6 +2,7 @@ use jsonrpsee_types::error::{
|
||||
INTERNAL_ERROR_CODE, INVALID_PARAMS_CODE, INVALID_PARAMS_MSG, SERVER_ERROR_MSG,
|
||||
};
|
||||
use reth_beacon_consensus::{BeaconForkChoiceUpdateError, BeaconOnNewPayloadError};
|
||||
use reth_node_api::AttributesValidationError;
|
||||
use reth_payload_builder::error::PayloadBuilderError;
|
||||
use reth_primitives::{B256, U256};
|
||||
use thiserror::Error;
|
||||
@@ -43,27 +44,6 @@ pub enum EngineApiError {
|
||||
/// Requested number of items
|
||||
count: u64,
|
||||
},
|
||||
/// Thrown if `PayloadAttributes` provided in engine_forkchoiceUpdated before V3 contains a
|
||||
/// parent beacon block root
|
||||
#[error("parent beacon block root not supported before V3")]
|
||||
ParentBeaconBlockRootNotSupportedBeforeV3,
|
||||
/// Thrown if engine_forkchoiceUpdatedV1 contains withdrawals
|
||||
#[error("withdrawals not supported in V1")]
|
||||
WithdrawalsNotSupportedInV1,
|
||||
/// Thrown if engine_forkchoiceUpdated contains no withdrawals after Shanghai
|
||||
#[error("no withdrawals post-Shanghai")]
|
||||
NoWithdrawalsPostShanghai,
|
||||
/// Thrown if engine_forkchoiceUpdated contains withdrawals before Shanghai
|
||||
#[error("withdrawals pre-Shanghai")]
|
||||
HasWithdrawalsPreShanghai,
|
||||
/// Thrown if the `PayloadAttributes` provided in engine_forkchoiceUpdated contains no parent
|
||||
/// beacon block root after Cancun
|
||||
#[error("no parent beacon block root post-cancun")]
|
||||
NoParentBeaconBlockRootPostCancun,
|
||||
/// Thrown if `PayloadAttributes` were provided with a timestamp, but the version of the engine
|
||||
/// method called is meant for a fork that occurs after the provided timestamp.
|
||||
#[error("Unsupported fork")]
|
||||
UnsupportedFork,
|
||||
/// Terminal total difficulty mismatch during transition configuration exchange.
|
||||
#[error(
|
||||
"invalid transition terminal total difficulty: \
|
||||
@@ -98,6 +78,9 @@ pub enum EngineApiError {
|
||||
/// Fetching the payload failed
|
||||
#[error(transparent)]
|
||||
GetPayloadError(#[from] PayloadBuilderError),
|
||||
/// The payload or attributes are known to be malformed before processing.
|
||||
#[error(transparent)]
|
||||
AttributesValidationError(#[from] AttributesValidationError),
|
||||
/// If the optimism feature flag is enabled, the payload attributes must have a present
|
||||
/// gas limit for the forkchoice updated method.
|
||||
#[cfg(feature = "optimism")]
|
||||
@@ -123,11 +106,24 @@ impl From<EngineApiError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
fn from(error: EngineApiError) -> Self {
|
||||
match error {
|
||||
EngineApiError::InvalidBodiesRange { .. } |
|
||||
EngineApiError::WithdrawalsNotSupportedInV1 |
|
||||
EngineApiError::ParentBeaconBlockRootNotSupportedBeforeV3 |
|
||||
EngineApiError::NoParentBeaconBlockRootPostCancun |
|
||||
EngineApiError::NoWithdrawalsPostShanghai |
|
||||
EngineApiError::HasWithdrawalsPreShanghai => {
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::WithdrawalsNotSupportedInV1,
|
||||
) |
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::ParentBeaconBlockRootNotSupportedBeforeV3,
|
||||
) |
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::NoParentBeaconBlockRootPostCancun,
|
||||
) |
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::NoWithdrawalsPostShanghai,
|
||||
) |
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::HasWithdrawalsPreShanghai,
|
||||
) |
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::InvalidParams(_),
|
||||
) => {
|
||||
// Note: the data field is not required by the spec, but is also included by other
|
||||
// clients
|
||||
jsonrpsee_types::error::ErrorObject::owned(
|
||||
@@ -148,7 +144,9 @@ impl From<EngineApiError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
Some(ErrorData::new(error)),
|
||||
)
|
||||
}
|
||||
EngineApiError::UnsupportedFork => jsonrpsee_types::error::ErrorObject::owned(
|
||||
EngineApiError::AttributesValidationError(
|
||||
AttributesValidationError::UnsupportedFork,
|
||||
) => jsonrpsee_types::error::ErrorObject::owned(
|
||||
UNSUPPORTED_FORK_CODE,
|
||||
error.to_string(),
|
||||
None::<()>,
|
||||
@@ -238,7 +236,7 @@ mod tests {
|
||||
ensure_engine_rpc_error(
|
||||
UNSUPPORTED_FORK_CODE,
|
||||
"Unsupported fork",
|
||||
EngineApiError::UnsupportedFork,
|
||||
EngineApiError::AttributesValidationError(AttributesValidationError::UnsupportedFork),
|
||||
);
|
||||
|
||||
ensure_engine_rpc_error(
|
||||
|
||||
@@ -14,9 +14,6 @@ mod engine_api;
|
||||
/// The Engine API message type.
|
||||
mod message;
|
||||
|
||||
/// An type representing either an execution payload or payload attributes.
|
||||
mod payload;
|
||||
|
||||
/// Engine API error.
|
||||
mod error;
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
use reth_primitives::B256;
|
||||
|
||||
use reth_rpc_types::engine::{ExecutionPayload, PayloadAttributes};
|
||||
/// Either an [ExecutionPayload] or a [PayloadAttributes].
|
||||
pub(crate) enum PayloadOrAttributes<'a> {
|
||||
/// An [ExecutionPayload] and optional parent beacon block root.
|
||||
ExecutionPayload {
|
||||
/// The inner execution payload
|
||||
payload: &'a ExecutionPayload,
|
||||
/// The parent beacon block root
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
},
|
||||
/// A [PayloadAttributes].
|
||||
PayloadAttributes(&'a PayloadAttributes),
|
||||
}
|
||||
|
||||
impl<'a> PayloadOrAttributes<'a> {
|
||||
/// Construct a [PayloadOrAttributes] from an [ExecutionPayload] and optional parent beacon
|
||||
/// block root.
|
||||
pub(crate) fn from_execution_payload(
|
||||
payload: &'a ExecutionPayload,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
) -> Self {
|
||||
Self::ExecutionPayload { payload, parent_beacon_block_root }
|
||||
}
|
||||
|
||||
/// Return the withdrawals for the payload or attributes.
|
||||
pub(crate) fn withdrawals(&self) -> Option<&Vec<reth_rpc_types::engine::payload::Withdrawal>> {
|
||||
match self {
|
||||
Self::ExecutionPayload { payload, .. } => payload.withdrawals(),
|
||||
Self::PayloadAttributes(attributes) => attributes.withdrawals.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the timestamp for the payload or attributes.
|
||||
pub(crate) fn timestamp(&self) -> u64 {
|
||||
match self {
|
||||
Self::ExecutionPayload { payload, .. } => payload.timestamp(),
|
||||
Self::PayloadAttributes(attributes) => attributes.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the parent beacon block root for the payload or attributes.
|
||||
pub(crate) fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
match self {
|
||||
Self::ExecutionPayload { parent_beacon_block_root, .. } => *parent_beacon_block_root,
|
||||
Self::PayloadAttributes(attributes) => attributes.parent_beacon_block_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PayloadAttributes> for PayloadOrAttributes<'a> {
|
||||
fn from(attributes: &'a PayloadAttributes) -> Self {
|
||||
Self::PayloadAttributes(attributes)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user