cherry_ingest/
evm.rs

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