1#[cfg(feature = "pyo3")]
4use anyhow::Context;
5use serde::{Deserialize, Serialize};
6
7#[derive(Default, Debug, Clone)]
9#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
10pub struct Query {
11 pub from_block: u64,
12 pub to_block: Option<u64>,
13 pub include_all_blocks: bool,
14 pub transactions: Vec<TransactionRequest>,
15 pub logs: Vec<LogRequest>,
16 pub traces: Vec<TraceRequest>,
17 pub fields: Fields,
18}
19
20#[derive(Debug, Clone, Copy)]
22pub struct Hash(pub [u8; 32]);
23
24#[derive(Debug, Clone, Copy)]
26pub struct Address(pub [u8; 20]);
27
28#[derive(Debug, Clone, Copy)]
30pub struct Sighash(pub [u8; 4]);
31
32#[derive(Debug, Clone, Copy)]
34pub struct Topic(pub [u8; 32]);
35
36#[cfg(feature = "pyo3")]
37fn extract_hex<const N: usize>(ob: &pyo3::Bound<'_, pyo3::PyAny>) -> pyo3::PyResult<[u8; N]> {
38 use pyo3::types::PyAnyMethods;
39
40 let s: &str = ob.extract()?;
41 let s = s.strip_prefix("0x").context("strip 0x prefix")?;
42 let mut out = [0; N];
43 faster_hex::hex_decode(s.as_bytes(), &mut out).context("decode hex")?;
44
45 Ok(out)
46}
47
48#[cfg(feature = "pyo3")]
49impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for Hash {
50 type Error = pyo3::PyErr;
51 fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
52 let out = extract_hex(&ob)?;
53 Ok(Self(out))
54 }
55}
56
57#[cfg(feature = "pyo3")]
58impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for Address {
59 type Error = pyo3::PyErr;
60 fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
61 let out = extract_hex(&ob)?;
62 Ok(Self(out))
63 }
64}
65
66#[cfg(feature = "pyo3")]
67impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for Sighash {
68 type Error = pyo3::PyErr;
69 fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
70 let out = extract_hex(&ob)?;
71 Ok(Self(out))
72 }
73}
74
75#[cfg(feature = "pyo3")]
76impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for Topic {
77 type Error = pyo3::PyErr;
78 fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
79 let out = extract_hex(&ob)?;
80 Ok(Self(out))
81 }
82}
83
84#[derive(Default, Debug, Clone)]
86#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
87pub struct TransactionRequest {
88 pub from_: Vec<Address>,
89 pub to: Vec<Address>,
90 pub sighash: Vec<Sighash>,
91 pub status: Vec<u8>,
92 pub type_: Vec<u8>,
93 pub contract_deployment_address: Vec<Address>,
94 pub hash: Vec<Hash>,
95 pub include_logs: bool,
96 pub include_traces: bool,
97 pub include_blocks: bool,
98}
99
100#[derive(Default, Debug, Clone)]
102#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
103#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
104pub struct LogRequest {
105 pub address: Vec<Address>,
106 pub topic0: Vec<Topic>,
107 pub topic1: Vec<Topic>,
108 pub topic2: Vec<Topic>,
109 pub topic3: Vec<Topic>,
110 pub include_transactions: bool,
111 pub include_transaction_logs: bool,
112 pub include_transaction_traces: bool,
113 pub include_blocks: bool,
114}
115
116#[derive(Default, Debug, Clone)]
118#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
119#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
120pub struct TraceRequest {
121 pub from_: Vec<Address>,
122 pub to: Vec<Address>,
123 pub address: Vec<Address>,
124 pub call_type: Vec<String>,
125 pub reward_type: Vec<String>,
126 pub type_: Vec<String>,
127 pub sighash: Vec<Sighash>,
128 pub author: Vec<Address>,
129 pub include_transactions: bool,
130 pub include_transaction_logs: bool,
131 pub include_transaction_traces: bool,
132 pub include_blocks: bool,
133}
134
135#[derive(Deserialize, Serialize, Default, Debug, Clone, Copy)]
137#[serde(default)]
138#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
139pub struct Fields {
140 pub block: BlockFields,
141 pub transaction: TransactionFields,
142 pub log: LogFields,
143 pub trace: TraceFields,
144}
145
146impl Fields {
147 pub fn all() -> Self {
148 Self {
149 block: BlockFields::all(),
150 transaction: TransactionFields::all(),
151 log: LogFields::all(),
152 trace: TraceFields::all(),
153 }
154 }
155}
156
157#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
159#[serde(default)]
160#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
161#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
162pub struct BlockFields {
163 pub number: bool,
164 pub hash: bool,
165 pub parent_hash: bool,
166 pub nonce: bool,
167 pub sha3_uncles: bool,
168 pub logs_bloom: bool,
169 pub transactions_root: bool,
170 pub state_root: bool,
171 pub receipts_root: bool,
172 pub miner: bool,
173 pub difficulty: bool,
174 pub total_difficulty: bool,
175 pub extra_data: bool,
176 pub size: bool,
177 pub gas_limit: bool,
178 pub gas_used: bool,
179 pub timestamp: bool,
180 pub uncles: bool,
181 pub base_fee_per_gas: bool,
182 pub blob_gas_used: bool,
183 pub excess_blob_gas: bool,
184 pub parent_beacon_block_root: bool,
185 pub withdrawals_root: bool,
186 pub withdrawals: bool,
187 pub l1_block_number: bool,
188 pub send_count: bool,
189 pub send_root: bool,
190 pub mix_hash: bool,
191}
192
193impl BlockFields {
194 pub fn all() -> Self {
195 BlockFields {
196 number: true,
197 hash: true,
198 parent_hash: true,
199 nonce: true,
200 sha3_uncles: true,
201 logs_bloom: true,
202 transactions_root: true,
203 state_root: true,
204 receipts_root: true,
205 miner: true,
206 difficulty: true,
207 total_difficulty: true,
208 extra_data: true,
209 size: true,
210 gas_limit: true,
211 gas_used: true,
212 timestamp: true,
213 uncles: true,
214 base_fee_per_gas: true,
215 blob_gas_used: true,
216 excess_blob_gas: true,
217 parent_beacon_block_root: true,
218 withdrawals_root: true,
219 withdrawals: true,
220 l1_block_number: true,
221 send_count: true,
222 send_root: true,
223 mix_hash: true,
224 }
225 }
226}
227
228#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
230#[serde(default)]
231#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
232#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
233pub struct TransactionFields {
234 pub block_hash: bool,
235 pub block_number: bool,
236 #[serde(rename = "from")]
237 pub from_: bool,
238 pub gas: bool,
239 pub gas_price: bool,
240 pub hash: bool,
241 pub input: bool,
242 pub nonce: bool,
243 pub to: bool,
244 pub transaction_index: bool,
245 pub value: bool,
246 pub v: bool,
247 pub r: bool,
248 pub s: bool,
249 pub max_priority_fee_per_gas: bool,
250 pub max_fee_per_gas: bool,
251 pub chain_id: bool,
252 pub cumulative_gas_used: bool,
253 pub effective_gas_price: bool,
254 pub gas_used: bool,
255 pub contract_address: bool,
256 pub logs_bloom: bool,
257 #[serde(rename = "type")]
258 pub type_: bool,
259 pub root: bool,
260 pub status: bool,
261 pub sighash: bool,
262 pub y_parity: bool,
263 pub access_list: bool,
264 pub l1_fee: bool,
265 pub l1_gas_price: bool,
266 pub l1_fee_scalar: bool,
267 pub gas_used_for_l1: bool,
268 pub max_fee_per_blob_gas: bool,
269 pub blob_versioned_hashes: bool,
270 pub deposit_nonce: bool,
271 pub blob_gas_price: bool,
272 pub deposit_receipt_version: bool,
273 pub blob_gas_used: bool,
274 pub l1_base_fee_scalar: bool,
275 pub l1_blob_base_fee: bool,
276 pub l1_blob_base_fee_scalar: bool,
277 pub l1_block_number: bool,
278 pub mint: bool,
279 pub source_hash: bool,
280}
281
282impl TransactionFields {
283 pub fn all() -> Self {
284 TransactionFields {
285 block_hash: true,
286 block_number: true,
287 from_: true,
288 gas: true,
289 gas_price: true,
290 hash: true,
291 input: true,
292 nonce: true,
293 to: true,
294 transaction_index: true,
295 value: true,
296 v: true,
297 r: true,
298 s: true,
299 max_priority_fee_per_gas: true,
300 max_fee_per_gas: true,
301 chain_id: true,
302 cumulative_gas_used: true,
303 effective_gas_price: true,
304 gas_used: true,
305 contract_address: true,
306 logs_bloom: true,
307 type_: true,
308 root: true,
309 status: true,
310 sighash: true,
311 y_parity: true,
312 access_list: true,
313 l1_fee: true,
314 l1_gas_price: true,
315 l1_fee_scalar: true,
316 gas_used_for_l1: true,
317 max_fee_per_blob_gas: true,
318 blob_versioned_hashes: true,
319 deposit_nonce: true,
320 blob_gas_price: true,
321 deposit_receipt_version: true,
322 blob_gas_used: true,
323 l1_base_fee_scalar: true,
324 l1_blob_base_fee: true,
325 l1_blob_base_fee_scalar: true,
326 l1_block_number: true,
327 mint: true,
328 source_hash: true,
329 }
330 }
331}
332
333#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
335#[serde(default)]
336#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
337#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
338pub struct LogFields {
339 pub removed: bool,
340 pub log_index: bool,
341 pub transaction_index: bool,
342 pub transaction_hash: bool,
343 pub block_hash: bool,
344 pub block_number: bool,
345 pub address: bool,
346 pub data: bool,
347 pub topic0: bool,
348 pub topic1: bool,
349 pub topic2: bool,
350 pub topic3: bool,
351}
352
353impl LogFields {
354 pub fn all() -> Self {
355 LogFields {
356 removed: true,
357 log_index: true,
358 transaction_index: true,
359 transaction_hash: true,
360 block_hash: true,
361 block_number: true,
362 address: true,
363 data: true,
364 topic0: true,
365 topic1: true,
366 topic2: true,
367 topic3: true,
368 }
369 }
370}
371
372#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
374#[serde(default)]
375#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
376#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
377pub struct TraceFields {
378 #[serde(rename = "from")]
379 pub from_: bool,
380 pub to: bool,
381 pub call_type: bool,
382 pub gas: bool,
383 pub input: bool,
384 pub init: bool,
385 pub value: bool,
386 pub author: bool,
387 pub reward_type: bool,
388 pub block_hash: bool,
389 pub block_number: bool,
390 pub address: bool,
391 pub code: bool,
392 pub gas_used: bool,
393 pub output: bool,
394 pub subtraces: bool,
395 pub trace_address: bool,
396 pub transaction_hash: bool,
397 pub transaction_position: bool,
398 #[serde(rename = "type")]
399 pub type_: bool,
400 pub error: bool,
401 pub sighash: bool,
402 pub action_address: bool,
403 pub balance: bool,
404 pub refund_address: bool,
405}
406
407impl TraceFields {
408 pub fn all() -> Self {
409 TraceFields {
410 from_: true,
411 to: true,
412 call_type: true,
413 gas: true,
414 input: true,
415 init: true,
416 value: true,
417 author: true,
418 reward_type: true,
419 block_hash: true,
420 block_number: true,
421 address: true,
422 code: true,
423 gas_used: true,
424 output: true,
425 subtraces: true,
426 trace_address: true,
427 transaction_hash: true,
428 transaction_position: true,
429 type_: true,
430 error: true,
431 sighash: true,
432 action_address: true,
433 balance: true,
434 refund_address: true,
435 }
436 }
437}