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
16impl Query {}
17
18#[derive(Debug, Clone, Copy)]
19pub struct Hash(pub [u8; 32]);
20
21#[derive(Debug, Clone, Copy)]
22pub struct Address(pub [u8; 20]);
23
24#[derive(Debug, Clone, Copy)]
25pub struct Sighash(pub [u8; 4]);
26
27#[derive(Debug, Clone, Copy)]
28pub struct Topic(pub [u8; 32]);
29
30#[cfg(feature = "pyo3")]
31fn extract_hex<const N: usize>(ob: &pyo3::Bound<'_, pyo3::PyAny>) -> pyo3::PyResult<[u8; N]> {
32    use pyo3::types::PyAnyMethods;
33
34    let s: &str = ob.extract()?;
35    let s = s.strip_prefix("0x").context("strip 0x prefix")?;
36    let mut out = [0; N];
37    faster_hex::hex_decode(s.as_bytes(), &mut out).context("decode hex")?;
38
39    Ok(out)
40}
41
42#[cfg(feature = "pyo3")]
43impl<'py> pyo3::FromPyObject<'py> for Hash {
44    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
45        let out = extract_hex(ob)?;
46        Ok(Self(out))
47    }
48}
49
50#[cfg(feature = "pyo3")]
51impl<'py> pyo3::FromPyObject<'py> for Address {
52    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
53        let out = extract_hex(ob)?;
54        Ok(Self(out))
55    }
56}
57
58#[cfg(feature = "pyo3")]
59impl<'py> pyo3::FromPyObject<'py> for Sighash {
60    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
61        let out = extract_hex(ob)?;
62        Ok(Self(out))
63    }
64}
65
66#[cfg(feature = "pyo3")]
67impl<'py> pyo3::FromPyObject<'py> for Topic {
68    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
69        let out = extract_hex(ob)?;
70        Ok(Self(out))
71    }
72}
73
74// #[derive(Default, Debug, Clone)]
75// pub struct BlockRequest {
76//     pub hash: Vec<Hash>,
77//     pub miner: Vec<Address>,
78// }
79
80#[derive(Default, Debug, Clone)]
81#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
82pub struct TransactionRequest {
83    pub from_: Vec<Address>,
84    pub to: Vec<Address>,
85    pub sighash: Vec<Sighash>,
86    pub status: Vec<u8>,
87    pub type_: Vec<u8>,
88    pub contract_deployment_address: Vec<Address>,
89    pub hash: Vec<Hash>,
90    pub include_logs: bool,
91    pub include_traces: bool,
92}
93
94#[derive(Default, Debug, Clone)]
95#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
96pub struct LogRequest {
97    pub address: Vec<Address>,
98    pub event_signatures: Vec<String>,
99    pub topic0: Vec<Topic>,
100    pub topic1: Vec<Topic>,
101    pub topic2: Vec<Topic>,
102    pub topic3: Vec<Topic>,
103    pub include_transactions: bool,
104    pub include_transaction_logs: bool,
105    pub include_transaction_traces: bool,
106}
107
108#[derive(Default, Debug, Clone)]
109#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
110pub struct TraceRequest {
111    pub from_: Vec<Address>,
112    pub to: Vec<Address>,
113    pub address: Vec<Address>,
114    pub call_type: Vec<String>,
115    pub reward_type: Vec<String>,
116    pub type_: Vec<String>,
117    pub sighash: Vec<Sighash>,
118    pub author: Vec<Address>,
119    pub include_transactions: bool,
120    pub include_transaction_logs: bool,
121    pub include_transaction_traces: 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}