From f03e7e02f7654cabe541b7944a6dfeb5b85e9c78 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 20 Feb 2025 12:45:34 +0100 Subject: [PATCH] chore(payload): Custom `PayloadError` variant (#14607) --- crates/engine/primitives/src/lib.rs | 6 +-- crates/ethereum/engine-primitives/src/lib.rs | 8 ++-- crates/optimism/node/src/engine.rs | 10 ++--- crates/payload/primitives/src/error.rs | 44 +++++++++++++++++++- crates/payload/primitives/src/lib.rs | 4 +- crates/rpc/rpc/src/validation.rs | 5 ++- examples/custom-engine-types/src/main.rs | 12 +++--- 7 files changed, 64 insertions(+), 25 deletions(-) diff --git a/crates/engine/primitives/src/lib.rs b/crates/engine/primitives/src/lib.rs index 1aac9398d..ed67a491c 100644 --- a/crates/engine/primitives/src/lib.rs +++ b/crates/engine/primitives/src/lib.rs @@ -14,11 +14,11 @@ extern crate alloc; use alloy_consensus::BlockHeader; use alloy_eips::eip7685::Requests; use alloy_primitives::B256; -use alloy_rpc_types_engine::{ExecutionData, PayloadError}; +use alloy_rpc_types_engine::ExecutionData; use core::fmt::{self, Debug}; use reth_payload_primitives::{ validate_execution_requests, BuiltPayload, EngineApiMessageVersion, - EngineObjectValidationError, InvalidPayloadAttributesError, PayloadAttributes, + EngineObjectValidationError, InvalidPayloadAttributesError, NewPayloadError, PayloadAttributes, PayloadOrAttributes, PayloadTypes, }; use reth_primitives::{NodePrimitives, SealedBlock}; @@ -145,7 +145,7 @@ pub trait PayloadValidator: fmt::Debug + Send + Sync + Unpin + 'static { fn ensure_well_formed_payload( &self, payload: Self::ExecutionData, - ) -> Result, PayloadError>; + ) -> Result, NewPayloadError>; } /// Type that validates the payloads processed by the engine. diff --git a/crates/ethereum/engine-primitives/src/lib.rs b/crates/ethereum/engine-primitives/src/lib.rs index 39644fed0..a8eec97bd 100644 --- a/crates/ethereum/engine-primitives/src/lib.rs +++ b/crates/ethereum/engine-primitives/src/lib.rs @@ -13,7 +13,7 @@ extern crate alloc; mod payload; use alloc::sync::Arc; -use alloy_rpc_types_engine::{ExecutionData, ExecutionPayload, PayloadError}; +use alloy_rpc_types_engine::{ExecutionData, ExecutionPayload}; pub use alloy_rpc_types_engine::{ ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, ExecutionPayloadV1, PayloadAttributes as EthPayloadAttributes, @@ -23,7 +23,7 @@ use reth_chainspec::ChainSpec; use reth_engine_primitives::{EngineTypes, EngineValidator, PayloadValidator}; use reth_payload_primitives::{ validate_version_specific_fields, BuiltPayload, EngineApiMessageVersion, - EngineObjectValidationError, PayloadOrAttributes, PayloadTypes, + EngineObjectValidationError, NewPayloadError, PayloadOrAttributes, PayloadTypes, }; use reth_payload_validator::ExecutionPayloadValidator; use reth_primitives::{Block, NodePrimitives, SealedBlock}; @@ -104,8 +104,8 @@ impl PayloadValidator for EthereumEngineValidator { fn ensure_well_formed_payload( &self, payload: ExecutionData, - ) -> Result { - self.inner.ensure_well_formed_payload(payload) + ) -> Result { + Ok(self.inner.ensure_well_formed_payload(payload)?) } } diff --git a/crates/optimism/node/src/engine.rs b/crates/optimism/node/src/engine.rs index e7cff087d..9fb9fc3c5 100644 --- a/crates/optimism/node/src/engine.rs +++ b/crates/optimism/node/src/engine.rs @@ -1,5 +1,5 @@ use alloy_rpc_types_engine::{ - ExecutionData, ExecutionPayload, ExecutionPayloadEnvelopeV2, ExecutionPayloadV1, PayloadError, + ExecutionData, ExecutionPayload, ExecutionPayloadEnvelopeV2, ExecutionPayloadV1, }; use op_alloy_rpc_types_engine::{ OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, OpPayloadAttributes, @@ -8,8 +8,8 @@ use reth_chainspec::ChainSpec; use reth_node_api::{ payload::{ validate_parent_beacon_block_root_presence, EngineApiMessageVersion, - EngineObjectValidationError, MessageValidationKind, PayloadOrAttributes, PayloadTypes, - VersionSpecificValidationError, + EngineObjectValidationError, MessageValidationKind, NewPayloadError, PayloadOrAttributes, + PayloadTypes, VersionSpecificValidationError, }, validate_version_specific_fields, BuiltPayload, EngineTypes, EngineValidator, NodePrimitives, PayloadValidator, @@ -97,8 +97,8 @@ impl PayloadValidator for OpEngineValidator { fn ensure_well_formed_payload( &self, payload: ExecutionData, - ) -> Result, PayloadError> { - self.inner.ensure_well_formed_payload(payload) + ) -> Result, NewPayloadError> { + Ok(self.inner.ensure_well_formed_payload(payload)?) } } diff --git a/crates/payload/primitives/src/error.rs b/crates/payload/primitives/src/error.rs index 5465c02f9..c1dc3c442 100644 --- a/crates/payload/primitives/src/error.rs +++ b/crates/payload/primitives/src/error.rs @@ -1,8 +1,9 @@ //! Error types emitted by types or implementations of this crate. -use alloc::boxed::Box; +use alloc::{boxed::Box, string::ToString}; use alloy_primitives::B256; -use alloy_rpc_types_engine::ForkchoiceUpdateError; +use alloy_rpc_types_engine::{ForkchoiceUpdateError, PayloadError, PayloadStatusEnum}; +use core::error; use reth_errors::{ProviderError, RethError}; use tokio::sync::oneshot; @@ -115,6 +116,45 @@ pub enum VersionSpecificValidationError { NoParentBeaconBlockRootPostCancun, } +/// Error validating payload received over `newPayload` API. +#[derive(thiserror::Error, Debug)] +pub enum NewPayloadError { + /// Payload validation error. + #[error(transparent)] + Eth(#[from] PayloadError), + /// Custom payload validation error. + #[error(transparent)] + Other(Box), +} + +impl NewPayloadError { + /// Creates instance of variant [`NewPayloadError::Other`]. + #[inline] + pub const fn other(err: Box) -> Self { + Self::Other(err) + } +} + +impl NewPayloadError { + /// Returns `true` if the error is caused by a block hash mismatch. + #[inline] + pub const fn is_block_hash_mismatch(&self) -> bool { + matches!(self, Self::Eth(PayloadError::BlockHash { .. })) + } + + /// Returns `true` if the error is caused by invalid block hashes (Cancun). + #[inline] + pub const fn is_invalid_versioned_hashes(&self) -> bool { + matches!(self, Self::Eth(PayloadError::InvalidVersionedHashes)) + } +} + +impl From for PayloadStatusEnum { + fn from(error: NewPayloadError) -> Self { + Self::Invalid { validation_error: error.to_string() } + } +} + impl EngineObjectValidationError { /// Creates an instance of the `InvalidParams` variant with the given error. pub fn invalid_params(error: E) -> Self diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 03a44dabd..69fda0bf8 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -17,8 +17,8 @@ use reth_chainspec::EthereumHardforks; mod error; pub use error::{ - EngineObjectValidationError, InvalidPayloadAttributesError, PayloadBuilderError, - VersionSpecificValidationError, + EngineObjectValidationError, InvalidPayloadAttributesError, NewPayloadError, + PayloadBuilderError, VersionSpecificValidationError, }; /// Contains traits to abstract over payload attributes types and default implementations of the diff --git a/crates/rpc/rpc/src/validation.rs b/crates/rpc/rpc/src/validation.rs index 5c58a6056..d1791984d 100644 --- a/crates/rpc/rpc/src/validation.rs +++ b/crates/rpc/rpc/src/validation.rs @@ -8,7 +8,7 @@ use alloy_rpc_types_beacon::relay::{ }; use alloy_rpc_types_engine::{ BlobsBundleV1, CancunPayloadFields, ExecutionData, ExecutionPayload, ExecutionPayloadSidecar, - PayloadError, PraguePayloadFields, + PraguePayloadFields, }; use async_trait::async_trait; use jsonrpsee::core::RpcResult; @@ -18,6 +18,7 @@ use reth_engine_primitives::PayloadValidator; use reth_errors::{BlockExecutionError, ConsensusError, ProviderError}; use reth_evm::execute::{BlockExecutorProvider, Executor}; use reth_metrics::{metrics, metrics::Gauge, Metrics}; +use reth_node_api::NewPayloadError; use reth_primitives::{GotExpected, NodePrimitives, RecoveredBlock}; use reth_primitives_traits::{ constants::GAS_LIMIT_BOUND_DIVISOR, BlockBody, SealedBlock, SealedHeaderFor, @@ -555,7 +556,7 @@ pub enum ValidationApiError { #[error(transparent)] Execution(#[from] BlockExecutionError), #[error(transparent)] - Payload(#[from] PayloadError), + Payload(#[from] NewPayloadError), } /// Metrics for the validation endpoint. diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index faf62260e..50bc60f80 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -40,10 +40,7 @@ use reth::{ payload::ExecutionPayloadValidator, primitives::{Block, EthPrimitives, SealedBlock, TransactionSigned}, providers::{EthStorage, StateProviderFactory}, - rpc::{ - eth::EthApi, - types::engine::{ExecutionPayload, PayloadError}, - }, + rpc::{eth::EthApi, types::engine::ExecutionPayload}, tasks::TaskManager, transaction_pool::{PoolTransaction, TransactionPool}, version::default_extra_data_bytes, @@ -55,7 +52,8 @@ use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_node_api::{ payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes}, validate_version_specific_fields, AddOnsContext, EngineTypes, EngineValidator, - FullNodeComponents, PayloadAttributes, PayloadBuilderAttributes, PayloadValidator, + FullNodeComponents, NewPayloadError, PayloadAttributes, PayloadBuilderAttributes, + PayloadValidator, }; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_ethereum::{ @@ -207,8 +205,8 @@ impl PayloadValidator for CustomEngineValidator { fn ensure_well_formed_payload( &self, payload: ExecutionData, - ) -> Result, PayloadError> { - self.inner.ensure_well_formed_payload(payload) + ) -> Result, NewPayloadError> { + Ok(self.inner.ensure_well_formed_payload(payload)?) } }