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 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(Serialize, Default, Debug, Clone, Copy)]
215#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
216pub struct Fields {
217 pub instruction: InstructionFields,
218 pub transaction: TransactionFields,
219 pub log: LogFields,
220 pub balance: BalanceFields,
221 pub token_balance: TokenBalanceFields,
222 pub reward: RewardFields,
223 pub block: BlockFields,
224}
225
226impl Fields {
227 pub fn all() -> Self {
228 Self {
229 instruction: InstructionFields::all(),
230 transaction: TransactionFields::all(),
231 log: LogFields::all(),
232 balance: BalanceFields::all(),
233 token_balance: TokenBalanceFields::all(),
234 reward: RewardFields::all(),
235 block: BlockFields::all(),
236 }
237 }
238}
239
240#[derive(Default, Debug, Clone, Copy, Serialize)]
241#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
242pub struct InstructionFields {
243 pub block_slot: bool,
244 pub block_hash: bool,
245 pub transaction_index: bool,
246 pub instruction_address: bool,
247 pub program_id: bool,
248 pub a0: bool,
249 pub a1: bool,
250 pub a2: bool,
251 pub a3: bool,
252 pub a4: bool,
253 pub a5: bool,
254 pub a6: bool,
255 pub a7: bool,
256 pub a8: bool,
257 pub a9: bool,
258 pub rest_of_accounts: bool,
259 pub data: bool,
260 pub d1: bool,
261 pub d2: bool,
262 pub d4: bool,
263 pub d8: bool,
264 pub error: bool,
265 pub compute_units_consumed: bool,
266 pub is_committed: bool,
267 pub has_dropped_log_messages: bool,
268}
269
270impl InstructionFields {
271 pub fn all() -> Self {
272 InstructionFields {
273 block_slot: true,
274 block_hash: true,
275 transaction_index: true,
276 instruction_address: true,
277 program_id: true,
278 a0: true,
279 a1: true,
280 a2: true,
281 a3: true,
282 a4: true,
283 a5: true,
284 a6: true,
285 a7: true,
286 a8: true,
287 a9: true,
288 rest_of_accounts: true,
289 data: true,
290 d1: true,
291 d2: true,
292 d4: true,
293 d8: true,
294 error: true,
295 compute_units_consumed: true,
296 is_committed: true,
297 has_dropped_log_messages: true,
298 }
299 }
300}
301
302#[derive(Default, Debug, Clone, Copy, Serialize)]
303#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
304pub struct TransactionFields {
305 pub block_slot: bool,
306 pub block_hash: bool,
307 pub transaction_index: bool,
308 pub signature: bool,
309 pub version: bool,
310 pub account_keys: bool,
311 pub address_table_lookups: bool,
312 pub num_readonly_signed_accounts: bool,
313 pub num_readonly_unsigned_accounts: bool,
314 pub num_required_signatures: bool,
315 pub recent_blockhash: bool,
316 pub signatures: bool,
317 pub err: bool,
318 pub fee: bool,
319 pub compute_units_consumed: bool,
320 pub loaded_readonly_addresses: bool,
321 pub loaded_writable_addresses: bool,
322 pub fee_payer: bool,
323 pub has_dropped_log_messages: bool,
324}
325
326impl TransactionFields {
327 pub fn all() -> Self {
328 TransactionFields {
329 block_slot: true,
330 block_hash: true,
331 transaction_index: true,
332 signature: true,
333 version: true,
334 account_keys: true,
335 address_table_lookups: true,
336 num_readonly_signed_accounts: true,
337 num_readonly_unsigned_accounts: true,
338 num_required_signatures: true,
339 recent_blockhash: true,
340 signatures: true,
341 err: true,
342 fee: true,
343 compute_units_consumed: true,
344 loaded_readonly_addresses: true,
345 loaded_writable_addresses: true,
346 fee_payer: true,
347 has_dropped_log_messages: true,
348 }
349 }
350}
351
352#[derive(Default, Debug, Clone, Copy, Serialize)]
353#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
354pub struct LogFields {
355 pub block_slot: bool,
356 pub block_hash: bool,
357 pub transaction_index: bool,
358 pub log_index: bool,
359 pub instruction_address: bool,
360 pub program_id: bool,
361 pub kind: bool,
362 pub message: bool,
363}
364
365impl LogFields {
366 pub fn all() -> Self {
367 LogFields {
368 block_slot: true,
369 block_hash: true,
370 transaction_index: true,
371 log_index: true,
372 instruction_address: true,
373 program_id: true,
374 kind: true,
375 message: true,
376 }
377 }
378}
379
380#[derive(Default, Debug, Clone, Copy, Serialize)]
381#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
382pub struct BalanceFields {
383 pub block_slot: bool,
384 pub block_hash: bool,
385 pub transaction_index: bool,
386 pub account: bool,
387 pub pre: bool,
388 pub post: bool,
389}
390
391impl BalanceFields {
392 pub fn all() -> Self {
393 BalanceFields {
394 block_slot: true,
395 block_hash: true,
396 transaction_index: true,
397 account: true,
398 pre: true,
399 post: true,
400 }
401 }
402}
403
404#[derive(Default, Debug, Clone, Copy, Serialize)]
405#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
406pub struct TokenBalanceFields {
407 pub block_slot: bool,
408 pub block_hash: bool,
409 pub transaction_index: bool,
410 pub account: bool,
411 pub pre_mint: bool,
412 pub post_mint: bool,
413 pub pre_decimals: bool,
414 pub post_decimals: bool,
415 pub pre_program_id: bool,
416 pub post_program_id: bool,
417 pub pre_owner: bool,
418 pub post_owner: bool,
419 pub pre_amount: bool,
420 pub post_amount: bool,
421}
422
423impl TokenBalanceFields {
424 pub fn all() -> Self {
425 TokenBalanceFields {
426 block_slot: true,
427 block_hash: true,
428 transaction_index: true,
429 account: true,
430 pre_mint: true,
431 post_mint: true,
432 pre_decimals: true,
433 post_decimals: true,
434 pre_program_id: true,
435 post_program_id: true,
436 pre_owner: true,
437 post_owner: true,
438 pre_amount: true,
439 post_amount: true,
440 }
441 }
442}
443
444#[derive(Default, Debug, Clone, Copy, Serialize)]
445#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
446pub struct RewardFields {
447 pub block_slot: bool,
448 pub block_hash: bool,
449 pub pubkey: bool,
450 pub lamports: bool,
451 pub post_balance: bool,
452 pub reward_type: bool,
453 pub commission: bool,
454}
455
456impl RewardFields {
457 pub fn all() -> Self {
458 RewardFields {
459 block_slot: true,
460 block_hash: true,
461 pubkey: true,
462 lamports: true,
463 post_balance: true,
464 reward_type: true,
465 commission: true,
466 }
467 }
468}
469
470#[derive(Default, Debug, Clone, Copy, Serialize)]
471#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
472pub struct BlockFields {
473 pub slot: bool,
474 pub hash: bool,
475 pub parent_slot: bool,
476 pub parent_hash: bool,
477 pub height: bool,
478 pub timestamp: bool,
479}
480
481impl BlockFields {
482 pub fn all() -> Self {
483 BlockFields {
484 slot: true,
485 hash: true,
486 parent_slot: true,
487 parent_hash: true,
488 height: true,
489 timestamp: true,
490 }
491 }
492}