use reth_chainspec::{ChainSpec, OptimismHardfork}; use reth_node_api::{ payload::{ validate_parent_beacon_block_root_presence, EngineApiMessageVersion, EngineObjectValidationError, MessageValidationKind, PayloadOrAttributes, PayloadTypes, VersionSpecificValidationError, }, EngineTypes, }; use reth_optimism_payload_builder::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes}; use reth_rpc_types::{ engine::{ ExecutionPayloadEnvelopeV2, OptimismExecutionPayloadEnvelopeV3, OptimismExecutionPayloadEnvelopeV4, OptimismPayloadAttributes, }, ExecutionPayloadV1, }; /// The types used in the optimism beacon consensus engine. #[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)] #[non_exhaustive] pub struct OptimismEngineTypes; impl PayloadTypes for OptimismEngineTypes { type BuiltPayload = OptimismBuiltPayload; type PayloadAttributes = OptimismPayloadAttributes; type PayloadBuilderAttributes = OptimismPayloadBuilderAttributes; } impl EngineTypes for OptimismEngineTypes { type ExecutionPayloadV1 = ExecutionPayloadV1; type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; type ExecutionPayloadV3 = OptimismExecutionPayloadEnvelopeV3; type ExecutionPayloadV4 = OptimismExecutionPayloadEnvelopeV4; fn validate_version_specific_fields( chain_spec: &ChainSpec, version: EngineApiMessageVersion, payload_or_attrs: PayloadOrAttributes<'_, Self::PayloadAttributes>, ) -> Result<(), EngineObjectValidationError> { validate_withdrawals_presence( chain_spec, version, payload_or_attrs.message_validation_kind(), payload_or_attrs.timestamp(), payload_or_attrs.withdrawals().is_some(), )?; validate_parent_beacon_block_root_presence( chain_spec, version, payload_or_attrs.message_validation_kind(), payload_or_attrs.timestamp(), payload_or_attrs.parent_beacon_block_root().is_some(), ) } } /// 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: /// pub fn validate_withdrawals_presence( chain_spec: &ChainSpec, version: EngineApiMessageVersion, message_validation_kind: MessageValidationKind, timestamp: u64, has_withdrawals: bool, ) -> Result<(), EngineObjectValidationError> { let is_shanghai = chain_spec.fork(OptimismHardfork::Canyon).active_at_timestamp(timestamp); match version { EngineApiMessageVersion::V1 => { if has_withdrawals { return Err(message_validation_kind .to_error(VersionSpecificValidationError::WithdrawalsNotSupportedInV1)) } if is_shanghai { return Err(message_validation_kind .to_error(VersionSpecificValidationError::NoWithdrawalsPostShanghai)) } } EngineApiMessageVersion::V2 | EngineApiMessageVersion::V3 | EngineApiMessageVersion::V4 => { if is_shanghai && !has_withdrawals { return Err(message_validation_kind .to_error(VersionSpecificValidationError::NoWithdrawalsPostShanghai)) } if !is_shanghai && has_withdrawals { return Err(message_validation_kind .to_error(VersionSpecificValidationError::HasWithdrawalsPreShanghai)) } } }; Ok(()) }