use crate::streaming::{
event_parser::{
common::{filter::EventTypeFilter, EventMetadata, EventType, ProtocolType},
core::dispatcher::EventDispatcher,
Protocol, DexEvent,
},
grpc::AccountPretty,
};
use solana_sdk::pubkey::Pubkey;
use std::{
collections::HashMap,
sync::{Arc, LazyLock},
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CacheKey {
pub protocols: Vec<Protocol>,
pub event_types: Option<Vec<EventType>>,
}
impl CacheKey {
pub fn new(mut protocols: Vec<Protocol>, filter: Option<&EventTypeFilter>) -> Self {
protocols.sort_by_cached_key(|p| format!("{:?}", p));
let event_types = filter.map(|f| {
let mut types = f.include.clone();
types.sort_by_cached_key(|t| format!("{:?}", t));
types
});
Self { protocols, event_types }
}
}
static GLOBAL_PROGRAM_IDS_CACHE: LazyLock<
std::sync::RwLock<HashMap<CacheKey, Arc<Vec<Pubkey>>>>,
> = LazyLock::new(|| std::sync::RwLock::new(HashMap::new()));
pub fn get_global_program_ids(
protocols: &[Protocol],
filter: Option<&EventTypeFilter>,
) -> Arc<Vec<Pubkey>> {
let cache_key = CacheKey::new(protocols.to_vec(), filter);
{
let cache = GLOBAL_PROGRAM_IDS_CACHE.read().unwrap();
if let Some(program_ids) = cache.get(&cache_key) {
return program_ids.clone();
}
}
let program_ids = Arc::new(EventDispatcher::get_program_ids(protocols));
GLOBAL_PROGRAM_IDS_CACHE.write().unwrap().insert(cache_key, program_ids.clone());
program_ids
}
#[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: std::cell::RefCell<AccountPubkeyCache> =
std::cell::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()
})
}
pub type AccountEventParserFn =
fn(account: &AccountPretty, metadata: EventMetadata) -> Option<DexEvent>;
#[derive(Debug, Clone)]
pub struct AccountEventParseConfig {
pub program_id: Pubkey,
pub protocol_type: ProtocolType,
pub event_type: EventType,
pub account_discriminator: &'static [u8],
pub account_parser: AccountEventParserFn,
}