feat: EngineValidator (#11144)

This commit is contained in:
Arsenii Kulikov
2024-09-24 14:23:52 +03:00
committed by GitHub
parent 73962b1eae
commit c851a1740c
18 changed files with 414 additions and 169 deletions

1
Cargo.lock generated
View File

@ -7401,6 +7401,7 @@ dependencies = [
"reth-consensus",
"reth-db",
"reth-db-common",
"reth-ethereum-engine-primitives",
"reth-evm",
"reth-execution-types",
"reth-exex",

View File

@ -31,9 +31,6 @@ pub trait EngineTypes:
+ Serialize
+ 'static
{
/// The chain specification of the node.
type ChainSpec: Send + Sync;
/// Execution Payload V1 type.
type ExecutionPayloadV1: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static;
/// Execution Payload V2 type.
@ -42,12 +39,22 @@ pub trait EngineTypes:
type ExecutionPayloadV3: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static;
/// Execution Payload V4 type.
type ExecutionPayloadV4: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static;
}
/// Type that validates the payloads sent to the engine.
pub trait EngineValidator<Types: EngineTypes>: Clone + Send + Sync + Unpin + 'static {
/// 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: &Self::ChainSpec,
&self,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, Self::PayloadAttributes>,
payload_or_attrs: PayloadOrAttributes<'_, <Types as PayloadTypes>::PayloadAttributes>,
) -> Result<(), EngineObjectValidationError>;
/// Ensures that the payload attributes are valid for the given [`EngineApiMessageVersion`].
fn ensure_well_formed_attributes(
&self,
version: EngineApiMessageVersion,
attributes: &<Types as PayloadTypes>::PayloadAttributes,
) -> Result<(), EngineObjectValidationError>;
}

View File

@ -9,9 +9,11 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
mod payload;
use std::sync::Arc;
pub use payload::{EthBuiltPayload, EthPayloadBuilderAttributes};
use reth_chainspec::ChainSpec;
use reth_engine_primitives::EngineTypes;
use reth_engine_primitives::{EngineTypes, EngineValidator};
use reth_payload_primitives::{
validate_version_specific_fields, EngineApiMessageVersion, EngineObjectValidationError,
PayloadOrAttributes, PayloadTypes,
@ -36,18 +38,42 @@ impl PayloadTypes for EthEngineTypes {
}
impl EngineTypes for EthEngineTypes {
type ChainSpec = ChainSpec;
type ExecutionPayloadV1 = ExecutionPayloadV1;
type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2;
type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3;
type ExecutionPayloadV4 = ExecutionPayloadEnvelopeV4;
}
/// Validator for the ethereum engine API.
#[derive(Debug, Clone)]
pub struct EthereumEngineValidator {
chain_spec: Arc<ChainSpec>,
}
impl EthereumEngineValidator {
/// Instantiates a new validator.
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self { chain_spec }
}
}
impl<Types> EngineValidator<Types> for EthereumEngineValidator
where
Types: EngineTypes<PayloadAttributes = EthPayloadAttributes>,
{
fn validate_version_specific_fields(
chain_spec: &ChainSpec,
&self,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, EthPayloadAttributes>,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(chain_spec, version, payload_or_attrs)
validate_version_specific_fields(&self.chain_spec, version, payload_or_attrs)
}
fn ensure_well_formed_attributes(
&self,
version: EngineApiMessageVersion,
attributes: &EthPayloadAttributes,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(&self.chain_spec, version, attributes.into())
}
}

View File

@ -7,15 +7,15 @@ use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGenera
use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec;
use reth_ethereum_engine_primitives::{
EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes,
EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes, EthereumEngineValidator,
};
use reth_evm_ethereum::execute::EthExecutorProvider;
use reth_network::NetworkHandle;
use reth_node_api::{ConfigureEvm, FullNodeComponents, NodeAddOns};
use reth_node_api::{ConfigureEvm, EngineValidator, FullNodeComponents, NodeAddOns};
use reth_node_builder::{
components::{
ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder,
PayloadServiceBuilder, PoolBuilder,
ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder,
NetworkBuilder, PayloadServiceBuilder, PoolBuilder,
},
node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine},
BuilderContext, Node, PayloadBuilderConfig, PayloadTypes,
@ -46,6 +46,7 @@ impl EthereumNode {
EthereumNetworkBuilder,
EthereumExecutorBuilder,
EthereumConsensusBuilder,
EthereumEngineValidatorBuilder,
>
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec>>,
@ -62,6 +63,7 @@ impl EthereumNode {
.network(EthereumNetworkBuilder::default())
.executor(EthereumExecutorBuilder::default())
.consensus(EthereumConsensusBuilder::default())
.engine_validator(EthereumEngineValidatorBuilder::default())
}
}
@ -94,6 +96,7 @@ where
EthereumNetworkBuilder,
EthereumExecutorBuilder,
EthereumConsensusBuilder,
EthereumEngineValidatorBuilder,
>;
type AddOns = EthereumAddOns;
@ -316,3 +319,21 @@ where
}
}
}
/// Builder for [`EthereumEngineValidator`].
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct EthereumEngineValidatorBuilder;
impl<Node, Types> EngineValidatorBuilder<Node> for EthereumEngineValidatorBuilder
where
Types: NodeTypesWithEngine<ChainSpec = ChainSpec>,
Node: FullNodeTypes<Types = Types>,
EthereumEngineValidator: EngineValidator<Types::Engine>,
{
type Validator = EthereumEngineValidator;
async fn build_validator(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Validator> {
Ok(EthereumEngineValidator::new(ctx.chain_spec()))
}
}

View File

@ -31,6 +31,7 @@ reth-primitives.workspace = true
reth-provider = { workspace = true, features = ["test-utils"] }
reth-tasks.workspace = true
reth-transaction-pool = { workspace = true, features = ["test-utils"] }
reth-ethereum-engine-primitives.workspace = true
## async
futures-util.workspace = true

View File

@ -17,6 +17,7 @@ use reth_db::{
DatabaseEnv,
};
use reth_db_common::init::init_genesis;
use reth_ethereum_engine_primitives::EthereumEngineValidator;
use reth_evm::test_utils::MockExecutorProvider;
use reth_execution_types::Chain;
use reth_exex::{ExExContext, ExExEvent, ExExNotification, ExExNotifications};
@ -33,7 +34,10 @@ use reth_node_builder::{
};
use reth_node_core::node_config::NodeConfig;
use reth_node_ethereum::{
node::{EthereumAddOns, EthereumNetworkBuilder, EthereumPayloadBuilder},
node::{
EthereumAddOns, EthereumEngineValidatorBuilder, EthereumNetworkBuilder,
EthereumPayloadBuilder,
},
EthEngineTypes, EthEvmConfig,
};
use reth_payload_builder::noop::NoopPayloadBuilderService;
@ -133,6 +137,7 @@ where
EthereumNetworkBuilder,
TestExecutorBuilder,
TestConsensusBuilder,
EthereumEngineValidatorBuilder,
>;
type AddOns = EthereumAddOns;
@ -144,6 +149,7 @@ where
.network(EthereumNetworkBuilder::default())
.executor(TestExecutorBuilder::default())
.consensus(TestConsensusBuilder::default())
.engine_validator(EthereumEngineValidatorBuilder::default())
}
}
@ -246,7 +252,7 @@ pub async fn test_exex_context_with_chain_spec(
let db = create_test_rw_db();
let provider_factory = ProviderFactory::new(
db,
chain_spec,
chain_spec.clone(),
StaticFileProvider::read_write(static_dir.into_path()).expect("static file provider"),
);
@ -266,6 +272,8 @@ pub async fn test_exex_context_with_chain_spec(
let tasks = TaskManager::current();
let task_executor = tasks.executor();
let engine_validator = EthereumEngineValidator::new(chain_spec.clone());
let components = NodeAdapter::<FullNodeTypesAdapter<NodeTypesWithDBAdapter<TestNode, _>, _>, _> {
components: Components {
transaction_pool,
@ -274,6 +282,7 @@ pub async fn test_exex_context_with_chain_spec(
consensus,
network,
payload_builder,
engine_validator,
},
task_executor,
provider,

View File

@ -4,6 +4,7 @@ use std::{future::Future, marker::PhantomData};
use reth_consensus::Consensus;
use reth_evm::execute::BlockExecutorProvider;
use reth_node_api::{EngineValidator, NodeTypesWithEngine};
use reth_primitives::Header;
use reth_transaction_pool::TransactionPool;
@ -15,6 +16,8 @@ use crate::{
BuilderContext, ConfigureEvm, FullNodeTypes,
};
use super::EngineValidatorBuilder;
/// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation.
///
/// This type is stateful and captures the configuration of the node's components.
@ -35,22 +38,23 @@ use crate::{
/// All component builders are captured in the builder state and will be consumed once the node is
/// launched.
#[derive(Debug)]
pub struct ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> {
pub struct ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB> {
pool_builder: PoolB,
payload_builder: PayloadB,
network_builder: NetworkB,
executor_builder: ExecB,
consensus_builder: ConsB,
engine_validator_builder: EVB,
_marker: PhantomData<Node>,
}
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
{
/// Configures the node types.
pub fn node_types<Types>(
self,
) -> ComponentsBuilder<Types, PoolB, PayloadB, NetworkB, ExecB, ConsB>
) -> ComponentsBuilder<Types, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
where
Types: FullNodeTypes,
{
@ -60,6 +64,7 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
} = self;
ComponentsBuilder {
@ -68,6 +73,7 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
payload_builder,
network_builder,
consensus_builder,
engine_validator_builder,
_marker: Default::default(),
}
}
@ -80,6 +86,7 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
network_builder: self.network_builder,
executor_builder: self.executor_builder,
consensus_builder: self.consensus_builder,
engine_validator_builder: self.engine_validator_builder,
_marker: self._marker,
}
}
@ -92,6 +99,7 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
network_builder: self.network_builder,
executor_builder: self.executor_builder,
consensus_builder: self.consensus_builder,
engine_validator_builder: self.engine_validator_builder,
_marker: self._marker,
}
}
@ -104,6 +112,7 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
network_builder: f(self.network_builder),
executor_builder: self.executor_builder,
consensus_builder: self.consensus_builder,
engine_validator_builder: self.engine_validator_builder,
_marker: self._marker,
}
}
@ -116,6 +125,7 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
network_builder: self.network_builder,
executor_builder: f(self.executor_builder),
consensus_builder: self.consensus_builder,
engine_validator_builder: self.engine_validator_builder,
_marker: self._marker,
}
}
@ -128,13 +138,14 @@ impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
network_builder: self.network_builder,
executor_builder: self.executor_builder,
consensus_builder: f(self.consensus_builder),
engine_validator_builder: self.engine_validator_builder,
_marker: self._marker,
}
}
}
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
where
Node: FullNodeTypes,
{
@ -145,7 +156,7 @@ where
pub fn pool<PB>(
self,
pool_builder: PB,
) -> ComponentsBuilder<Node, PB, PayloadB, NetworkB, ExecB, ConsB>
) -> ComponentsBuilder<Node, PB, PayloadB, NetworkB, ExecB, ConsB, EVB>
where
PB: PoolBuilder<Node>,
{
@ -155,6 +166,7 @@ where
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
} = self;
ComponentsBuilder {
@ -163,13 +175,14 @@ where
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
}
}
}
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
where
Node: FullNodeTypes,
PoolB: PoolBuilder<Node>,
@ -181,7 +194,7 @@ where
pub fn network<NB>(
self,
network_builder: NB,
) -> ComponentsBuilder<Node, PoolB, PayloadB, NB, ExecB, ConsB>
) -> ComponentsBuilder<Node, PoolB, PayloadB, NB, ExecB, ConsB, EVB>
where
NB: NetworkBuilder<Node, PoolB::Pool>,
{
@ -191,6 +204,7 @@ where
network_builder: _,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
} = self;
ComponentsBuilder {
@ -199,6 +213,7 @@ where
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
}
}
@ -210,7 +225,7 @@ where
pub fn payload<PB>(
self,
payload_builder: PB,
) -> ComponentsBuilder<Node, PoolB, PB, NetworkB, ExecB, ConsB>
) -> ComponentsBuilder<Node, PoolB, PB, NetworkB, ExecB, ConsB, EVB>
where
PB: PayloadServiceBuilder<Node, PoolB::Pool>,
{
@ -220,6 +235,7 @@ where
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
} = self;
ComponentsBuilder {
@ -228,6 +244,7 @@ where
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
}
}
@ -239,7 +256,7 @@ where
pub fn executor<EB>(
self,
executor_builder: EB,
) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, EB, ConsB>
) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, EB, ConsB, EVB>
where
EB: ExecutorBuilder<Node>,
{
@ -249,6 +266,7 @@ where
network_builder,
executor_builder: _,
consensus_builder,
engine_validator_builder,
_marker,
} = self;
ComponentsBuilder {
@ -257,6 +275,7 @@ where
network_builder,
executor_builder,
consensus_builder,
engine_validator_builder,
_marker,
}
}
@ -268,7 +287,7 @@ where
pub fn consensus<CB>(
self,
consensus_builder: CB,
) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, CB>
) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, CB, EVB>
where
CB: ConsensusBuilder<Node>,
{
@ -278,6 +297,7 @@ where
network_builder,
executor_builder,
consensus_builder: _,
engine_validator_builder,
_marker,
} = self;
ComponentsBuilder {
@ -286,13 +306,45 @@ where
network_builder,
executor_builder,
consensus_builder,
engine_validator_builder,
_marker,
}
}
/// Configures the consensus builder.
///
/// This accepts a [`ConsensusBuilder`] instance that will be used to create the node's
/// components for consensus.
pub fn engine_validator<EngineVB>(
self,
engine_validator_builder: EngineVB,
) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EngineVB>
where
EngineVB: EngineValidatorBuilder<Node>,
{
let Self {
pool_builder,
payload_builder,
network_builder,
executor_builder,
consensus_builder,
engine_validator_builder: _,
_marker,
} = self;
ComponentsBuilder {
pool_builder,
payload_builder,
network_builder,
executor_builder,
consensus_builder,
engine_validator_builder,
_marker,
}
}
}
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> NodeComponentsBuilder<Node>
for ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB> NodeComponentsBuilder<Node>
for ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB, EVB>
where
Node: FullNodeTypes,
PoolB: PoolBuilder<Node>,
@ -300,8 +352,16 @@ where
PayloadB: PayloadServiceBuilder<Node, PoolB::Pool>,
ExecB: ExecutorBuilder<Node>,
ConsB: ConsensusBuilder<Node>,
EVB: EngineValidatorBuilder<Node>,
{
type Components = Components<Node, PoolB::Pool, ExecB::EVM, ExecB::Executor, ConsB::Consensus>;
type Components = Components<
Node,
PoolB::Pool,
ExecB::EVM,
ExecB::Executor,
ConsB::Consensus,
EVB::Validator,
>;
async fn build_components(
self,
@ -313,6 +373,7 @@ where
network_builder,
executor_builder: evm_builder,
consensus_builder,
engine_validator_builder,
_marker,
} = self;
@ -321,6 +382,7 @@ where
let network = network_builder.build_network(context, pool.clone()).await?;
let payload_builder = payload_builder.spawn_payload_service(context, pool.clone()).await?;
let consensus = consensus_builder.build_consensus(context).await?;
let engine_validator = engine_validator_builder.build_validator(context).await?;
Ok(Components {
transaction_pool: pool,
@ -329,11 +391,12 @@ where
payload_builder,
executor,
consensus,
engine_validator,
})
}
}
impl Default for ComponentsBuilder<(), (), (), (), (), ()> {
impl Default for ComponentsBuilder<(), (), (), (), (), (), ()> {
fn default() -> Self {
Self {
pool_builder: (),
@ -341,6 +404,7 @@ impl Default for ComponentsBuilder<(), (), (), (), (), ()> {
network_builder: (),
executor_builder: (),
consensus_builder: (),
engine_validator_builder: (),
_marker: Default::default(),
}
}
@ -366,17 +430,18 @@ pub trait NodeComponentsBuilder<Node: FullNodeTypes>: Send {
) -> impl Future<Output = eyre::Result<Self::Components>> + Send;
}
impl<Node, F, Fut, Pool, EVM, Executor, Cons> NodeComponentsBuilder<Node> for F
impl<Node, F, Fut, Pool, EVM, Executor, Cons, Val> NodeComponentsBuilder<Node> for F
where
Node: FullNodeTypes,
F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
Fut: Future<Output = eyre::Result<Components<Node, Pool, EVM, Executor, Cons>>> + Send,
Fut: Future<Output = eyre::Result<Components<Node, Pool, EVM, Executor, Cons, Val>>> + Send,
Pool: TransactionPool + Unpin + 'static,
EVM: ConfigureEvm<Header = Header>,
Executor: BlockExecutorProvider,
Cons: Consensus + Clone + Unpin + 'static,
Val: EngineValidator<<Node::Types as NodeTypesWithEngine>::Engine> + Clone + Unpin + 'static,
{
type Components = Components<Node, Pool, EVM, Executor, Cons>;
type Components = Components<Node, Pool, EVM, Executor, Cons, Val>;
fn build_components(
self,

View File

@ -0,0 +1,38 @@
//! Consensus component for the node builder.
use reth_node_api::{EngineValidator, NodeTypesWithEngine};
use crate::{BuilderContext, FullNodeTypes};
use std::future::Future;
/// A type that knows how to build the engine validator.
pub trait EngineValidatorBuilder<Node: FullNodeTypes>: Send {
/// The consensus implementation to build.
type Validator: EngineValidator<<Node::Types as NodeTypesWithEngine>::Engine>
+ Clone
+ Unpin
+ 'static;
/// Creates the engine validator.
fn build_validator(
self,
ctx: &BuilderContext<Node>,
) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
}
impl<Node, F, Fut, Validator> EngineValidatorBuilder<Node> for F
where
Node: FullNodeTypes,
Validator:
EngineValidator<<Node::Types as NodeTypesWithEngine>::Engine> + Clone + Unpin + 'static,
F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
Fut: Future<Output = eyre::Result<Validator>> + Send,
{
type Validator = Validator;
fn build_validator(
self,
ctx: &BuilderContext<Node>,
) -> impl Future<Output = eyre::Result<Self::Validator>> {
self(ctx)
}
}

View File

@ -9,6 +9,7 @@
mod builder;
mod consensus;
mod engine;
mod execute;
mod network;
mod payload;
@ -16,6 +17,7 @@ mod pool;
pub use builder::*;
pub use consensus::*;
pub use engine::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
@ -25,7 +27,7 @@ use reth_consensus::Consensus;
use reth_evm::execute::BlockExecutorProvider;
use reth_network::NetworkHandle;
use reth_network_api::FullNetwork;
use reth_node_api::NodeTypesWithEngine;
use reth_node_api::{EngineValidator, NodeTypesWithEngine};
use reth_payload_builder::PayloadBuilderHandle;
use reth_primitives::Header;
use reth_transaction_pool::TransactionPool;
@ -53,6 +55,9 @@ pub trait NodeComponents<T: FullNodeTypes>: Clone + Unpin + Send + Sync + 'stati
/// Network API.
type Network: FullNetwork;
/// Validator for the engine API.
type EngineValidator: EngineValidator<<T::Types as NodeTypesWithEngine>::Engine>;
/// Returns the transaction pool of the node.
fn pool(&self) -> &Self::Pool;
@ -70,13 +75,16 @@ pub trait NodeComponents<T: FullNodeTypes>: Clone + Unpin + Send + Sync + 'stati
/// Returns the handle to the payload builder service.
fn payload_builder(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypesWithEngine>::Engine>;
/// Returns the engine validator.
fn engine_validator(&self) -> &Self::EngineValidator;
}
/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Pool, EVM, Executor, Consensus> {
pub struct Components<Node: FullNodeTypes, Pool, EVM, Executor, Consensus, Validator> {
/// The transaction pool of the node.
pub transaction_pool: Pool,
/// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
@ -89,22 +97,26 @@ pub struct Components<Node: FullNodeTypes, Pool, EVM, Executor, Consensus> {
pub network: NetworkHandle,
/// The handle to the payload builder service.
pub payload_builder: PayloadBuilderHandle<<Node::Types as NodeTypesWithEngine>::Engine>,
/// The validator for the engine API.
pub engine_validator: Validator,
}
impl<Node, Pool, EVM, Executor, Cons> NodeComponents<Node>
for Components<Node, Pool, EVM, Executor, Cons>
impl<Node, Pool, EVM, Executor, Cons, Val> NodeComponents<Node>
for Components<Node, Pool, EVM, Executor, Cons, Val>
where
Node: FullNodeTypes,
Pool: TransactionPool + Unpin + 'static,
EVM: ConfigureEvm<Header = Header>,
Executor: BlockExecutorProvider,
Cons: Consensus + Clone + Unpin + 'static,
Val: EngineValidator<<Node::Types as NodeTypesWithEngine>::Engine> + Clone + Unpin + 'static,
{
type Pool = Pool;
type Evm = EVM;
type Executor = Executor;
type Consensus = Cons;
type Network = NetworkHandle;
type EngineValidator = Val;
fn pool(&self) -> &Self::Pool {
&self.transaction_pool
@ -131,15 +143,21 @@ where
) -> &PayloadBuilderHandle<<Node::Types as NodeTypesWithEngine>::Engine> {
&self.payload_builder
}
fn engine_validator(&self) -> &Self::EngineValidator {
&self.engine_validator
}
}
impl<Node, Pool, EVM, Executor, Cons> Clone for Components<Node, Pool, EVM, Executor, Cons>
impl<Node, Pool, EVM, Executor, Cons, Val> Clone
for Components<Node, Pool, EVM, Executor, Cons, Val>
where
Node: FullNodeTypes,
Pool: TransactionPool,
EVM: ConfigureEvm<Header = Header>,
Executor: BlockExecutorProvider,
Cons: Consensus + Clone,
Val: EngineValidator<<Node::Types as NodeTypesWithEngine>::Engine>,
{
fn clone(&self) -> Self {
Self {
@ -149,6 +167,7 @@ where
consensus: self.consensus.clone(),
network: self.network.clone(),
payload_builder: self.payload_builder.clone(),
engine_validator: self.engine_validator.clone(),
}
}
}

View File

@ -275,6 +275,7 @@ where
Box::new(ctx.task_executor().clone()),
client,
EngineCapabilities::default(),
ctx.components().engine_validator().clone(),
);
info!(target: "reth::cli", "Engine API handler initialized");

View File

@ -351,6 +351,7 @@ where
Box::new(ctx.task_executor().clone()),
client,
EngineCapabilities::default(),
ctx.components().engine_validator().clone(),
);
info!(target: "reth::cli", "Engine API handler initialized");

View File

@ -39,7 +39,7 @@ pub trait NodeTypes: Send + Sync + Unpin + 'static {
/// The type that configures an Ethereum-like node with an engine for consensus.
pub trait NodeTypesWithEngine: NodeTypes {
/// The node's engine types, defining the interaction with the consensus engine.
type Engine: EngineTypes<ChainSpec = Self::ChainSpec>;
type Engine: EngineTypes;
}
/// A helper trait that is downstream of the [`NodeTypesWithEngine`] trait and adds database to the
@ -166,7 +166,7 @@ where
impl<P, E, C> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes<ChainSpec = C> + Send + Sync + Unpin,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec,
{
type Engine = E;

View File

@ -1,3 +1,5 @@
use std::sync::Arc;
use op_alloy_rpc_types_engine::{
OptimismExecutionPayloadEnvelopeV3, OptimismExecutionPayloadEnvelopeV4,
OptimismPayloadAttributes,
@ -9,7 +11,7 @@ use reth_node_api::{
EngineObjectValidationError, MessageValidationKind, PayloadOrAttributes, PayloadTypes,
VersionSpecificValidationError,
},
EngineTypes,
validate_version_specific_fields, EngineTypes, EngineValidator,
};
use reth_optimism_forks::OptimismHardfork;
use reth_optimism_payload_builder::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes};
@ -20,6 +22,19 @@ use reth_rpc_types::{engine::ExecutionPayloadEnvelopeV2, ExecutionPayloadV1};
#[non_exhaustive]
pub struct OptimismEngineTypes;
/// Validator for Optimism engine API.
#[derive(Debug, Clone)]
pub struct OptimismEngineValidator {
chain_spec: Arc<ChainSpec>,
}
impl OptimismEngineValidator {
/// Instantiates a new validator.
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self { chain_spec }
}
}
impl PayloadTypes for OptimismEngineTypes {
type BuiltPayload = OptimismBuiltPayload;
type PayloadAttributes = OptimismPayloadAttributes;
@ -27,33 +42,10 @@ impl PayloadTypes for OptimismEngineTypes {
}
impl EngineTypes for OptimismEngineTypes {
type ChainSpec = ChainSpec;
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.
@ -97,3 +89,45 @@ pub fn validate_withdrawals_presence(
Ok(())
}
impl<Types> EngineValidator<Types> for OptimismEngineValidator
where
Types: EngineTypes<PayloadAttributes = OptimismPayloadAttributes>,
{
fn validate_version_specific_fields(
&self,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, OptimismPayloadAttributes>,
) -> Result<(), EngineObjectValidationError> {
validate_withdrawals_presence(
&self.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(
&self.chain_spec,
version,
payload_or_attrs.message_validation_kind(),
payload_or_attrs.timestamp(),
payload_or_attrs.parent_beacon_block_root().is_some(),
)
}
fn ensure_well_formed_attributes(
&self,
version: EngineApiMessageVersion,
attributes: &OptimismPayloadAttributes,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(&self.chain_spec, version, attributes.into())?;
if attributes.gas_limit.is_none() {
return Err(EngineObjectValidationError::InvalidParams(
"MissingGasLimitInPayloadAttributes".to_string().into(),
))
}
Ok(())
}
}

View File

@ -7,11 +7,11 @@ use reth_chainspec::ChainSpec;
use reth_evm::ConfigureEvm;
use reth_evm_optimism::{OpExecutorProvider, OptimismEvmConfig};
use reth_network::{NetworkHandle, NetworkManager};
use reth_node_api::{FullNodeComponents, NodeAddOns};
use reth_node_api::{EngineValidator, FullNodeComponents, NodeAddOns};
use reth_node_builder::{
components::{
ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder,
PayloadServiceBuilder, PoolBuilder,
ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder,
NetworkBuilder, PayloadServiceBuilder, PoolBuilder,
},
node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine},
BuilderContext, Node, PayloadBuilderConfig,
@ -30,6 +30,7 @@ use reth_transaction_pool::{
use crate::{
args::RollupArgs,
engine::OptimismEngineValidator,
txpool::{OpTransactionPool, OpTransactionValidator},
OptimismEngineTypes,
};
@ -58,6 +59,7 @@ impl OptimismNode {
OptimismNetworkBuilder,
OptimismExecutorBuilder,
OptimismConsensusBuilder,
OptimismEngineValidatorBuilder,
>
where
Node: FullNodeTypes<
@ -75,6 +77,7 @@ impl OptimismNode {
})
.executor(OptimismExecutorBuilder::default())
.consensus(OptimismConsensusBuilder::default())
.engine_validator(OptimismEngineValidatorBuilder::default())
}
}
@ -91,6 +94,7 @@ where
OptimismNetworkBuilder,
OptimismExecutorBuilder,
OptimismConsensusBuilder,
OptimismEngineValidatorBuilder,
>;
type AddOns = OptimismAddOns;
@ -386,3 +390,21 @@ where
}
}
}
/// Builder for [`OptimismEngineValidator`].
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct OptimismEngineValidatorBuilder;
impl<Node, Types> EngineValidatorBuilder<Node> for OptimismEngineValidatorBuilder
where
Types: NodeTypesWithEngine<ChainSpec = ChainSpec>,
Node: FullNodeTypes<Types = Types>,
OptimismEngineValidator: EngineValidator<Types::Engine>,
{
type Validator = OptimismEngineValidator;
async fn build_validator(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Validator> {
Ok(OptimismEngineValidator::new(ctx.chain_spec()))
}
}

View File

@ -1,7 +1,4 @@
use crate::{
validate_version_specific_fields, EngineApiMessageVersion, EngineObjectValidationError,
PayloadBuilderError, PayloadEvents, PayloadTypes,
};
use crate::{PayloadBuilderError, PayloadEvents, PayloadTypes};
use alloy_primitives::{Address, B256, U256};
use alloy_rpc_types::{
engine::{PayloadAttributes as EthPayloadAttributes, PayloadId},
@ -9,7 +6,6 @@ use alloy_rpc_types::{
};
use op_alloy_rpc_types_engine::OptimismPayloadAttributes;
use reth_chain_state::ExecutedBlock;
use reth_chainspec::ChainSpec;
use reth_primitives::{SealedBlock, Withdrawals};
use std::{future::Future, pin::Pin};
use tokio::sync::oneshot;
@ -133,14 +129,6 @@ pub trait PayloadAttributes:
/// Return the parent beacon block root for the payload attributes.
fn parent_beacon_block_root(&self) -> Option<B256>;
/// Ensures that the payload attributes are valid for the given [`ChainSpec`] and
/// [`EngineApiMessageVersion`].
fn ensure_well_formed_attributes(
&self,
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
) -> Result<(), EngineObjectValidationError>;
}
impl PayloadAttributes for EthPayloadAttributes {
@ -155,14 +143,6 @@ impl PayloadAttributes for EthPayloadAttributes {
fn parent_beacon_block_root(&self) -> Option<B256> {
self.parent_beacon_block_root
}
fn ensure_well_formed_attributes(
&self,
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(chain_spec, version, self.into())
}
}
impl PayloadAttributes for OptimismPayloadAttributes {
@ -177,22 +157,6 @@ impl PayloadAttributes for OptimismPayloadAttributes {
fn parent_beacon_block_root(&self) -> Option<B256> {
self.payload_attributes.parent_beacon_block_root
}
fn ensure_well_formed_attributes(
&self,
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(chain_spec, version, self.into())?;
if self.gas_limit.is_none() {
return Err(EngineObjectValidationError::InvalidParams(
"MissingGasLimitInPayloadAttributes".to_string().into(),
))
}
Ok(())
}
}
/// A builder that can return the current payload attribute.

View File

@ -2,7 +2,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use reth_beacon_consensus::BeaconConsensusEngineHandle;
use reth_chainspec::MAINNET;
use reth_ethereum_engine_primitives::EthEngineTypes;
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
use reth_evm_ethereum::EthEvmConfig;
use reth_network_api::noop::NoopNetwork;
use reth_payload_builder::test_utils::spawn_test_payload_service;
@ -50,6 +50,7 @@ pub async fn launch_auth(secret: JwtSecret) -> AuthServerHandle {
Box::<TokioTaskExecutor>::default(),
client,
EngineCapabilities::default(),
EthereumEngineValidator::new(MAINNET.clone()),
);
let module = AuthRpcModule::new(engine_api);
module.start_server(config).await.unwrap()

View File

@ -7,12 +7,12 @@ use async_trait::async_trait;
use jsonrpsee_core::RpcResult;
use reth_beacon_consensus::BeaconConsensusEngineHandle;
use reth_chainspec::ChainSpec;
use reth_engine_primitives::EngineTypes;
use reth_engine_primitives::{EngineTypes, EngineValidator};
use reth_evm::provider::EvmEnvProvider;
use reth_payload_builder::PayloadStore;
use reth_payload_primitives::{
validate_payload_timestamp, EngineApiMessageVersion, PayloadAttributes,
PayloadBuilderAttributes, PayloadOrAttributes,
validate_payload_timestamp, EngineApiMessageVersion, PayloadBuilderAttributes,
PayloadOrAttributes,
};
use reth_primitives::{Block, BlockHashOrNumber, EthereumHardfork};
use reth_rpc_api::EngineApiServer;
@ -43,11 +43,11 @@ const MAX_BLOB_LIMIT: usize = 128;
/// The Engine API implementation that grants the Consensus layer access to data and
/// functions in the Execution layer that are crucial for the consensus process.
pub struct EngineApi<Provider, EngineT: EngineTypes, Pool> {
inner: Arc<EngineApiInner<Provider, EngineT, Pool>>,
pub struct EngineApi<Provider, EngineT: EngineTypes, Pool, Validator> {
inner: Arc<EngineApiInner<Provider, EngineT, Pool, Validator>>,
}
struct EngineApiInner<Provider, EngineT: EngineTypes, Pool> {
struct EngineApiInner<Provider, EngineT: EngineTypes, Pool, Validator> {
/// The provider to interact with the chain.
provider: Provider,
/// Consensus configuration
@ -66,13 +66,16 @@ struct EngineApiInner<Provider, EngineT: EngineTypes, Pool> {
capabilities: EngineCapabilities,
/// Transaction pool.
tx_pool: Pool,
/// Engine validator.
validator: Validator,
}
impl<Provider, EngineT, Pool> EngineApi<Provider, EngineT, Pool>
impl<Provider, EngineT, Pool, Validator> EngineApi<Provider, EngineT, Pool, Validator>
where
Provider: HeaderProvider + BlockReader + StateProviderFactory + EvmEnvProvider + 'static,
EngineT: EngineTypes<ChainSpec = ChainSpec>,
EngineT: EngineTypes,
Pool: TransactionPool + 'static,
Validator: EngineValidator<EngineT>,
{
/// Create new instance of [`EngineApi`].
#[allow(clippy::too_many_arguments)]
@ -85,6 +88,7 @@ where
task_spawner: Box<dyn TaskSpawner>,
client: ClientVersionV1,
capabilities: EngineCapabilities,
validator: Validator,
) -> Self {
let inner = Arc::new(EngineApiInner {
provider,
@ -96,6 +100,7 @@ where
client,
capabilities,
tx_pool,
validator,
});
Self { inner }
}
@ -131,11 +136,9 @@ where
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V1,
payload_or_attrs,
)?;
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?;
Ok(self.inner.beacon_consensus.new_payload(payload, None).await?)
}
@ -149,11 +152,9 @@ where
PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload(
&payload, None,
);
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V2,
payload_or_attrs,
)?;
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V2, payload_or_attrs)?;
Ok(self.inner.beacon_consensus.new_payload(payload, None).await?)
}
@ -170,11 +171,9 @@ where
&payload,
Some(parent_beacon_block_root),
);
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V3,
payload_or_attrs,
)?;
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V3, payload_or_attrs)?;
let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root };
@ -194,11 +193,9 @@ where
&payload,
Some(parent_beacon_block_root),
);
EngineT::validate_version_specific_fields(
&self.inner.chain_spec,
EngineApiMessageVersion::V4,
payload_or_attrs,
)?;
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V4, payload_or_attrs)?;
let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root };
@ -588,7 +585,7 @@ where
) -> EngineApiResult<ForkchoiceUpdated> {
if let Some(ref attrs) = payload_attrs {
let attr_validation_res =
attrs.ensure_well_formed_attributes(&self.inner.chain_spec, version);
self.inner.validator.ensure_well_formed_attributes(version, attrs);
// From the engine API spec:
//
@ -619,11 +616,13 @@ where
}
#[async_trait]
impl<Provider, EngineT, Pool> EngineApiServer<EngineT> for EngineApi<Provider, EngineT, Pool>
impl<Provider, EngineT, Pool, Validator> EngineApiServer<EngineT>
for EngineApi<Provider, EngineT, Pool, Validator>
where
Provider: HeaderProvider + BlockReader + StateProviderFactory + EvmEnvProvider + 'static,
EngineT: EngineTypes<ChainSpec = ChainSpec>,
EngineT: EngineTypes,
Pool: TransactionPool + 'static,
Validator: EngineValidator<EngineT>,
{
/// Handler for `engine_newPayloadV1`
/// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/paris.md#engine_newpayloadv1>
@ -933,7 +932,8 @@ where
}
}
impl<Provider, EngineT, Pool> std::fmt::Debug for EngineApi<Provider, EngineT, Pool>
impl<Provider, EngineT, Pool, Validator> std::fmt::Debug
for EngineApi<Provider, EngineT, Pool, Validator>
where
EngineT: EngineTypes,
{
@ -948,7 +948,7 @@ mod tests {
use assert_matches::assert_matches;
use reth_beacon_consensus::{BeaconConsensusEngineEvent, BeaconEngineMessage};
use reth_chainspec::MAINNET;
use reth_ethereum_engine_primitives::EthEngineTypes;
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
use reth_payload_builder::test_utils::spawn_test_payload_service;
use reth_primitives::SealedBlock;
use reth_provider::test_utils::MockEthProvider;
@ -960,9 +960,15 @@ mod tests {
use reth_transaction_pool::noop::NoopTransactionPool;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
fn setup_engine_api(
) -> (EngineApiTestHandle, EngineApi<Arc<MockEthProvider>, EthEngineTypes, NoopTransactionPool>)
{
fn setup_engine_api() -> (
EngineApiTestHandle,
EngineApi<
Arc<MockEthProvider>,
EthEngineTypes,
NoopTransactionPool,
EthereumEngineValidator,
>,
) {
let client = ClientVersionV1 {
code: ClientCode::RH,
name: "Reth".to_string(),
@ -985,6 +991,7 @@ mod tests {
task_executor,
client,
EngineCapabilities::default(),
EthereumEngineValidator::new(chain_spec.clone()),
);
let handle = EngineApiTestHandle { chain_spec, provider, from_api: engine_rx };
(handle, api)

View File

@ -17,7 +17,7 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
use std::convert::Infallible;
use std::{convert::Infallible, sync::Arc};
use serde::{Deserialize, Serialize};
use thiserror::Error;
@ -33,7 +33,7 @@ use alloy_rpc_types::{
use reth::{
api::PayloadTypes,
builder::{
components::{ComponentsBuilder, PayloadServiceBuilder},
components::{ComponentsBuilder, EngineValidatorBuilder, PayloadServiceBuilder},
node::{NodeTypes, NodeTypesWithEngine},
BuilderContext, FullNodeTypes, Node, NodeBuilder, PayloadBuilderConfig,
},
@ -48,7 +48,8 @@ use reth_basic_payload_builder::{
use reth_chainspec::{Chain, ChainSpec};
use reth_node_api::{
payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes},
validate_version_specific_fields, EngineTypes, PayloadAttributes, PayloadBuilderAttributes,
validate_version_specific_fields, EngineTypes, EngineValidator, PayloadAttributes,
PayloadBuilderAttributes,
};
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
use reth_node_ethereum::{
@ -94,23 +95,6 @@ impl PayloadAttributes for CustomPayloadAttributes {
fn parent_beacon_block_root(&self) -> Option<B256> {
self.inner.parent_beacon_block_root()
}
fn ensure_well_formed_attributes(
&self,
chain_spec: &ChainSpec,
version: EngineApiMessageVersion,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(chain_spec, version, self.into())?;
// custom validation logic - ensure that the custom field is not zero
if self.custom == 0 {
return Err(EngineObjectValidationError::invalid_params(
CustomError::CustomFieldIsNotZero,
))
}
Ok(())
}
}
/// New type around the payload builder attributes type
@ -167,19 +151,61 @@ impl PayloadTypes for CustomEngineTypes {
}
impl EngineTypes for CustomEngineTypes {
type ChainSpec = ChainSpec;
type ExecutionPayloadV1 = ExecutionPayloadV1;
type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2;
type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3;
type ExecutionPayloadV4 = ExecutionPayloadEnvelopeV4;
}
/// Custom engine validator
#[derive(Debug, Clone)]
pub struct CustomEngineValidator {
chain_spec: Arc<ChainSpec>,
}
impl<T> EngineValidator<T> for CustomEngineValidator
where
T: EngineTypes<PayloadAttributes = CustomPayloadAttributes>,
{
fn validate_version_specific_fields(
chain_spec: &ChainSpec,
&self,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, CustomPayloadAttributes>,
payload_or_attrs: PayloadOrAttributes<'_, T::PayloadAttributes>,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(chain_spec, version, payload_or_attrs)
validate_version_specific_fields(&self.chain_spec, version, payload_or_attrs)
}
fn ensure_well_formed_attributes(
&self,
version: EngineApiMessageVersion,
attributes: &T::PayloadAttributes,
) -> Result<(), EngineObjectValidationError> {
validate_version_specific_fields(&self.chain_spec, version, attributes.into())?;
// custom validation logic - ensure that the custom field is not zero
if attributes.custom == 0 {
return Err(EngineObjectValidationError::invalid_params(
CustomError::CustomFieldIsNotZero,
))
}
Ok(())
}
}
/// Custom engine validator builder
#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive]
pub struct CustomEngineValidatorBuilder;
impl<N> EngineValidatorBuilder<N> for CustomEngineValidatorBuilder
where
N: FullNodeTypes<Types: NodeTypesWithEngine<Engine = CustomEngineTypes, ChainSpec = ChainSpec>>,
{
type Validator = CustomEngineValidator;
async fn build_validator(self, ctx: &BuilderContext<N>) -> eyre::Result<Self::Validator> {
Ok(CustomEngineValidator { chain_spec: ctx.chain_spec() })
}
}
@ -212,6 +238,7 @@ where
EthereumNetworkBuilder,
EthereumExecutorBuilder,
EthereumConsensusBuilder,
CustomEngineValidatorBuilder,
>;
type AddOns = EthereumAddOns;
@ -223,6 +250,7 @@ where
.network(EthereumNetworkBuilder::default())
.executor(EthereumExecutorBuilder::default())
.consensus(EthereumConsensusBuilder::default())
.engine_validator(CustomEngineValidatorBuilder::default())
}
}