use solana_sdk::pubkey::Pubkey;
use std::cell::RefCell;
#[derive(Debug)]
pub struct AccountPubkeyCache {
cache: Vec<Pubkey>,
}
impl AccountPubkeyCache {
pub fn new() -> Self {
Self { cache: Vec::with_capacity(32) }
}
#[inline]
pub fn build_account_pubkeys(
&mut self,
instruction_accounts: &[u8],
all_accounts: &[Pubkey],
) -> &[Pubkey] {
self.cache.clear();
if self.cache.capacity() < instruction_accounts.len() {
self.cache.reserve(instruction_accounts.len() - self.cache.capacity());
}
for &idx in instruction_accounts.iter() {
if (idx as usize) < all_accounts.len() {
self.cache.push(all_accounts[idx as usize]);
}
}
&self.cache
}
}
impl Default for AccountPubkeyCache {
fn default() -> Self {
Self::new()
}
}
thread_local! {
static THREAD_LOCAL_ACCOUNT_CACHE: RefCell<AccountPubkeyCache> =
RefCell::new(AccountPubkeyCache::new());
}
#[inline]
pub fn build_account_pubkeys_with_cache(
instruction_accounts: &[u8],
all_accounts: &[Pubkey],
) -> Vec<Pubkey> {
THREAD_LOCAL_ACCOUNT_CACHE.with(|cache| {
let mut cache = cache.borrow_mut();
cache.build_account_pubkeys(instruction_accounts, all_accounts).to_vec()
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_account_pubkey_cache_basic() {
let mut cache = AccountPubkeyCache::new();
let all_accounts = vec![Pubkey::new_unique(), Pubkey::new_unique(), Pubkey::new_unique()];
let instruction_accounts = vec![0u8, 2];
let result = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
assert_eq!(result.len(), 2);
assert_eq!(result[0], all_accounts[0]);
assert_eq!(result[1], all_accounts[2]);
}
#[test]
fn test_account_pubkey_cache_reuse() {
let mut cache = AccountPubkeyCache::new();
let all_accounts = vec![Pubkey::new_unique(); 10];
let instruction_accounts = vec![0u8, 1, 2];
let result1 = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
assert_eq!(result1.len(), 3);
let instruction_accounts = vec![5u8, 6];
let result2 = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
assert_eq!(result2.len(), 2);
assert_eq!(result2[0], all_accounts[5]);
assert_eq!(result2[1], all_accounts[6]);
}
#[test]
fn test_account_pubkey_cache_out_of_bounds() {
let mut cache = AccountPubkeyCache::new();
let all_accounts = vec![Pubkey::new_unique(); 3];
let instruction_accounts = vec![0u8, 1, 10];
let result = cache.build_account_pubkeys(&instruction_accounts, &all_accounts);
assert_eq!(result.len(), 2); }
#[test]
fn test_thread_local_cache() {
let all_accounts = vec![Pubkey::new_unique(); 5];
let instruction_accounts = vec![0u8, 1, 2];
let result = build_account_pubkeys_with_cache(&instruction_accounts, &all_accounts);
assert_eq!(result.len(), 3);
assert_eq!(result[0], all_accounts[0]);
assert_eq!(result[1], all_accounts[1]);
assert_eq!(result[2], all_accounts[2]);
}
#[test]
fn test_thread_local_cache_multiple_calls() {
let all_accounts = vec![Pubkey::new_unique(); 10];
let result1 = build_account_pubkeys_with_cache(&[0u8, 1], &all_accounts);
assert_eq!(result1.len(), 2);
let result2 = build_account_pubkeys_with_cache(&[5u8, 6, 7], &all_accounts);
assert_eq!(result2.len(), 3);
}
}