light_instruction_decoder/
types.rs1use std::collections::HashMap;
8
9use solana_instruction::AccountMeta;
10use solana_pubkey::Pubkey;
11use solana_signature::Signature;
12
13use crate::{DecodedInstruction, DecoderRegistry, EnhancedLoggingConfig};
14
15#[derive(Debug, Clone, Default)]
17pub struct AccountStateSnapshot {
18 pub lamports_before: u64,
19 pub lamports_after: u64,
20 pub data_len_before: usize,
21 pub data_len_after: usize,
22}
23
24#[derive(Debug, Clone)]
26pub struct EnhancedTransactionLog {
27 pub signature: Signature,
28 pub slot: u64,
29 pub status: TransactionStatus,
30 pub fee: u64,
31 pub compute_used: u64,
32 pub compute_total: u64,
33 pub instructions: Vec<EnhancedInstructionLog>,
34 pub account_changes: Vec<AccountChange>,
35 pub program_logs_pretty: String,
36 pub light_events: Vec<LightProtocolEvent>,
37 pub account_states: Option<HashMap<Pubkey, AccountStateSnapshot>>,
39}
40
41impl EnhancedTransactionLog {
42 pub fn new(signature: Signature, slot: u64) -> Self {
44 Self {
45 signature,
46 slot,
47 status: TransactionStatus::Unknown,
48 fee: 0,
49 compute_used: 0,
50 compute_total: 1_400_000,
51 instructions: Vec::new(),
52 account_changes: Vec::new(),
53 program_logs_pretty: String::new(),
54 light_events: Vec::new(),
55 account_states: None,
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
62pub enum TransactionStatus {
63 Success,
64 Failed(String),
65 Unknown,
66}
67
68impl TransactionStatus {
69 pub fn text(&self) -> String {
70 match self {
71 TransactionStatus::Success => "Success".to_string(),
72 TransactionStatus::Failed(err) => format!("Failed: {}", err),
73 TransactionStatus::Unknown => "Unknown".to_string(),
74 }
75 }
76}
77
78#[derive(Debug, Clone)]
80pub struct EnhancedInstructionLog {
81 pub index: usize,
82 pub program_id: Pubkey,
83 pub program_name: String,
84 pub instruction_name: Option<String>,
85 pub accounts: Vec<AccountMeta>,
86 pub data: Vec<u8>,
87 pub decoded_instruction: Option<DecodedInstruction>,
89 pub inner_instructions: Vec<EnhancedInstructionLog>,
90 pub compute_consumed: Option<u64>,
91 pub success: bool,
92 pub depth: usize,
93}
94
95impl EnhancedInstructionLog {
96 pub fn new(index: usize, program_id: Pubkey, program_name: String) -> Self {
98 Self {
99 index,
100 program_id,
101 program_name,
102 instruction_name: None,
103 accounts: Vec::new(),
104 data: Vec::new(),
105 decoded_instruction: None,
106 inner_instructions: Vec::new(),
107 compute_consumed: None,
108 success: true,
109 depth: 0,
110 }
111 }
112
113 pub fn decode(&mut self, config: &EnhancedLoggingConfig) {
115 if !config.decode_light_instructions {
116 return;
117 }
118
119 if let Some(registry) = config.decoder_registry() {
121 if let Some((decoded, decoder)) =
122 registry.decode(&self.program_id, &self.data, &self.accounts)
123 {
124 self.instruction_name = Some(decoded.name.clone());
125 self.decoded_instruction = Some(decoded);
126 self.program_name = decoder.program_name().to_string();
127 }
128 }
129 }
130
131 pub fn find_parent_for_instruction(
133 instructions: &mut [EnhancedInstructionLog],
134 target_depth: usize,
135 ) -> Option<&mut EnhancedInstructionLog> {
136 for instruction in instructions.iter_mut().rev() {
137 if instruction.depth == target_depth {
138 return Some(instruction);
139 }
140 if let Some(parent) =
141 Self::find_parent_for_instruction(&mut instruction.inner_instructions, target_depth)
142 {
143 return Some(parent);
144 }
145 }
146 None
147 }
148}
149
150#[derive(Debug, Clone)]
152pub struct AccountChange {
153 pub pubkey: Pubkey,
154 pub account_type: String,
155 pub access: AccountAccess,
156 pub account_index: usize,
157 pub lamports_before: u64,
158 pub lamports_after: u64,
159 pub data_len_before: usize,
160 pub data_len_after: usize,
161 pub owner: Pubkey,
162 pub executable: bool,
163 pub rent_epoch: u64,
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub enum AccountAccess {
169 Readonly,
170 Writable,
171 Signer,
172 SignerWritable,
173}
174
175impl AccountAccess {
176 pub fn symbol(&self, index: usize) -> String {
177 format!("#{}", index)
178 }
179
180 pub fn text(&self) -> &'static str {
181 match self {
182 AccountAccess::Readonly => "readonly",
183 AccountAccess::Writable => "writable",
184 AccountAccess::Signer => "signer",
185 AccountAccess::SignerWritable => "signer+writable",
186 }
187 }
188}
189
190#[derive(Debug, Clone)]
192pub struct LightProtocolEvent {
193 pub event_type: String,
194 pub compressed_accounts: Vec<CompressedAccountInfo>,
195 pub merkle_tree_changes: Vec<MerkleTreeChange>,
196 pub nullifiers: Vec<String>,
197}
198
199#[derive(Debug, Clone)]
201pub struct CompressedAccountInfo {
202 pub hash: String,
203 pub owner: Pubkey,
204 pub lamports: u64,
205 pub data: Option<Vec<u8>>,
206 pub address: Option<String>,
207}
208
209#[derive(Debug, Clone)]
211pub struct MerkleTreeChange {
212 pub tree_pubkey: Pubkey,
213 pub tree_type: String,
214 pub sequence_number: u64,
215 pub leaf_index: u64,
216}
217
218pub fn get_program_name(program_id: &Pubkey, registry: Option<&DecoderRegistry>) -> String {
222 if let Some(reg) = registry {
224 if let Some(decoder) = reg.get_decoder(program_id) {
225 return decoder.program_name().to_string();
226 }
227 }
228
229 match program_id.to_string().as_str() {
231 "11111111111111111111111111111111" => "System Program".to_string(),
232 "ComputeBudget111111111111111111111111111111" => "Compute Budget".to_string(),
233 "SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7" => "Light System Program".to_string(),
234 "compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq" => "Account Compression".to_string(),
235 "cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m" => "Light Token Program".to_string(),
236 _ => format!("Unknown Program ({})", program_id),
237 }
238}