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