Skip to content

Commit

Permalink
Relax EngineApi ExecutionData bounds (#14648)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
  • Loading branch information
yohkaz and mattsse authored Feb 22, 2025
1 parent 5c8a0a1 commit 40364d5
Showing 1 changed file with 189 additions and 178 deletions.
367 changes: 189 additions & 178 deletions crates/rpc/rpc-engine-api/src/engine_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<Provider, EngineT, Pool, Validator, ChainSpec>
EngineApi<Provider, EngineT, Pool, Validator, ChainSpec>
where
Provider: HeaderProvider + BlockReader + StateProviderFactory + 'static,
EngineT: EngineTypes<ExecutionData = ExecutionData>,
EngineT: EngineTypes,
Pool: TransactionPool + 'static,
Validator: EngineValidator<EngineT>,
ChainSpec: EthereumHardforks + Send + Sync + 'static,
Expand Down Expand Up @@ -118,6 +118,7 @@ where
) -> EngineApiResult<Vec<ClientVersionV1>> {
Ok(vec![self.inner.client.clone()])
}

/// Fetches the attributes for the payload with the given id.
async fn get_payload_attributes(
&self,
Expand All @@ -131,183 +132,6 @@ where
.ok_or(EngineApiError::UnknownPayload)??)
}

/// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/paris.md#engine_newpayloadv1>
/// Caution: This should not accept the `withdrawals` field
pub async fn new_payload_v1(
&self,
payload: ExecutionPayloadV1,
) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload);
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?;

Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() })
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

/// Metered version of `new_payload_v1`.
async fn new_payload_v1_metered(
&self,
payload: ExecutionPayloadV1,
) -> EngineApiResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.gas_used;
let res = Self::new_payload_v1(self, payload).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v1.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
res
}

/// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
pub async fn new_payload_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> EngineApiResult<PayloadStatus> {
let payload = payload.into_payload();
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V2, payload_or_attrs)?;
Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() })
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

/// Metered version of `new_payload_v2`.
pub async fn new_payload_v2_metered(
&self,
payload: ExecutionPayloadInputV2,
) -> EngineApiResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.execution_payload.gas_used;
let res = Self::new_payload_v2(self, payload).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v2.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
res
}

/// See also <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#engine_newpayloadv3>
pub async fn new_payload_v3(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload);
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload,
Some(parent_beacon_block_root),
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V3, payload_or_attrs)?;

Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData {
payload,
sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields {
versioned_hashes,
parent_beacon_block_root,
}),
})
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

// Metrics version of `new_payload_v3`
async fn new_payload_v3_metered(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> RpcResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.payload_inner.payload_inner.gas_used;
let res =
Self::new_payload_v3(self, payload, versioned_hashes, parent_beacon_block_root).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v3.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
Ok(res?)
}

/// See also <https://github.com/ethereum/execution-apis/blob/7907424db935b93c2fe6a3c0faab943adebe8557/src/engine/prague.md#engine_newpayloadv4>
pub async fn new_payload_v4(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload);
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload,
Some(parent_beacon_block_root),
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V4, payload_or_attrs)?;

self.inner.validator.validate_execution_requests(&execution_requests)?;
Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData {
payload,
sidecar: ExecutionPayloadSidecar::v4(
CancunPayloadFields { versioned_hashes, parent_beacon_block_root },
PraguePayloadFields { requests: RequestsOrHash::Requests(execution_requests) },
),
})
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

/// Metrics version of `new_payload_v4`
async fn new_payload_v4_metered(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> RpcResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.payload_inner.payload_inner.gas_used;
let res = Self::new_payload_v4(
self,
payload,
versioned_hashes,
parent_beacon_block_root,
execution_requests,
)
.await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v4.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
Ok(res?)
}

/// Sends a message to the beacon consensus engine to update the fork choice _without_
/// withdrawals.
///
Expand Down Expand Up @@ -721,6 +545,193 @@ where
}
}

impl<Provider, EngineT, Pool, Validator, ChainSpec>
EngineApi<Provider, EngineT, Pool, Validator, ChainSpec>
where
Provider: HeaderProvider + BlockReader + StateProviderFactory + 'static,
EngineT: EngineTypes<ExecutionData = ExecutionData>,
Pool: TransactionPool + 'static,
Validator: EngineValidator<EngineT>,
ChainSpec: EthereumHardforks + Send + Sync + 'static,
{
/// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/paris.md#engine_newpayloadv1>
/// Caution: This should not accept the `withdrawals` field
pub async fn new_payload_v1(
&self,
payload: ExecutionPayloadV1,
) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload);
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?;

Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() })
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

/// Metered version of `new_payload_v1`.
async fn new_payload_v1_metered(
&self,
payload: ExecutionPayloadV1,
) -> EngineApiResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.gas_used;
let res = Self::new_payload_v1(self, payload).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v1.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
res
}

/// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
pub async fn new_payload_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> EngineApiResult<PayloadStatus> {
let payload = payload.into_payload();
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V2, payload_or_attrs)?;
Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() })
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

/// Metered version of `new_payload_v2`.
pub async fn new_payload_v2_metered(
&self,
payload: ExecutionPayloadInputV2,
) -> EngineApiResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.execution_payload.gas_used;
let res = Self::new_payload_v2(self, payload).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v2.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
res
}

/// See also <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#engine_newpayloadv3>
pub async fn new_payload_v3(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload);
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload,
Some(parent_beacon_block_root),
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V3, payload_or_attrs)?;

Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData {
payload,
sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields {
versioned_hashes,
parent_beacon_block_root,
}),
})
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

// Metrics version of `new_payload_v3`
async fn new_payload_v3_metered(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> RpcResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.payload_inner.payload_inner.gas_used;
let res =
Self::new_payload_v3(self, payload, versioned_hashes, parent_beacon_block_root).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v3.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
Ok(res?)
}

/// See also <https://github.com/ethereum/execution-apis/blob/7907424db935b93c2fe6a3c0faab943adebe8557/src/engine/prague.md#engine_newpayloadv4>
pub async fn new_payload_v4(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload);
let payload_or_attrs =
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload,
Some(parent_beacon_block_root),
);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V4, payload_or_attrs)?;

self.inner.validator.validate_execution_requests(&execution_requests)?;
Ok(self
.inner
.beacon_consensus
.new_payload(ExecutionData {
payload,
sidecar: ExecutionPayloadSidecar::v4(
CancunPayloadFields { versioned_hashes, parent_beacon_block_root },
PraguePayloadFields { requests: RequestsOrHash::Requests(execution_requests) },
),
})
.await
.inspect(|_| self.inner.on_new_payload_response())?)
}

/// Metrics version of `new_payload_v4`
async fn new_payload_v4_metered(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> RpcResult<PayloadStatus> {
let start = Instant::now();
let gas_used = payload.payload_inner.payload_inner.gas_used;
let res = Self::new_payload_v4(
self,
payload,
versioned_hashes,
parent_beacon_block_root,
execution_requests,
)
.await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v4.record(elapsed);
self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed);
Ok(res?)
}
}

impl<Provider, EngineT, Pool, Validator, ChainSpec>
EngineApiInner<Provider, EngineT, Pool, Validator, ChainSpec>
where
Expand Down

0 comments on commit 40364d5

Please sign in to comment.