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 event_signatures: Vec<String>,
98    pub topic0: Vec<Topic>,
99    pub topic1: Vec<Topic>,
100    pub topic2: Vec<Topic>,
101    pub topic3: Vec<Topic>,
102    pub include_transactions: bool,
103    pub include_transaction_logs: bool,
104    pub include_transaction_traces: bool,
105    pub include_blocks: 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    pub include_blocks: bool,
123}
124
125#[derive(Serialize, Default, Debug, Clone, Copy)]
126#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
127pub struct Fields {
128    pub block: BlockFields,
129    pub transaction: TransactionFields,
130    pub log: LogFields,
131    pub trace: TraceFields,
132}
133
134impl Fields {
135    pub fn all() -> Self {
136        Self {
137            block: BlockFields::all(),
138            transaction: TransactionFields::all(),
139            log: LogFields::all(),
140            trace: TraceFields::all(),
141        }
142    }
143}
144
145#[derive(Default, Debug, Clone, Copy, Serialize)]
146#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
147pub struct BlockFields {
148    pub number: bool,
149    pub hash: bool,
150    pub parent_hash: bool,
151    pub nonce: bool,
152    pub sha3_uncles: bool,
153    pub logs_bloom: bool,
154    pub transactions_root: bool,
155    pub state_root: bool,
156    pub receipts_root: bool,
157    pub miner: bool,
158    pub difficulty: bool,
159    pub total_difficulty: bool,
160    pub extra_data: bool,
161    pub size: bool,
162    pub gas_limit: bool,
163    pub gas_used: bool,
164    pub timestamp: bool,
165    pub uncles: bool,
166    pub base_fee_per_gas: bool,
167    pub blob_gas_used: bool,
168    pub excess_blob_gas: bool,
169    pub parent_beacon_block_root: bool,
170    pub withdrawals_root: bool,
171    pub withdrawals: bool,
172    pub l1_block_number: bool,
173    pub send_count: bool,
174    pub send_root: bool,
175    pub mix_hash: bool,
176}
177
178impl BlockFields {
179    pub fn all() -> Self {
180        BlockFields {
181            number: true,
182            hash: true,
183            parent_hash: true,
184            nonce: true,
185            sha3_uncles: true,
186            logs_bloom: true,
187            transactions_root: true,
188            state_root: true,
189            receipts_root: true,
190            miner: true,
191            difficulty: true,
192            total_difficulty: true,
193            extra_data: true,
194            size: true,
195            gas_limit: true,
196            gas_used: true,
197            timestamp: true,
198            uncles: true,
199            base_fee_per_gas: true,
200            blob_gas_used: true,
201            excess_blob_gas: true,
202            parent_beacon_block_root: true,
203            withdrawals_root: true,
204            withdrawals: true,
205            l1_block_number: true,
206            send_count: true,
207            send_root: true,
208            mix_hash: true,
209        }
210    }
211}
212
213#[derive(Default, Debug, Clone, Copy, Serialize)]
214#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
215pub struct TransactionFields {
216    pub block_hash: bool,
217    pub block_number: bool,
218    #[serde(rename = "from")]
219    pub from_: bool,
220    pub gas: bool,
221    pub gas_price: bool,
222    pub hash: bool,
223    pub input: bool,
224    pub nonce: bool,
225    pub to: bool,
226    pub transaction_index: bool,
227    pub value: bool,
228    pub v: bool,
229    pub r: bool,
230    pub s: bool,
231    pub max_priority_fee_per_gas: bool,
232    pub max_fee_per_gas: bool,
233    pub chain_id: bool,
234    pub cumulative_gas_used: bool,
235    pub effective_gas_price: bool,
236    pub gas_used: bool,
237    pub contract_address: bool,
238    pub logs_bloom: bool,
239    #[serde(rename = "type")]
240    pub type_: bool,
241    pub root: bool,
242    pub status: bool,
243    pub sighash: bool,
244    pub y_parity: bool,
245    pub access_list: bool,
246    pub l1_fee: bool,
247    pub l1_gas_price: bool,
248    pub l1_fee_scalar: bool,
249    pub gas_used_for_l1: bool,
250    pub max_fee_per_blob_gas: bool,
251    pub blob_versioned_hashes: bool,
252    pub deposit_nonce: bool,
253    pub blob_gas_price: bool,
254    pub deposit_receipt_version: bool,
255    pub blob_gas_used: bool,
256    pub l1_base_fee_scalar: bool,
257    pub l1_blob_base_fee: bool,
258    pub l1_blob_base_fee_scalar: bool,
259    pub l1_block_number: bool,
260    pub mint: bool,
261    pub source_hash: bool,
262}
263
264impl TransactionFields {
265    pub fn all() -> Self {
266        TransactionFields {
267            block_hash: true,
268            block_number: true,
269            from_: true,
270            gas: true,
271            gas_price: true,
272            hash: true,
273            input: true,
274            nonce: true,
275            to: true,
276            transaction_index: true,
277            value: true,
278            v: true,
279            r: true,
280            s: true,
281            max_priority_fee_per_gas: true,
282            max_fee_per_gas: true,
283            chain_id: true,
284            cumulative_gas_used: true,
285            effective_gas_price: true,
286            gas_used: true,
287            contract_address: true,
288            logs_bloom: true,
289            type_: true,
290            root: true,
291            status: true,
292            sighash: true,
293            y_parity: true,
294            access_list: true,
295            l1_fee: true,
296            l1_gas_price: true,
297            l1_fee_scalar: true,
298            gas_used_for_l1: true,
299            max_fee_per_blob_gas: true,
300            blob_versioned_hashes: true,
301            deposit_nonce: true,
302            blob_gas_price: true,
303            deposit_receipt_version: true,
304            blob_gas_used: true,
305            l1_base_fee_scalar: true,
306            l1_blob_base_fee: true,
307            l1_blob_base_fee_scalar: true,
308            l1_block_number: true,
309            mint: true,
310            source_hash: true,
311        }
312    }
313}
314
315#[derive(Default, Debug, Clone, Copy, Serialize)]
316#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
317pub struct LogFields {
318    pub removed: bool,
319    pub log_index: bool,
320    pub transaction_index: bool,
321    pub transaction_hash: bool,
322    pub block_hash: bool,
323    pub block_number: bool,
324    pub address: bool,
325    pub data: bool,
326    pub topic0: bool,
327    pub topic1: bool,
328    pub topic2: bool,
329    pub topic3: bool,
330}
331
332impl LogFields {
333    pub fn all() -> Self {
334        LogFields {
335            removed: true,
336            log_index: true,
337            transaction_index: true,
338            transaction_hash: true,
339            block_hash: true,
340            block_number: true,
341            address: true,
342            data: true,
343            topic0: true,
344            topic1: true,
345            topic2: true,
346            topic3: true,
347        }
348    }
349}
350
351#[derive(Default, Debug, Clone, Copy, Serialize)]
352#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
353pub struct TraceFields {
354    #[serde(rename = "from")]
355    pub from_: bool,
356    pub to: bool,
357    pub call_type: bool,
358    pub gas: bool,
359    pub input: bool,
360    pub init: bool,
361    pub value: bool,
362    pub author: bool,
363    pub reward_type: bool,
364    pub block_hash: bool,
365    pub block_number: bool,
366    pub address: bool,
367    pub code: bool,
368    pub gas_used: bool,
369    pub output: bool,
370    pub subtraces: bool,
371    pub trace_address: bool,
372    pub transaction_hash: bool,
373    pub transaction_position: bool,
374    #[serde(rename = "type")]
375    pub type_: bool,
376    pub error: bool,
377    pub sighash: bool,
378    pub action_address: bool,
379    pub balance: bool,
380    pub refund_address: bool,
381}
382
383impl TraceFields {
384    pub fn all() -> Self {
385        TraceFields {
386            from_: true,
387            to: true,
388            call_type: true,
389            gas: true,
390            input: true,
391            init: true,
392            value: true,
393            author: true,
394            reward_type: true,
395            block_hash: true,
396            block_number: true,
397            address: true,
398            code: true,
399            gas_used: true,
400            output: true,
401            subtraces: true,
402            trace_address: true,
403            transaction_hash: true,
404            transaction_position: true,
405            type_: true,
406            error: true,
407            sighash: true,
408            action_address: true,
409            balance: true,
410            refund_address: true,
411        }
412    }
413}