solana_message/versions/v0/
loaded.rs1#[cfg(feature = "serde")]
2use serde_derive::{Deserialize, Serialize};
3use {
4 crate::v0,
5 alloc::{borrow::Cow, vec::Vec},
6 solana_address::Address,
7};
8#[cfg(feature = "std")]
9use {crate::AccountKeys, solana_sdk_ids::bpf_loader_upgradeable, std::collections::HashSet};
10
11#[derive(Debug, Clone, Eq, PartialEq)]
13pub struct LoadedMessage<'a> {
14 pub message: Cow<'a, v0::Message>,
16 pub loaded_addresses: Cow<'a, LoadedAddresses>,
18 pub is_writable_account_cache: Vec<bool>,
21}
22
23#[derive(Clone, Default, Debug, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
27pub struct LoadedAddresses {
28 pub writable: Vec<Address>,
30 pub readonly: Vec<Address>,
32}
33
34#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
37pub struct LoadedAddressesView<'a> {
38 pub writable: &'a [Address],
40 pub readonly: &'a [Address],
42}
43
44impl<'a> From<&'a LoadedAddresses> for LoadedAddressesView<'a> {
45 fn from(loaded_addresses: &'a LoadedAddresses) -> Self {
46 Self {
47 writable: &loaded_addresses.writable,
48 readonly: &loaded_addresses.readonly,
49 }
50 }
51}
52
53impl FromIterator<LoadedAddresses> for LoadedAddresses {
54 fn from_iter<T: IntoIterator<Item = LoadedAddresses>>(iter: T) -> Self {
55 let (writable, readonly): (Vec<Vec<Address>>, Vec<Vec<Address>>) = iter
56 .into_iter()
57 .map(|addresses| (addresses.writable, addresses.readonly))
58 .unzip();
59 LoadedAddresses {
60 writable: writable.into_iter().flatten().collect(),
61 readonly: readonly.into_iter().flatten().collect(),
62 }
63 }
64}
65
66impl LoadedAddresses {
67 pub fn is_empty(&self) -> bool {
69 self.len() == 0
70 }
71
72 pub fn len(&self) -> usize {
74 self.writable.len().saturating_add(self.readonly.len())
75 }
76}
77
78#[cfg(feature = "std")]
79impl<'a> LoadedMessage<'a> {
80 pub fn new(
81 message: v0::Message,
82 loaded_addresses: LoadedAddresses,
83 reserved_account_keys: &HashSet<Address>,
84 ) -> Self {
85 let mut loaded_message = Self {
86 message: Cow::Owned(message),
87 loaded_addresses: Cow::Owned(loaded_addresses),
88 is_writable_account_cache: Vec::default(),
89 };
90 loaded_message.set_is_writable_account_cache(reserved_account_keys);
91 loaded_message
92 }
93
94 pub fn new_borrowed(
95 message: &'a v0::Message,
96 loaded_addresses: &'a LoadedAddresses,
97 reserved_account_keys: &HashSet<Address>,
98 ) -> Self {
99 let mut loaded_message = Self {
100 message: Cow::Borrowed(message),
101 loaded_addresses: Cow::Borrowed(loaded_addresses),
102 is_writable_account_cache: Vec::default(),
103 };
104 loaded_message.set_is_writable_account_cache(reserved_account_keys);
105 loaded_message
106 }
107
108 fn set_is_writable_account_cache(&mut self, reserved_account_keys: &HashSet<Address>) {
109 let is_writable_account_cache = self
110 .account_keys()
111 .iter()
112 .enumerate()
113 .map(|(i, _key)| self.is_writable_internal(i, reserved_account_keys))
114 .collect::<Vec<_>>();
115 let _ = core::mem::replace(
116 &mut self.is_writable_account_cache,
117 is_writable_account_cache,
118 );
119 }
120
121 pub fn account_keys(&self) -> AccountKeys<'_> {
123 AccountKeys::new(&self.message.account_keys, Some(&self.loaded_addresses))
124 }
125
126 pub fn static_account_keys(&self) -> &[Address] {
128 &self.message.account_keys
129 }
130
131 pub fn has_duplicates(&self) -> bool {
133 let mut uniq = HashSet::with_capacity(self.account_keys().len());
134 self.account_keys().iter().any(|x| !uniq.insert(x))
135 }
136
137 fn is_writable_index(&self, key_index: usize) -> bool {
140 let header = &self.message.header;
141 let num_account_keys = self.message.account_keys.len();
142 let num_signed_accounts = usize::from(header.num_required_signatures);
143 if key_index >= num_account_keys {
144 let loaded_addresses_index = key_index.saturating_sub(num_account_keys);
145 loaded_addresses_index < self.loaded_addresses.writable.len()
146 } else if key_index >= num_signed_accounts {
147 let num_unsigned_accounts = num_account_keys.saturating_sub(num_signed_accounts);
148 let num_writable_unsigned_accounts = num_unsigned_accounts
149 .saturating_sub(usize::from(header.num_readonly_unsigned_accounts));
150 let unsigned_account_index = key_index.saturating_sub(num_signed_accounts);
151 unsigned_account_index < num_writable_unsigned_accounts
152 } else {
153 let num_writable_signed_accounts = num_signed_accounts
154 .saturating_sub(usize::from(header.num_readonly_signed_accounts));
155 key_index < num_writable_signed_accounts
156 }
157 }
158
159 fn is_writable_internal(
161 &self,
162 key_index: usize,
163 reserved_account_keys: &HashSet<Address>,
164 ) -> bool {
165 if self.is_writable_index(key_index) {
166 if let Some(key) = self.account_keys().get(key_index) {
167 return !(reserved_account_keys.contains(key) || self.demote_program_id(key_index));
168 }
169 }
170 false
171 }
172
173 pub fn is_writable(&self, key_index: usize) -> bool {
174 *self
175 .is_writable_account_cache
176 .get(key_index)
177 .unwrap_or(&false)
178 }
179
180 pub fn is_signer(&self, i: usize) -> bool {
181 i < self.message.header.num_required_signatures as usize
182 }
183
184 pub fn demote_program_id(&self, i: usize) -> bool {
185 self.is_key_called_as_program(i) && !self.is_upgradeable_loader_present()
186 }
187
188 pub fn is_key_called_as_program(&self, key_index: usize) -> bool {
190 if let Ok(key_index) = u8::try_from(key_index) {
191 self.message
192 .instructions
193 .iter()
194 .any(|ix| ix.program_id_index == key_index)
195 } else {
196 false
197 }
198 }
199
200 pub fn is_upgradeable_loader_present(&self) -> bool {
202 self.account_keys()
203 .iter()
204 .any(|&key| key == bpf_loader_upgradeable::id())
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use {
211 super::*,
212 crate::{compiled_instruction::CompiledInstruction, MessageHeader},
213 alloc::vec,
214 itertools::Itertools,
215 solana_sdk_ids::{system_program, sysvar},
216 };
217
218 fn check_test_loaded_message() -> (LoadedMessage<'static>, [Address; 6]) {
219 let key0 = Address::new_unique();
220 let key1 = Address::new_unique();
221 let key2 = Address::new_unique();
222 let key3 = Address::new_unique();
223 let key4 = Address::new_unique();
224 let key5 = Address::new_unique();
225
226 let message = LoadedMessage::new(
227 v0::Message {
228 header: MessageHeader {
229 num_required_signatures: 2,
230 num_readonly_signed_accounts: 1,
231 num_readonly_unsigned_accounts: 1,
232 },
233 account_keys: vec![key0, key1, key2, key3],
234 ..v0::Message::default()
235 },
236 LoadedAddresses {
237 writable: vec![key4],
238 readonly: vec![key5],
239 },
240 &HashSet::default(),
241 );
242
243 (message, [key0, key1, key2, key3, key4, key5])
244 }
245
246 #[test]
247 fn test_has_duplicates() {
248 let message = check_test_loaded_message().0;
249
250 assert!(!message.has_duplicates());
251 }
252
253 #[test]
254 fn test_has_duplicates_with_dupe_keys() {
255 let create_message_with_dupe_keys = |mut keys: Vec<Address>| {
256 LoadedMessage::new(
257 v0::Message {
258 account_keys: keys.split_off(2),
259 ..v0::Message::default()
260 },
261 LoadedAddresses {
262 writable: keys.split_off(2),
263 readonly: keys,
264 },
265 &HashSet::default(),
266 )
267 };
268
269 let key0 = Address::new_unique();
270 let key1 = Address::new_unique();
271 let key2 = Address::new_unique();
272 let key3 = Address::new_unique();
273 let dupe_key = Address::new_unique();
274
275 let keys = vec![key0, key1, key2, key3, dupe_key, dupe_key];
276 let keys_len = keys.len();
277 for keys in keys.into_iter().permutations(keys_len).unique() {
278 let message = create_message_with_dupe_keys(keys);
279 assert!(message.has_duplicates());
280 }
281 }
282
283 #[test]
284 fn test_is_writable_index() {
285 let message = check_test_loaded_message().0;
286
287 assert!(message.is_writable_index(0));
288 assert!(!message.is_writable_index(1));
289 assert!(message.is_writable_index(2));
290 assert!(!message.is_writable_index(3));
291 assert!(message.is_writable_index(4));
292 assert!(!message.is_writable_index(5));
293 }
294
295 #[test]
296 fn test_is_writable() {
297 let reserved_account_keys = HashSet::from_iter([sysvar::clock::id(), system_program::id()]);
298 let create_message_with_keys = |keys: Vec<Address>| {
299 LoadedMessage::new(
300 v0::Message {
301 header: MessageHeader {
302 num_required_signatures: 1,
303 num_readonly_signed_accounts: 0,
304 num_readonly_unsigned_accounts: 1,
305 },
306 account_keys: keys[..2].to_vec(),
307 ..v0::Message::default()
308 },
309 LoadedAddresses {
310 writable: keys[2..=2].to_vec(),
311 readonly: keys[3..].to_vec(),
312 },
313 &reserved_account_keys,
314 )
315 };
316
317 let key0 = Address::new_unique();
318 let key1 = Address::new_unique();
319 let key2 = Address::new_unique();
320 {
321 let message = create_message_with_keys(vec![sysvar::clock::id(), key0, key1, key2]);
322 assert!(message.is_writable_index(0));
323 assert!(!message.is_writable(0));
324 }
325
326 {
327 let message = create_message_with_keys(vec![system_program::id(), key0, key1, key2]);
328 assert!(message.is_writable_index(0));
329 assert!(!message.is_writable(0));
330 }
331
332 {
333 let message = create_message_with_keys(vec![key0, key1, system_program::id(), key2]);
334 assert!(message.is_writable_index(2));
335 assert!(!message.is_writable(2));
336 }
337 }
338
339 #[test]
340 fn test_demote_writable_program() {
341 let key0 = Address::new_unique();
342 let key1 = Address::new_unique();
343 let key2 = Address::new_unique();
344 let message = LoadedMessage::new(
345 v0::Message {
346 header: MessageHeader {
347 num_required_signatures: 1,
348 num_readonly_signed_accounts: 0,
349 num_readonly_unsigned_accounts: 0,
350 },
351 account_keys: vec![key0],
352 instructions: vec![CompiledInstruction {
353 program_id_index: 2,
354 accounts: vec![1],
355 data: vec![],
356 }],
357 ..v0::Message::default()
358 },
359 LoadedAddresses {
360 writable: vec![key1, key2],
361 readonly: vec![],
362 },
363 &HashSet::default(),
364 );
365
366 assert!(message.is_writable_index(2));
367 assert!(!message.is_writable(2));
368 }
369}