From f98b1524bba6ef3e48fbd421eb540ef363db8b27 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 27 Jul 2023 10:15:24 +0200 Subject: [PATCH] feat: add fcu v3 skeleton (#3940) --- crates/consensus/beacon/src/engine/message.rs | 1 + crates/rpc/rpc-api/src/engine.rs | 18 ++++++++++ crates/rpc/rpc-engine-api/src/engine_api.rs | 33 ++++++++++++++++++- crates/rpc/rpc-engine-api/src/message.rs | 6 ++++ .../rpc/rpc-types/src/eth/engine/payload.rs | 19 +++++++---- 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/crates/consensus/beacon/src/engine/message.rs b/crates/consensus/beacon/src/engine/message.rs index 2e5e542aab17..76808558595f 100644 --- a/crates/consensus/beacon/src/engine/message.rs +++ b/crates/consensus/beacon/src/engine/message.rs @@ -145,6 +145,7 @@ impl Future for PendingPayloadId { /// A message for the beacon engine from other components of the node (engine RPC API invoked by the /// consensus layer). #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum BeaconEngineMessage { /// Message with new payload. NewPayload { diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index 65b5039965ac..9905957e91da 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -50,6 +50,16 @@ pub trait EngineApi { payload_attributes: Option, ) -> RpcResult; + /// Same as `forkchoiceUpdatedV2` but supports additional [PayloadAttributes] field. + /// + /// See also + #[method(name = "forkchoiceUpdatedV3")] + async fn fork_choice_updated_v3( + &self, + fork_choice_state: ForkchoiceState, + payload_attributes: Option, + ) -> RpcResult; + /// See also /// /// Returns the most recent version of the payload that is available in the corresponding @@ -72,6 +82,8 @@ pub trait EngineApi { /// Post Cancun payload handler which also returns a blobs bundle. /// + /// See also + /// /// Returns the most recent version of the payload that is available in the corresponding /// payload build process at the time of receiving this call. Note: /// > Provider software MAY stop the corresponding build process after serving this call. @@ -105,6 +117,12 @@ pub trait EngineApi { ) -> RpcResult; /// See also + /// + /// Note: This method will be deprecated after the cancun hardfork: + /// + /// > Consensus and execution layer clients MAY remove support of this method after Cancun. If + /// > no longer supported, this method MUST be removed from the engine_exchangeCapabilities + /// > request or response list depending on whether it is consensus or execution layer client. #[method(name = "exchangeTransitionConfigurationV1")] async fn exchange_transition_configuration( &self, diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 5cb0b9bedac2..56ddc71cdf90 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -130,6 +130,26 @@ where Ok(self.inner.beacon_consensus.fork_choice_updated(state, payload_attrs).await?) } + /// Sends a message to the beacon consensus engine to update the fork choice _with_ withdrawals, + /// but only _after_ cancun. + /// + /// See also + pub async fn fork_choice_updated_v3( + &self, + state: ForkchoiceState, + payload_attrs: Option, + ) -> EngineApiResult { + if let Some(ref attrs) = payload_attrs { + self.validate_withdrawals_presence( + EngineApiMessageVersion::V3, + attrs.timestamp.as_u64(), + attrs.withdrawals.is_some(), + )?; + } + + Ok(self.inner.beacon_consensus.fork_choice_updated(state, payload_attrs).await?) + } + /// Returns the most recent version of the payload that is available in the corresponding /// payload build process at the time of receiving this call. /// @@ -321,7 +341,7 @@ where return Err(EngineApiError::NoWithdrawalsPostShanghai) } } - EngineApiMessageVersion::V2 => { + EngineApiMessageVersion::V2 | EngineApiMessageVersion::V3 => { if is_shanghai && !has_withdrawals { return Err(EngineApiError::NoWithdrawalsPostShanghai) } @@ -388,6 +408,17 @@ where Ok(EngineApi::fork_choice_updated_v2(self, fork_choice_state, payload_attributes).await?) } + /// Handler for `engine_forkchoiceUpdatedV2` + /// + /// See also + async fn fork_choice_updated_v3( + &self, + _fork_choice_state: ForkchoiceState, + _payload_attributes: Option, + ) -> RpcResult { + Err(jsonrpsee_types::error::ErrorCode::MethodNotFound.into()) + } + /// Handler for `engine_getPayloadV1` /// /// Returns the most recent version of the payload that is available in the corresponding diff --git a/crates/rpc/rpc-engine-api/src/message.rs b/crates/rpc/rpc-engine-api/src/message.rs index 9d000ed7440f..c0d6b85d5118 100644 --- a/crates/rpc/rpc-engine-api/src/message.rs +++ b/crates/rpc/rpc-engine-api/src/message.rs @@ -4,5 +4,11 @@ pub enum EngineApiMessageVersion { /// Version 1 V1, /// Version 2 + /// + /// Added for shanghai hardfork. V2, + /// Version 3 + /// + /// Added for cancun hardfork. + V3, } diff --git a/crates/rpc/rpc-types/src/eth/engine/payload.rs b/crates/rpc/rpc-types/src/eth/engine/payload.rs index 6085377bee59..f187ec662a99 100644 --- a/crates/rpc/rpc-types/src/eth/engine/payload.rs +++ b/crates/rpc/rpc-types/src/eth/engine/payload.rs @@ -267,6 +267,11 @@ pub struct PayloadAttributes { /// See #[serde(default, skip_serializing_if = "Option::is_none")] pub withdrawals: Option>, + /// Root of the parent beacon block enabled with V3. + /// + /// See also + #[serde(default, skip_serializing_if = "Option::is_none")] + pub parent_beacon_block_root: Option, } /// This structure contains the result of processing a payload or fork choice update. @@ -347,25 +352,25 @@ impl From for PayloadStatusEnum { #[serde(tag = "status", rename_all = "SCREAMING_SNAKE_CASE")] pub enum PayloadStatusEnum { /// VALID is returned by the engine API in the following calls: - /// - newPayloadV1: if the payload was already known or was just validated and executed - /// - forkchoiceUpdateV1: if the chain accepted the reorg (might ignore if it's stale) + /// - newPayload: if the payload was already known or was just validated and executed + /// - forkchoiceUpdate: if the chain accepted the reorg (might ignore if it's stale) Valid, /// INVALID is returned by the engine API in the following calls: - /// - newPayloadV1: if the payload failed to execute on top of the local chain - /// - forkchoiceUpdateV1: if the new head is unknown, pre-merge, or reorg to it fails + /// - newPayload: if the payload failed to execute on top of the local chain + /// - forkchoiceUpdate: if the new head is unknown, pre-merge, or reorg to it fails Invalid { #[serde(rename = "validationError")] validation_error: String, }, /// SYNCING is returned by the engine API in the following calls: - /// - newPayloadV1: if the payload was accepted on top of an active sync - /// - forkchoiceUpdateV1: if the new head was seen before, but not part of the chain + /// - newPayload: if the payload was accepted on top of an active sync + /// - forkchoiceUpdate: if the new head was seen before, but not part of the chain Syncing, /// ACCEPTED is returned by the engine API in the following calls: - /// - newPayloadV1: if the payload was accepted, but not processed (side chain) + /// - newPayload: if the payload was accepted, but not processed (side chain) Accepted, }