use std::sync::{Arc, RwLock}; use crate::chain_data::*; use client::AccountFetcher; use mango_v4::accounts_zerocopy::LoadZeroCopy; use anyhow::Context; use solana_client::rpc_client::RpcClient; use solana_sdk::account::AccountSharedData; use solana_sdk::pubkey::Pubkey; pub struct ChainDataAccountFetcher { pub chain_data: Arc>, pub rpc: RpcClient, } impl ChainDataAccountFetcher { // loads from ChainData pub fn fetch( &self, address: &Pubkey, ) -> anyhow::Result { Ok(self .fetch_raw(address)? .load::() .with_context(|| format!("loading account {}", address))? .clone()) } // fetches via RPC, stores in ChainData, returns new version pub fn fetch_fresh( &self, address: &Pubkey, ) -> anyhow::Result { self.refresh_account_via_rpc(address)?; self.fetch(address) } pub fn fetch_raw(&self, address: &Pubkey) -> anyhow::Result { let chain_data = self.chain_data.read().unwrap(); Ok(chain_data .account(address) .with_context(|| format!("fetch account {} via chain_data", address))? .clone()) } pub fn refresh_account_via_rpc(&self, address: &Pubkey) -> anyhow::Result<()> { let response = self .rpc .get_account_with_commitment(&address, self.rpc.commitment()) .with_context(|| format!("refresh account {} via rpc", address))?; let account = response .value .ok_or(anchor_client::ClientError::AccountNotFound) .with_context(|| format!("refresh account {} via rpc", address))?; let mut chain_data = self.chain_data.write().unwrap(); chain_data.update_from_rpc( address, AccountData { slot: response.context.slot, account: account.into(), }, ); log::trace!( "refreshed data of account {} via rpc, got context slot {}", address, response.context.slot ); Ok(()) } } impl AccountFetcher for ChainDataAccountFetcher { fn fetch_raw_account(&self, address: Pubkey) -> anyhow::Result { self.fetch_raw(&address).map(|a| a.into()) } }