cherry_ingest/
svm.rs

1use anyhow::{anyhow, Context, Result};
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 fields: Fields,
11    pub instructions: Vec<InstructionRequest>,
12    pub transactions: Vec<TransactionRequest>,
13    pub logs: Vec<LogRequest>,
14    pub balances: Vec<BalanceRequest>,
15    pub token_balances: Vec<TokenBalanceRequest>,
16    pub rewards: Vec<RewardRequest>,
17}
18
19#[derive(Debug, Clone, Copy)]
20pub struct Address(pub [u8; 32]);
21
22#[derive(Debug, Clone, Copy)]
23pub struct D1(pub [u8; 1]);
24
25#[derive(Debug, Clone, Copy)]
26pub struct D2(pub [u8; 2]);
27
28#[derive(Debug, Clone, Copy)]
29pub struct D3(pub [u8; 3]);
30
31#[derive(Debug, Clone, Copy)]
32pub struct D4(pub [u8; 4]);
33
34#[derive(Debug, Clone, Copy)]
35pub struct D8(pub [u8; 8]);
36
37#[cfg(feature = "pyo3")]
38fn extract_base58<const N: usize>(ob: &pyo3::Bound<'_, pyo3::PyAny>) -> pyo3::PyResult<[u8; N]> {
39    use pyo3::types::PyAnyMethods;
40
41    let s: &str = ob.extract()?;
42    let mut out = [0; N];
43
44    bs58::decode(s)
45        .with_alphabet(bs58::Alphabet::BITCOIN)
46        .onto(&mut out)
47        .context("decode base58")?;
48
49    Ok(out)
50}
51
52#[cfg(feature = "pyo3")]
53impl<'py> pyo3::FromPyObject<'py> for Address {
54    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
55        let out = extract_base58(ob)?;
56        Ok(Self(out))
57    }
58}
59
60#[cfg(feature = "pyo3")]
61impl<'py> pyo3::FromPyObject<'py> for D1 {
62    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
63        let out = extract_base58(ob)?;
64        Ok(Self(out))
65    }
66}
67
68#[cfg(feature = "pyo3")]
69impl<'py> pyo3::FromPyObject<'py> for D2 {
70    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
71        let out = extract_base58(ob)?;
72        Ok(Self(out))
73    }
74}
75
76#[cfg(feature = "pyo3")]
77impl<'py> pyo3::FromPyObject<'py> for D3 {
78    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
79        let out = extract_base58(ob)?;
80        Ok(Self(out))
81    }
82}
83
84#[cfg(feature = "pyo3")]
85impl<'py> pyo3::FromPyObject<'py> for D4 {
86    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
87        let out = extract_base58(ob)?;
88        Ok(Self(out))
89    }
90}
91
92#[cfg(feature = "pyo3")]
93impl<'py> pyo3::FromPyObject<'py> for D8 {
94    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
95        let out = extract_base58(ob)?;
96        Ok(Self(out))
97    }
98}
99
100#[derive(Default, Debug, Clone)]
101#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
102pub struct InstructionRequest {
103    pub program_id: Vec<Address>,
104    pub d1: Vec<D1>,
105    pub d2: Vec<D2>,
106    pub d3: Vec<D3>,
107    pub d4: Vec<D4>,
108    pub d8: Vec<D8>,
109    pub a0: Vec<Address>,
110    pub a1: Vec<Address>,
111    pub a2: Vec<Address>,
112    pub a3: Vec<Address>,
113    pub a4: Vec<Address>,
114    pub a5: Vec<Address>,
115    pub a6: Vec<Address>,
116    pub a7: Vec<Address>,
117    pub a8: Vec<Address>,
118    pub a9: Vec<Address>,
119    pub is_committed: bool,
120    pub transaction: bool,
121    pub transaction_token_balances: bool,
122    pub logs: bool,
123    pub inner_instructions: bool,
124}
125
126#[derive(Default, Debug, Clone)]
127#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
128pub struct TransactionRequest {
129    pub fee_payer: Vec<Address>,
130    pub instructions: bool,
131    pub logs: bool,
132}
133
134#[derive(Default, Debug, Clone)]
135#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
136pub struct LogRequest {
137    pub program_id: Vec<Address>,
138    pub kind: Vec<LogKind>,
139    pub transaction: bool,
140    pub instruction: bool,
141}
142
143#[derive(Debug, Clone, Copy)]
144pub enum LogKind {
145    Log,
146    Data,
147    Other,
148}
149
150impl LogKind {
151    pub fn as_str(&self) -> &str {
152        match self {
153            Self::Log => "log",
154            Self::Data => "data",
155            Self::Other => "other",
156        }
157    }
158
159    pub fn from_str(s: &str) -> Result<Self> {
160        match s {
161            "log" => Ok(Self::Log),
162            "data" => Ok(Self::Data),
163            "other" => Ok(Self::Other),
164            _ => Err(anyhow!("unknown log kind: {}", s)),
165        }
166    }
167}
168
169#[cfg(feature = "pyo3")]
170impl<'py> pyo3::FromPyObject<'py> for LogKind {
171    fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
172        use pyo3::types::PyAnyMethods;
173
174        let s: &str = ob.extract().context("extract string")?;
175
176        Ok(Self::from_str(s).context("from str")?)
177    }
178}
179
180#[derive(Default, Debug, Clone)]
181#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
182pub struct BalanceRequest {
183    pub account: Vec<Address>,
184    pub transaction: bool,
185    pub transaction_instructions: bool,
186}
187
188#[derive(Default, Debug, Clone)]
189#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
190pub struct TokenBalanceRequest {
191    pub account: Vec<Address>,
192    pub pre_program_id: Vec<Address>,
193    pub post_program_id: Vec<Address>,
194    pub pre_mint: Vec<Address>,
195    pub post_mint: Vec<Address>,
196    pub pre_owner: Vec<Address>,
197    pub post_owner: Vec<Address>,
198    pub transaction: bool,
199    pub transaction_instructions: bool,
200}
201
202#[derive(Default, Debug, Clone)]
203#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
204pub struct RewardRequest {
205    pub pubkey: Vec<Address>,
206}
207
208#[derive(Serialize, Default, Debug, Clone, Copy)]
209#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
210pub struct Fields {
211    pub instruction: InstructionFields,
212    pub transaction: TransactionFields,
213    pub log: LogFields,
214    pub balance: BalanceFields,
215    pub token_balance: TokenBalanceFields,
216    pub reward: RewardFields,
217    pub block: BlockFields,
218}
219
220impl Fields {
221    pub fn all() -> Self {
222        Self {
223            instruction: InstructionFields::all(),
224            transaction: TransactionFields::all(),
225            log: LogFields::all(),
226            balance: BalanceFields::all(),
227            token_balance: TokenBalanceFields::all(),
228            reward: RewardFields::all(),
229            block: BlockFields::all(),
230        }
231    }
232}
233
234#[derive(Default, Debug, Clone, Copy, Serialize)]
235#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
236pub struct InstructionFields {
237    pub block_slot: bool,
238    pub block_hash: bool,
239    pub transaction_index: bool,
240    pub instruction_address: bool,
241    pub program_id: bool,
242    pub a0: bool,
243    pub a1: bool,
244    pub a2: bool,
245    pub a3: bool,
246    pub a4: bool,
247    pub a5: bool,
248    pub a6: bool,
249    pub a7: bool,
250    pub a8: bool,
251    pub a9: bool,
252    pub rest_of_accounts: bool,
253    pub data: bool,
254    pub d1: bool,
255    pub d2: bool,
256    pub d4: bool,
257    pub d8: bool,
258    pub error: bool,
259    pub compute_units_consumed: bool,
260    pub is_committed: bool,
261    pub has_dropped_log_messages: bool,
262}
263
264impl InstructionFields {
265    pub fn all() -> Self {
266        InstructionFields {
267            block_slot: true,
268            block_hash: true,
269            transaction_index: true,
270            instruction_address: true,
271            program_id: true,
272            a0: true,
273            a1: true,
274            a2: true,
275            a3: true,
276            a4: true,
277            a5: true,
278            a6: true,
279            a7: true,
280            a8: true,
281            a9: true,
282            rest_of_accounts: true,
283            data: true,
284            d1: true,
285            d2: true,
286            d4: true,
287            d8: true,
288            error: true,
289            compute_units_consumed: true,
290            is_committed: true,
291            has_dropped_log_messages: true,
292        }
293    }
294}
295
296#[derive(Default, Debug, Clone, Copy, Serialize)]
297#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
298pub struct TransactionFields {
299    pub block_slot: bool,
300    pub block_hash: bool,
301    pub transaction_index: bool,
302    pub version: bool,
303    pub account_keys: bool,
304    pub address_table_lookups: bool,
305    pub num_readonly_signed_accounts: bool,
306    pub num_readonly_unsigned_accounts: bool,
307    pub num_required_signatures: bool,
308    pub recent_blockhash: bool,
309    pub signatures: bool,
310    pub err: bool,
311    pub fee: bool,
312    pub compute_units_consumed: bool,
313    pub loaded_readonly_addresses: bool,
314    pub loaded_writable_addresses: bool,
315    pub fee_payer: bool,
316    pub has_dropped_log_messages: bool,
317}
318
319impl TransactionFields {
320    pub fn all() -> Self {
321        TransactionFields {
322            block_slot: true,
323            block_hash: true,
324            transaction_index: true,
325            version: true,
326            account_keys: true,
327            address_table_lookups: true,
328            num_readonly_signed_accounts: true,
329            num_readonly_unsigned_accounts: true,
330            num_required_signatures: true,
331            recent_blockhash: true,
332            signatures: true,
333            err: true,
334            fee: true,
335            compute_units_consumed: true,
336            loaded_readonly_addresses: true,
337            loaded_writable_addresses: true,
338            fee_payer: true,
339            has_dropped_log_messages: true,
340        }
341    }
342}
343
344#[derive(Default, Debug, Clone, Copy, Serialize)]
345#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
346pub struct LogFields {
347    pub block_slot: bool,
348    pub block_hash: bool,
349    pub transaction_index: bool,
350    pub log_index: bool,
351    pub instruction_address: bool,
352    pub program_id: bool,
353    pub kind: bool,
354    pub message: bool,
355}
356
357impl LogFields {
358    pub fn all() -> Self {
359        LogFields {
360            block_slot: true,
361            block_hash: true,
362            transaction_index: true,
363            log_index: true,
364            instruction_address: true,
365            program_id: true,
366            kind: true,
367            message: true,
368        }
369    }
370}
371
372#[derive(Default, Debug, Clone, Copy, Serialize)]
373#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
374pub struct BalanceFields {
375    pub block_slot: bool,
376    pub block_hash: bool,
377    pub transaction_index: bool,
378    pub account: bool,
379    pub pre: bool,
380    pub post: bool,
381}
382
383impl BalanceFields {
384    pub fn all() -> Self {
385        BalanceFields {
386            block_slot: true,
387            block_hash: true,
388            transaction_index: true,
389            account: true,
390            pre: true,
391            post: true,
392        }
393    }
394}
395
396#[derive(Default, Debug, Clone, Copy, Serialize)]
397#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
398pub struct TokenBalanceFields {
399    pub block_slot: bool,
400    pub block_hash: bool,
401    pub transaction_index: bool,
402    pub account: bool,
403    pub pre_mint: bool,
404    pub post_mint: bool,
405    pub pre_decimals: bool,
406    pub post_decimals: bool,
407    pub pre_program_id: bool,
408    pub post_program_id: bool,
409    pub pre_owner: bool,
410    pub post_owner: bool,
411    pub pre_amount: bool,
412    pub post_amount: bool,
413}
414
415impl TokenBalanceFields {
416    pub fn all() -> Self {
417        TokenBalanceFields {
418            block_slot: true,
419            block_hash: true,
420            transaction_index: true,
421            account: true,
422            pre_mint: true,
423            post_mint: true,
424            pre_decimals: true,
425            post_decimals: true,
426            pre_program_id: true,
427            post_program_id: true,
428            pre_owner: true,
429            post_owner: true,
430            pre_amount: true,
431            post_amount: true,
432        }
433    }
434}
435
436#[derive(Default, Debug, Clone, Copy, Serialize)]
437#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
438pub struct RewardFields {
439    pub block_slot: bool,
440    pub block_hash: bool,
441    pub pubkey: bool,
442    pub lamports: bool,
443    pub post_balance: bool,
444    pub reward_type: bool,
445    pub commission: bool,
446}
447
448impl RewardFields {
449    pub fn all() -> Self {
450        RewardFields {
451            block_slot: true,
452            block_hash: true,
453            pubkey: true,
454            lamports: true,
455            post_balance: true,
456            reward_type: true,
457            commission: true,
458        }
459    }
460}
461
462#[derive(Default, Debug, Clone, Copy, Serialize)]
463#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
464pub struct BlockFields {
465    pub slot: bool,
466    pub hash: bool,
467    pub parent_slot: bool,
468    pub parent_hash: bool,
469    pub height: bool,
470    pub timestamp: bool,
471}
472
473impl BlockFields {
474    pub fn all() -> Self {
475        BlockFields {
476            slot: true,
477            hash: true,
478            parent_slot: true,
479            parent_hash: true,
480            height: true,
481            timestamp: true,
482        }
483    }
484}