1use std::{fmt::Display, str::FromStr};
6
7use alloy::primitives::U256;
8use anyhow::{bail, Result};
9use serde::{Deserialize, Serialize};
10
11use crate::{
12 block::{account::Account, header::Header},
13 task::datalake::DatalakeField,
14};
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(try_from = "String")]
18pub enum HeaderField {
19 ParentHash,
20 OmmerHash,
21 Beneficiary,
22 StateRoot,
23 TransactionsRoot,
24 ReceiptsRoot,
25 LogsBloom,
26 Difficulty,
27 Number,
28 GasLimit,
29 GasUsed,
30 Timestamp,
31 ExtraData,
32 MixHash,
33 Nonce,
34 BaseFeePerGas,
35 WithdrawalsRoot,
36 BlobGasUsed,
37 ExcessBlobGas,
38 ParentBeaconBlockRoot,
39}
40
41impl HeaderField {
42 pub fn variants() -> Vec<String> {
43 vec![
44 "PARENT_HASH".to_string(),
45 "OMMERS_HASH".to_string(),
46 "BENEFICIARY".to_string(),
47 "STATE_ROOT".to_string(),
48 "TRANSACTIONS_ROOT".to_string(),
49 "RECEIPTS_ROOT".to_string(),
50 "LOGS_BLOOM".to_string(),
51 "DIFFICULTY".to_string(),
52 "NUMBER".to_string(),
53 "GAS_LIMIT".to_string(),
54 "GAS_USED".to_string(),
55 "TIMESTAMP".to_string(),
56 "EXTRA_DATA".to_string(),
57 "MIX_HASH".to_string(),
58 "NONCE".to_string(),
59 "BASE_FEE_PER_GAS".to_string(),
60 "WITHDRAWALS_ROOT".to_string(),
61 "BLOB_GAS_USED".to_string(),
62 "EXCESS_BLOB_GAS".to_string(),
63 "PARENT_BEACON_BLOCK_ROOT".to_string(),
64 ]
65 }
66
67 pub fn integer_variants_index(index: u8) -> Self {
68 match index {
69 0 => HeaderField::Difficulty,
70 1 => HeaderField::Number,
71 2 => HeaderField::GasLimit,
72 3 => HeaderField::GasUsed,
73 4 => HeaderField::Timestamp,
74 5 => HeaderField::Nonce,
75 6 => HeaderField::BaseFeePerGas,
76 7 => HeaderField::BlobGasUsed,
77 8 => HeaderField::ExcessBlobGas,
78 _ => unreachable!(),
79 }
80 }
81}
82
83impl DatalakeField for HeaderField {
84 fn from_index(index: u8) -> Result<Self> {
85 match index {
86 0 => Ok(HeaderField::ParentHash),
87 1 => Ok(HeaderField::OmmerHash),
88 2 => Ok(HeaderField::Beneficiary),
89 3 => Ok(HeaderField::StateRoot),
90 4 => Ok(HeaderField::TransactionsRoot),
91 5 => Ok(HeaderField::ReceiptsRoot),
92 6 => Ok(HeaderField::LogsBloom),
93 7 => Ok(HeaderField::Difficulty),
94 8 => Ok(HeaderField::Number),
95 9 => Ok(HeaderField::GasLimit),
96 10 => Ok(HeaderField::GasUsed),
97 11 => Ok(HeaderField::Timestamp),
98 12 => Ok(HeaderField::ExtraData),
99 13 => Ok(HeaderField::MixHash),
100 14 => Ok(HeaderField::Nonce),
101 15 => Ok(HeaderField::BaseFeePerGas),
102 16 => Ok(HeaderField::WithdrawalsRoot),
103 17 => Ok(HeaderField::BlobGasUsed),
104 18 => Ok(HeaderField::ExcessBlobGas),
105 19 => Ok(HeaderField::ParentBeaconBlockRoot),
106 _ => bail!("Unknown header field"),
107 }
108 }
109
110 fn to_index(&self) -> u8 {
111 match self {
112 HeaderField::ParentHash => 0,
113 HeaderField::OmmerHash => 1,
114 HeaderField::Beneficiary => 2,
115 HeaderField::StateRoot => 3,
116 HeaderField::TransactionsRoot => 4,
117 HeaderField::ReceiptsRoot => 5,
118 HeaderField::LogsBloom => 6,
119 HeaderField::Difficulty => 7,
120 HeaderField::Number => 8,
121 HeaderField::GasLimit => 9,
122 HeaderField::GasUsed => 10,
123 HeaderField::Timestamp => 11,
124 HeaderField::ExtraData => 12,
125 HeaderField::MixHash => 13,
126 HeaderField::Nonce => 14,
127 HeaderField::BaseFeePerGas => 15,
128 HeaderField::WithdrawalsRoot => 16,
129 HeaderField::BlobGasUsed => 17,
130 HeaderField::ExcessBlobGas => 18,
131 HeaderField::ParentBeaconBlockRoot => 19,
132 }
133 }
134
135 fn decode_field_from_rlp(&self, header_rlp: &[u8]) -> U256 {
136 let decoded = <Header>::rlp_decode(header_rlp);
137
138 match self {
139 HeaderField::ParentHash => decoded.parent_hash.into(),
140 HeaderField::OmmerHash => decoded.ommers_hash.into(),
141 HeaderField::Beneficiary => {
142 U256::from_str_radix(&decoded.beneficiary.to_string(), 16).unwrap()
143 }
144 HeaderField::StateRoot => decoded.state_root.into(),
145 HeaderField::TransactionsRoot => decoded.transactions_root.into(),
146 HeaderField::ReceiptsRoot => decoded.receipts_root.into(),
147 HeaderField::LogsBloom => U256::from_str_radix(&decoded.logs_bloom.to_string(), 16)
148 .expect("logs bloom does not match U256"),
149 HeaderField::Difficulty => U256::from(decoded.difficulty),
150 HeaderField::Number => U256::from(decoded.number),
151 HeaderField::GasLimit => U256::from(decoded.gas_limit),
152 HeaderField::GasUsed => U256::from(decoded.gas_used),
153 HeaderField::Timestamp => U256::from(decoded.timestamp),
154 HeaderField::ExtraData => todo!("extra data doesn't fit into U256"),
155 HeaderField::MixHash => decoded.mix_hash.into(),
156 HeaderField::Nonce => U256::from(decoded.nonce),
157 HeaderField::BaseFeePerGas => U256::from(
158 decoded
159 .base_fee_per_gas
160 .expect("base fee per gas does not exist"),
161 ),
162 HeaderField::WithdrawalsRoot => decoded
163 .withdrawals_root
164 .expect("withdrawals root does not exist")
165 .into(),
166 HeaderField::BlobGasUsed => U256::from(decoded.blob_gas_used.unwrap()),
167 HeaderField::ExcessBlobGas => U256::from(decoded.excess_blob_gas.unwrap()),
168 HeaderField::ParentBeaconBlockRoot => decoded
169 .parent_beacon_block_root
170 .expect("parent beacon block root does not exist")
171 .into(),
172 }
173 }
174}
175
176impl FromStr for HeaderField {
177 type Err = anyhow::Error;
178
179 fn from_str(s: &str) -> Result<Self> {
180 match s {
181 "PARENT_HASH" => Ok(HeaderField::ParentHash),
182 "OMMERS_HASH" => Ok(HeaderField::OmmerHash),
183 "BENEFICIARY" => Ok(HeaderField::Beneficiary),
184 "STATE_ROOT" => Ok(HeaderField::StateRoot),
185 "TRANSACTIONS_ROOT" => Ok(HeaderField::TransactionsRoot),
186 "RECEIPTS_ROOT" => Ok(HeaderField::ReceiptsRoot),
187 "LOGS_BLOOM" => Ok(HeaderField::LogsBloom),
188 "DIFFICULTY" => Ok(HeaderField::Difficulty),
189 "NUMBER" => Ok(HeaderField::Number),
190 "GAS_LIMIT" => Ok(HeaderField::GasLimit),
191 "GAS_USED" => Ok(HeaderField::GasUsed),
192 "TIMESTAMP" => Ok(HeaderField::Timestamp),
193 "EXTRA_DATA" => Ok(HeaderField::ExtraData),
194 "MIX_HASH" => Ok(HeaderField::MixHash),
195 "NONCE" => Ok(HeaderField::Nonce),
196 "BASE_FEE_PER_GAS" => Ok(HeaderField::BaseFeePerGas),
197 "WITHDRAWALS_ROOT" => Ok(HeaderField::WithdrawalsRoot),
198 "BLOB_GAS_USED" => Ok(HeaderField::BlobGasUsed),
199 "EXCESS_BLOB_GAS" => Ok(HeaderField::ExcessBlobGas),
200 "PARENT_BEACON_BLOCK_ROOT" => Ok(HeaderField::ParentBeaconBlockRoot),
201 _ => bail!("Unknown header field"),
202 }
203 }
204}
205
206impl TryFrom<String> for HeaderField {
207 type Error = anyhow::Error;
208
209 fn try_from(value: String) -> Result<Self> {
210 HeaderField::from_str(&value)
211 }
212}
213
214impl Display for HeaderField {
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 match self {
217 HeaderField::ParentHash => write!(f, "PARENT_HASH"),
218 HeaderField::OmmerHash => write!(f, "OMMERS_HASH"),
219 HeaderField::Beneficiary => write!(f, "BENEFICIARY"),
220 HeaderField::StateRoot => write!(f, "STATE_ROOT"),
221 HeaderField::TransactionsRoot => write!(f, "TRANSACTIONS_ROOT"),
222 HeaderField::ReceiptsRoot => write!(f, "RECEIPTS_ROOT"),
223 HeaderField::LogsBloom => write!(f, "LOGS_BLOOM"),
224 HeaderField::Difficulty => write!(f, "DIFFICULTY"),
225 HeaderField::Number => write!(f, "NUMBER"),
226 HeaderField::GasLimit => write!(f, "GAS_LIMIT"),
227 HeaderField::GasUsed => write!(f, "GAS_USED"),
228 HeaderField::Timestamp => write!(f, "TIMESTAMP"),
229 HeaderField::ExtraData => write!(f, "EXTRA_DATA"),
230 HeaderField::MixHash => write!(f, "MIX_HASH"),
231 HeaderField::Nonce => write!(f, "NONCE"),
232 HeaderField::BaseFeePerGas => write!(f, "BASE_FEE_PER_GAS"),
233 HeaderField::WithdrawalsRoot => write!(f, "WITHDRAWALS_ROOT"),
234 HeaderField::BlobGasUsed => write!(f, "BLOB_GAS_USED"),
235 HeaderField::ExcessBlobGas => write!(f, "EXCESS_BLOB_GAS"),
236 HeaderField::ParentBeaconBlockRoot => write!(f, "PARENT_BEACON_BLOCK_ROOT"),
237 }
238 }
239}
240
241#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
244#[serde(try_from = "String")]
245pub enum AccountField {
246 Nonce,
247 Balance,
248 StorageRoot,
249 CodeHash,
250}
251
252impl AccountField {
253 pub fn variants() -> Vec<String> {
254 vec![
255 "NONCE".to_string(),
256 "BALANCE".to_string(),
257 "STORAGE_ROOT".to_string(),
258 "CODE_HASH".to_string(),
259 ]
260 }
261}
262
263impl FromStr for AccountField {
264 type Err = anyhow::Error;
265
266 fn from_str(s: &str) -> Result<Self> {
267 match s {
268 "NONCE" => Ok(AccountField::Nonce),
269 "BALANCE" => Ok(AccountField::Balance),
270 "STORAGE_ROOT" => Ok(AccountField::StorageRoot),
271 "CODE_HASH" => Ok(AccountField::CodeHash),
272 _ => bail!("Unknown account field"),
273 }
274 }
275}
276
277impl TryFrom<String> for AccountField {
278 type Error = anyhow::Error;
279
280 fn try_from(value: String) -> Result<Self> {
281 AccountField::from_str(&value)
282 }
283}
284
285impl DatalakeField for AccountField {
286 fn from_index(index: u8) -> Result<Self> {
287 match index {
288 0 => Ok(AccountField::Nonce),
289 1 => Ok(AccountField::Balance),
290 2 => Ok(AccountField::StorageRoot),
291 3 => Ok(AccountField::CodeHash),
292 _ => bail!("Invalid account field index"),
293 }
294 }
295
296 fn to_index(&self) -> u8 {
297 match self {
298 AccountField::Nonce => 0,
299 AccountField::Balance => 1,
300 AccountField::StorageRoot => 2,
301 AccountField::CodeHash => 3,
302 }
303 }
304
305 fn decode_field_from_rlp(&self, account_rlp: &[u8]) -> U256 {
306 let decoded = <Account>::rlp_decode(account_rlp);
307 match self {
308 AccountField::Nonce => U256::from(decoded.nonce),
309 AccountField::Balance => U256::from(decoded.balance),
310 AccountField::StorageRoot => decoded.storage_root.into(),
311 AccountField::CodeHash => decoded.code_hash.into(),
312 }
313 }
314}
315
316impl Display for AccountField {
317 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318 match self {
319 AccountField::Nonce => write!(f, "NONCE"),
320 AccountField::Balance => write!(f, "BALANCE"),
321 AccountField::StorageRoot => write!(f, "STORAGE_ROOT"),
322 AccountField::CodeHash => write!(f, "CODE_HASH"),
323 }
324 }
325}