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