1use anyhow::{anyhow, Context, Result};
2use serde::{Deserialize, 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 include_transactions: bool,
121 pub include_transaction_token_balances: bool,
122 pub include_logs: bool,
123 pub include_inner_instructions: bool,
124 pub include_blocks: bool,
125}
126
127#[derive(Default, Debug, Clone)]
128#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
129pub struct TransactionRequest {
130 pub fee_payer: Vec<Address>,
131 pub include_instructions: bool,
132 pub include_logs: bool,
133 pub include_blocks: bool,
134}
135
136#[derive(Default, Debug, Clone)]
137#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
138pub struct LogRequest {
139 pub program_id: Vec<Address>,
140 pub kind: Vec<LogKind>,
141 pub include_transactions: bool,
142 pub include_instructions: bool,
143 pub include_blocks: bool,
144}
145
146#[derive(Debug, Clone, Copy)]
147pub enum LogKind {
148 Log,
149 Data,
150 Other,
151}
152
153impl LogKind {
154 pub fn as_str(&self) -> &str {
155 match self {
156 Self::Log => "log",
157 Self::Data => "data",
158 Self::Other => "other",
159 }
160 }
161
162 pub fn from_str(s: &str) -> Result<Self> {
163 match s {
164 "log" => Ok(Self::Log),
165 "data" => Ok(Self::Data),
166 "other" => Ok(Self::Other),
167 _ => Err(anyhow!("unknown log kind: {}", s)),
168 }
169 }
170}
171
172#[cfg(feature = "pyo3")]
173impl<'py> pyo3::FromPyObject<'py> for LogKind {
174 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
175 use pyo3::types::PyAnyMethods;
176
177 let s: &str = ob.extract().context("extract string")?;
178
179 Ok(Self::from_str(s).context("from str")?)
180 }
181}
182
183#[derive(Default, Debug, Clone)]
184#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
185pub struct BalanceRequest {
186 pub account: Vec<Address>,
187 pub include_transactions: bool,
188 pub include_transaction_instructions: bool,
189 pub include_blocks: bool,
190}
191
192#[derive(Default, Debug, Clone)]
193#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
194pub struct TokenBalanceRequest {
195 pub account: Vec<Address>,
196 pub pre_program_id: Vec<Address>,
197 pub post_program_id: Vec<Address>,
198 pub pre_mint: Vec<Address>,
199 pub post_mint: Vec<Address>,
200 pub pre_owner: Vec<Address>,
201 pub post_owner: Vec<Address>,
202 pub include_transactions: bool,
203 pub include_transaction_instructions: bool,
204 pub include_blocks: bool,
205}
206
207#[derive(Default, Debug, Clone)]
208#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
209pub struct RewardRequest {
210 pub pubkey: Vec<Address>,
211 pub include_blocks: bool,
212}
213
214#[derive(Deserialize, Serialize, Default, Debug, Clone, Copy)]
215#[serde(default)]
216#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
217pub struct Fields {
218 pub instruction: InstructionFields,
219 pub transaction: TransactionFields,
220 pub log: LogFields,
221 pub balance: BalanceFields,
222 pub token_balance: TokenBalanceFields,
223 pub reward: RewardFields,
224 pub block: BlockFields,
225}
226
227impl Fields {
228 pub fn all() -> Self {
229 Self {
230 instruction: InstructionFields::all(),
231 transaction: TransactionFields::all(),
232 log: LogFields::all(),
233 balance: BalanceFields::all(),
234 token_balance: TokenBalanceFields::all(),
235 reward: RewardFields::all(),
236 block: BlockFields::all(),
237 }
238 }
239}
240
241#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
242#[serde(default)]
243#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
244pub struct InstructionFields {
245 pub block_slot: bool,
246 pub block_hash: bool,
247 pub transaction_index: bool,
248 pub instruction_address: bool,
249 pub program_id: bool,
250 pub a0: bool,
251 pub a1: bool,
252 pub a2: bool,
253 pub a3: bool,
254 pub a4: bool,
255 pub a5: bool,
256 pub a6: bool,
257 pub a7: bool,
258 pub a8: bool,
259 pub a9: bool,
260 pub rest_of_accounts: bool,
261 pub data: bool,
262 pub d1: bool,
263 pub d2: bool,
264 pub d4: bool,
265 pub d8: bool,
266 pub error: bool,
267 pub compute_units_consumed: bool,
268 pub is_committed: bool,
269 pub has_dropped_log_messages: bool,
270}
271
272impl InstructionFields {
273 pub fn all() -> Self {
274 InstructionFields {
275 block_slot: true,
276 block_hash: true,
277 transaction_index: true,
278 instruction_address: true,
279 program_id: true,
280 a0: true,
281 a1: true,
282 a2: true,
283 a3: true,
284 a4: true,
285 a5: true,
286 a6: true,
287 a7: true,
288 a8: true,
289 a9: true,
290 rest_of_accounts: true,
291 data: true,
292 d1: true,
293 d2: true,
294 d4: true,
295 d8: true,
296 error: true,
297 compute_units_consumed: true,
298 is_committed: true,
299 has_dropped_log_messages: true,
300 }
301 }
302}
303
304#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
305#[serde(default)]
306#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
307pub struct TransactionFields {
308 pub block_slot: bool,
309 pub block_hash: bool,
310 pub transaction_index: bool,
311 pub signature: bool,
312 pub version: bool,
313 pub account_keys: bool,
314 pub address_table_lookups: bool,
315 pub num_readonly_signed_accounts: bool,
316 pub num_readonly_unsigned_accounts: bool,
317 pub num_required_signatures: bool,
318 pub recent_blockhash: bool,
319 pub signatures: bool,
320 pub err: bool,
321 pub fee: bool,
322 pub compute_units_consumed: bool,
323 pub loaded_readonly_addresses: bool,
324 pub loaded_writable_addresses: bool,
325 pub fee_payer: bool,
326 pub has_dropped_log_messages: bool,
327}
328
329impl TransactionFields {
330 pub fn all() -> Self {
331 TransactionFields {
332 block_slot: true,
333 block_hash: true,
334 transaction_index: true,
335 signature: true,
336 version: true,
337 account_keys: true,
338 address_table_lookups: true,
339 num_readonly_signed_accounts: true,
340 num_readonly_unsigned_accounts: true,
341 num_required_signatures: true,
342 recent_blockhash: true,
343 signatures: true,
344 err: true,
345 fee: true,
346 compute_units_consumed: true,
347 loaded_readonly_addresses: true,
348 loaded_writable_addresses: true,
349 fee_payer: true,
350 has_dropped_log_messages: true,
351 }
352 }
353}
354
355#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
356#[serde(default)]
357#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
358pub struct LogFields {
359 pub block_slot: bool,
360 pub block_hash: bool,
361 pub transaction_index: bool,
362 pub log_index: bool,
363 pub instruction_address: bool,
364 pub program_id: bool,
365 pub kind: bool,
366 pub message: bool,
367}
368
369impl LogFields {
370 pub fn all() -> Self {
371 LogFields {
372 block_slot: true,
373 block_hash: true,
374 transaction_index: true,
375 log_index: true,
376 instruction_address: true,
377 program_id: true,
378 kind: true,
379 message: true,
380 }
381 }
382}
383
384#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
385#[serde(default)]
386#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
387pub struct BalanceFields {
388 pub block_slot: bool,
389 pub block_hash: bool,
390 pub transaction_index: bool,
391 pub account: bool,
392 pub pre: bool,
393 pub post: bool,
394}
395
396impl BalanceFields {
397 pub fn all() -> Self {
398 BalanceFields {
399 block_slot: true,
400 block_hash: true,
401 transaction_index: true,
402 account: true,
403 pre: true,
404 post: true,
405 }
406 }
407}
408
409#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
410#[serde(default)]
411#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
412pub struct TokenBalanceFields {
413 pub block_slot: bool,
414 pub block_hash: bool,
415 pub transaction_index: bool,
416 pub account: bool,
417 pub pre_mint: bool,
418 pub post_mint: bool,
419 pub pre_decimals: bool,
420 pub post_decimals: bool,
421 pub pre_program_id: bool,
422 pub post_program_id: bool,
423 pub pre_owner: bool,
424 pub post_owner: bool,
425 pub pre_amount: bool,
426 pub post_amount: bool,
427}
428
429impl TokenBalanceFields {
430 pub fn all() -> Self {
431 TokenBalanceFields {
432 block_slot: true,
433 block_hash: true,
434 transaction_index: true,
435 account: true,
436 pre_mint: true,
437 post_mint: true,
438 pre_decimals: true,
439 post_decimals: true,
440 pre_program_id: true,
441 post_program_id: true,
442 pre_owner: true,
443 post_owner: true,
444 pre_amount: true,
445 post_amount: true,
446 }
447 }
448}
449
450#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
451#[serde(default)]
452#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
453pub struct RewardFields {
454 pub block_slot: bool,
455 pub block_hash: bool,
456 pub pubkey: bool,
457 pub lamports: bool,
458 pub post_balance: bool,
459 pub reward_type: bool,
460 pub commission: bool,
461}
462
463impl RewardFields {
464 pub fn all() -> Self {
465 RewardFields {
466 block_slot: true,
467 block_hash: true,
468 pubkey: true,
469 lamports: true,
470 post_balance: true,
471 reward_type: true,
472 commission: true,
473 }
474 }
475}
476
477#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
478#[serde(default)]
479#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
480pub struct BlockFields {
481 pub slot: bool,
482 pub hash: bool,
483 pub parent_slot: bool,
484 pub parent_hash: bool,
485 pub height: bool,
486 pub timestamp: bool,
487}
488
489impl BlockFields {
490 pub fn all() -> Self {
491 BlockFields {
492 slot: true,
493 hash: true,
494 parent_slot: true,
495 parent_hash: true,
496 height: true,
497 timestamp: true,
498 }
499 }
500}