reth_payload_primitives/
payload.rs

1use crate::{MessageValidationKind, PayloadAttributes};
2use alloc::vec::Vec;
3use alloy_eips::{eip4895::Withdrawal, eip7685::Requests};
4use alloy_primitives::B256;
5use alloy_rpc_types_engine::ExecutionData;
6use core::fmt::Debug;
7use serde::{de::DeserializeOwned, Serialize};
8
9/// An execution payload.
10pub trait ExecutionPayload:
11    Serialize + DeserializeOwned + Debug + Clone + Send + Sync + 'static
12{
13    /// Returns the parent hash of the block.
14    fn parent_hash(&self) -> B256;
15
16    /// Returns the hash of the block.
17    fn block_hash(&self) -> B256;
18
19    /// Returns the number of the block.
20    fn block_number(&self) -> u64;
21
22    /// Returns the withdrawals for the payload, if it exists.
23    fn withdrawals(&self) -> Option<&Vec<Withdrawal>>;
24
25    /// Return the parent beacon block root for the payload, if it exists.
26    fn parent_beacon_block_root(&self) -> Option<B256>;
27
28    /// Returns the timestamp to be used in the payload.
29    fn timestamp(&self) -> u64;
30
31    /// Gas used by the payload
32    fn gas_used(&self) -> u64;
33}
34
35impl ExecutionPayload for ExecutionData {
36    fn parent_hash(&self) -> B256 {
37        self.payload.parent_hash()
38    }
39
40    fn block_hash(&self) -> B256 {
41        self.payload.block_hash()
42    }
43
44    fn block_number(&self) -> u64 {
45        self.payload.block_number()
46    }
47
48    fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
49        self.payload.withdrawals()
50    }
51
52    fn parent_beacon_block_root(&self) -> Option<B256> {
53        self.sidecar.parent_beacon_block_root()
54    }
55
56    fn timestamp(&self) -> u64 {
57        self.payload.timestamp()
58    }
59
60    fn gas_used(&self) -> u64 {
61        self.payload.as_v1().gas_used
62    }
63}
64
65/// Either a type that implements the [`ExecutionPayload`] or a type that implements the
66/// [`PayloadAttributes`] trait.
67///
68/// This is a helper type to unify pre-validation of version specific fields of the engine API.
69#[derive(Debug)]
70pub enum PayloadOrAttributes<'a, Payload, Attributes> {
71    /// An [`ExecutionPayload`]
72    ExecutionPayload(&'a Payload),
73    /// A payload attributes type.
74    PayloadAttributes(&'a Attributes),
75}
76
77impl<'a, Payload, Attributes> PayloadOrAttributes<'a, Payload, Attributes> {
78    /// Construct a [`PayloadOrAttributes::ExecutionPayload`] variant
79    pub const fn from_execution_payload(payload: &'a Payload) -> Self {
80        Self::ExecutionPayload(payload)
81    }
82
83    /// Construct a [`PayloadOrAttributes::PayloadAttributes`] variant
84    pub const fn from_attributes(attributes: &'a Attributes) -> Self {
85        Self::PayloadAttributes(attributes)
86    }
87}
88
89impl<Payload, Attributes> PayloadOrAttributes<'_, Payload, Attributes>
90where
91    Payload: ExecutionPayload,
92    Attributes: PayloadAttributes,
93{
94    /// Return the withdrawals for the payload or attributes.
95    pub fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
96        match self {
97            Self::ExecutionPayload(payload) => payload.withdrawals(),
98            Self::PayloadAttributes(attributes) => attributes.withdrawals(),
99        }
100    }
101
102    /// Return the timestamp for the payload or attributes.
103    pub fn timestamp(&self) -> u64 {
104        match self {
105            Self::ExecutionPayload(payload) => payload.timestamp(),
106            Self::PayloadAttributes(attributes) => attributes.timestamp(),
107        }
108    }
109
110    /// Return the parent beacon block root for the payload or attributes.
111    pub fn parent_beacon_block_root(&self) -> Option<B256> {
112        match self {
113            Self::ExecutionPayload(payload) => payload.parent_beacon_block_root(),
114            Self::PayloadAttributes(attributes) => attributes.parent_beacon_block_root(),
115        }
116    }
117
118    /// Return a [`MessageValidationKind`] for the payload or attributes.
119    pub const fn message_validation_kind(&self) -> MessageValidationKind {
120        match self {
121            Self::ExecutionPayload { .. } => MessageValidationKind::Payload,
122            Self::PayloadAttributes(_) => MessageValidationKind::PayloadAttributes,
123        }
124    }
125}
126
127impl<'a, Payload, AttributesType> From<&'a AttributesType>
128    for PayloadOrAttributes<'a, Payload, AttributesType>
129where
130    AttributesType: PayloadAttributes,
131{
132    fn from(attributes: &'a AttributesType) -> Self {
133        Self::PayloadAttributes(attributes)
134    }
135}
136
137#[cfg(feature = "op")]
138impl ExecutionPayload for op_alloy_rpc_types_engine::OpExecutionData {
139    fn parent_hash(&self) -> B256 {
140        self.parent_hash()
141    }
142
143    fn block_hash(&self) -> B256 {
144        self.block_hash()
145    }
146
147    fn block_number(&self) -> u64 {
148        self.block_number()
149    }
150
151    fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
152        self.payload.as_v2().map(|p| &p.withdrawals)
153    }
154
155    fn parent_beacon_block_root(&self) -> Option<B256> {
156        self.sidecar.parent_beacon_block_root()
157    }
158
159    fn timestamp(&self) -> u64 {
160        self.payload.as_v1().timestamp
161    }
162
163    fn gas_used(&self) -> u64 {
164        self.payload.as_v1().gas_used
165    }
166}
167
168/// Special implementation for Ethereum types that provides additional helper methods
169impl<'a, Attributes> PayloadOrAttributes<'a, ExecutionData, Attributes>
170where
171    Attributes: PayloadAttributes,
172{
173    /// Return the execution requests from the payload, if available.
174    ///
175    /// This will return `Some(requests)` only if:
176    /// - The payload is an `ExecutionData` (not `PayloadAttributes`)
177    /// - The payload has Prague payload fields
178    /// - The Prague fields contain requests (not a hash)
179    ///
180    /// Returns `None` in all other cases.
181    pub fn execution_requests(&self) -> Option<&Requests> {
182        if let Self::ExecutionPayload(payload) = self {
183            payload.sidecar.requests()
184        } else {
185            None
186        }
187    }
188}