1use std::{marker::PhantomData, sync::Arc};
7
8use alloy_eips::{eip4895::Withdrawal, eip7685::Requests};
9use alloy_primitives::{B256, Bytes, U256};
10use alloy_rpc_types_engine::{
11 BlobsBundleV1, BlobsBundleV2, ExecutionData, ExecutionPayload as AlloyExecutionPayload,
12 ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
13 ExecutionPayloadEnvelopeV5, ExecutionPayloadEnvelopeV6, ExecutionPayloadFieldV2,
14 ExecutionPayloadV1, ExecutionPayloadV3, PayloadAttributes as AlloyPayloadAttributes, PayloadId,
15};
16use arb_primitives::ArbPrimitives;
17use reth_engine_primitives::EngineTypes;
18use reth_payload_primitives::{
19 BuiltPayload, PayloadAttributes as PayloadAttributesTrait, PayloadTypes,
20};
21use reth_primitives_traits::{NodePrimitives, SealedBlock};
22use serde::{Deserialize, Serialize};
23
24pub type ArbBlock = <ArbPrimitives as NodePrimitives>::Block;
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct ArbPayloadAttributes {
33 #[serde(flatten)]
35 pub inner: AlloyPayloadAttributes,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub transactions: Option<Vec<Bytes>>,
39 #[serde(default)]
41 pub no_tx_pool: bool,
42}
43
44impl PayloadAttributesTrait for ArbPayloadAttributes {
45 fn timestamp(&self) -> u64 {
46 self.inner.timestamp
47 }
48
49 fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
50 self.inner.withdrawals.as_ref()
51 }
52
53 fn parent_beacon_block_root(&self) -> Option<B256> {
54 self.inner.parent_beacon_block_root
55 }
56
57 fn payload_id(&self, parent_hash: &B256) -> PayloadId {
58 arb_payload_id(parent_hash, self)
59 }
60}
61
62pub fn arb_payload_id(parent: &B256, attributes: &ArbPayloadAttributes) -> PayloadId {
66 use alloy_rlp::Encodable;
67 use sha2::Digest;
68
69 let mut hasher = sha2::Sha256::new();
70 hasher.update(parent.as_slice());
71 hasher.update(attributes.inner.timestamp.to_be_bytes());
72 hasher.update(attributes.inner.prev_randao.as_slice());
73 hasher.update(attributes.inner.suggested_fee_recipient.as_slice());
74 if let Some(withdrawals) = &attributes.inner.withdrawals {
75 let mut buf = Vec::new();
76 withdrawals.encode(&mut buf);
77 hasher.update(buf);
78 }
79 if let Some(root) = attributes.inner.parent_beacon_block_root {
80 hasher.update(root);
81 }
82 if attributes.no_tx_pool {
84 hasher.update([1u8]);
85 }
86 if let Some(txs) = &attributes.transactions {
87 for tx in txs {
88 hasher.update(tx.as_ref());
89 }
90 }
91
92 let out = hasher.finalize();
93 PayloadId::new(out.as_slice()[..8].try_into().expect("sufficient length"))
94}
95
96#[derive(Debug, Clone)]
100pub struct ArbBuiltPayload {
101 pub id: PayloadId,
103 pub block: Arc<SealedBlock<ArbBlock>>,
105 pub fees: U256,
107 pub requests: Option<Requests>,
109}
110
111impl ArbBuiltPayload {
112 pub fn new(id: PayloadId, block: Arc<SealedBlock<ArbBlock>>, fees: U256) -> Self {
114 Self {
115 id,
116 block,
117 fees,
118 requests: None,
119 }
120 }
121
122 pub fn with_requests(mut self, requests: Option<Requests>) -> Self {
124 self.requests = requests;
125 self
126 }
127}
128
129impl BuiltPayload for ArbBuiltPayload {
130 type Primitives = ArbPrimitives;
131
132 fn block(&self) -> &SealedBlock<ArbBlock> {
133 &self.block
134 }
135
136 fn fees(&self) -> U256 {
137 self.fees
138 }
139
140 fn requests(&self) -> Option<Requests> {
141 self.requests.clone()
142 }
143}
144
145#[derive(Debug, Clone, thiserror::Error)]
149#[error("payload conversion failed")]
150pub struct ArbPayloadConversionError;
151
152impl From<ArbBuiltPayload> for ExecutionPayloadV1 {
156 fn from(value: ArbBuiltPayload) -> Self {
157 Self::from_block_unchecked(
158 value.block.hash(),
159 &Arc::unwrap_or_clone(value.block).into_block(),
160 )
161 }
162}
163
164impl From<ArbBuiltPayload> for ExecutionPayloadEnvelopeV2 {
166 fn from(value: ArbBuiltPayload) -> Self {
167 let ArbBuiltPayload { block, fees, .. } = value;
168 Self {
169 block_value: fees,
170 execution_payload: ExecutionPayloadFieldV2::from_block_unchecked(
171 block.hash(),
172 &Arc::unwrap_or_clone(block).into_block(),
173 ),
174 }
175 }
176}
177
178impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV3 {
180 type Error = ArbPayloadConversionError;
181
182 fn try_from(value: ArbBuiltPayload) -> Result<Self, Self::Error> {
183 let ArbBuiltPayload { block, fees, .. } = value;
184 Ok(Self {
185 execution_payload: ExecutionPayloadV3::from_block_unchecked(
186 block.hash(),
187 &Arc::unwrap_or_clone(block).into_block(),
188 ),
189 block_value: fees,
190 should_override_builder: false,
191 blobs_bundle: BlobsBundleV1::empty(),
192 })
193 }
194}
195
196impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV4 {
198 type Error = ArbPayloadConversionError;
199
200 fn try_from(value: ArbBuiltPayload) -> Result<Self, Self::Error> {
201 let requests = value.requests.clone().unwrap_or_default();
202 let v3: ExecutionPayloadEnvelopeV3 = value.try_into()?;
203 Ok(Self {
204 execution_requests: requests,
205 envelope_inner: v3,
206 })
207 }
208}
209
210impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV5 {
212 type Error = ArbPayloadConversionError;
213
214 fn try_from(value: ArbBuiltPayload) -> Result<Self, Self::Error> {
215 let ArbBuiltPayload {
216 block,
217 fees,
218 requests,
219 ..
220 } = value;
221 Ok(Self {
222 execution_payload: ExecutionPayloadV3::from_block_unchecked(
223 block.hash(),
224 &Arc::unwrap_or_clone(block).into_block(),
225 ),
226 block_value: fees,
227 should_override_builder: false,
228 blobs_bundle: BlobsBundleV2::empty(),
229 execution_requests: requests.unwrap_or_default(),
230 })
231 }
232}
233
234impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV6 {
236 type Error = ArbPayloadConversionError;
237
238 fn try_from(_value: ArbBuiltPayload) -> Result<Self, Self::Error> {
239 Err(ArbPayloadConversionError)
240 }
241}
242
243#[derive(Debug, Default, Clone, Serialize, Deserialize)]
247#[non_exhaustive]
248pub struct ArbPayloadTypes;
249
250impl PayloadTypes for ArbPayloadTypes {
251 type ExecutionData = ExecutionData;
252 type BuiltPayload = ArbBuiltPayload;
253 type PayloadAttributes = ArbPayloadAttributes;
254
255 fn block_to_payload(
256 block: SealedBlock<
257 <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
258 >,
259 ) -> Self::ExecutionData {
260 let (payload, sidecar) =
261 AlloyExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
262 ExecutionData { payload, sidecar }
263 }
264}
265
266#[derive(Debug, Default, Clone, Serialize, Deserialize)]
270#[non_exhaustive]
271pub struct ArbEngineTypes<T: PayloadTypes = ArbPayloadTypes> {
272 _marker: PhantomData<T>,
273}
274
275impl<T: PayloadTypes<ExecutionData = ExecutionData>> PayloadTypes for ArbEngineTypes<T>
276where
277 T::BuiltPayload: BuiltPayload<Primitives: NodePrimitives<Block = ArbBlock>>,
278{
279 type ExecutionData = T::ExecutionData;
280 type BuiltPayload = T::BuiltPayload;
281 type PayloadAttributes = T::PayloadAttributes;
282
283 fn block_to_payload(
284 block: SealedBlock<
285 <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
286 >,
287 ) -> Self::ExecutionData {
288 T::block_to_payload(block)
289 }
290}
291
292impl<T> EngineTypes for ArbEngineTypes<T>
293where
294 T: PayloadTypes<ExecutionData = ExecutionData>,
295 T::BuiltPayload: BuiltPayload<Primitives: NodePrimitives<Block = ArbBlock>>
296 + TryInto<ExecutionPayloadV1>
297 + TryInto<ExecutionPayloadEnvelopeV2>
298 + TryInto<ExecutionPayloadEnvelopeV3>
299 + TryInto<ExecutionPayloadEnvelopeV4>
300 + TryInto<ExecutionPayloadEnvelopeV5>
301 + TryInto<ExecutionPayloadEnvelopeV6>,
302{
303 type ExecutionPayloadEnvelopeV1 = ExecutionPayloadV1;
304 type ExecutionPayloadEnvelopeV2 = ExecutionPayloadEnvelopeV2;
305 type ExecutionPayloadEnvelopeV3 = ExecutionPayloadEnvelopeV3;
306 type ExecutionPayloadEnvelopeV4 = ExecutionPayloadEnvelopeV4;
307 type ExecutionPayloadEnvelopeV5 = ExecutionPayloadEnvelopeV5;
308 type ExecutionPayloadEnvelopeV6 = ExecutionPayloadEnvelopeV6;
309}