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}