Skip to content

Commit

Permalink
feat: add version_specific_fields method to EngineTypes (#6050)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rjected authored Jan 15, 2024
1 parent 685d1c5 commit 9d65a4c
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 21 deletions.
1 change: 1 addition & 0 deletions bin/reth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ optimism = [
"reth-optimism-payload-builder/optimism",
"reth-ethereum-payload-builder/optimism",
"reth-node-api/optimism",
"reth-node-builder/optimism",
]

# no-op feature flag for switching between the `optimism` and default functionality in CI matrices
Expand Down
2 changes: 1 addition & 1 deletion crates/node-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ serde.workspace = true
reth-payload-builder.workspace = true

[features]
optimism = []
optimism = []
85 changes: 82 additions & 3 deletions crates/node-api/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! ```no_run
//! # use reth_rpc_types::engine::{PayloadAttributes as EthPayloadAttributes, PayloadId, Withdrawal};
//! # use reth_primitives::{B256, ChainSpec, Address};
//! # use reth_node_api::{EngineTypes, EngineApiMessageVersion, validate_version_specific_fields, AttributesValidationError, PayloadAttributes, PayloadBuilderAttributes};
//! # use reth_node_api::{EngineTypes, EngineApiMessageVersion, validate_version_specific_fields, AttributesValidationError, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes};
//! # use reth_payload_builder::{EthPayloadBuilderAttributes, EthBuiltPayload};
//! # use serde::{Deserialize, Serialize};
//! # use thiserror::Error;
Expand Down Expand Up @@ -58,7 +58,7 @@
//! chain_spec: &ChainSpec,
//! version: EngineApiMessageVersion,
//! ) -> Result<(), AttributesValidationError> {
//! validate_version_specific_fields(chain_spec, version, &self.into())?;
//! validate_version_specific_fields(chain_spec, version, self.into())?;
//!
//! // custom validation logic - ensure that the custom field is not zero
//! if self.custom == 0 {
Expand Down Expand Up @@ -122,6 +122,14 @@
//! type PayloadAttributes = CustomPayloadAttributes;
//! type PayloadBuilderAttributes = CustomPayloadBuilderAttributes;
//! type BuiltPayload = EthBuiltPayload;
//!
//! fn validate_version_specific_fields(
//! chain_spec: &ChainSpec,
//! version: EngineApiMessageVersion,
//! payload_or_attrs: PayloadOrAttributes<'_, CustomPayloadAttributes>,
//! ) -> Result<(), AttributesValidationError> {
//! validate_version_specific_fields(chain_spec, version, payload_or_attrs)
//! }
//! }
//! ```
Expand Down Expand Up @@ -152,6 +160,14 @@ pub trait EngineTypes: Send + Sync {

/// The built payload type.
type BuiltPayload: BuiltPayload + Clone + Unpin;

/// Validates the presence or exclusion of fork-specific fields based on the payload attributes
/// and the message version.
fn validate_version_specific_fields(
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, Self::PayloadAttributes>,
) -> Result<(), AttributesValidationError>;
}

/// Validates the timestamp depending on the version called:
Expand Down Expand Up @@ -198,6 +214,44 @@ pub fn validate_payload_timestamp(
Ok(())
}

#[cfg(feature = "optimism")]
/// Validates the presence of the `withdrawals` field according to the payload timestamp.
///
/// After Canyon, withdrawals field must be [Some].
/// Before Canyon, withdrawals field must be [None];
///
/// Canyon activates the Shanghai EIPs, see the Canyon specs for more details:
/// <https://github.com/ethereum-optimism/optimism/blob/ab926c5fd1e55b5c864341c44842d6d1ca679d99/specs/superchain-upgrades.md#canyon>
pub fn optimism_validate_withdrawals_presence(
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
timestamp: u64,
has_withdrawals: bool,
) -> Result<(), AttributesValidationError> {
let is_shanghai = chain_spec.fork(Hardfork::Canyon).active_at_timestamp(timestamp);

match version {
EngineApiMessageVersion::V1 => {
if has_withdrawals {
return Err(AttributesValidationError::WithdrawalsNotSupportedInV1)
}
if is_shanghai {
return Err(AttributesValidationError::NoWithdrawalsPostShanghai)
}
}
EngineApiMessageVersion::V2 | EngineApiMessageVersion::V3 => {
if is_shanghai && !has_withdrawals {
return Err(AttributesValidationError::NoWithdrawalsPostShanghai)
}
if !is_shanghai && has_withdrawals {
return Err(AttributesValidationError::HasWithdrawalsPreShanghai)
}
}
};

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];
Expand Down Expand Up @@ -290,7 +344,7 @@ pub fn validate_parent_beacon_block_root_presence(
pub fn validate_version_specific_fields<Type>(
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
payload_or_attrs: &PayloadOrAttributes<'_, Type>,
payload_or_attrs: PayloadOrAttributes<'_, Type>,
) -> Result<(), AttributesValidationError>
where
Type: PayloadAttributes,
Expand All @@ -309,6 +363,31 @@ where
)
}

#[cfg(feature = "optimism")]
/// Validates the presence or exclusion of fork-specific fields based on the payload attributes
/// and the message version.
pub fn optimism_validate_version_specific_fields<Type>(
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, Type>,
) -> Result<(), AttributesValidationError>
where
Type: PayloadAttributes,
{
optimism_validate_withdrawals_presence(
chain_spec,
version,
payload_or_attrs.timestamp(),
payload_or_attrs.withdrawals().is_some(),
)?;
validate_parent_beacon_block_root_presence(
chain_spec,
version,
payload_or_attrs.timestamp(),
payload_or_attrs.parent_beacon_block_root().is_some(),
)
}

/// The version of Engine API message.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EngineApiMessageVersion {
Expand Down
4 changes: 2 additions & 2 deletions crates/node-api/src/engine/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl PayloadAttributes for EthPayloadAttributes {
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
) -> Result<(), AttributesValidationError> {
validate_version_specific_fields(chain_spec, version, &self.into())
validate_version_specific_fields(chain_spec, version, self.into())
}
}

Expand All @@ -202,7 +202,7 @@ impl PayloadAttributes for OptimismPayloadAttributes {
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
) -> Result<(), AttributesValidationError> {
validate_version_specific_fields(chain_spec, version, &self.into())?;
validate_version_specific_fields(chain_spec, version, self.into())?;

if self.gas_limit.is_none() && chain_spec.is_optimism() {
return Err(AttributesValidationError::InvalidParams(
Expand Down
2 changes: 2 additions & 0 deletions crates/node-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
///
/// Notably contains the [EngineTypes] trait and implementations for ethereum mainnet types.
pub mod engine;
#[cfg(feature = "optimism")]
pub use engine::optimism_validate_version_specific_fields;
pub use engine::{
validate_payload_timestamp, validate_version_specific_fields, validate_withdrawals_presence,
AttributesValidationError, BuiltPayload, EngineApiMessageVersion, EngineTypes,
Expand Down
3 changes: 3 additions & 0 deletions crates/node-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ reth-node-api.workspace = true

# io
serde.workspace = true

[features]
optimism = ["reth-node-api/optimism"]
37 changes: 32 additions & 5 deletions crates/node-builder/src/engine.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,54 @@
use reth_node_api::EngineTypes;
use reth_payload_builder::{
EthBuiltPayload, EthPayloadBuilderAttributes, OptimismPayloadBuilderAttributes,
#[cfg(feature = "optimism")]
use reth_node_api::optimism_validate_version_specific_fields;
use reth_node_api::{
validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion,
EngineTypes, PayloadOrAttributes,
};
use reth_rpc_types::engine::{OptimismPayloadAttributes, PayloadAttributes};
#[cfg(feature = "optimism")]
use reth_payload_builder::OptimismPayloadBuilderAttributes;
use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes};
use reth_primitives::ChainSpec;
#[cfg(feature = "optimism")]
use reth_rpc_types::engine::OptimismPayloadAttributes;
use reth_rpc_types::engine::PayloadAttributes as EthPayloadAttributes;

/// The types used in the default mainnet ethereum beacon consensus engine.
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct EthEngineTypes;

impl EngineTypes for EthEngineTypes {
type PayloadAttributes = PayloadAttributes;
type PayloadAttributes = EthPayloadAttributes;
type PayloadBuilderAttributes = EthPayloadBuilderAttributes;
type BuiltPayload = EthBuiltPayload;

fn validate_version_specific_fields(
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, EthPayloadAttributes>,
) -> Result<(), AttributesValidationError> {
validate_version_specific_fields(chain_spec, version, payload_or_attrs)
}
}

#[cfg(feature = "optimism")]
/// The types used in the optimism beacon consensus engine.
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct OptimismEngineTypes;

// TODO: remove cfg once Hardfork::Canyon can be used without the flag
#[cfg(feature = "optimism")]
impl EngineTypes for OptimismEngineTypes {
type PayloadAttributes = OptimismPayloadAttributes;
type PayloadBuilderAttributes = OptimismPayloadBuilderAttributes;
type BuiltPayload = EthBuiltPayload;

fn validate_version_specific_fields(
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, OptimismPayloadAttributes>,
) -> Result<(), AttributesValidationError> {
optimism_validate_version_specific_fields(chain_spec, version, payload_or_attrs)
}
}
5 changes: 4 additions & 1 deletion crates/node-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@
/// Exports commonly used concrete instances of the [EngineTypes](reth_node_api::EngineTypes)
/// trait.
pub mod engine;
pub use engine::{EthEngineTypes, OptimismEngineTypes};
pub use engine::EthEngineTypes;

#[cfg(feature = "optimism")]
pub use engine::OptimismEngineTypes;
17 changes: 8 additions & 9 deletions crates/rpc/rpc-engine-api/src/engine_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use jsonrpsee_core::RpcResult;
use reth_beacon_consensus::BeaconConsensusEngineHandle;
use reth_interfaces::consensus::ForkchoiceState;
use reth_node_api::{
validate_payload_timestamp, validate_version_specific_fields, BuiltPayload,
EngineApiMessageVersion, EngineTypes, PayloadAttributes, PayloadBuilderAttributes,
PayloadOrAttributes,
validate_payload_timestamp, BuiltPayload, EngineApiMessageVersion, EngineTypes,
PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes,
};
use reth_payload_builder::PayloadStore;
use reth_primitives::{BlockHash, BlockHashOrNumber, BlockNumber, ChainSpec, Hardfork, B256, U64};
Expand Down Expand Up @@ -100,10 +99,10 @@ where
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
validate_version_specific_fields(
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V1,
&payload_or_attrs,
payload_or_attrs,
)?;
Ok(self.inner.beacon_consensus.new_payload(payload, None).await?)
}
Expand All @@ -118,10 +117,10 @@ where
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
validate_version_specific_fields(
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V2,
&payload_or_attrs,
payload_or_attrs,
)?;
Ok(self.inner.beacon_consensus.new_payload(payload, None).await?)
}
Expand All @@ -139,10 +138,10 @@ where
&payload,
Some(parent_beacon_block_root),
);
validate_version_specific_fields(
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V3,
&payload_or_attrs,
payload_or_attrs,
)?;

let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root };
Expand Down

0 comments on commit 9d65a4c

Please sign in to comment.