Skip to main content

solana_message/versions/v1/
cached.rs

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