1use std::{marker::PhantomData, sync::Arc};
7
8use alloy_eips::{
9 eip4895::{Withdrawal, Withdrawals},
10 eip7685::Requests,
11};
12use alloy_primitives::{Address, B256, Bytes, U256};
13use alloy_rpc_types_engine::{
14 BlobsBundleV1, BlobsBundleV2, ExecutionData, ExecutionPayload as AlloyExecutionPayload,
15 ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
16 ExecutionPayloadEnvelopeV5, ExecutionPayloadEnvelopeV6, ExecutionPayloadFieldV2,
17 ExecutionPayloadV1, ExecutionPayloadV3, PayloadAttributes as AlloyPayloadAttributes, PayloadId,
18};
19use arb_primitives::ArbPrimitives;
20use reth_engine_primitives::EngineTypes;
21use reth_payload_primitives::{
22 BuiltPayload, PayloadAttributes as PayloadAttributesTrait, PayloadBuilderAttributes,
23 PayloadTypes,
24};
25use reth_primitives_traits::{NodePrimitives, SealedBlock};
26use serde::{Deserialize, Serialize};
27
28pub type ArbBlock = <ArbPrimitives as NodePrimitives>::Block;
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct ArbPayloadAttributes {
37 #[serde(flatten)]
39 pub inner: AlloyPayloadAttributes,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub transactions: Option<Vec<Bytes>>,
43 #[serde(default)]
45 pub no_tx_pool: bool,
46}
47
48impl PayloadAttributesTrait for ArbPayloadAttributes {
49 fn timestamp(&self) -> u64 {
50 self.inner.timestamp
51 }
52
53 fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
54 self.inner.withdrawals.as_ref()
55 }
56
57 fn parent_beacon_block_root(&self) -> Option<B256> {
58 self.inner.parent_beacon_block_root
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct ArbPayloadBuilderAttributes {
67 pub id: PayloadId,
69 pub parent: B256,
71 pub timestamp: u64,
73 pub suggested_fee_recipient: Address,
75 pub prev_randao: B256,
77 pub withdrawals: Withdrawals,
79 pub parent_beacon_block_root: Option<B256>,
81 pub no_tx_pool: bool,
83 pub transactions: Vec<Bytes>,
85}
86
87impl PayloadBuilderAttributes for ArbPayloadBuilderAttributes {
88 type RpcPayloadAttributes = ArbPayloadAttributes;
89 type Error = PayloadIdComputeError;
90
91 fn try_new(
92 parent: B256,
93 attributes: ArbPayloadAttributes,
94 _version: u8,
95 ) -> Result<Self, Self::Error> {
96 let id = arb_payload_id(&parent, &attributes);
97 Ok(Self {
98 id,
99 parent,
100 timestamp: attributes.inner.timestamp,
101 suggested_fee_recipient: attributes.inner.suggested_fee_recipient,
102 prev_randao: attributes.inner.prev_randao,
103 withdrawals: attributes.inner.withdrawals.unwrap_or_default().into(),
104 parent_beacon_block_root: attributes.inner.parent_beacon_block_root,
105 no_tx_pool: attributes.no_tx_pool,
106 transactions: attributes.transactions.unwrap_or_default(),
107 })
108 }
109
110 fn payload_id(&self) -> PayloadId {
111 self.id
112 }
113
114 fn parent(&self) -> B256 {
115 self.parent
116 }
117
118 fn timestamp(&self) -> u64 {
119 self.timestamp
120 }
121
122 fn parent_beacon_block_root(&self) -> Option<B256> {
123 self.parent_beacon_block_root
124 }
125
126 fn suggested_fee_recipient(&self) -> Address {
127 self.suggested_fee_recipient
128 }
129
130 fn prev_randao(&self) -> B256 {
131 self.prev_randao
132 }
133
134 fn withdrawals(&self) -> &Withdrawals {
135 &self.withdrawals
136 }
137}
138
139#[derive(Debug, Clone, Copy, thiserror::Error)]
143#[error("payload id computation failed")]
144pub struct PayloadIdComputeError;
145
146pub fn arb_payload_id(parent: &B256, attributes: &ArbPayloadAttributes) -> PayloadId {
148 use alloy_rlp::Encodable;
149 use sha2::Digest;
150
151 let mut hasher = sha2::Sha256::new();
152 hasher.update(parent.as_slice());
153 hasher.update(attributes.inner.timestamp.to_be_bytes());
154 hasher.update(attributes.inner.prev_randao.as_slice());
155 hasher.update(attributes.inner.suggested_fee_recipient.as_slice());
156 if let Some(withdrawals) = &attributes.inner.withdrawals {
157 let mut buf = Vec::new();
158 withdrawals.encode(&mut buf);
159 hasher.update(buf);
160 }
161 if let Some(root) = attributes.inner.parent_beacon_block_root {
162 hasher.update(root);
163 }
164 if attributes.no_tx_pool {
166 hasher.update([1u8]);
167 }
168 if let Some(txs) = &attributes.transactions {
169 for tx in txs {
170 hasher.update(tx.as_ref());
171 }
172 }
173
174 let out = hasher.finalize();
175 PayloadId::new(out.as_slice()[..8].try_into().expect("sufficient length"))
176}
177
178#[derive(Debug, Clone)]
182pub struct ArbBuiltPayload {
183 pub id: PayloadId,
185 pub block: Arc<SealedBlock<ArbBlock>>,
187 pub fees: U256,
189 pub requests: Option<Requests>,
191}
192
193impl ArbBuiltPayload {
194 pub fn new(id: PayloadId, block: Arc<SealedBlock<ArbBlock>>, fees: U256) -> Self {
196 Self {
197 id,
198 block,
199 fees,
200 requests: None,
201 }
202 }
203
204 pub fn with_requests(mut self, requests: Option<Requests>) -> Self {
206 self.requests = requests;
207 self
208 }
209}
210
211impl BuiltPayload for ArbBuiltPayload {
212 type Primitives = ArbPrimitives;
213
214 fn block(&self) -> &SealedBlock<ArbBlock> {
215 &self.block
216 }
217
218 fn fees(&self) -> U256 {
219 self.fees
220 }
221
222 fn requests(&self) -> Option<Requests> {
223 self.requests.clone()
224 }
225}
226
227#[derive(Debug, Clone, thiserror::Error)]
231#[error("payload conversion failed")]
232pub struct ArbPayloadConversionError;
233
234impl From<ArbBuiltPayload> for ExecutionPayloadV1 {
238 fn from(value: ArbBuiltPayload) -> Self {
239 Self::from_block_unchecked(
240 value.block.hash(),
241 &Arc::unwrap_or_clone(value.block).into_block(),
242 )
243 }
244}
245
246impl From<ArbBuiltPayload> for ExecutionPayloadEnvelopeV2 {
248 fn from(value: ArbBuiltPayload) -> Self {
249 let ArbBuiltPayload { block, fees, .. } = value;
250 Self {
251 block_value: fees,
252 execution_payload: ExecutionPayloadFieldV2::from_block_unchecked(
253 block.hash(),
254 &Arc::unwrap_or_clone(block).into_block(),
255 ),
256 }
257 }
258}
259
260impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV3 {
262 type Error = ArbPayloadConversionError;
263
264 fn try_from(value: ArbBuiltPayload) -> Result<Self, Self::Error> {
265 let ArbBuiltPayload { block, fees, .. } = value;
266 Ok(Self {
267 execution_payload: ExecutionPayloadV3::from_block_unchecked(
268 block.hash(),
269 &Arc::unwrap_or_clone(block).into_block(),
270 ),
271 block_value: fees,
272 should_override_builder: false,
273 blobs_bundle: BlobsBundleV1::empty(),
274 })
275 }
276}
277
278impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV4 {
280 type Error = ArbPayloadConversionError;
281
282 fn try_from(value: ArbBuiltPayload) -> Result<Self, Self::Error> {
283 let requests = value.requests.clone().unwrap_or_default();
284 let v3: ExecutionPayloadEnvelopeV3 = value.try_into()?;
285 Ok(Self {
286 execution_requests: requests,
287 envelope_inner: v3,
288 })
289 }
290}
291
292impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV5 {
294 type Error = ArbPayloadConversionError;
295
296 fn try_from(value: ArbBuiltPayload) -> Result<Self, Self::Error> {
297 let ArbBuiltPayload {
298 block,
299 fees,
300 requests,
301 ..
302 } = value;
303 Ok(Self {
304 execution_payload: ExecutionPayloadV3::from_block_unchecked(
305 block.hash(),
306 &Arc::unwrap_or_clone(block).into_block(),
307 ),
308 block_value: fees,
309 should_override_builder: false,
310 blobs_bundle: BlobsBundleV2::empty(),
311 execution_requests: requests.unwrap_or_default(),
312 })
313 }
314}
315
316impl TryFrom<ArbBuiltPayload> for ExecutionPayloadEnvelopeV6 {
318 type Error = ArbPayloadConversionError;
319
320 fn try_from(_value: ArbBuiltPayload) -> Result<Self, Self::Error> {
321 Err(ArbPayloadConversionError)
322 }
323}
324
325#[derive(Debug, Default, Clone, Serialize, Deserialize)]
329#[non_exhaustive]
330pub struct ArbPayloadTypes;
331
332impl PayloadTypes for ArbPayloadTypes {
333 type ExecutionData = ExecutionData;
334 type BuiltPayload = ArbBuiltPayload;
335 type PayloadAttributes = ArbPayloadAttributes;
336 type PayloadBuilderAttributes = ArbPayloadBuilderAttributes;
337
338 fn block_to_payload(
339 block: SealedBlock<
340 <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
341 >,
342 ) -> Self::ExecutionData {
343 let (payload, sidecar) =
344 AlloyExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
345 ExecutionData { payload, sidecar }
346 }
347}
348
349#[derive(Debug, Default, Clone, Serialize, Deserialize)]
353#[non_exhaustive]
354pub struct ArbEngineTypes<T: PayloadTypes = ArbPayloadTypes> {
355 _marker: PhantomData<T>,
356}
357
358impl<T: PayloadTypes<ExecutionData = ExecutionData>> PayloadTypes for ArbEngineTypes<T>
359where
360 T::BuiltPayload: BuiltPayload<Primitives: NodePrimitives<Block = ArbBlock>>,
361{
362 type ExecutionData = T::ExecutionData;
363 type BuiltPayload = T::BuiltPayload;
364 type PayloadAttributes = T::PayloadAttributes;
365 type PayloadBuilderAttributes = T::PayloadBuilderAttributes;
366
367 fn block_to_payload(
368 block: SealedBlock<
369 <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
370 >,
371 ) -> Self::ExecutionData {
372 T::block_to_payload(block)
373 }
374}
375
376impl<T> EngineTypes for ArbEngineTypes<T>
377where
378 T: PayloadTypes<ExecutionData = ExecutionData>,
379 T::BuiltPayload: BuiltPayload<Primitives: NodePrimitives<Block = ArbBlock>>
380 + TryInto<ExecutionPayloadV1>
381 + TryInto<ExecutionPayloadEnvelopeV2>
382 + TryInto<ExecutionPayloadEnvelopeV3>
383 + TryInto<ExecutionPayloadEnvelopeV4>
384 + TryInto<ExecutionPayloadEnvelopeV5>
385 + TryInto<ExecutionPayloadEnvelopeV6>,
386{
387 type ExecutionPayloadEnvelopeV1 = ExecutionPayloadV1;
388 type ExecutionPayloadEnvelopeV2 = ExecutionPayloadEnvelopeV2;
389 type ExecutionPayloadEnvelopeV3 = ExecutionPayloadEnvelopeV3;
390 type ExecutionPayloadEnvelopeV4 = ExecutionPayloadEnvelopeV4;
391 type ExecutionPayloadEnvelopeV5 = ExecutionPayloadEnvelopeV5;
392 type ExecutionPayloadEnvelopeV6 = ExecutionPayloadEnvelopeV6;
393}