refactor: Replace global address lookup table cache with direct fetch approach
Replace the global AddressLookupTableCache with a direct fetch function to simplify address lookup table management. This change improves code maintainability by removing global state and makes the API more explicit. Key changes: - Remove AddressLookupTableCache and AddressLookupManager - Add new fetch_address_lookup_table_account function - Update TradeBuyParams and TradeSellParams to use AddressLookupTableAccount instead of Pubkey - Update all examples to use the new direct fetch approach - Update documentation to reflect the simplified workflow
This commit is contained in:
Executable
+70
@@ -0,0 +1,70 @@
|
||||
use crate::common::SolanaRpcClient;
|
||||
use anyhow::Result;
|
||||
use solana_address_lookup_table_interface::state::AddressLookupTable;
|
||||
use solana_sdk::{
|
||||
message::{v0, AddressLookupTableAccount},
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
pub async fn fetch_address_lookup_table_account(
|
||||
rpc: &SolanaRpcClient,
|
||||
lookup_table_address: &Pubkey,
|
||||
) -> Result<AddressLookupTableAccount, anyhow::Error> {
|
||||
let account = rpc.get_account(lookup_table_address).await?;
|
||||
let lookup_table = AddressLookupTable::deserialize(&account.data)?;
|
||||
let address_lookup_table_account = AddressLookupTableAccount {
|
||||
key: *lookup_table_address,
|
||||
addresses: lookup_table.addresses.to_vec(),
|
||||
};
|
||||
Ok(address_lookup_table_account)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extract_lookup_table_indexes(
|
||||
instructions: &[solana_sdk::instruction::Instruction],
|
||||
lookup_table_account: &AddressLookupTableAccount,
|
||||
) -> Option<v0::MessageAddressTableLookup> {
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
// 构建地址到索引的映射(O(1) 查找)
|
||||
let addr_to_index: HashMap<&Pubkey, u8> = lookup_table_account
|
||||
.addresses
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, addr)| u8::try_from(idx).ok().map(|i| (addr, i)))
|
||||
.collect();
|
||||
|
||||
// 收集所有需要的账户及其权限
|
||||
let mut writable_indexes = Vec::new();
|
||||
let mut readonly_indexes = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
for instruction in instructions {
|
||||
for account_meta in &instruction.accounts {
|
||||
// 跳过已处理的账户
|
||||
if !seen.insert(&account_meta.pubkey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在查找表中查找账户
|
||||
if let Some(&index) = addr_to_index.get(&account_meta.pubkey) {
|
||||
if account_meta.is_writable {
|
||||
writable_indexes.push(index);
|
||||
} else {
|
||||
readonly_indexes.push(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到任何账户,返回 None
|
||||
if writable_indexes.is_empty() && readonly_indexes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(v0::MessageAddressTableLookup {
|
||||
account_key: lookup_table_account.key,
|
||||
writable_indexes,
|
||||
readonly_indexes,
|
||||
})
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
use dashmap::DashMap;
|
||||
use solana_address_lookup_table_interface::state::AddressLookupTable;
|
||||
use solana_sdk::{message::AddressLookupTableAccount, pubkey::Pubkey};
|
||||
use std::{
|
||||
error::Error,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
use crate::common::SolanaRpcClient;
|
||||
|
||||
/// AddressLookupTableInfo struct, stores address lookup table related information
|
||||
#[derive(Clone)]
|
||||
pub struct AddressLookupTableInfo {
|
||||
/// Address lookup table account address
|
||||
pub lookup_table_address: Option<Pubkey>,
|
||||
/// Address lookup table content
|
||||
pub address_lookup_table: Option<AddressLookupTableAccount>,
|
||||
}
|
||||
|
||||
/// AddressLookupTableCache singleton for storing and managing address lookup tables
|
||||
pub struct AddressLookupTableCache {
|
||||
/// Lock-free hash map supporting high concurrent access
|
||||
tables: DashMap<Pubkey, AddressLookupTableInfo>,
|
||||
}
|
||||
|
||||
// Use static OnceLock to ensure thread safety of singleton pattern
|
||||
static ADDRESS_LOOKUP_TABLE_CACHE: OnceLock<Arc<AddressLookupTableCache>> = OnceLock::new();
|
||||
|
||||
impl AddressLookupTableCache {
|
||||
/// Get AddressLookupTableCache singleton instance
|
||||
pub fn get_instance() -> Arc<AddressLookupTableCache> {
|
||||
ADDRESS_LOOKUP_TABLE_CACHE
|
||||
.get_or_init(|| Arc::new(AddressLookupTableCache { tables: DashMap::new() }))
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// Get lookup table information
|
||||
pub async fn set_address_lookup_table(
|
||||
&self,
|
||||
client: Arc<SolanaRpcClient>,
|
||||
lookup_table_address: &Pubkey,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let account = client.get_account(lookup_table_address).await?;
|
||||
let lookup_table = AddressLookupTable::deserialize(&account.data)?;
|
||||
let address_lookup_table_account = AddressLookupTableAccount {
|
||||
key: *lookup_table_address,
|
||||
addresses: lookup_table.addresses.to_vec(),
|
||||
};
|
||||
self.add_or_update_table(lookup_table_address.clone(), Some(address_lookup_table_account));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add or update address lookup table information - lock-free implementation
|
||||
fn add_or_update_table(
|
||||
&self,
|
||||
lookup_table_address: Pubkey,
|
||||
address_lookup_table: Option<AddressLookupTableAccount>,
|
||||
) {
|
||||
if let Some(mut entry) = self.tables.get_mut(&lookup_table_address) {
|
||||
// Update existing table
|
||||
if let Some(table) = address_lookup_table {
|
||||
entry.address_lookup_table = Some(table);
|
||||
}
|
||||
} else {
|
||||
// Add new table
|
||||
self.tables.insert(
|
||||
lookup_table_address,
|
||||
AddressLookupTableInfo {
|
||||
lookup_table_address: Some(lookup_table_address),
|
||||
address_lookup_table,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get table content - high-performance lock-free implementation
|
||||
fn get_table_content(&self, lookup_table_address: &Pubkey) -> AddressLookupTableAccount {
|
||||
let result = self
|
||||
.tables
|
||||
.get(lookup_table_address)
|
||||
.and_then(|entry| entry.address_lookup_table.clone())
|
||||
.unwrap_or_else(|| AddressLookupTableAccount {
|
||||
key: *lookup_table_address,
|
||||
addresses: Vec::new(),
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get address lookup table account
|
||||
pub async fn get_address_lookup_table_account(
|
||||
lookup_table_address: &Pubkey,
|
||||
) -> AddressLookupTableAccount {
|
||||
let cache = AddressLookupTableCache::get_instance();
|
||||
cache.get_table_content(lookup_table_address)
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,3 @@
|
||||
pub mod address_lookup_cache;
|
||||
pub mod bonding_curve;
|
||||
pub mod fast_fn;
|
||||
pub mod fast_timing;
|
||||
@@ -11,6 +10,7 @@ pub mod spl_token;
|
||||
pub mod spl_token_2022;
|
||||
pub mod subscription_handle;
|
||||
pub mod types;
|
||||
pub mod address_lookup;
|
||||
|
||||
pub use gas_fee_strategy::*;
|
||||
pub use types::*;
|
||||
|
||||
Reference in New Issue
Block a user