Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rpc): define traits for stateless APIs #13016

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions crates/rpc/rpc-api/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,45 @@ pub trait EngineApi<Engine: EngineTypes> {
execution_requests: Requests,
) -> RpcResult<PayloadStatus>;

/// Analogous to `new_payload_v1`, but with the addition of a witness.
///
/// Caution: This should not accept the `withdrawals` field
#[method(name = "newPayloadWithWitnessV1")]
async fn new_payload_with_witness_v1(
&self,
payload: ExecutionPayloadV1,
) -> RpcResult<PayloadStatus>;

/// Analogous to `new_payload_v2`, but with the addition of a witness.
#[method(name = "newPayloadWithWitnessV2")]
async fn new_payload_with_witness_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> RpcResult<PayloadStatus>;

/// Analogous to `new_payload_v3`, but with the addition of a witness.
///
/// Post Cancun payload handler
#[method(name = "newPayloadWithWitnessV3")]
async fn new_payload_with_witness_v3(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> RpcResult<PayloadStatus>;

/// Analogous to `new_payload_v4`, but with the addition of a witness.
///
/// Post Prague payload handler
#[method(name = "newPayloadWithWitnessV4")]
async fn new_payload_with_witness_v4(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> RpcResult<PayloadStatus>;

/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
///
/// Caution: This should not accept the `withdrawals` field in the payload attributes.
Expand Down Expand Up @@ -100,6 +139,45 @@ pub trait EngineApi<Engine: EngineTypes> {
payload_attributes: Option<Engine::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated>;

/// Analogous to `fork_choice_updated_v1`, but with the addition of a witness.
///
/// Caution: This should not accept the `withdrawals` field in the payload attributes.
#[method(name = "forkchoiceUpdatedWithWitnessV1")]
async fn fork_choice_updated_with_witness_v1(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<Engine::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated>;

/// Analogous to `fork_choice_updated_v2`, but with the addition of a witness.
///
/// Post Shanghai forkchoice update handler
///
/// This is the same as `forkchoiceUpdatedWithWitnessV1`, but expects an additional
/// `withdrawals` field in the `payloadAttributes`, if payload attributes are provided.
///
/// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload
/// attributes.
#[method(name = "forkchoiceUpdatedWithWitnessV2")]
async fn fork_choice_updated_with_witness_v2(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<Engine::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated>;

/// Analogous to `fork_choice_updated_v3`, but with the addition of a witness.
/// Post Cancun forkchoice update handler
///
/// This is the same as `forkchoiceUpdatedWithWitnessV2`, but expects an additional
/// `parentBeaconBlockRoot` field in the `payloadAttributes`, if payload attributes
/// are provided.
#[method(name = "forkchoiceUpdatedWithWitnessV3")]
async fn fork_choice_updated_with_witness_v3(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<Engine::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated>;

/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
///
/// Returns the most recent version of the payload that is available in the corresponding
Expand Down Expand Up @@ -217,6 +295,57 @@ pub trait EngineApi<Engine: EngineTypes> {
&self,
versioned_hashes: Vec<B256>,
) -> RpcResult<Vec<Option<BlobAndProofV1>>>;

/// Analogous to newPayloadV1.
/// This function operates in a stateless mode on top of a provided witness.
///
/// See also <https://gist.github.com/karalabe/47c906f0ab4fdc5b8b791b74f084e5f9>
///
/// Caution: This should not accept the `withdrawals` field
#[method(name = "executeStatelessPayloadV1")]
async fn execute_stateless_payload_v1(
&self,
payload: ExecutionPayloadV1,
) -> RpcResult<PayloadStatus>;

/// Analogous to newPayloadV2.
/// This function operates in a stateless mode on top of a provided witness.
///
/// See also <https://gist.github.com/karalabe/47c906f0ab4fdc5b8b791b74f084e5f9>
#[method(name = "executeStatelessPayloadV2")]
async fn execute_stateless_payload_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> RpcResult<PayloadStatus>;

/// Analogous to newPayloadV3.
/// This function operates in a stateless mode on top of a provided witness.
///
/// See also <https://gist.github.com/karalabe/47c906f0ab4fdc5b8b791b74f084e5f9>
///
/// Post Cancun payload handler
#[method(name = "executeStatelessPayloadV3")]
async fn execute_stateless_payload_v3(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> RpcResult<PayloadStatus>;
Comment on lines +327 to +333
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this different from the existing payloadv3 function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it is same as new_payload_vx methods rn. I have a question about the scope of this PR: It seems new structs need to be defined(as I mentioned at alloy#12766), so I planned to touch the function signature after those structs are ready(I'm happy to be assigned to that issue also).
Is there any good way to note that this method is not yet implemented? Or could you elaborate the scope more if I understood wrong?


/// Analogous to newPayloadV4.
/// This function operates in a stateless mode on top of a provided witness.
///
/// See also <https://gist.github.com/karalabe/47c906f0ab4fdc5b8b791b74f084e5f9>
///
/// Post Prague payload handler
#[method(name = "executeStatelessPayloadV4")]
async fn execute_stateless_payload_v4(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> RpcResult<PayloadStatus>;
Comment on lines +340 to +348
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function no longer exists

}

/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation/>
Expand Down
152 changes: 147 additions & 5 deletions crates/rpc/rpc-engine-api/src/engine_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ where
return Err(EngineApiError::TerminalTD {
execution: merge_terminal_td,
consensus: terminal_total_difficulty,
})
});
}

self.inner.beacon_consensus.transition_configuration_exchanged();
Expand All @@ -637,7 +637,7 @@ where
return Ok(TransitionConfiguration {
terminal_total_difficulty: merge_terminal_td,
..Default::default()
})
});
}

// Attempt to look up terminal block hash
Expand Down Expand Up @@ -705,9 +705,9 @@ where
// TODO: decide if we want this branch - the FCU INVALID response might be more
// useful than the payload attributes INVALID response
if fcu_res.is_invalid() {
return Ok(fcu_res)
return Ok(fcu_res);
}
return Err(err.into())
return Err(err.into());
}
}

Expand Down Expand Up @@ -796,6 +796,55 @@ where
.await?)
}

/// Handler for `engine_newPayloadWithWitnessV1`
/// Caution: This should not accept the `withdrawals` field
async fn new_payload_with_witness_v1(
&self,
payload: ExecutionPayloadV1,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_newPayloadWithWitnessV1");
Ok(self.new_payload_v1_metered(payload).await?)
}

/// Handler for `engine_newPayloadWithWitnessV2`
async fn new_payload_with_witness_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_newPayloadWithWitnessV2");
Ok(self.new_payload_v2_metered(payload).await?)
}

/// Handler for `engine_newPayloadWithWitnessV3`
async fn new_payload_with_witness_v3(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_newPayloadWithWitnessV3");
Ok(self.new_payload_v3_metered(payload, versioned_hashes, parent_beacon_block_root).await?)
}

/// Handler for `engine_newPayloadWithWitnessV4`
async fn new_payload_with_witness_v4(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_newPayloadWithWitnessV4");
Ok(self
.new_payload_v4_metered(
payload,
versioned_hashes,
parent_beacon_block_root,
execution_requests,
)
.await?)
}

/// Handler for `engine_forkchoiceUpdatedV1`
/// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/paris.md#engine_forkchoiceupdatedv1>
///
Expand Down Expand Up @@ -844,6 +893,50 @@ where
Ok(res?)
}

/// Handler for `engine_forkchoiceUpdatedWithWitnessV1`
///
/// Caution: This should not accept the `withdrawals` field
async fn fork_choice_updated_with_witness_v1(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<EngineT::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated> {
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedWithWitnessV1");
let start = Instant::now();
let res = Self::fork_choice_updated_v1(self, fork_choice_state, payload_attributes).await;
self.inner.metrics.latency.fork_choice_updated_v1.record(start.elapsed());
self.inner.metrics.fcu_response.update_response_metrics(&res);
Ok(res?)
}

/// Handler for `engine_forkchoiceUpdatedWithWitnessV2`
async fn fork_choice_updated_with_witness_v2(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<EngineT::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated> {
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedWithWitnessV2");
let start = Instant::now();
let res = Self::fork_choice_updated_v2(self, fork_choice_state, payload_attributes).await;
self.inner.metrics.latency.fork_choice_updated_v2.record(start.elapsed());
self.inner.metrics.fcu_response.update_response_metrics(&res);
Ok(res?)
}

/// Handler for `engine_forkchoiceUpdatedWithWitnessV3`
async fn fork_choice_updated_with_witness_v3(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<EngineT::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated> {
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedWithWitnessV3");
let start = Instant::now();
let res = Self::fork_choice_updated_v3(self, fork_choice_state, payload_attributes).await;
self.inner.metrics.latency.fork_choice_updated_v3.record(start.elapsed());
self.inner.metrics.fcu_response.update_response_metrics(&res);
Ok(res?)
}

/// Handler for `engine_getPayloadV1`
///
/// Returns the most recent version of the payload that is available in the corresponding
Expand Down Expand Up @@ -1005,7 +1098,7 @@ where
) -> RpcResult<Vec<Option<BlobAndProofV1>>> {
trace!(target: "rpc::engine", "Serving engine_getBlobsV1");
if versioned_hashes.len() > MAX_BLOB_LIMIT {
return Err(EngineApiError::BlobRequestTooLarge { len: versioned_hashes.len() }.into())
return Err(EngineApiError::BlobRequestTooLarge { len: versioned_hashes.len() }.into());
}

Ok(self
Expand All @@ -1014,6 +1107,55 @@ where
.get_blobs_for_versioned_hashes(&versioned_hashes)
.map_err(|err| EngineApiError::Internal(Box::new(err)))?)
}

/// Handler for `engine_executeStatelessPayloadV1`
/// Caution: This should not accept the `withdrawals` field
async fn execute_stateless_payload_v1(
&self,
payload: ExecutionPayloadV1,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_executeStatelessPayloadV1");
Ok(self.new_payload_v1_metered(payload).await?)
}

/// Handler for `engine_executeStatelessPayloadV2`
async fn execute_stateless_payload_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_executeStatelessPayloadV2");
Ok(self.new_payload_v2_metered(payload).await?)
}

/// Handler for `engine_executeStatelessPayloadV3`
async fn execute_stateless_payload_v3(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_executeStatelessPayloadV3");
Ok(self.new_payload_v3_metered(payload, versioned_hashes, parent_beacon_block_root).await?)
}

/// Handler for `engine_executeStatelessPayloadV4`
async fn execute_stateless_payload_v4(
&self,
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_executeStatelessPayloadV4");
Ok(self
.new_payload_v4_metered(
payload,
versioned_hashes,
parent_beacon_block_root,
execution_requests,
)
.await?)
}
}

impl<Provider, EngineT, Pool, Validator, ChainSpec> std::fmt::Debug
Expand Down
Loading