1use {
2 crate::{
3 compiled_instruction::CompiledInstruction,
4 v0::{LoadedAddresses, LoadedAddressesView},
5 CompileError,
6 },
7 alloc::{collections::BTreeMap, vec::Vec},
8 core::ops::Index,
9 solana_address::Address,
10 solana_instruction::Instruction,
11};
12
13#[derive(Clone, Default, Debug, Eq)]
16pub struct AccountKeys<'a> {
17 static_keys: &'a [Address],
18 dynamic_keys: Option<LoadedAddressesView<'a>>,
19}
20
21impl Index<usize> for AccountKeys<'_> {
22 type Output = Address;
23 #[inline]
24 fn index(&self, index: usize) -> &Self::Output {
25 self.get(index).expect("index is invalid")
26 }
27}
28
29impl<'a> AccountKeys<'a> {
30 pub fn new(static_keys: &'a [Address], dynamic_keys: Option<&'a LoadedAddresses>) -> Self {
31 Self::new_with_loaded_addresses_view(
32 static_keys,
33 dynamic_keys.map(LoadedAddressesView::from),
34 )
35 }
36
37 pub fn new_with_loaded_addresses_view(
40 static_keys: &'a [Address],
41 dynamic_keys: Option<LoadedAddressesView<'a>>,
42 ) -> Self {
43 Self {
44 static_keys,
45 dynamic_keys,
46 }
47 }
48
49 #[inline]
53 fn key_segment_iter(&self) -> impl Iterator<Item = &'a [Address]> + Clone {
54 if let Some(dynamic_keys) = self.dynamic_keys {
55 [
56 self.static_keys,
57 dynamic_keys.writable,
58 dynamic_keys.readonly,
59 ]
60 .into_iter()
61 } else {
62 [self.static_keys, &[], &[]].into_iter()
64 }
65 }
66
67 #[inline]
72 pub fn get(&self, mut index: usize) -> Option<&'a Address> {
73 for key_segment in self.key_segment_iter() {
74 if index < key_segment.len() {
75 return Some(&key_segment[index]);
76 }
77 index = index.saturating_sub(key_segment.len());
78 }
79
80 None
81 }
82
83 #[inline]
85 pub fn len(&self) -> usize {
86 let mut len = 0usize;
87 for key_segment in self.key_segment_iter() {
88 len = len.saturating_add(key_segment.len());
89 }
90 len
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.len() == 0
96 }
97
98 #[inline]
100 pub fn iter(&self) -> impl Iterator<Item = &'a Address> + Clone {
101 self.key_segment_iter().flatten()
102 }
103
104 pub fn compile_instructions(&self, instructions: &[Instruction]) -> Vec<CompiledInstruction> {
112 self.try_compile_instructions(instructions)
113 .expect("compilation failure")
114 }
115
116 pub fn try_compile_instructions(
127 &self,
128 instructions: &[Instruction],
129 ) -> Result<Vec<CompiledInstruction>, CompileError> {
130 let mut account_index_map = BTreeMap::<&Address, u8>::new();
131 for (index, key) in self.iter().enumerate() {
132 let index = u8::try_from(index).map_err(|_| CompileError::AccountIndexOverflow)?;
133 account_index_map.insert(key, index);
134 }
135
136 let get_account_index = |key: &Address| -> Result<u8, CompileError> {
137 account_index_map
138 .get(key)
139 .cloned()
140 .ok_or(CompileError::UnknownInstructionKey(*key))
141 };
142
143 instructions
144 .iter()
145 .map(|ix| {
146 let accounts: Vec<u8> = ix
147 .accounts
148 .iter()
149 .map(|account_meta| get_account_index(&account_meta.pubkey))
150 .collect::<Result<Vec<u8>, CompileError>>()?;
151
152 Ok(CompiledInstruction {
153 program_id_index: get_account_index(&ix.program_id)?,
154 data: ix.data.clone(),
155 accounts,
156 })
157 })
158 .collect()
159 }
160}
161
162impl PartialEq for AccountKeys<'_> {
163 fn eq(&self, other: &Self) -> bool {
164 self.iter().eq(other.iter())
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use {super::*, alloc::vec, solana_instruction::AccountMeta};
171
172 fn test_account_keys() -> [Address; 6] {
173 let key0 = Address::new_unique();
174 let key1 = Address::new_unique();
175 let key2 = Address::new_unique();
176 let key3 = Address::new_unique();
177 let key4 = Address::new_unique();
178 let key5 = Address::new_unique();
179
180 [key0, key1, key2, key3, key4, key5]
181 }
182
183 #[test]
184 fn test_key_segment_iter() {
185 let keys = test_account_keys();
186
187 let static_keys = vec![keys[0], keys[1], keys[2]];
188 let dynamic_keys = LoadedAddresses {
189 writable: vec![keys[3], keys[4]],
190 readonly: vec![keys[5]],
191 };
192 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
193
194 let expected_segments = [
195 vec![keys[0], keys[1], keys[2]],
196 vec![keys[3], keys[4]],
197 vec![keys[5]],
198 ];
199
200 assert!(account_keys.key_segment_iter().eq(expected_segments.iter()));
201 }
202
203 #[test]
204 fn test_key_segment_iter_with_loaded_addresses_view() {
205 let keys = test_account_keys();
206
207 let static_keys = [keys[0], keys[1], keys[2]];
208 let writable_dynamic_keys = [keys[3], keys[4]];
209 let readonly_dynamic_keys = [keys[5]];
210 let dynamic_keys = LoadedAddressesView {
211 writable: &writable_dynamic_keys,
212 readonly: &readonly_dynamic_keys,
213 };
214 let account_keys =
215 AccountKeys::new_with_loaded_addresses_view(&static_keys, Some(dynamic_keys));
216
217 let expected_segments = [
218 &static_keys[..],
219 &writable_dynamic_keys[..],
220 &readonly_dynamic_keys[..],
221 ];
222
223 assert!(account_keys
224 .key_segment_iter()
225 .eq(expected_segments.into_iter()));
226 }
227
228 #[test]
229 fn test_len() {
230 let keys = test_account_keys();
231
232 let static_keys = vec![keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]];
233 let account_keys = AccountKeys::new(&static_keys, None);
234
235 assert_eq!(account_keys.len(), keys.len());
236 }
237
238 #[test]
239 fn test_len_with_dynamic_keys() {
240 let keys = test_account_keys();
241
242 let static_keys = vec![keys[0], keys[1], keys[2]];
243 let dynamic_keys = LoadedAddresses {
244 writable: vec![keys[3], keys[4]],
245 readonly: vec![keys[5]],
246 };
247 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
248
249 assert_eq!(account_keys.len(), keys.len());
250 }
251
252 #[test]
253 fn test_iter() {
254 let keys = test_account_keys();
255
256 let static_keys = vec![keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]];
257 let account_keys = AccountKeys::new(&static_keys, None);
258
259 assert!(account_keys.iter().eq(keys.iter()));
260 }
261
262 #[test]
263 fn test_iter_with_dynamic_keys() {
264 let keys = test_account_keys();
265
266 let static_keys = vec![keys[0], keys[1], keys[2]];
267 let dynamic_keys = LoadedAddresses {
268 writable: vec![keys[3], keys[4]],
269 readonly: vec![keys[5]],
270 };
271 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
272
273 assert!(account_keys.iter().eq(keys.iter()));
274 }
275
276 #[test]
277 fn test_eq() {
278 let keys = test_account_keys();
279
280 let static_keys = vec![keys[0], keys[1], keys[2]];
281 let split_static_keys = vec![keys[0]];
282 let split_dynamic_keys = LoadedAddresses {
283 writable: vec![keys[1]],
284 readonly: vec![keys[2]],
285 };
286
287 assert_eq!(
288 AccountKeys::new(&static_keys, None),
289 AccountKeys::new(&split_static_keys, Some(&split_dynamic_keys)),
290 );
291 }
292
293 #[test]
294 fn test_ne_with_different_lengths() {
295 let keys = test_account_keys();
296
297 let short_static_keys = vec![keys[0]];
298 let long_static_keys = vec![keys[0], keys[1]];
299 let long_dynamic_keys = LoadedAddresses {
300 writable: vec![keys[1]],
301 readonly: vec![],
302 };
303
304 let short_account_keys = AccountKeys::new(&short_static_keys, None);
305 let long_static_account_keys = AccountKeys::new(&long_static_keys, None);
306 let long_dynamic_account_keys =
307 AccountKeys::new(&short_static_keys, Some(&long_dynamic_keys));
308
309 assert_ne!(short_account_keys, long_static_account_keys);
310 assert_ne!(long_static_account_keys, short_account_keys);
311 assert_ne!(short_account_keys, long_dynamic_account_keys);
312 assert_ne!(long_dynamic_account_keys, short_account_keys);
313 }
314
315 #[test]
316 fn test_get() {
317 let keys = test_account_keys();
318
319 let static_keys = vec![keys[0], keys[1], keys[2], keys[3]];
320 let account_keys = AccountKeys::new(&static_keys, None);
321
322 assert_eq!(account_keys.get(0), Some(&keys[0]));
323 assert_eq!(account_keys.get(1), Some(&keys[1]));
324 assert_eq!(account_keys.get(2), Some(&keys[2]));
325 assert_eq!(account_keys.get(3), Some(&keys[3]));
326 assert_eq!(account_keys.get(4), None);
327 assert_eq!(account_keys.get(5), None);
328 }
329
330 #[test]
331 fn test_get_with_dynamic_keys() {
332 let keys = test_account_keys();
333
334 let static_keys = vec![keys[0], keys[1], keys[2]];
335 let dynamic_keys = LoadedAddresses {
336 writable: vec![keys[3], keys[4]],
337 readonly: vec![keys[5]],
338 };
339 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
340
341 assert_eq!(account_keys.get(0), Some(&keys[0]));
342 assert_eq!(account_keys.get(1), Some(&keys[1]));
343 assert_eq!(account_keys.get(2), Some(&keys[2]));
344 assert_eq!(account_keys.get(3), Some(&keys[3]));
345 assert_eq!(account_keys.get(4), Some(&keys[4]));
346 assert_eq!(account_keys.get(5), Some(&keys[5]));
347 }
348
349 #[test]
350 fn test_owned_and_view_dynamic_keys_behave_the_same() {
351 let keys = test_account_keys();
352
353 let static_keys = [keys[0], keys[1]];
354 let dynamic_keys = LoadedAddresses {
355 writable: vec![keys[2], keys[3]],
356 readonly: vec![keys[4], keys[5]],
357 };
358 let dynamic_keys_view = LoadedAddressesView::from(&dynamic_keys);
359 let owned_backed_account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
360 let view_backed_account_keys =
361 AccountKeys::new_with_loaded_addresses_view(&static_keys, Some(dynamic_keys_view));
362
363 assert_eq!(
364 dynamic_keys_view,
365 LoadedAddressesView {
366 writable: &dynamic_keys.writable,
367 readonly: &dynamic_keys.readonly,
368 },
369 );
370 assert_eq!(
371 owned_backed_account_keys.len(),
372 view_backed_account_keys.len()
373 );
374 for index in 0..=keys.len() {
375 assert_eq!(
376 owned_backed_account_keys.get(index),
377 view_backed_account_keys.get(index),
378 );
379 }
380 assert!(owned_backed_account_keys
381 .iter()
382 .eq(view_backed_account_keys.iter()));
383 assert_eq!(owned_backed_account_keys, view_backed_account_keys);
384 }
385
386 #[test]
387 fn test_loaded_addresses_view_from_borrowed_slices() {
388 let keys = test_account_keys();
389
390 let static_keys = [keys[0], keys[1]];
391 let writable_dynamic_keys = [keys[2], keys[3]];
392 let readonly_dynamic_keys = [keys[4], keys[5]];
393 let account_keys = AccountKeys::new_with_loaded_addresses_view(
394 &static_keys,
395 Some(LoadedAddressesView {
396 writable: &writable_dynamic_keys,
397 readonly: &readonly_dynamic_keys,
398 }),
399 );
400
401 assert_eq!(account_keys.len(), keys.len());
402 for (index, expected_key) in keys.iter().enumerate() {
403 assert_eq!(account_keys.get(index), Some(expected_key));
404 }
405 assert_eq!(account_keys.get(keys.len()), None);
406 assert!(account_keys.iter().eq(keys.iter()));
407 }
408
409 #[test]
410 fn test_try_compile_instructions() {
411 let keys = test_account_keys();
412
413 let static_keys = vec![keys[0]];
414 let dynamic_keys = LoadedAddresses {
415 writable: vec![keys[1]],
416 readonly: vec![keys[2]],
417 };
418 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
419
420 let instruction = Instruction {
421 program_id: keys[0],
422 accounts: vec![
423 AccountMeta::new(keys[1], true),
424 AccountMeta::new(keys[2], true),
425 ],
426 data: vec![0],
427 };
428
429 assert_eq!(
430 account_keys.try_compile_instructions(&[instruction]),
431 Ok(vec![CompiledInstruction {
432 program_id_index: 0,
433 accounts: vec![1, 2],
434 data: vec![0],
435 }]),
436 );
437 }
438
439 #[test]
440 fn test_try_compile_instructions_with_unknown_key() {
441 let static_keys = test_account_keys();
442 let account_keys = AccountKeys::new(&static_keys, None);
443
444 let unknown_key = Address::new_unique();
445 let test_instructions = [
446 Instruction {
447 program_id: unknown_key,
448 accounts: vec![],
449 data: vec![],
450 },
451 Instruction {
452 program_id: static_keys[0],
453 accounts: vec![
454 AccountMeta::new(static_keys[1], false),
455 AccountMeta::new(unknown_key, false),
456 ],
457 data: vec![],
458 },
459 ];
460
461 for ix in test_instructions {
462 assert_eq!(
463 account_keys.try_compile_instructions(&[ix]),
464 Err(CompileError::UnknownInstructionKey(unknown_key))
465 );
466 }
467 }
468
469 #[test]
470 fn test_try_compile_instructions_with_too_many_account_keys() {
471 const MAX_LENGTH_WITHOUT_OVERFLOW: usize = u8::MAX as usize + 1;
472 let static_keys = vec![Address::default(); MAX_LENGTH_WITHOUT_OVERFLOW];
473 let dynamic_keys = LoadedAddresses {
474 writable: vec![Address::default()],
475 readonly: vec![],
476 };
477 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
478 assert_eq!(
479 account_keys.try_compile_instructions(&[]),
480 Err(CompileError::AccountIndexOverflow)
481 );
482 }
483}