1use {
2 crate::error::{DebuggerError, DebuggerResult},
3 serde::Deserialize,
4 solana_account::Account as SolAccount,
5 solana_address::Address,
6 solana_instruction::{AccountMeta, Instruction},
7 std::{collections::HashMap, fs, mem::size_of, path::Path, str::FromStr},
8};
9
10const BPF_ALIGN_OF_U128: usize = 16;
11const MAX_PERMITTED_DATA_INCREASE: usize = 10240;
12const NON_DUP_MARKER: u8 = 0xff;
13
14#[derive(Deserialize)]
15struct DebuggerInput {
16 instruction: InstructionJson,
17 accounts: Vec<AccountJson>,
18}
19
20#[derive(Deserialize)]
21struct InstructionJson {
22 program_id: String,
23 accounts: Vec<AccountMetaJson>,
24 #[serde(default)]
25 data: String,
26}
27
28#[derive(Deserialize)]
29struct AccountMetaJson {
30 pubkey: String,
31 is_signer: bool,
32 is_writable: bool,
33}
34
35#[derive(Deserialize)]
36struct AccountJson {
37 pubkey: String,
38 owner: String,
39 lamports: u64,
40 #[serde(default)]
41 data: String,
42 #[serde(default)]
43 executable: bool,
44}
45
46struct Serializer {
47 buffer: Vec<u8>,
48}
49
50impl Serializer {
51 fn new() -> Self {
52 Self { buffer: Vec::new() }
53 }
54
55 fn write<T>(&mut self, value: T) {
56 let bytes =
57 unsafe { std::slice::from_raw_parts(&value as *const T as *const u8, size_of::<T>()) };
58 self.buffer.extend_from_slice(bytes);
59 }
60
61 fn write_all(&mut self, data: &[u8]) {
62 self.buffer.extend_from_slice(data);
63 }
64
65 fn write_account_data(&mut self, data: &[u8]) {
66 self.write_all(data);
67 self.buffer
68 .extend(std::iter::repeat_n(0u8, MAX_PERMITTED_DATA_INCREASE));
69 let current_len = self.buffer.len();
70 let alignment_needed =
71 (BPF_ALIGN_OF_U128 - (current_len % BPF_ALIGN_OF_U128)) % BPF_ALIGN_OF_U128;
72 self.buffer
73 .extend(std::iter::repeat_n(0u8, alignment_needed));
74 }
75
76 fn finish(self) -> Vec<u8> {
77 self.buffer
78 }
79}
80
81enum SerializeAccount {
82 Account(Address, SolAccount, bool, bool),
83 Duplicate(u8),
84}
85
86fn serialize_parameters(
87 accounts: Vec<SerializeAccount>,
88 instruction_data: &[u8],
89 program_id: &Address,
90) -> Vec<u8> {
91 let mut s = Serializer::new();
92
93 s.write::<u64>((accounts.len() as u64).to_le());
94
95 for account in accounts {
96 match account {
97 SerializeAccount::Account(pubkey, acct, is_signer, is_writable) => {
98 s.write::<u8>(NON_DUP_MARKER);
99 s.write::<u8>(is_signer as u8);
100 s.write::<u8>(is_writable as u8);
101 s.write::<u8>(acct.executable as u8);
102 s.write_all(&[0u8; 4]); s.write_all(pubkey.as_ref());
104 s.write_all(acct.owner.as_ref());
105 s.write::<u64>(acct.lamports.to_le());
106 s.write::<u64>((acct.data.len() as u64).to_le());
107 s.write_account_data(&acct.data);
108 s.write::<u64>(acct.rent_epoch.to_le());
109 }
110 SerializeAccount::Duplicate(position) => {
111 s.write::<u8>(position);
112 s.write_all(&[0u8; 7]); }
114 }
115 }
116
117 s.write::<u64>((instruction_data.len() as u64).to_le());
118 s.write_all(instruction_data);
119 s.write_all(program_id.as_ref());
120
121 s.finish()
122}
123
124pub fn parse_input(input: &str) -> DebuggerResult<(Vec<u8>, Address)> {
127 let input = input.trim();
128 if input.is_empty() {
129 return Ok((Vec::new(), Address::new_unique()));
130 }
131
132 let json_str = if Path::new(input).exists() {
134 fs::read_to_string(input)?
135 } else {
136 input.to_string()
137 };
138
139 let debugger_input: DebuggerInput =
140 serde_json::from_str(&json_str).map_err(|e| DebuggerError::InvalidInput(e.to_string()))?;
141
142 let program_id = Address::from_str(&debugger_input.instruction.program_id)
143 .map_err(|e| DebuggerError::InvalidInput(format!("Invalid program_id: {}", e)))?;
144
145 let account_metas: Vec<AccountMeta> = debugger_input
146 .instruction
147 .accounts
148 .iter()
149 .map(|a| {
150 let pubkey = Address::from_str(&a.pubkey)
151 .map_err(|e| DebuggerError::InvalidInput(format!("Invalid pubkey: {}", e)))?;
152 Ok(AccountMeta {
153 pubkey,
154 is_signer: a.is_signer,
155 is_writable: a.is_writable,
156 })
157 })
158 .collect::<DebuggerResult<Vec<_>>>()?;
159
160 let instruction_data = if debugger_input.instruction.data.is_empty() {
161 Vec::new()
162 } else {
163 bs58::decode(&debugger_input.instruction.data)
164 .into_vec()
165 .map_err(|e| {
166 DebuggerError::InvalidInput(format!("Invalid base58 instruction data: {}", e))
167 })?
168 };
169
170 let instruction = Instruction::new_with_bytes(program_id, &instruction_data, account_metas);
171
172 let account_map: HashMap<Address, SolAccount> = debugger_input
173 .accounts
174 .iter()
175 .map(|a| {
176 let pubkey = Address::from_str(&a.pubkey)
177 .map_err(|e| DebuggerError::InvalidInput(format!("Invalid pubkey: {}", e)))?;
178 let owner = Address::from_str(&a.owner)
179 .map_err(|e| DebuggerError::InvalidInput(format!("Invalid owner: {}", e)))?;
180 let data = if a.data.is_empty() {
181 Vec::new()
182 } else {
183 bs58::decode(&a.data).into_vec().map_err(|e| {
184 DebuggerError::InvalidInput(format!("Invalid base58 account data: {}", e))
185 })?
186 };
187 Ok((
188 pubkey,
189 SolAccount {
190 lamports: a.lamports,
191 data,
192 owner,
193 executable: a.executable,
194 rent_epoch: 0,
195 },
196 ))
197 })
198 .collect::<DebuggerResult<HashMap<_, _>>>()?;
199
200 let mut serialized_accounts = Vec::new();
201 let mut seen: HashMap<Address, usize> = HashMap::new();
202
203 for (i, meta) in instruction.accounts.iter().enumerate() {
204 if let Some(&first_idx) = seen.get(&meta.pubkey) {
205 serialized_accounts.push(SerializeAccount::Duplicate(first_idx as u8));
206 } else {
207 seen.insert(meta.pubkey, i);
208 let acct = account_map.get(&meta.pubkey).ok_or_else(|| {
209 DebuggerError::InvalidInput(format!("Missing account data for {}", meta.pubkey))
210 })?;
211 serialized_accounts.push(SerializeAccount::Account(
212 meta.pubkey,
213 acct.clone(),
214 meta.is_signer,
215 meta.is_writable,
216 ));
217 }
218 }
219
220 let bytes = serialize_parameters(
221 serialized_accounts,
222 &instruction.data,
223 &instruction.program_id,
224 );
225
226 Ok((bytes, program_id))
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn test_parse_empty_input() {
235 let (bytes, _) = parse_input("").unwrap();
236 assert!(bytes.is_empty());
237 }
238
239 #[test]
240 fn test_parse_json_string() {
241 let program_id = Address::new_unique();
242 let account_pubkey = Address::new_unique();
243 let owner = Address::new_unique();
244
245 let json = format!(
246 r#"{{
247 "instruction": {{
248 "program_id": "{}",
249 "accounts": [
250 {{ "pubkey": "{}", "is_signer": true, "is_writable": true }}
251 ],
252 "data": "q"
253 }},
254 "accounts": [
255 {{
256 "pubkey": "{}",
257 "owner": "{}",
258 "lamports": 1000000,
259 "data": "",
260 "executable": false
261 }}
262 ]
263 }}"#,
264 program_id, account_pubkey, account_pubkey, owner
265 );
266
267 let (bytes, pid) = parse_input(&json).unwrap();
268 assert!(!bytes.is_empty());
269 assert_eq!(pid, program_id);
270 }
271}