solana_tx_parser/
instruction_classifier.rs1use crate::constants::{SKIP_PROGRAM_IDS, SYSTEM_PROGRAMS};
4use crate::transaction_adapter::TransactionAdapter;
5use crate::types::{ClassifiedInstruction, ParsedInstruction};
6use std::collections::HashMap;
7
8pub struct InstructionClassifier<'a> {
9 instruction_map: HashMap<String, Vec<ClassifiedInstruction>>,
10 _adapter: &'a TransactionAdapter<'a>,
11}
12
13impl<'a> InstructionClassifier<'a> {
14 pub fn new(adapter: &'a TransactionAdapter<'a>) -> Self {
15 let mut classifier = Self {
16 instruction_map: HashMap::new(),
17 _adapter: adapter,
18 };
19 classifier.classify_instructions(adapter);
20 classifier
21 }
22
23 fn classify_instructions(&mut self, adapter: &TransactionAdapter<'a>) {
24 for (outer_index, raw) in adapter.raw_instructions().iter().enumerate() {
25 let program_id = adapter.get_instruction_program_id(raw);
26 self.add_instruction(ClassifiedInstruction {
27 instruction: ParsedInstruction {
28 program_id: program_id.clone(),
29 accounts: raw
30 .account_key_indexes
31 .iter()
32 .filter_map(|&i| adapter.get_account_key(i as usize))
33 .collect(),
34 data: raw.data.clone(),
35 parsed: None,
36 },
37 program_id,
38 outer_index,
39 inner_index: None,
40 });
41 }
42 if let Some(inner) = adapter.raw_inner_instructions() {
43 for set in inner {
44 for (inner_index, raw) in set.instructions.iter().enumerate() {
45 let program_id = adapter.get_instruction_program_id(raw);
46 self.add_instruction(ClassifiedInstruction {
47 instruction: ParsedInstruction {
48 program_id: program_id.clone(),
49 accounts: raw
50 .account_key_indexes
51 .iter()
52 .filter_map(|&i| adapter.get_account_key(i as usize))
53 .collect(),
54 data: raw.data.clone(),
55 parsed: None,
56 },
57 program_id,
58 outer_index: set.index as usize,
59 inner_index: Some(inner_index),
60 });
61 }
62 }
63 }
64 }
65
66 fn add_instruction(&mut self, classified: ClassifiedInstruction) {
67 if classified.program_id.is_empty() {
68 return;
69 }
70 self.instruction_map
71 .entry(classified.program_id.clone())
72 .or_default()
73 .push(classified);
74 }
75
76 pub fn get_instructions(&self, program_id: &str) -> Vec<ClassifiedInstruction> {
77 self.instruction_map
78 .get(program_id)
79 .cloned()
80 .unwrap_or_default()
81 }
82
83 pub fn get_all_program_ids(&self) -> Vec<String> {
84 self.instruction_map
85 .keys()
86 .filter(|id| {
87 !SYSTEM_PROGRAMS.contains(&id.as_str()) && !SKIP_PROGRAM_IDS.contains(&id.as_str())
88 })
89 .cloned()
90 .collect()
91 }
92}