fix: enforce unsupported fork rules on get_payload_v3 (#4562)

This commit is contained in:
Dan Cline
2023-09-12 13:07:52 -04:00
committed by GitHub
parent 261a9f9499
commit c4956143b0
6 changed files with 74 additions and 0 deletions

View File

@ -412,6 +412,10 @@ where
build_empty_payload(&self.client, self.config.clone()).map(Arc::new)
}
fn payload_attributes(&self) -> Result<PayloadBuilderAttributes, PayloadBuilderError> {
Ok(self.config.attributes.clone())
}
fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) {
let best_payload = self.best_payload.take();
let maybe_better = self.pending_block.take();

View File

@ -86,6 +86,10 @@
//! Ok(Arc::new(payload))
//! }
//!
//! fn payload_attributes(&self) -> Result<PayloadBuilderAttributes, PayloadBuilderError> {
//! Ok(self.attributes.clone())
//! }
//!
//! fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) {
//! let payload = self.best_payload();
//! (futures_util::future::ready(payload), KeepPayloadJobAlive::No)

View File

@ -48,6 +48,16 @@ impl PayloadStore {
) -> Option<Result<Arc<BuiltPayload>, PayloadBuilderError>> {
self.inner.best_payload(id).await
}
/// Returns the payload attributes associated with the given identifier.
///
/// Note: this returns the attributes of the payload and does not resolve the job.
pub async fn payload_attributes(
&self,
id: PayloadId,
) -> Option<Result<PayloadBuilderAttributes, PayloadBuilderError>> {
self.inner.payload_attributes(id).await
}
}
impl From<PayloadBuilderHandle> for PayloadStore {
@ -94,6 +104,18 @@ impl PayloadBuilderHandle {
rx.await.ok()?
}
/// Returns the payload attributes associated with the given identifier.
///
/// Note: this returns the attributes of the payload and does not resolve the job.
pub async fn payload_attributes(
&self,
id: PayloadId,
) -> Option<Result<PayloadBuilderAttributes, PayloadBuilderError>> {
let (tx, rx) = oneshot::channel();
self.to_service.send(PayloadServiceCommand::PayloadAttributes(id, tx)).ok()?;
rx.await.ok()?
}
/// Sends a message to the service to start building a new payload for the given payload.
///
/// This is the same as [PayloadBuilderHandle::new_payload] but does not wait for the result and
@ -178,6 +200,17 @@ where
self.payload_jobs.iter().find(|(_, job_id)| *job_id == id).map(|(j, _)| j.best_payload())
}
/// Returns the payload attributes for the given payload.
fn payload_attributes(
&self,
id: PayloadId,
) -> Option<Result<PayloadBuilderAttributes, PayloadBuilderError>> {
self.payload_jobs
.iter()
.find(|(_, job_id)| *job_id == id)
.map(|(j, _)| j.payload_attributes())
}
/// Returns the best payload for the given identifier that has been built so far and terminates
/// the job if requested.
fn resolve(&mut self, id: PayloadId) -> Option<PayloadFuture> {
@ -262,6 +295,9 @@ where
PayloadServiceCommand::BestPayload(id, tx) => {
let _ = tx.send(this.best_payload(id));
}
PayloadServiceCommand::PayloadAttributes(id, tx) => {
let _ = tx.send(this.payload_attributes(id));
}
PayloadServiceCommand::Resolve(id, tx) => {
let _ = tx.send(this.resolve(id));
}
@ -287,6 +323,11 @@ enum PayloadServiceCommand {
),
/// Get the best payload so far
BestPayload(PayloadId, oneshot::Sender<Option<Result<Arc<BuiltPayload>, PayloadBuilderError>>>),
/// Get the payload attributes for the given payload
PayloadAttributes(
PayloadId,
oneshot::Sender<Option<Result<PayloadBuilderAttributes, PayloadBuilderError>>>,
),
/// Resolve the payload and return the payload
Resolve(PayloadId, oneshot::Sender<Option<PayloadFuture>>),
}

View File

@ -68,6 +68,10 @@ impl PayloadJob for TestPayloadJob {
)))
}
fn payload_attributes(&self) -> Result<PayloadBuilderAttributes, PayloadBuilderError> {
Ok(self.attr.clone())
}
fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) {
let fut = futures_util::future::ready(self.best_payload());
(fut, KeepPayloadJobAlive::No)

View File

@ -26,6 +26,9 @@ pub trait PayloadJob: Future<Output = Result<(), PayloadBuilderError>> + Send +
/// Note: This is never called by the CL.
fn best_payload(&self) -> Result<Arc<BuiltPayload>, PayloadBuilderError>;
/// Returns the payload attributes for the payload being built.
fn payload_attributes(&self) -> Result<PayloadBuilderAttributes, PayloadBuilderError>;
/// Called when the payload is requested by the CL.
///
/// This is invoked on [`engine_getPayloadV2`](https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#engine_getpayloadv2) and [`engine_getPayloadV1`](https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#engine_getpayloadv1).

View File

@ -208,6 +208,24 @@ where
&self,
payload_id: PayloadId,
) -> EngineApiResult<ExecutionPayloadEnvelopeV3> {
// First we fetch the payload attributes to check the timestamp
let attributes = self
.inner
.payload_store
.payload_attributes(payload_id)
.await
.ok_or(EngineApiError::UnknownPayload)??;
// 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.
if !self.inner.chain_spec.is_cancun_activated_at_timestamp(attributes.timestamp) {
return Err(EngineApiError::UnsupportedFork)
}
// Now resolve the payload
Ok(self
.inner
.payload_store