Skip to main content

solana_message/
account_keys.rs

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/// Collection of static and dynamically loaded keys used to load accounts
14/// during transaction processing.
15#[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    /// Creates account keys from static keys and an optional borrowed view of
38    /// dynamically loaded addresses.
39    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    /// Returns an iterator of account key segments. The ordering of segments
50    /// affects how account indexes from compiled instructions are resolved and
51    /// so should not be changed.
52    #[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            // empty segments added for branch type compatibility
63            [self.static_keys, &[], &[]].into_iter()
64        }
65    }
66
67    /// Returns the address of the account at the specified index of the list of
68    /// message account keys constructed from static keys, followed by dynamically
69    /// loaded writable addresses, and lastly the list of dynamically loaded
70    /// readonly addresses.
71    #[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    /// Returns the total length of loaded accounts for a message
84    #[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    /// Returns true if this collection of account keys is empty
94    pub fn is_empty(&self) -> bool {
95        self.len() == 0
96    }
97
98    /// Iterator for the addresses of the loaded accounts for a message
99    #[inline]
100    pub fn iter(&self) -> impl Iterator<Item = &'a Address> + Clone {
101        self.key_segment_iter().flatten()
102    }
103
104    /// Compile instructions using the order of account keys to determine
105    /// compiled instruction account indexes.
106    ///
107    /// # Panics
108    ///
109    /// Panics when compiling fails. See [`AccountKeys::try_compile_instructions`]
110    /// for a full description of failure scenarios.
111    pub fn compile_instructions(&self, instructions: &[Instruction]) -> Vec<CompiledInstruction> {
112        self.try_compile_instructions(instructions)
113            .expect("compilation failure")
114    }
115
116    /// Compile instructions using the order of account keys to determine
117    /// compiled instruction account indexes.
118    ///
119    /// # Errors
120    ///
121    /// Compilation will fail if any `instructions` use account keys which are not
122    /// present in this account key collection.
123    ///
124    /// Compilation will fail if any `instructions` use account keys which are located
125    /// at an index which cannot be cast to a `u8` without overflow.
126    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}