1use alloy_primitives::{Address, B256, Bytes};
2use alloy_rpc_types_engine::PayloadId;
3use alloy_rpc_types_eth::Withdrawals;
4use reth_ethereum_engine_primitives::{EthPayloadAttributes, EthPayloadBuilderAttributes};
5use reth_node_api::{PayloadAttributes, PayloadBuilderAttributes};
6use serde::{Deserialize, Serialize};
7use std::{
8 convert::Infallible,
9 sync::{Arc, atomic, atomic::Ordering},
10};
11use tempo_primitives::RecoveredSubBlock;
12
13#[derive(Debug, Clone, Default)]
17pub struct InterruptHandle(Arc<atomic::AtomicBool>);
18
19impl InterruptHandle {
20 pub fn interrupt(&self) {
22 self.0.store(true, Ordering::Relaxed);
23 }
24
25 pub fn is_interrupted(&self) -> bool {
27 self.0.load(Ordering::Relaxed)
28 }
29}
30
31#[derive(derive_more::Debug, Clone)]
37pub struct TempoPayloadBuilderAttributes {
38 inner: EthPayloadBuilderAttributes,
39 interrupt: InterruptHandle,
40 timestamp_millis_part: u64,
41 extra_data: Bytes,
46 #[debug(skip)]
47 subblocks: Arc<dyn Fn() -> Vec<RecoveredSubBlock> + Send + Sync + 'static>,
48}
49
50impl TempoPayloadBuilderAttributes {
51 pub fn new(
53 id: PayloadId,
54 parent: B256,
55 suggested_fee_recipient: Address,
56 timestamp_millis: u64,
57 extra_data: Bytes,
58 subblocks: impl Fn() -> Vec<RecoveredSubBlock> + Send + Sync + 'static,
59 ) -> Self {
60 let (seconds, millis) = (timestamp_millis / 1000, timestamp_millis % 1000);
61 Self {
62 inner: EthPayloadBuilderAttributes {
63 id,
64 parent,
65 timestamp: seconds,
66 suggested_fee_recipient,
67 prev_randao: B256::ZERO,
68 withdrawals: Withdrawals::default(),
69 parent_beacon_block_root: Some(B256::ZERO),
70 },
71 interrupt: InterruptHandle::default(),
72 timestamp_millis_part: millis,
73 extra_data,
74 subblocks: Arc::new(subblocks),
75 }
76 }
77
78 pub fn extra_data(&self) -> &Bytes {
80 &self.extra_data
81 }
82
83 pub fn is_interrupted(&self) -> bool {
86 self.interrupt.0.load(Ordering::Relaxed)
87 }
88
89 pub fn interrupt_handle(&self) -> &InterruptHandle {
91 &self.interrupt
92 }
93
94 pub fn timestamp_millis_part(&self) -> u64 {
96 self.timestamp_millis_part
97 }
98
99 pub fn timestamp_millis(&self) -> u64 {
101 self.inner
102 .timestamp()
103 .saturating_mul(1000)
104 .saturating_add(self.timestamp_millis_part)
105 }
106
107 pub fn subblocks(&self) -> Vec<RecoveredSubBlock> {
109 (self.subblocks)()
110 }
111}
112
113impl From<EthPayloadBuilderAttributes> for TempoPayloadBuilderAttributes {
117 fn from(inner: EthPayloadBuilderAttributes) -> Self {
118 Self {
119 inner,
120 interrupt: InterruptHandle::default(),
121 timestamp_millis_part: 0,
122 extra_data: Bytes::default(),
123 subblocks: Arc::new(Vec::new),
124 }
125 }
126}
127
128impl PayloadBuilderAttributes for TempoPayloadBuilderAttributes {
129 type RpcPayloadAttributes = TempoPayloadAttributes;
130 type Error = Infallible;
131
132 fn try_new(
133 parent: B256,
134 rpc_payload_attributes: Self::RpcPayloadAttributes,
135 version: u8,
136 ) -> Result<Self, Self::Error>
137 where
138 Self: Sized,
139 {
140 let TempoPayloadAttributes {
141 inner,
142 timestamp_millis_part,
143 } = rpc_payload_attributes;
144 Ok(Self {
145 inner: EthPayloadBuilderAttributes::try_new(parent, inner, version)?,
146 interrupt: InterruptHandle::default(),
147 timestamp_millis_part,
148 extra_data: Bytes::default(),
149 subblocks: Arc::new(Vec::new),
150 })
151 }
152
153 fn payload_id(&self) -> alloy_rpc_types_engine::payload::PayloadId {
154 self.inner.payload_id()
155 }
156
157 fn parent(&self) -> B256 {
158 self.inner.parent()
159 }
160
161 fn timestamp(&self) -> u64 {
162 self.inner.timestamp()
163 }
164
165 fn parent_beacon_block_root(&self) -> Option<B256> {
166 self.inner.parent_beacon_block_root()
167 }
168
169 fn suggested_fee_recipient(&self) -> Address {
170 self.inner.suggested_fee_recipient()
171 }
172
173 fn prev_randao(&self) -> B256 {
174 self.inner.prev_randao()
175 }
176
177 fn withdrawals(&self) -> &Withdrawals {
178 self.inner.withdrawals()
179 }
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut)]
184#[serde(rename_all = "camelCase")]
185pub struct TempoPayloadAttributes {
186 #[serde(flatten)]
188 #[deref]
189 #[deref_mut]
190 pub inner: EthPayloadAttributes,
191
192 #[serde(with = "alloy_serde::quantity")]
194 pub timestamp_millis_part: u64,
195}
196
197impl PayloadAttributes for TempoPayloadAttributes {
198 fn timestamp(&self) -> u64 {
199 self.inner.timestamp()
200 }
201
202 fn withdrawals(&self) -> Option<&Vec<alloy_rpc_types_eth::Withdrawal>> {
203 self.inner.withdrawals()
204 }
205
206 fn parent_beacon_block_root(&self) -> Option<B256> {
207 self.inner.parent_beacon_block_root()
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn test_attributes_without_extra_data() {
217 let parent = B256::default();
218 let id = PayloadId::default();
219 let recipient = Address::default();
220 let timestamp_millis = 1000;
221
222 let attrs = TempoPayloadBuilderAttributes::new(
223 id,
224 parent,
225 recipient,
226 timestamp_millis,
227 Bytes::default(),
228 Vec::new,
229 );
230
231 assert_eq!(attrs.extra_data(), &Bytes::default());
232 assert_eq!(attrs.parent(), parent);
233 assert_eq!(attrs.suggested_fee_recipient(), recipient);
234 assert_eq!(attrs.timestamp(), 1); }
236
237 #[test]
238 fn test_attributes_with_extra_data() {
239 let parent = B256::default();
240 let id = PayloadId::default();
241 let recipient = Address::default();
242 let timestamp_millis = 1000;
243 let extra_data = Bytes::from(vec![1, 2, 3, 4, 5]);
244
245 let attrs = TempoPayloadBuilderAttributes::new(
246 id,
247 parent,
248 recipient,
249 timestamp_millis,
250 extra_data.clone(),
251 Vec::new,
252 );
253
254 assert_eq!(attrs.extra_data(), &extra_data);
255 assert_eq!(attrs.parent(), parent);
256 assert_eq!(attrs.suggested_fee_recipient(), recipient);
257 }
258
259 #[test]
260 fn test_attributes_with_empty_extra_data() {
261 let parent = B256::default();
262 let id = PayloadId::default();
263 let recipient = Address::default();
264 let timestamp_millis = 1000;
265
266 let attrs = TempoPayloadBuilderAttributes::new(
267 id,
268 parent,
269 recipient,
270 timestamp_millis,
271 Bytes::default(),
272 Vec::new,
273 );
274
275 assert_eq!(attrs.extra_data(), &Bytes::default());
276 }
277}