1use {
2 crate::{
3 instruction::{CompiledInstruction, Instruction},
4 message::{v0::LoadedAddresses, CompileError},
5 pubkey::Pubkey,
6 },
7 std::{collections::BTreeMap, ops::Index},
8};
9
10pub struct AccountKeys<'a> {
13 static_keys: &'a [Pubkey],
14 dynamic_keys: Option<&'a LoadedAddresses>,
15}
16
17impl Index<usize> for AccountKeys<'_> {
18 type Output = Pubkey;
19 fn index(&self, index: usize) -> &Self::Output {
20 self.get(index).expect("index is invalid")
21 }
22}
23
24impl<'a> AccountKeys<'a> {
25 pub fn new(static_keys: &'a [Pubkey], dynamic_keys: Option<&'a LoadedAddresses>) -> Self {
26 Self {
27 static_keys,
28 dynamic_keys,
29 }
30 }
31
32 fn key_segment_iter(&self) -> impl Iterator<Item = &'a [Pubkey]> {
36 if let Some(dynamic_keys) = self.dynamic_keys {
37 [
38 self.static_keys,
39 &dynamic_keys.writable,
40 &dynamic_keys.readonly,
41 ]
42 .into_iter()
43 } else {
44 [self.static_keys, &[], &[]].into_iter()
46 }
47 }
48
49 pub fn get(&self, mut index: usize) -> Option<&'a Pubkey> {
54 for key_segment in self.key_segment_iter() {
55 if index < key_segment.len() {
56 return Some(&key_segment[index]);
57 }
58 index = index.saturating_sub(key_segment.len());
59 }
60
61 None
62 }
63
64 pub fn len(&self) -> usize {
66 let mut len = 0usize;
67 for key_segment in self.key_segment_iter() {
68 len = len.saturating_add(key_segment.len());
69 }
70 len
71 }
72
73 pub fn is_empty(&self) -> bool {
75 self.len() == 0
76 }
77
78 pub fn iter(&self) -> impl Iterator<Item = &'a Pubkey> {
80 self.key_segment_iter().flatten()
81 }
82
83 pub fn compile_instructions(&self, instructions: &[Instruction]) -> Vec<CompiledInstruction> {
91 self.try_compile_instructions(instructions)
92 .expect("compilation failure")
93 }
94
95 pub fn try_compile_instructions(
106 &self,
107 instructions: &[Instruction],
108 ) -> Result<Vec<CompiledInstruction>, CompileError> {
109 let mut account_index_map = BTreeMap::<&Pubkey, u8>::new();
110 for (index, key) in self.iter().enumerate() {
111 let index = u8::try_from(index).map_err(|_| CompileError::AccountIndexOverflow)?;
112 account_index_map.insert(key, index);
113 }
114
115 let get_account_index = |key: &Pubkey| -> Result<u8, CompileError> {
116 account_index_map
117 .get(key)
118 .cloned()
119 .ok_or(CompileError::UnknownInstructionKey(*key))
120 };
121
122 instructions
123 .iter()
124 .map(|ix| {
125 let accounts: Vec<u8> = ix
126 .accounts
127 .iter()
128 .map(|account_meta| get_account_index(&account_meta.pubkey))
129 .collect::<Result<Vec<u8>, CompileError>>()?;
130
131 Ok(CompiledInstruction {
132 program_id_index: get_account_index(&ix.program_id)?,
133 data: ix.data.clone(),
134 accounts,
135 })
136 })
137 .collect()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use {super::*, crate::instruction::AccountMeta};
144
145 fn test_account_keys() -> [Pubkey; 6] {
146 let key0 = Pubkey::new_unique();
147 let key1 = Pubkey::new_unique();
148 let key2 = Pubkey::new_unique();
149 let key3 = Pubkey::new_unique();
150 let key4 = Pubkey::new_unique();
151 let key5 = Pubkey::new_unique();
152
153 [key0, key1, key2, key3, key4, key5]
154 }
155
156 #[test]
157 fn test_key_segment_iter() {
158 let keys = test_account_keys();
159
160 let static_keys = vec![keys[0], keys[1], keys[2]];
161 let dynamic_keys = LoadedAddresses {
162 writable: vec![keys[3], keys[4]],
163 readonly: vec![keys[5]],
164 };
165 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
166
167 let expected_segments = vec![
168 vec![keys[0], keys[1], keys[2]],
169 vec![keys[3], keys[4]],
170 vec![keys[5]],
171 ];
172
173 assert!(account_keys
174 .key_segment_iter()
175 .into_iter()
176 .eq(expected_segments.iter()));
177 }
178
179 #[test]
180 fn test_len() {
181 let keys = test_account_keys();
182
183 let static_keys = vec![keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]];
184 let account_keys = AccountKeys::new(&static_keys, None);
185
186 assert_eq!(account_keys.len(), keys.len());
187 }
188
189 #[test]
190 fn test_len_with_dynamic_keys() {
191 let keys = test_account_keys();
192
193 let static_keys = vec![keys[0], keys[1], keys[2]];
194 let dynamic_keys = LoadedAddresses {
195 writable: vec![keys[3], keys[4]],
196 readonly: vec![keys[5]],
197 };
198 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
199
200 assert_eq!(account_keys.len(), keys.len());
201 }
202
203 #[test]
204 fn test_iter() {
205 let keys = test_account_keys();
206
207 let static_keys = vec![keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]];
208 let account_keys = AccountKeys::new(&static_keys, None);
209
210 assert!(account_keys.iter().eq(keys.iter()));
211 }
212
213 #[test]
214 fn test_iter_with_dynamic_keys() {
215 let keys = test_account_keys();
216
217 let static_keys = vec![keys[0], keys[1], keys[2]];
218 let dynamic_keys = LoadedAddresses {
219 writable: vec![keys[3], keys[4]],
220 readonly: vec![keys[5]],
221 };
222 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
223
224 assert!(account_keys.iter().eq(keys.iter()));
225 }
226
227 #[test]
228 fn test_get() {
229 let keys = test_account_keys();
230
231 let static_keys = vec![keys[0], keys[1], keys[2], keys[3]];
232 let account_keys = AccountKeys::new(&static_keys, None);
233
234 assert_eq!(account_keys.get(0), Some(&keys[0]));
235 assert_eq!(account_keys.get(1), Some(&keys[1]));
236 assert_eq!(account_keys.get(2), Some(&keys[2]));
237 assert_eq!(account_keys.get(3), Some(&keys[3]));
238 assert_eq!(account_keys.get(4), None);
239 assert_eq!(account_keys.get(5), None);
240 }
241
242 #[test]
243 fn test_get_with_dynamic_keys() {
244 let keys = test_account_keys();
245
246 let static_keys = vec![keys[0], keys[1], keys[2]];
247 let dynamic_keys = LoadedAddresses {
248 writable: vec![keys[3], keys[4]],
249 readonly: vec![keys[5]],
250 };
251 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
252
253 assert_eq!(account_keys.get(0), Some(&keys[0]));
254 assert_eq!(account_keys.get(1), Some(&keys[1]));
255 assert_eq!(account_keys.get(2), Some(&keys[2]));
256 assert_eq!(account_keys.get(3), Some(&keys[3]));
257 assert_eq!(account_keys.get(4), Some(&keys[4]));
258 assert_eq!(account_keys.get(5), Some(&keys[5]));
259 }
260
261 #[test]
262 fn test_try_compile_instructions() {
263 let keys = test_account_keys();
264
265 let static_keys = vec![keys[0]];
266 let dynamic_keys = LoadedAddresses {
267 writable: vec![keys[1]],
268 readonly: vec![keys[2]],
269 };
270 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
271
272 let instruction = Instruction {
273 program_id: keys[0],
274 accounts: vec![
275 AccountMeta::new(keys[1], true),
276 AccountMeta::new(keys[2], true),
277 ],
278 data: vec![0],
279 };
280
281 assert_eq!(
282 account_keys.try_compile_instructions(&[instruction]),
283 Ok(vec![CompiledInstruction {
284 program_id_index: 0,
285 accounts: vec![1, 2],
286 data: vec![0],
287 }]),
288 );
289 }
290
291 #[test]
292 fn test_try_compile_instructions_with_unknown_key() {
293 let static_keys = test_account_keys();
294 let account_keys = AccountKeys::new(&static_keys, None);
295
296 let unknown_key = Pubkey::new_unique();
297 let test_instructions = [
298 Instruction {
299 program_id: unknown_key,
300 accounts: vec![],
301 data: vec![],
302 },
303 Instruction {
304 program_id: static_keys[0],
305 accounts: vec![
306 AccountMeta::new(static_keys[1], false),
307 AccountMeta::new(unknown_key, false),
308 ],
309 data: vec![],
310 },
311 ];
312
313 for ix in test_instructions {
314 assert_eq!(
315 account_keys.try_compile_instructions(&[ix]),
316 Err(CompileError::UnknownInstructionKey(unknown_key))
317 );
318 }
319 }
320
321 #[test]
322 fn test_try_compile_instructions_with_too_many_account_keys() {
323 const MAX_LENGTH_WITHOUT_OVERFLOW: usize = u8::MAX as usize + 1;
324 let static_keys = vec![Pubkey::default(); MAX_LENGTH_WITHOUT_OVERFLOW];
325 let dynamic_keys = LoadedAddresses {
326 writable: vec![Pubkey::default()],
327 readonly: vec![],
328 };
329 let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
330 assert_eq!(
331 account_keys.try_compile_instructions(&[]),
332 Err(CompileError::AccountIndexOverflow)
333 );
334 }
335}