Skip to main content

solana_message/versions/v1/
cached.rs

1use {
2    crate::{v1::Message, AccountKeys},
3    solana_address::Address,
4    std::{borrow::Cow, collections::HashSet},
5};
6
7#[derive(Debug, Clone, Eq, PartialEq)]
8pub struct CachedMessage<'a> {
9    /// Wrapped message.
10    pub message: Cow<'a, Message>,
11    /// List of boolean with same length as account_keys(), each boolean value indicates if
12    /// corresponding account key is writable or not.
13    pub is_writable_account_cache: Vec<bool>,
14}
15
16impl CachedMessage<'_> {
17    pub fn new(message: Message, reserved_account_keys: &HashSet<Address>) -> Self {
18        let is_writable_account_cache = message
19            .account_keys
20            .iter()
21            .enumerate()
22            .map(|(i, key)| {
23                message.is_writable_index(i)
24                    && !reserved_account_keys.contains(key)
25                    && !message.demote_program_id(i)
26            })
27            .collect::<Vec<_>>();
28        Self {
29            message: Cow::Owned(message),
30            is_writable_account_cache,
31        }
32    }
33
34    /// Returns true if any account keys are duplicates
35    pub fn has_duplicates(&self) -> bool {
36        let mut uniq = HashSet::with_capacity(self.account_keys().len());
37        self.account_keys().iter().any(|x| !uniq.insert(x))
38    }
39
40    pub fn is_key_called_as_program(&self, key_index: usize) -> bool {
41        self.message.is_key_called_as_program(key_index)
42    }
43
44    /// Inspect all message keys for the bpf upgradeable loader
45    pub fn is_upgradeable_loader_present(&self) -> bool {
46        self.message.is_upgradeable_loader_present()
47    }
48
49    /// Returns the full list of account keys.
50    pub fn account_keys(&self) -> AccountKeys<'_> {
51        AccountKeys::new(&self.message.account_keys, None)
52    }
53
54    pub fn is_writable(&self, index: usize) -> bool {
55        *self.is_writable_account_cache.get(index).unwrap_or(&false)
56    }
57
58    pub fn demote_program_id(&self, i: usize) -> bool {
59        self.is_key_called_as_program(i) && !self.is_upgradeable_loader_present()
60    }
61}