sol_parser_sdk/core/
cache.rs1use solana_sdk::pubkey::Pubkey;
27use std::cell::RefCell;
28
29#[derive(Debug)]
37pub struct AccountPubkeyCache {
38 cache: Vec<Pubkey>,
40}
41
42impl AccountPubkeyCache {
43 pub fn new() -> Self {
47 Self { cache: Vec::with_capacity(32) }
48 }
49
50 #[inline]
63 pub fn build_account_pubkeys(
64 &mut self,
65 instruction_accounts: &[u8],
66 all_accounts: &[Pubkey],
67 ) -> &[Pubkey] {
68 self.cache.clear();
69
70 if self.cache.capacity() < instruction_accounts.len() {
72 self.cache.reserve(instruction_accounts.len() - self.cache.capacity());
73 }
74
75 for &idx in instruction_accounts.iter() {
77 if (idx as usize) < all_accounts.len() {
78 self.cache.push(all_accounts[idx as usize]);
79 }
80 }
81
82 &self.cache
83 }
84}
85
86impl Default for AccountPubkeyCache {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92thread_local! {
93 static THREAD_LOCAL_ACCOUNT_CACHE: RefCell<AccountPubkeyCache> =
94 RefCell::new(AccountPubkeyCache::new());
95}
96
97#[inline]
125pub fn build_account_pubkeys_with_cache(
126 instruction_accounts: &[u8],
127 all_accounts: &[Pubkey],
128) -> Vec<Pubkey> {
129 THREAD_LOCAL_ACCOUNT_CACHE.with(|cache| {
130 let mut cache = cache.borrow_mut();
131 cache.build_account_pubkeys(instruction_accounts, all_accounts).to_vec()
132 })
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_account_pubkey_cache_basic() {
141 let mut cache = AccountPubkeyCache::new();
142 let all_accounts = vec![Pubkey::new_unique(), Pubkey::new_unique(), Pubkey::new_unique()];
143 let instruction_accounts = vec![0u8, 2];
144
145 let result = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
146 assert_eq!(result.len(), 2);
147 assert_eq!(result[0], all_accounts[0]);
148 assert_eq!(result[1], all_accounts[2]);
149 }
150
151 #[test]
152 fn test_account_pubkey_cache_reuse() {
153 let mut cache = AccountPubkeyCache::new();
154 let all_accounts = vec![Pubkey::new_unique(); 10];
155
156 let instruction_accounts = vec![0u8, 1, 2];
158 let result1 = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
159 assert_eq!(result1.len(), 3);
160
161 let instruction_accounts = vec![5u8, 6];
163 let result2 = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
164 assert_eq!(result2.len(), 2);
165 assert_eq!(result2[0], all_accounts[5]);
166 assert_eq!(result2[1], all_accounts[6]);
167 }
168
169 #[test]
170 fn test_account_pubkey_cache_out_of_bounds() {
171 let mut cache = AccountPubkeyCache::new();
172 let all_accounts = vec![Pubkey::new_unique(); 3];
173 let instruction_accounts = vec![0u8, 1, 10]; let result = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
176 assert_eq!(result.len(), 2); }
178
179 #[test]
180 fn test_thread_local_cache() {
181 let all_accounts = vec![Pubkey::new_unique(); 5];
182 let instruction_accounts = vec![0u8, 1, 2];
183
184 let result = build_account_pubkeys_with_cache(&instruction_accounts, &all_accounts);
185 assert_eq!(result.len(), 3);
186 assert_eq!(result[0], all_accounts[0]);
187 assert_eq!(result[1], all_accounts[1]);
188 assert_eq!(result[2], all_accounts[2]);
189 }
190
191 #[test]
192 fn test_thread_local_cache_multiple_calls() {
193 let all_accounts = vec![Pubkey::new_unique(); 10];
194
195 let result1 = build_account_pubkeys_with_cache(&[0u8, 1], &all_accounts);
197 assert_eq!(result1.len(), 2);
198
199 let result2 = build_account_pubkeys_with_cache(&[5u8, 6, 7], &all_accounts);
201 assert_eq!(result2.len(), 3);
202 }
203}