mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 17:18:08 -05:00
feat: make payload builder generic over attributes type (#5948)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
24
crates/node-api/Cargo.toml
Normal file
24
crates/node-api/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "reth-node-api"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-primitives.workspace = true
|
||||
reth-rpc-types.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
# io
|
||||
serde.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
# for examples
|
||||
reth-payload-builder.workspace = true
|
||||
41
crates/node-api/src/engine/error.rs
Normal file
41
crates/node-api/src/engine/error.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
//! Defines a payload validation error type
|
||||
use thiserror::Error;
|
||||
|
||||
/// Thrown when the payload or attributes are known to be invalid before processing.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AttributesValidationError {
|
||||
/// Thrown if `PayloadAttributes` provided in engine_forkchoiceUpdated before V3 contains a
|
||||
/// parent beacon block root
|
||||
#[error("parent beacon block root not supported before V3")]
|
||||
ParentBeaconBlockRootNotSupportedBeforeV3,
|
||||
/// Thrown if engine_forkchoiceUpdatedV1 contains withdrawals
|
||||
#[error("withdrawals not supported in V1")]
|
||||
WithdrawalsNotSupportedInV1,
|
||||
/// Thrown if engine_forkchoiceUpdated contains no withdrawals after Shanghai
|
||||
#[error("no withdrawals post-Shanghai")]
|
||||
NoWithdrawalsPostShanghai,
|
||||
/// Thrown if engine_forkchoiceUpdated contains withdrawals before Shanghai
|
||||
#[error("withdrawals pre-Shanghai")]
|
||||
HasWithdrawalsPreShanghai,
|
||||
/// Thrown if the `PayloadAttributes` provided in engine_forkchoiceUpdated contains no parent
|
||||
/// beacon block root after Cancun
|
||||
#[error("no parent beacon block root post-cancun")]
|
||||
NoParentBeaconBlockRootPostCancun,
|
||||
/// Thrown if `PayloadAttributes` were provided with a timestamp, but the version of the engine
|
||||
/// method called is meant for a fork that occurs after the provided timestamp.
|
||||
#[error("Unsupported fork")]
|
||||
UnsupportedFork,
|
||||
/// Another type of error that is not covered by the above variants.
|
||||
#[error("Invalid params: {0}")]
|
||||
InvalidParams(#[from] Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
impl AttributesValidationError {
|
||||
/// Creates an instance of the `InvalidParams` variant with the given error.
|
||||
pub fn invalid_params<E>(error: E) -> Self
|
||||
where
|
||||
E: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
Self::InvalidParams(Box::new(error))
|
||||
}
|
||||
}
|
||||
323
crates/node-api/src/engine/mod.rs
Normal file
323
crates/node-api/src/engine/mod.rs
Normal file
@@ -0,0 +1,323 @@
|
||||
//! This contains the [EngineTypes] trait and implementations for ethereum mainnet types.
|
||||
//!
|
||||
//! The [EngineTypes] trait can be implemented to configure the engine to work with custom types,
|
||||
//! as long as those types implement certain traits.
|
||||
//!
|
||||
//! Custom payload attributes can be supported by implementing two main traits:
|
||||
//!
|
||||
//! [PayloadAttributes] can be implemented for payload attributes types that are used as
|
||||
//! arguments to the `engine_forkchoiceUpdated` method. This type should be used to define and
|
||||
//! _spawn_ payload jobs.
|
||||
//!
|
||||
//! [PayloadBuilderAttributes] can be implemented for payload attributes types that _describe_
|
||||
//! running payload jobs.
|
||||
//!
|
||||
//! Once traits are implemented and custom types are defined, the [EngineTypes] trait can be
|
||||
//! implemented:
|
||||
//! ```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_payload_builder::EthPayloadBuilderAttributes;
|
||||
//! # use serde::{Deserialize, Serialize};
|
||||
//! # use thiserror::Error;
|
||||
//! # use std::convert::Infallible;
|
||||
//!
|
||||
//! /// A custom payload attributes type.
|
||||
//! #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
//! pub struct CustomPayloadAttributes {
|
||||
//! /// An inner payload type
|
||||
//! #[serde(flatten)]
|
||||
//! pub inner: EthPayloadAttributes,
|
||||
//! /// A custom field
|
||||
//! pub custom: u64,
|
||||
//! }
|
||||
//!
|
||||
//! /// Custom error type used in payload attributes validation
|
||||
//! #[derive(Debug, Error)]
|
||||
//! pub enum CustomError {
|
||||
//! #[error("Custom field is not zero")]
|
||||
//! CustomFieldIsNotZero,
|
||||
//! }
|
||||
//!
|
||||
//! impl PayloadAttributes for CustomPayloadAttributes {
|
||||
//! fn timestamp(&self) -> u64 {
|
||||
//! self.inner.timestamp()
|
||||
//! }
|
||||
//!
|
||||
//! fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
|
||||
//! self.inner.withdrawals()
|
||||
//! }
|
||||
//!
|
||||
//! 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<(), AttributesValidationError> {
|
||||
//! 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(AttributesValidationError::invalid_params(
|
||||
//! CustomError::CustomFieldIsNotZero,
|
||||
//! ))
|
||||
//! }
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! /// Newtype around the payload builder attributes type
|
||||
//! #[derive(Clone, Debug, PartialEq, Eq)]
|
||||
//! pub struct CustomPayloadBuilderAttributes(EthPayloadBuilderAttributes);
|
||||
//!
|
||||
//! impl PayloadBuilderAttributes for CustomPayloadBuilderAttributes {
|
||||
//! type RpcPayloadAttributes = CustomPayloadAttributes;
|
||||
//! type Error = Infallible;
|
||||
//!
|
||||
//! fn try_new(parent: B256, attributes: CustomPayloadAttributes) -> Result<Self, Infallible> {
|
||||
//! Ok(Self(EthPayloadBuilderAttributes::new(parent, attributes.inner)))
|
||||
//! }
|
||||
//!
|
||||
//! fn parent(&self) -> B256 {
|
||||
//! self.0.parent
|
||||
//! }
|
||||
//!
|
||||
//! fn payload_id(&self) -> PayloadId {
|
||||
//! self.0.id
|
||||
//! }
|
||||
//!
|
||||
//! fn timestamp(&self) -> u64 {
|
||||
//! self.0.timestamp
|
||||
//! }
|
||||
//!
|
||||
//! fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
//! self.0.parent_beacon_block_root
|
||||
//! }
|
||||
//!
|
||||
//! fn suggested_fee_recipient(&self) -> Address {
|
||||
//! self.0.suggested_fee_recipient
|
||||
//! }
|
||||
//!
|
||||
//! fn prev_randao(&self) -> B256 {
|
||||
//! self.0.prev_randao
|
||||
//! }
|
||||
//!
|
||||
//! fn withdrawals(&self) -> &Vec<reth_primitives::Withdrawal> {
|
||||
//! &self.0.withdrawals
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! /// Custom engine types - uses a custom payload attributes RPC type, but uses the default
|
||||
//! /// payload builder attributes type.
|
||||
//! #[derive(Clone, Debug, Default)]
|
||||
//! #[non_exhaustive]
|
||||
//! pub struct CustomEngineTypes;
|
||||
//!
|
||||
//! impl EngineTypes for CustomEngineTypes {
|
||||
//! type PayloadAttributes = CustomPayloadAttributes;
|
||||
//! type PayloadBuilderAttributes = CustomPayloadBuilderAttributes;
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use reth_primitives::{ChainSpec, Hardfork};
|
||||
|
||||
/// Contains traits to abstract over payload attributes types and default implementations of the
|
||||
/// [PayloadAttributes] trait for ethereum mainnet and optimism types.
|
||||
pub mod traits;
|
||||
pub use traits::{PayloadAttributes, PayloadBuilderAttributes};
|
||||
|
||||
/// Contains error types used in the traits defined in this crate.
|
||||
pub mod error;
|
||||
pub use error::AttributesValidationError;
|
||||
|
||||
/// Contains types used in implementations of the [PayloadAttributes] trait.
|
||||
pub mod payload;
|
||||
pub use payload::PayloadOrAttributes;
|
||||
|
||||
/// The types that are used by the engine.
|
||||
pub trait EngineTypes: Send + Sync {
|
||||
/// The RPC payload attributes type the CL node emits via the engine API.
|
||||
type PayloadAttributes: PayloadAttributes + Unpin;
|
||||
|
||||
/// The payload attributes type that contains information about a running payload job.
|
||||
type PayloadBuilderAttributes: PayloadBuilderAttributes<RpcPayloadAttributes = Self::PayloadAttributes>
|
||||
+ Clone
|
||||
+ Unpin;
|
||||
|
||||
// TODO: payload type
|
||||
}
|
||||
|
||||
/// Validates the timestamp depending on the version called:
|
||||
///
|
||||
/// * If V2, this ensure that the payload timestamp is pre-Cancun.
|
||||
/// * If V3, this ensures that the payload timestamp is within the Cancun timestamp.
|
||||
///
|
||||
/// Otherwise, this will return [AttributesValidationError::UnsupportedFork].
|
||||
pub fn validate_payload_timestamp(
|
||||
chain_spec: &ChainSpec,
|
||||
version: EngineApiMessageVersion,
|
||||
timestamp: u64,
|
||||
) -> Result<(), AttributesValidationError> {
|
||||
let is_cancun = chain_spec.is_cancun_active_at_timestamp(timestamp);
|
||||
if version == EngineApiMessageVersion::V2 && is_cancun {
|
||||
// From the Engine API spec:
|
||||
//
|
||||
// ### Update the methods of previous forks
|
||||
//
|
||||
// This document defines how Cancun payload should be handled by the [`Shanghai
|
||||
// API`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md).
|
||||
//
|
||||
// For the following methods:
|
||||
//
|
||||
// - [`engine_forkchoiceUpdatedV2`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md#engine_forkchoiceupdatedv2)
|
||||
// - [`engine_newPayloadV2`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md#engine_newpayloadV2)
|
||||
// - [`engine_getPayloadV2`](https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/shanghai.md#engine_getpayloadv2)
|
||||
//
|
||||
// a validation **MUST** be added:
|
||||
//
|
||||
// 1. Client software **MUST** return `-38005: Unsupported fork` error if the `timestamp` of
|
||||
// payload or payloadAttributes greater or equal to the Cancun activation timestamp.
|
||||
return Err(AttributesValidationError::UnsupportedFork)
|
||||
}
|
||||
|
||||
if version == EngineApiMessageVersion::V3 && !is_cancun {
|
||||
// From the Engine API spec:
|
||||
// <https://github.com/ethereum/execution-apis/blob/ff43500e653abde45aec0f545564abfb648317af/src/engine/cancun.md#specification-2>
|
||||
//
|
||||
// 1. Client software **MUST** return `-38005: Unsupported fork` error if the `timestamp` of
|
||||
// the built payload does not fall within the time frame of the Cancun fork.
|
||||
return Err(AttributesValidationError::UnsupportedFork)
|
||||
}
|
||||
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];
|
||||
pub fn validate_withdrawals_presence(
|
||||
chain_spec: &ChainSpec,
|
||||
version: EngineApiMessageVersion,
|
||||
timestamp: u64,
|
||||
has_withdrawals: bool,
|
||||
) -> Result<(), AttributesValidationError> {
|
||||
let is_shanghai = chain_spec.fork(Hardfork::Shanghai).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(())
|
||||
}
|
||||
|
||||
/// Validate the presence of the `parentBeaconBlockRoot` field according to the payload
|
||||
/// timestamp.
|
||||
///
|
||||
/// After Cancun, `parentBeaconBlockRoot` field must be [Some].
|
||||
/// Before Cancun, `parentBeaconBlockRoot` field must be [None].
|
||||
///
|
||||
/// If the engine API message version is V1 or V2, and the payload attribute's timestamp is
|
||||
/// post-Cancun, then this will return [AttributesValidationError::UnsupportedFork].
|
||||
///
|
||||
/// If the payload attribute's timestamp is before the Cancun fork and the engine API message
|
||||
/// version is V3, then this will return [AttributesValidationError::UnsupportedFork].
|
||||
///
|
||||
/// If the engine API message version is V3, but the `parentBeaconBlockRoot` is [None], then
|
||||
/// this will return [AttributesValidationError::NoParentBeaconBlockRootPostCancun].
|
||||
///
|
||||
/// This implements the following Engine API spec rules:
|
||||
///
|
||||
/// 1. Client software **MUST** check that provided set of parameters and their fields strictly
|
||||
/// matches the expected one and return `-32602: Invalid params` error if this check fails. Any
|
||||
/// field having `null` value **MUST** be considered as not provided.
|
||||
///
|
||||
/// 2. Client software **MUST** return `-38005: Unsupported fork` error if the `payloadAttributes`
|
||||
/// is set and the `payloadAttributes.timestamp` does not fall within the time frame of the
|
||||
/// Cancun fork.
|
||||
pub fn validate_parent_beacon_block_root_presence(
|
||||
chain_spec: &ChainSpec,
|
||||
version: EngineApiMessageVersion,
|
||||
timestamp: u64,
|
||||
has_parent_beacon_block_root: bool,
|
||||
) -> Result<(), AttributesValidationError> {
|
||||
// 1. Client software **MUST** check that provided set of parameters and their fields strictly
|
||||
// matches the expected one and return `-32602: Invalid params` error if this check fails.
|
||||
// Any field having `null` value **MUST** be considered as not provided.
|
||||
match version {
|
||||
EngineApiMessageVersion::V1 | EngineApiMessageVersion::V2 => {
|
||||
if has_parent_beacon_block_root {
|
||||
return Err(AttributesValidationError::ParentBeaconBlockRootNotSupportedBeforeV3)
|
||||
}
|
||||
}
|
||||
EngineApiMessageVersion::V3 => {
|
||||
if !has_parent_beacon_block_root {
|
||||
return Err(AttributesValidationError::NoParentBeaconBlockRootPostCancun)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 2. Client software **MUST** return `-38005: Unsupported fork` error if the
|
||||
// `payloadAttributes` is set and the `payloadAttributes.timestamp` does not fall within the
|
||||
// time frame of the Cancun fork.
|
||||
validate_payload_timestamp(chain_spec, version, timestamp)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates the presence or exclusion of fork-specific fields based on the payload attributes
|
||||
/// and the message version.
|
||||
pub fn validate_version_specific_fields<Type>(
|
||||
chain_spec: &ChainSpec,
|
||||
version: EngineApiMessageVersion,
|
||||
payload_or_attrs: &PayloadOrAttributes<'_, Type>,
|
||||
) -> Result<(), AttributesValidationError>
|
||||
where
|
||||
Type: PayloadAttributes,
|
||||
{
|
||||
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 {
|
||||
/// Version 1
|
||||
V1,
|
||||
/// Version 2
|
||||
///
|
||||
/// Added for shanghai hardfork.
|
||||
V2,
|
||||
/// Version 3
|
||||
///
|
||||
/// Added for cancun hardfork.
|
||||
V3,
|
||||
}
|
||||
64
crates/node-api/src/engine/payload.rs
Normal file
64
crates/node-api/src/engine/payload.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use crate::PayloadAttributes;
|
||||
use reth_primitives::B256;
|
||||
use reth_rpc_types::engine::ExecutionPayload;
|
||||
|
||||
/// Either an [ExecutionPayload] or a types that implements the [PayloadAttributes] trait.
|
||||
#[derive(Debug)]
|
||||
pub enum PayloadOrAttributes<'a, AttributesType> {
|
||||
/// An [ExecutionPayload] and optional parent beacon block root.
|
||||
ExecutionPayload {
|
||||
/// The inner execution payload
|
||||
payload: &'a ExecutionPayload,
|
||||
/// The parent beacon block root
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
},
|
||||
/// A payload attributes type.
|
||||
PayloadAttributes(&'a AttributesType),
|
||||
}
|
||||
|
||||
impl<'a, AttributesType> PayloadOrAttributes<'a, AttributesType>
|
||||
where
|
||||
AttributesType: PayloadAttributes,
|
||||
{
|
||||
/// Construct a [PayloadOrAttributes] from an [ExecutionPayload] and optional parent beacon
|
||||
/// block root.
|
||||
pub fn from_execution_payload(
|
||||
payload: &'a ExecutionPayload,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
) -> Self {
|
||||
Self::ExecutionPayload { payload, parent_beacon_block_root }
|
||||
}
|
||||
|
||||
/// Return the withdrawals for the payload or attributes.
|
||||
pub fn withdrawals(&self) -> Option<&Vec<reth_rpc_types::engine::payload::Withdrawal>> {
|
||||
match self {
|
||||
Self::ExecutionPayload { payload, .. } => payload.withdrawals(),
|
||||
Self::PayloadAttributes(attributes) => attributes.withdrawals(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the timestamp for the payload or attributes.
|
||||
pub fn timestamp(&self) -> u64 {
|
||||
match self {
|
||||
Self::ExecutionPayload { payload, .. } => payload.timestamp(),
|
||||
Self::PayloadAttributes(attributes) => attributes.timestamp(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the parent beacon block root for the payload or attributes.
|
||||
pub fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
match self {
|
||||
Self::ExecutionPayload { parent_beacon_block_root, .. } => *parent_beacon_block_root,
|
||||
Self::PayloadAttributes(attributes) => attributes.parent_beacon_block_root(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, AttributesType> From<&'a AttributesType> for PayloadOrAttributes<'a, AttributesType>
|
||||
where
|
||||
AttributesType: PayloadAttributes,
|
||||
{
|
||||
fn from(attributes: &'a AttributesType) -> Self {
|
||||
Self::PayloadAttributes(attributes)
|
||||
}
|
||||
}
|
||||
189
crates/node-api/src/engine/traits.rs
Normal file
189
crates/node-api/src/engine/traits.rs
Normal file
@@ -0,0 +1,189 @@
|
||||
use crate::{validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion};
|
||||
use reth_primitives::{
|
||||
revm::config::revm_spec_by_timestamp_after_merge,
|
||||
revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, SpecId},
|
||||
Address, ChainSpec, Header, B256, U256,
|
||||
};
|
||||
use reth_rpc_types::engine::{
|
||||
OptimismPayloadAttributes, PayloadAttributes as EthPayloadAttributes, PayloadId, Withdrawal,
|
||||
};
|
||||
|
||||
/// This can be implemented by types that describe a currently running payload job.
|
||||
///
|
||||
/// This is used as a conversion type, transforming a payload attributes type that the engine API
|
||||
/// receives, into a type that the payload builder can use.
|
||||
pub trait PayloadBuilderAttributes: Send + Sync + std::fmt::Debug {
|
||||
/// The payload attributes that can be used to construct this type. Used as the argument in
|
||||
/// [PayloadBuilderAttributes::try_new].
|
||||
type RpcPayloadAttributes;
|
||||
/// The error type used in [PayloadBuilderAttributes::try_new].
|
||||
type Error: std::error::Error;
|
||||
|
||||
/// Creates a new payload builder for the given parent block and the attributes.
|
||||
///
|
||||
/// Derives the unique [PayloadId] for the given parent and attributes
|
||||
fn try_new(
|
||||
parent: B256,
|
||||
rpc_payload_attributes: Self::RpcPayloadAttributes,
|
||||
) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Returns the [PayloadId] for the running payload job.
|
||||
fn payload_id(&self) -> PayloadId;
|
||||
|
||||
/// Returns the parent block hash for the running payload job.
|
||||
fn parent(&self) -> B256;
|
||||
|
||||
/// Returns the timestmap for the running payload job.
|
||||
fn timestamp(&self) -> u64;
|
||||
|
||||
/// Returns the parent beacon block root for the running payload job, if it exists.
|
||||
fn parent_beacon_block_root(&self) -> Option<B256>;
|
||||
|
||||
/// Returns the suggested fee recipient for the running payload job.
|
||||
fn suggested_fee_recipient(&self) -> Address;
|
||||
|
||||
/// Returns the prevrandao field for the running payload job.
|
||||
fn prev_randao(&self) -> B256;
|
||||
|
||||
/// Returns the withdrawals for the running payload job.
|
||||
fn withdrawals(&self) -> &Vec<reth_primitives::Withdrawal>;
|
||||
|
||||
/// Returns the configured [CfgEnv] and [BlockEnv] for the targeted payload (that has the
|
||||
/// `parent` as its parent).
|
||||
///
|
||||
/// The `chain_spec` is used to determine the correct chain id and hardfork for the payload
|
||||
/// based on its timestamp.
|
||||
///
|
||||
/// Block related settings are derived from the `parent` block and the configured attributes.
|
||||
///
|
||||
/// NOTE: This is only intended for beacon consensus (after merge).
|
||||
fn cfg_and_block_env(&self, chain_spec: &ChainSpec, parent: &Header) -> (CfgEnv, BlockEnv) {
|
||||
// TODO: should be different once revm has configurable cfgenv
|
||||
// configure evm env based on parent block
|
||||
let mut cfg = CfgEnv::default();
|
||||
cfg.chain_id = chain_spec.chain().id();
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
{
|
||||
cfg.optimism = chain_spec.is_optimism();
|
||||
}
|
||||
|
||||
// ensure we're not missing any timestamp based hardforks
|
||||
cfg.spec_id = revm_spec_by_timestamp_after_merge(chain_spec, self.timestamp());
|
||||
|
||||
// if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is
|
||||
// cancun now, we need to set the excess blob gas to the default value
|
||||
let blob_excess_gas_and_price = parent
|
||||
.next_block_excess_blob_gas()
|
||||
.map_or_else(
|
||||
|| {
|
||||
if cfg.spec_id == SpecId::CANCUN {
|
||||
// default excess blob gas is zero
|
||||
Some(0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Some,
|
||||
)
|
||||
.map(BlobExcessGasAndPrice::new);
|
||||
|
||||
let block_env = BlockEnv {
|
||||
number: U256::from(parent.number + 1),
|
||||
coinbase: self.suggested_fee_recipient(),
|
||||
timestamp: U256::from(self.timestamp()),
|
||||
difficulty: U256::ZERO,
|
||||
prevrandao: Some(self.prev_randao()),
|
||||
gas_limit: U256::from(parent.gas_limit),
|
||||
// calculate basefee based on parent block's gas usage
|
||||
basefee: U256::from(
|
||||
parent
|
||||
.next_block_base_fee(chain_spec.base_fee_params(self.timestamp()))
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
// calculate excess gas based on parent block's blob gas usage
|
||||
blob_excess_gas_and_price,
|
||||
};
|
||||
|
||||
(cfg, block_env)
|
||||
}
|
||||
}
|
||||
|
||||
/// The execution payload attribute type the CL node emits via the engine API.
|
||||
/// This trait should be implemented by types that could be used to spawn a payload job.
|
||||
///
|
||||
/// This type is emitted as part of the forkchoiceUpdated call
|
||||
pub trait PayloadAttributes:
|
||||
serde::de::DeserializeOwned + serde::Serialize + std::fmt::Debug + Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Returns the timestamp to be used in the payload job.
|
||||
fn timestamp(&self) -> u64;
|
||||
|
||||
/// Returns the withdrawals for the given payload attributes.
|
||||
fn withdrawals(&self) -> Option<&Vec<Withdrawal>>;
|
||||
|
||||
/// 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<(), AttributesValidationError>;
|
||||
}
|
||||
|
||||
impl PayloadAttributes for EthPayloadAttributes {
|
||||
fn timestamp(&self) -> u64 {
|
||||
self.timestamp
|
||||
}
|
||||
|
||||
fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
|
||||
self.withdrawals.as_ref()
|
||||
}
|
||||
|
||||
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<(), AttributesValidationError> {
|
||||
validate_version_specific_fields(chain_spec, version, &self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl PayloadAttributes for OptimismPayloadAttributes {
|
||||
fn timestamp(&self) -> u64 {
|
||||
self.payload_attributes.timestamp
|
||||
}
|
||||
|
||||
fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
|
||||
self.payload_attributes.withdrawals.as_ref()
|
||||
}
|
||||
|
||||
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<(), AttributesValidationError> {
|
||||
validate_version_specific_fields(chain_spec, version, &self.into())?;
|
||||
|
||||
if self.gas_limit.is_none() && chain_spec.is_optimism() {
|
||||
return Err(AttributesValidationError::InvalidParams(
|
||||
"MissingGasLimitInPayloadAttributes".to_string().into(),
|
||||
))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
18
crates/node-api/src/lib.rs
Normal file
18
crates/node-api/src/lib.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
//! Standalone crate for Reth configuration traits and builder types.
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
|
||||
/// Traits, validation methods, and helper types used to abstract over engine types.
|
||||
///
|
||||
/// Notably contains the [EngineTypes] trait and implementations for ethereum mainnet types.
|
||||
pub mod engine;
|
||||
pub use engine::{
|
||||
validate_payload_timestamp, validate_version_specific_fields, validate_withdrawals_presence,
|
||||
AttributesValidationError, EngineApiMessageVersion, EngineTypes, PayloadAttributes,
|
||||
PayloadBuilderAttributes, PayloadOrAttributes,
|
||||
};
|
||||
Reference in New Issue
Block a user