mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
chore(payload): Move ExecutionPayloadValidator into reth-ethereum-payload-builder (#14751)
This commit is contained in:
@@ -41,6 +41,7 @@ reth-evm-ethereum.workspace = true
|
||||
reth-exex-types.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
reth-node-ethereum.workspace = true
|
||||
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
tokio-stream.workspace = true
|
||||
|
||||
@@ -163,10 +163,11 @@ mod tests {
|
||||
use reth_engine_primitives::BeaconEngineMessage;
|
||||
use reth_engine_tree::{test_utils::TestPipelineBuilder, tree::NoopInvalidBlockHook};
|
||||
use reth_ethereum_consensus::EthBeaconConsensus;
|
||||
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
|
||||
use reth_ethereum_engine_primitives::EthEngineTypes;
|
||||
use reth_evm_ethereum::{execute::EthExecutorProvider, EthEvmConfig};
|
||||
use reth_exex_types::FinishedExExHeight;
|
||||
use reth_network_p2p::test_utils::TestFullBlockClient;
|
||||
use reth_node_ethereum::EthereumEngineValidator;
|
||||
use reth_primitives::SealedHeader;
|
||||
use reth_provider::{
|
||||
providers::BlockchainProvider, test_utils::create_test_provider_factory_with_chain_spec,
|
||||
|
||||
@@ -85,6 +85,7 @@ reth-static-file.workspace = true
|
||||
reth-testing-utils.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-trie-db.workspace = true
|
||||
reth-node-ethereum.workspace = true
|
||||
|
||||
# alloy
|
||||
alloy-rlp.workspace = true
|
||||
@@ -128,4 +129,5 @@ test-utils = [
|
||||
"reth-trie-db/test-utils",
|
||||
"reth-trie-parallel/test-utils",
|
||||
"reth-ethereum-primitives/test-utils",
|
||||
"reth-node-ethereum/test-utils",
|
||||
]
|
||||
|
||||
@@ -2897,10 +2897,11 @@ mod tests {
|
||||
use reth_chainspec::{ChainSpec, HOLESKY, MAINNET};
|
||||
use reth_engine_primitives::ForkchoiceStatus;
|
||||
use reth_ethereum_consensus::EthBeaconConsensus;
|
||||
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
|
||||
use reth_ethereum_engine_primitives::EthEngineTypes;
|
||||
use reth_ethereum_primitives::{Block, EthPrimitives};
|
||||
use reth_evm::test_utils::MockExecutorProvider;
|
||||
use reth_evm_ethereum::EthEvmConfig;
|
||||
use reth_node_ethereum::EthereumEngineValidator;
|
||||
use reth_primitives_traits::Block as _;
|
||||
use reth_provider::test_utils::MockEthProvider;
|
||||
use reth_trie::{updates::TrieUpdates, HashedPostState};
|
||||
|
||||
@@ -20,7 +20,6 @@ reth-chainspec.workspace = true
|
||||
reth-consensus-common.workspace = true
|
||||
reth-fs-util.workspace = true
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-payload-validator.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-revm.workspace = true
|
||||
reth-provider.workspace = true
|
||||
|
||||
@@ -12,11 +12,9 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-chainspec.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-payload-primitives.workspace = true
|
||||
reth-payload-validator.workspace = true
|
||||
|
||||
# alloy
|
||||
alloy-primitives.workspace = true
|
||||
@@ -34,7 +32,6 @@ serde_json.workspace = true
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"reth-chainspec/std",
|
||||
"reth-primitives/std",
|
||||
"alloy-primitives/std",
|
||||
"alloy-eips/std",
|
||||
|
||||
@@ -12,21 +12,16 @@
|
||||
extern crate alloc;
|
||||
|
||||
mod payload;
|
||||
use alloc::sync::Arc;
|
||||
pub use payload::{EthBuiltPayload, EthPayloadBuilderAttributes};
|
||||
|
||||
use alloy_rpc_types_engine::{ExecutionData, ExecutionPayload};
|
||||
pub use alloy_rpc_types_engine::{
|
||||
ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
|
||||
ExecutionPayloadV1, PayloadAttributes as EthPayloadAttributes,
|
||||
};
|
||||
pub use payload::{EthBuiltPayload, EthPayloadBuilderAttributes};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_engine_primitives::{EngineTypes, EngineValidator, PayloadValidator};
|
||||
use reth_payload_primitives::{
|
||||
validate_version_specific_fields, BuiltPayload, EngineApiMessageVersion,
|
||||
EngineObjectValidationError, NewPayloadError, PayloadOrAttributes, PayloadTypes,
|
||||
};
|
||||
use reth_payload_validator::ExecutionPayloadValidator;
|
||||
use reth_primitives::{Block, NodePrimitives, RecoveredBlock, SealedBlock};
|
||||
use reth_engine_primitives::EngineTypes;
|
||||
use reth_payload_primitives::{BuiltPayload, PayloadTypes};
|
||||
use reth_primitives::{NodePrimitives, SealedBlock};
|
||||
|
||||
/// The types used in the default mainnet ethereum beacon consensus engine.
|
||||
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
|
||||
@@ -77,62 +72,3 @@ impl PayloadTypes for EthPayloadTypes {
|
||||
type PayloadAttributes = EthPayloadAttributes;
|
||||
type PayloadBuilderAttributes = EthPayloadBuilderAttributes;
|
||||
}
|
||||
|
||||
/// Validator for the ethereum engine API.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthereumEngineValidator {
|
||||
inner: ExecutionPayloadValidator<ChainSpec>,
|
||||
}
|
||||
|
||||
impl EthereumEngineValidator {
|
||||
/// Instantiates a new validator.
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { inner: ExecutionPayloadValidator::new(chain_spec) }
|
||||
}
|
||||
|
||||
/// Returns the chain spec used by the validator.
|
||||
#[inline]
|
||||
fn chain_spec(&self) -> &ChainSpec {
|
||||
self.inner.chain_spec()
|
||||
}
|
||||
}
|
||||
|
||||
impl PayloadValidator for EthereumEngineValidator {
|
||||
type Block = Block;
|
||||
type ExecutionData = ExecutionData;
|
||||
|
||||
fn ensure_well_formed_payload(
|
||||
&self,
|
||||
payload: ExecutionData,
|
||||
) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
|
||||
let sealed_block = self.inner.ensure_well_formed_payload(payload)?;
|
||||
sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Types> EngineValidator<Types> for EthereumEngineValidator
|
||||
where
|
||||
Types: EngineTypes<PayloadAttributes = EthPayloadAttributes, ExecutionData = ExecutionData>,
|
||||
{
|
||||
fn validate_version_specific_fields(
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, EthPayloadAttributes>,
|
||||
) -> Result<(), EngineObjectValidationError> {
|
||||
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,
|
||||
PayloadOrAttributes::<Self::ExecutionData, EthPayloadAttributes>::PayloadAttributes(
|
||||
attributes,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,13 @@ reth-chainspec.workspace = true
|
||||
reth-revm = { workspace = true, features = ["std"] }
|
||||
reth-trie-db.workspace = true
|
||||
reth-rpc-eth-types.workspace = true
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-payload-primitives.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-rpc-types-eth.workspace = true
|
||||
|
||||
alloy-rpc-types-engine.workspace = true
|
||||
# revm with required ethereum features
|
||||
revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] }
|
||||
|
||||
@@ -87,4 +91,5 @@ test-utils = [
|
||||
"reth-trie-db/test-utils",
|
||||
"revm/test-utils",
|
||||
"reth-evm/test-utils",
|
||||
"reth-primitives/test-utils",
|
||||
]
|
||||
|
||||
75
crates/ethereum/node/src/engine.rs
Normal file
75
crates/ethereum/node/src/engine.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
//! Validates execution payload wrt Ethereum Execution Engine API version.
|
||||
|
||||
use alloy_rpc_types_engine::ExecutionData;
|
||||
pub use alloy_rpc_types_engine::{
|
||||
ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
|
||||
ExecutionPayloadV1, PayloadAttributes as EthPayloadAttributes,
|
||||
};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_engine_primitives::{EngineTypes, EngineValidator, PayloadValidator};
|
||||
use reth_ethereum_payload_builder::EthereumExecutionPayloadValidator;
|
||||
use reth_payload_primitives::{
|
||||
validate_version_specific_fields, EngineApiMessageVersion, EngineObjectValidationError,
|
||||
NewPayloadError, PayloadOrAttributes,
|
||||
};
|
||||
use reth_primitives::{Block, RecoveredBlock};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Validator for the ethereum engine API.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthereumEngineValidator {
|
||||
inner: EthereumExecutionPayloadValidator<ChainSpec>,
|
||||
}
|
||||
|
||||
impl EthereumEngineValidator {
|
||||
/// Instantiates a new validator.
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { inner: EthereumExecutionPayloadValidator::new(chain_spec) }
|
||||
}
|
||||
|
||||
/// Returns the chain spec used by the validator.
|
||||
#[inline]
|
||||
fn chain_spec(&self) -> &ChainSpec {
|
||||
self.inner.chain_spec()
|
||||
}
|
||||
}
|
||||
|
||||
impl PayloadValidator for EthereumEngineValidator {
|
||||
type Block = Block;
|
||||
type ExecutionData = ExecutionData;
|
||||
|
||||
fn ensure_well_formed_payload(
|
||||
&self,
|
||||
payload: ExecutionData,
|
||||
) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
|
||||
let sealed_block = self.inner.ensure_well_formed_payload(payload)?;
|
||||
sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Types> EngineValidator<Types> for EthereumEngineValidator
|
||||
where
|
||||
Types: EngineTypes<PayloadAttributes = EthPayloadAttributes, ExecutionData = ExecutionData>,
|
||||
{
|
||||
fn validate_version_specific_fields(
|
||||
&self,
|
||||
version: EngineApiMessageVersion,
|
||||
payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, EthPayloadAttributes>,
|
||||
) -> Result<(), EngineObjectValidationError> {
|
||||
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,
|
||||
PayloadOrAttributes::<Self::ExecutionData, EthPayloadAttributes>::PayloadAttributes(
|
||||
attributes,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -24,3 +24,6 @@ pub mod node;
|
||||
pub use node::EthereumNode;
|
||||
|
||||
pub mod payload;
|
||||
|
||||
pub mod engine;
|
||||
pub use engine::EthereumEngineValidator;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
//! Ethereum Node types config.
|
||||
|
||||
pub use crate::payload::EthereumPayloadBuilder;
|
||||
pub use crate::{payload::EthereumPayloadBuilder, EthereumEngineValidator};
|
||||
use crate::{EthEngineTypes, EthEvmConfig};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_consensus::{ConsensusError, FullConsensus};
|
||||
use reth_ethereum_consensus::EthBeaconConsensus;
|
||||
pub use reth_ethereum_engine_primitives::EthereumEngineValidator;
|
||||
use reth_ethereum_engine_primitives::{
|
||||
EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes,
|
||||
};
|
||||
|
||||
@@ -27,9 +27,12 @@ reth-evm.workspace = true
|
||||
reth-evm-ethereum.workspace = true
|
||||
reth-errors.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
reth-payload-validator.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
|
||||
# ethereum
|
||||
revm.workspace = true
|
||||
alloy-rpc-types-engine.workspace = true
|
||||
|
||||
# alloy
|
||||
alloy-eips.workspace = true
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
#![allow(clippy::useless_let_if_seq)]
|
||||
|
||||
pub mod validator;
|
||||
pub use validator::EthereumExecutionPayloadValidator;
|
||||
|
||||
use alloy_consensus::{BlockHeader, Header, Transaction, Typed2718, EMPTY_OMMER_ROOT_HASH};
|
||||
use alloy_eips::{eip4844::DATA_GAS_PER_BLOB, merge::BEACON_NONCE};
|
||||
use alloy_primitives::U256;
|
||||
|
||||
110
crates/ethereum/payload/src/validator.rs
Normal file
110
crates/ethereum/payload/src/validator.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
//! Validates execution payload wrt Ethereum consensus rules
|
||||
|
||||
use alloy_rpc_types_engine::{ExecutionData, PayloadError};
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_payload_validator::{cancun, prague, shanghai};
|
||||
use reth_primitives::Block;
|
||||
use reth_primitives_traits::{Block as _, SealedBlock, SignedTransaction};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Execution payload validator.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EthereumExecutionPayloadValidator<ChainSpec> {
|
||||
/// Chain spec to validate against.
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
}
|
||||
|
||||
impl<ChainSpec> EthereumExecutionPayloadValidator<ChainSpec> {
|
||||
/// Create a new validator.
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec }
|
||||
}
|
||||
|
||||
/// Returns the chain spec used by the validator.
|
||||
#[inline]
|
||||
pub const fn chain_spec(&self) -> &Arc<ChainSpec> {
|
||||
&self.chain_spec
|
||||
}
|
||||
}
|
||||
|
||||
impl<ChainSpec: EthereumHardforks> EthereumExecutionPayloadValidator<ChainSpec> {
|
||||
/// Returns true if the Cancun hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
self.chain_spec().is_cancun_active_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
/// Returns true if the Shanghai hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_shanghai_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
self.chain_spec().is_shanghai_active_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
/// Returns true if the Prague hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_prague_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
self.chain_spec().is_prague_active_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
/// Ensures that the given payload does not violate any consensus rules that concern the block's
|
||||
/// layout, like:
|
||||
/// - missing or invalid base fee
|
||||
/// - invalid extra data
|
||||
/// - invalid transactions
|
||||
/// - incorrect hash
|
||||
/// - the versioned hashes passed with the payload do not exactly match transaction versioned
|
||||
/// hashes
|
||||
/// - the block does not contain blob transactions if it is pre-cancun
|
||||
///
|
||||
/// The checks are done in the order that conforms with the engine-API specification.
|
||||
///
|
||||
/// This is intended to be invoked after receiving the payload from the CLI.
|
||||
/// The additional [`MaybeCancunPayloadFields`](alloy_rpc_types_engine::MaybeCancunPayloadFields) are not part of the payload, but are additional fields in the `engine_newPayloadV3` RPC call, See also <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#engine_newpayloadv3>
|
||||
///
|
||||
/// If the cancun fields are provided this also validates that the versioned hashes in the block
|
||||
/// match the versioned hashes passed in the
|
||||
/// [`CancunPayloadFields`](alloy_rpc_types_engine::CancunPayloadFields), if the cancun payload
|
||||
/// fields are provided. If the payload fields are not provided, but versioned hashes exist
|
||||
/// in the block, this is considered an error: [`PayloadError::InvalidVersionedHashes`].
|
||||
///
|
||||
/// This validates versioned hashes according to the Engine API Cancun spec:
|
||||
/// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification>
|
||||
pub fn ensure_well_formed_payload<T: SignedTransaction>(
|
||||
&self,
|
||||
payload: ExecutionData,
|
||||
) -> Result<SealedBlock<Block<T>>, PayloadError> {
|
||||
let ExecutionData { payload, sidecar } = payload;
|
||||
|
||||
let expected_hash = payload.block_hash();
|
||||
|
||||
// First parse the block
|
||||
let sealed_block = payload.try_into_block_with_sidecar(&sidecar)?.seal_slow();
|
||||
|
||||
// Ensure the hash included in the payload matches the block hash
|
||||
if expected_hash != sealed_block.hash() {
|
||||
return Err(PayloadError::BlockHash {
|
||||
execution: sealed_block.hash(),
|
||||
consensus: expected_hash,
|
||||
})
|
||||
}
|
||||
|
||||
shanghai::ensure_well_formed_fields(
|
||||
sealed_block.body(),
|
||||
self.is_shanghai_active_at_timestamp(sealed_block.timestamp),
|
||||
)?;
|
||||
|
||||
cancun::ensure_well_formed_fields(
|
||||
&sealed_block,
|
||||
sidecar.cancun(),
|
||||
self.is_cancun_active_at_timestamp(sealed_block.timestamp),
|
||||
)?;
|
||||
|
||||
prague::ensure_well_formed_fields(
|
||||
sealed_block.body(),
|
||||
sidecar.prague(),
|
||||
self.is_prague_active_at_timestamp(sealed_block.timestamp),
|
||||
)?;
|
||||
|
||||
Ok(sealed_block)
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,16 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-chainspec.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-primitives-traits.workspace = true
|
||||
|
||||
# alloy
|
||||
alloy-rpc-types-engine.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"alloy-consensus/std",
|
||||
"alloy-rpc-types-engine/std",
|
||||
"reth-primitives-traits/std",
|
||||
]
|
||||
|
||||
@@ -7,115 +7,8 @@
|
||||
)]
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod cancun;
|
||||
pub mod prague;
|
||||
pub mod shanghai;
|
||||
|
||||
use alloy_rpc_types_engine::{ExecutionData, PayloadError};
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_primitives::SealedBlock;
|
||||
use reth_primitives_traits::{Block, SignedTransaction};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Execution payload validator.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExecutionPayloadValidator<ChainSpec> {
|
||||
/// Chain spec to validate against.
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
}
|
||||
|
||||
impl<ChainSpec> ExecutionPayloadValidator<ChainSpec> {
|
||||
/// Create a new validator.
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec }
|
||||
}
|
||||
|
||||
/// Returns the chain spec used by the validator.
|
||||
#[inline]
|
||||
pub const fn chain_spec(&self) -> &Arc<ChainSpec> {
|
||||
&self.chain_spec
|
||||
}
|
||||
}
|
||||
|
||||
impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
|
||||
/// Returns true if the Cancun hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
self.chain_spec().is_cancun_active_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
/// Returns true if the Shanghai hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_shanghai_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
self.chain_spec().is_shanghai_active_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
/// Returns true if the Prague hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_prague_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
self.chain_spec().is_prague_active_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
/// Ensures that the given payload does not violate any consensus rules that concern the block's
|
||||
/// layout, like:
|
||||
/// - missing or invalid base fee
|
||||
/// - invalid extra data
|
||||
/// - invalid transactions
|
||||
/// - incorrect hash
|
||||
/// - the versioned hashes passed with the payload do not exactly match transaction versioned
|
||||
/// hashes
|
||||
/// - the block does not contain blob transactions if it is pre-cancun
|
||||
///
|
||||
/// The checks are done in the order that conforms with the engine-API specification.
|
||||
///
|
||||
/// This is intended to be invoked after receiving the payload from the CLI.
|
||||
/// The additional [`MaybeCancunPayloadFields`](alloy_rpc_types_engine::MaybeCancunPayloadFields) are not part of the payload, but are additional fields in the `engine_newPayloadV3` RPC call, See also <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#engine_newpayloadv3>
|
||||
///
|
||||
/// If the cancun fields are provided this also validates that the versioned hashes in the block
|
||||
/// match the versioned hashes passed in the
|
||||
/// [`CancunPayloadFields`](alloy_rpc_types_engine::CancunPayloadFields), if the cancun payload
|
||||
/// fields are provided. If the payload fields are not provided, but versioned hashes exist
|
||||
/// in the block, this is considered an error: [`PayloadError::InvalidVersionedHashes`].
|
||||
///
|
||||
/// This validates versioned hashes according to the Engine API Cancun spec:
|
||||
/// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification>
|
||||
pub fn ensure_well_formed_payload<T: SignedTransaction>(
|
||||
&self,
|
||||
payload: ExecutionData,
|
||||
) -> Result<SealedBlock<reth_primitives::Block<T>>, PayloadError> {
|
||||
let ExecutionData { payload, sidecar } = payload;
|
||||
|
||||
let expected_hash = payload.block_hash();
|
||||
|
||||
// First parse the block
|
||||
let sealed_block = payload.try_into_block_with_sidecar(&sidecar)?.seal_slow();
|
||||
|
||||
// Ensure the hash included in the payload matches the block hash
|
||||
if expected_hash != sealed_block.hash() {
|
||||
return Err(PayloadError::BlockHash {
|
||||
execution: sealed_block.hash(),
|
||||
consensus: expected_hash,
|
||||
})
|
||||
}
|
||||
|
||||
shanghai::ensure_well_formed_fields(
|
||||
sealed_block.body(),
|
||||
self.is_shanghai_active_at_timestamp(sealed_block.timestamp),
|
||||
)?;
|
||||
|
||||
cancun::ensure_well_formed_fields(
|
||||
&sealed_block,
|
||||
sidecar.cancun(),
|
||||
self.is_cancun_active_at_timestamp(sealed_block.timestamp),
|
||||
)?;
|
||||
|
||||
prague::ensure_well_formed_fields(
|
||||
sealed_block.body(),
|
||||
sidecar.prague(),
|
||||
self.is_prague_active_at_timestamp(sealed_block.timestamp),
|
||||
)?;
|
||||
|
||||
Ok(sealed_block)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ reth-transaction-pool = { workspace = true, features = ["test-utils"] }
|
||||
reth-rpc-types-compat.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-node-ethereum.workspace = true
|
||||
|
||||
alloy-primitives.workspace = true
|
||||
alloy-rpc-types-eth.workspace = true
|
||||
|
||||
@@ -4,10 +4,11 @@ use alloy_rpc_types_engine::{ClientCode, ClientVersionV1};
|
||||
use reth_chainspec::MAINNET;
|
||||
use reth_consensus::noop::NoopConsensus;
|
||||
use reth_engine_primitives::BeaconConsensusEngineHandle;
|
||||
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
|
||||
use reth_ethereum_engine_primitives::EthEngineTypes;
|
||||
use reth_evm::execute::BasicBlockExecutorProvider;
|
||||
use reth_evm_ethereum::EthEvmConfig;
|
||||
use reth_network_api::noop::NoopNetwork;
|
||||
use reth_node_ethereum::EthereumEngineValidator;
|
||||
use reth_payload_builder::test_utils::spawn_test_payload_service;
|
||||
use reth_provider::test_utils::NoopProvider;
|
||||
use reth_rpc::EthApi;
|
||||
|
||||
@@ -53,5 +53,6 @@ reth-primitives-traits.workspace = true
|
||||
reth-payload-builder = { workspace = true, features = ["test-utils"] }
|
||||
reth-testing-utils.workspace = true
|
||||
alloy-rlp.workspace = true
|
||||
reth-node-ethereum.workspace = true
|
||||
|
||||
assert_matches.workspace = true
|
||||
|
||||
@@ -1160,8 +1160,9 @@ mod tests {
|
||||
use assert_matches::assert_matches;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardfork, MAINNET};
|
||||
use reth_engine_primitives::BeaconEngineMessage;
|
||||
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
|
||||
use reth_ethereum_engine_primitives::EthEngineTypes;
|
||||
use reth_ethereum_primitives::Block;
|
||||
use reth_node_ethereum::EthereumEngineValidator;
|
||||
use reth_payload_builder::test_utils::spawn_test_payload_service;
|
||||
use reth_provider::test_utils::MockEthProvider;
|
||||
use reth_tasks::TokioTaskExecutor;
|
||||
|
||||
Reference in New Issue
Block a user