reth_payload_primitives/
traits.rs

1//! Core traits for working with execution payloads.
2
3use crate::PayloadBuilderError;
4use alloc::{boxed::Box, sync::Arc, vec::Vec};
5use alloy_eips::{
6    eip4895::{Withdrawal, Withdrawals},
7    eip7685::Requests,
8};
9use alloy_primitives::{Address, B256, U256};
10use alloy_rpc_types_engine::{PayloadAttributes as EthPayloadAttributes, PayloadId};
11use core::fmt;
12use either::Either;
13use reth_execution_types::ExecutionOutcome;
14use reth_primitives_traits::{NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader};
15use reth_trie_common::{
16    updates::{TrieUpdates, TrieUpdatesSorted},
17    HashedPostState, HashedPostStateSorted,
18};
19
20/// Represents an executed block for payload building purposes.
21///
22/// This type captures the complete execution state of a built block,
23/// including the recovered block, execution outcome, hashed state, and trie updates.
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct BuiltPayloadExecutedBlock<N: NodePrimitives> {
26    /// Recovered Block
27    pub recovered_block: Arc<RecoveredBlock<N::Block>>,
28    /// Block's execution outcome.
29    pub execution_output: Arc<ExecutionOutcome<N::Receipt>>,
30    /// Block's hashed state.
31    ///
32    /// Supports both unsorted and sorted variants so payload builders can avoid cloning in order
33    /// to convert from one to the other when it's not necessary.
34    pub hashed_state: Either<Arc<HashedPostState>, Arc<HashedPostStateSorted>>,
35    /// Trie updates that result from calculating the state root for the block.
36    ///
37    /// Supports both unsorted and sorted variants so payload builders can avoid cloning in order
38    /// to convert from one to the other when it's not necessary.
39    pub trie_updates: Either<Arc<TrieUpdates>, Arc<TrieUpdatesSorted>>,
40}
41
42impl<N: NodePrimitives> BuiltPayloadExecutedBlock<N> {
43    /// Converts this into an [`reth_chain_state::ExecutedBlock`].
44    ///
45    /// Ensures hashed state and trie updates are in their sorted representations
46    /// as required by `reth_chain_state::ExecutedBlock`.
47    pub fn into_executed_payload(self) -> reth_chain_state::ExecutedBlock<N> {
48        let hashed_state = match self.hashed_state {
49            // Convert unsorted to sorted
50            Either::Left(unsorted) => Arc::new(Arc::unwrap_or_clone(unsorted).into_sorted()),
51            // Already sorted
52            Either::Right(sorted) => sorted,
53        };
54
55        let trie_updates = match self.trie_updates {
56            // Convert unsorted to sorted
57            Either::Left(unsorted) => Arc::new(Arc::unwrap_or_clone(unsorted).into_sorted()),
58            // Already sorted
59            Either::Right(sorted) => sorted,
60        };
61
62        reth_chain_state::ExecutedBlock {
63            recovered_block: self.recovered_block,
64            execution_output: self.execution_output,
65            hashed_state,
66            trie_updates,
67        }
68    }
69}
70
71/// Represents a successfully built execution payload (block).
72///
73/// Provides access to the underlying block data, execution results, and associated metadata
74/// for payloads ready for execution or propagation.
75#[auto_impl::auto_impl(&, Arc)]
76pub trait BuiltPayload: Send + Sync + fmt::Debug {
77    /// The node's primitive types
78    type Primitives: NodePrimitives;
79
80    /// Returns the built block in its sealed (hash-verified) form.
81    fn block(&self) -> &SealedBlock<<Self::Primitives as NodePrimitives>::Block>;
82
83    /// Returns the total fees collected from all transactions in this block.
84    fn fees(&self) -> U256;
85
86    /// Returns the complete execution result including state updates.
87    ///
88    /// Returns `None` if execution data is not available or not tracked.
89    fn executed_block(&self) -> Option<BuiltPayloadExecutedBlock<Self::Primitives>> {
90        None
91    }
92
93    /// Returns the EIP-7685 execution layer requests included in this block.
94    ///
95    /// These are requests generated by the execution layer that need to be
96    /// processed by the consensus layer (e.g., validator deposits, withdrawals).
97    fn requests(&self) -> Option<Requests>;
98}
99
100/// Attributes used to guide the construction of a new execution payload.
101///
102/// Extends basic payload attributes with additional context needed during the
103/// building process, tracking in-progress payload jobs and their parameters.
104pub trait PayloadBuilderAttributes: Send + Sync + Unpin + fmt::Debug + 'static {
105    /// The external payload attributes format this type can be constructed from.
106    type RpcPayloadAttributes: Send + Sync + 'static;
107    /// The error type used in [`PayloadBuilderAttributes::try_new`].
108    type Error: core::error::Error + Send + Sync + 'static;
109
110    /// Constructs new builder attributes from external payload attributes.
111    ///
112    /// Validates attributes and generates a unique [`PayloadId`] based on the
113    /// parent block, attributes, and version.
114    fn try_new(
115        parent: B256,
116        rpc_payload_attributes: Self::RpcPayloadAttributes,
117        version: u8,
118    ) -> Result<Self, Self::Error>
119    where
120        Self: Sized;
121
122    /// Returns the unique identifier for this payload build job.
123    fn payload_id(&self) -> PayloadId;
124
125    /// Returns the hash of the parent block this payload builds on.
126    fn parent(&self) -> B256;
127
128    /// Returns the timestamp to be used in the payload's header.
129    fn timestamp(&self) -> u64;
130
131    /// Returns the beacon chain block root from the parent block.
132    ///
133    /// Returns `None` for pre-merge blocks or non-beacon contexts.
134    fn parent_beacon_block_root(&self) -> Option<B256>;
135
136    /// Returns the address that should receive transaction fees.
137    fn suggested_fee_recipient(&self) -> Address;
138
139    /// Returns the randomness value for this block.
140    fn prev_randao(&self) -> B256;
141
142    /// Returns the list of withdrawals to be processed in this block.
143    fn withdrawals(&self) -> &Withdrawals;
144}
145
146/// Basic attributes required to initiate payload construction.
147///
148/// Defines minimal parameters needed to build a new execution payload.
149/// Implementations must be serializable for transmission.
150pub trait PayloadAttributes:
151    serde::de::DeserializeOwned + serde::Serialize + fmt::Debug + Clone + Send + Sync + 'static
152{
153    /// Returns the timestamp for the new payload.
154    fn timestamp(&self) -> u64;
155
156    /// Returns the withdrawals to be included in the payload.
157    ///
158    /// `Some` for post-Shanghai blocks, `None` for earlier blocks.
159    fn withdrawals(&self) -> Option<&Vec<Withdrawal>>;
160
161    /// Returns the parent beacon block root.
162    ///
163    /// `Some` for post-merge blocks, `None` for pre-merge blocks.
164    fn parent_beacon_block_root(&self) -> Option<B256>;
165}
166
167impl PayloadAttributes for EthPayloadAttributes {
168    fn timestamp(&self) -> u64 {
169        self.timestamp
170    }
171
172    fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
173        self.withdrawals.as_ref()
174    }
175
176    fn parent_beacon_block_root(&self) -> Option<B256> {
177        self.parent_beacon_block_root
178    }
179}
180
181#[cfg(feature = "op")]
182impl PayloadAttributes for op_alloy_rpc_types_engine::OpPayloadAttributes {
183    fn timestamp(&self) -> u64 {
184        self.payload_attributes.timestamp
185    }
186
187    fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
188        self.payload_attributes.withdrawals.as_ref()
189    }
190
191    fn parent_beacon_block_root(&self) -> Option<B256> {
192        self.payload_attributes.parent_beacon_block_root
193    }
194}
195
196/// Factory trait for creating payload attributes.
197///
198/// Enables different strategies for generating payload attributes based on
199/// contextual information. Useful for testing and specialized building.
200pub trait PayloadAttributesBuilder<Attributes, Header = alloy_consensus::Header>:
201    Send + Sync + 'static
202{
203    /// Constructs new payload attributes for the given timestamp.
204    fn build(&self, parent: &SealedHeader<Header>) -> Attributes;
205}
206
207impl<Attributes, Header, F> PayloadAttributesBuilder<Attributes, Header> for F
208where
209    Header: Clone,
210    F: Fn(SealedHeader<Header>) -> Attributes + Send + Sync + 'static,
211{
212    fn build(&self, parent: &SealedHeader<Header>) -> Attributes {
213        self(parent.clone())
214    }
215}
216
217impl<Attributes, Header, L, R> PayloadAttributesBuilder<Attributes, Header> for Either<L, R>
218where
219    L: PayloadAttributesBuilder<Attributes, Header>,
220    R: PayloadAttributesBuilder<Attributes, Header>,
221{
222    fn build(&self, parent: &SealedHeader<Header>) -> Attributes {
223        match self {
224            Self::Left(l) => l.build(parent),
225            Self::Right(r) => r.build(parent),
226        }
227    }
228}
229
230impl<Attributes, Header> PayloadAttributesBuilder<Attributes, Header>
231    for Box<dyn PayloadAttributesBuilder<Attributes, Header>>
232where
233    Header: 'static,
234    Attributes: 'static,
235{
236    fn build(&self, parent: &SealedHeader<Header>) -> Attributes {
237        self.as_ref().build(parent)
238    }
239}
240
241/// Trait to build the EVM environment for the next block from the given payload attributes.
242///
243/// Accepts payload attributes from CL, parent header and additional payload builder context.
244pub trait BuildNextEnv<Attributes, Header, Ctx>: Sized {
245    /// Builds the EVM environment for the next block from the given payload attributes.
246    fn build_next_env(
247        attributes: &Attributes,
248        parent: &SealedHeader<Header>,
249        ctx: &Ctx,
250    ) -> Result<Self, PayloadBuilderError>;
251}