feat: optimize cache systems and add examples

This commit is contained in:
ysq
2025-09-04 16:32:34 +08:00
parent 692b0ce715
commit 597982653d
12 changed files with 558 additions and 272 deletions
+59 -88
View File
@@ -1,9 +1,9 @@
use solana_program::{
address_lookup_table::{
instruction::{
create_lookup_table as create_lookup_table_instruction,
extend_lookup_table as extend_lookup_table_instruction,
freeze_lookup_table as freeze_lookup_table_instruction
create_lookup_table as create_lookup_table_instruction,
extend_lookup_table as extend_lookup_table_instruction,
freeze_lookup_table as freeze_lookup_table_instruction,
},
state::AddressLookupTable,
},
@@ -11,29 +11,26 @@ use solana_program::{
pubkey::Pubkey,
};
use solana_sdk::{
message::{v0::Message as MessageV0, AddressLookupTableAccount, VersionedMessage},
signature::{Keypair, Signer},
message::{v0::Message as MessageV0, AddressLookupTableAccount, VersionedMessage},
signature::{Keypair, Signer},
transaction::{Transaction, VersionedTransaction},
};
use std::{error::Error, sync::Arc};
use crate::{common::SolanaRpcClient, constants};
/// 创建地址查找表(如果不存在)
/// Create address lookup table (if it doesn't exist)
pub async fn create_lookup_table_if_not_exists(
client: Arc<SolanaRpcClient>,
authority: &Keypair,
payer: &Keypair,
) -> Result<Pubkey, Box<dyn std::error::Error>> {
// 1. 计算预期的查找表地址
// 1. Calculate the expected lookup table address
let recent_slot = client.get_slot().await?;
let (create_ix, lookup_table_address) = create_lookup_table_instruction(
authority.pubkey(),
payer.pubkey(),
recent_slot
);
let (create_ix, lookup_table_address) =
create_lookup_table_instruction(authority.pubkey(), payer.pubkey(), recent_slot);
// 2. 创建新表
// 2. Create new table
let blockhash = client.get_latest_blockhash().await?;
let transaction = Transaction::new_signed_with_payer(
&[create_ix],
@@ -47,7 +44,7 @@ pub async fn create_lookup_table_if_not_exists(
Ok(lookup_table_address)
}
/// 向查找表添加地址
/// Add addresses to lookup table
pub async fn extend_lookup_table(
client: Arc<SolanaRpcClient>,
payer: &Keypair,
@@ -75,17 +72,14 @@ pub async fn extend_lookup_table(
Ok(())
}
/// 冻结查找表,防止进一步修改
/// Freeze lookup table to prevent further modifications
pub async fn freeze_lookup_table(
client: Arc<SolanaRpcClient>,
payer: &Keypair,
authority: &Keypair,
lookup_table_address: &Pubkey,
) -> Result<(), Box<dyn Error>> {
let freeze_ix = freeze_lookup_table_instruction(
*lookup_table_address,
authority.pubkey(),
);
let freeze_ix = freeze_lookup_table_instruction(*lookup_table_address, authority.pubkey());
let blockhash = client.get_latest_blockhash().await?;
let transaction = Transaction::new_signed_with_payer(
@@ -100,7 +94,7 @@ pub async fn freeze_lookup_table(
Ok(())
}
/// 获取查找表信息
/// Get lookup table information
pub async fn get_address_lookup_table(
client: Arc<SolanaRpcClient>,
lookup_table_address: &Pubkey,
@@ -113,14 +107,10 @@ pub async fn get_address_lookup_table(
addresses: lookup_table.addresses.to_vec(),
};
for (i, addr) in address_lookup_table_account.addresses.iter().enumerate() {
println!("地址 {}: {}", i, addr);
}
Ok(address_lookup_table_account)
}
/// 使用查找表发送交易
/// Send transaction using lookup table
pub async fn send_transaction_with_lut(
client: Arc<SolanaRpcClient>,
instructions: Vec<Instruction>,
@@ -141,37 +131,32 @@ pub async fn send_transaction_with_lut(
let signature = client.send_and_confirm_transaction(&tx).await?;
println!("交易已确认: {}", signature);
println!("Transaction confirmed: {}", signature);
Ok(())
}
/// 使用查找表的特定地址子集发送交易
/// Send transaction using a specific subset of addresses from lookup table
pub async fn send_transaction_with_filtered_lut(
client: Arc<SolanaRpcClient>,
instructions: Vec<Instruction>,
payer: &Keypair,
signers: Vec<&Keypair>,
lookup_table: AddressLookupTableAccount,
address_indices_to_use: &[usize], // 要使用的地址索引列表
address_indices_to_use: &[usize], // List of address indices to use
) -> Result<(), Box<dyn Error>> {
// 创建只包含选定地址的新查找表账户
// Create a new lookup table account containing only selected addresses
let filtered_addresses: Vec<Pubkey> = address_indices_to_use
.iter()
.filter_map(|&index| lookup_table.addresses.get(index).copied())
.collect();
println!(
"从查找表中选择了 {} 个地址用于交易",
filtered_addresses.len()
);
println!("Selected {} addresses from lookup table for transaction", filtered_addresses.len());
for (i, addr) in filtered_addresses.iter().enumerate() {
println!("使用地址 {}: {}", i, addr);
println!("Using address {}: {}", i, addr);
}
let filtered_lookup_table = AddressLookupTableAccount {
key: lookup_table.key,
addresses: filtered_addresses,
};
let filtered_lookup_table =
AddressLookupTableAccount { key: lookup_table.key, addresses: filtered_addresses };
let blockhash = client.get_latest_blockhash().await?;
@@ -186,30 +171,30 @@ pub async fn send_transaction_with_filtered_lut(
let signature = client.send_and_confirm_transaction(&tx).await?;
println!("交易已确认: {}", signature);
println!("Transaction confirmed: {}", signature);
Ok(())
}
/// 获取最近的区块槽位,用于创建查找表
/// Get recent block slot for creating lookup table
pub async fn get_recent_slot(client: Arc<SolanaRpcClient>) -> Result<u64, Box<dyn Error>> {
let slot = client.get_slot().await?;
Ok(slot)
}
/// 使用指定的地址列表发送交易
/// Send transaction using specified address list
///
/// 这个方法接受一组目标地址,自动查找它们在查找表中的索引,
/// 然后使用这些地址创建一个过滤后的查找表来发送交易
/// This method accepts a set of target addresses, automatically finds their indices in the lookup table,
/// then uses these addresses to create a filtered lookup table for sending transactions
///
/// # 参数
/// * `instructions` - 交易指令
/// * `payer` - 支付交易费用的账户
/// * `signers` - 交易签名者
/// * `lookup_table` - 地址查找表
/// * `addresses_to_use` - 要使用的地址列表
/// # Arguments
/// * `instructions` - Transaction instructions
/// * `payer` - Account that pays transaction fees
/// * `signers` - Transaction signers
/// * `lookup_table` - Address lookup table
/// * `addresses_to_use` - List of addresses to use
///
/// # 返回值
/// 成功返回交易签名,失败返回错误
/// # Returns
/// Returns transaction signature on success, error on failure
pub async fn send_transaction_with_addresses(
client: Arc<SolanaRpcClient>,
instructions: Vec<Instruction>,
@@ -218,13 +203,13 @@ pub async fn send_transaction_with_addresses(
lookup_table: AddressLookupTableAccount,
addresses_to_use: &[Pubkey],
) -> Result<String, Box<dyn Error>> {
// 构建地址到索引的映射
// Build address to index mapping
let mut address_to_index = std::collections::HashMap::new();
for (i, addr) in lookup_table.addresses.iter().enumerate() {
address_to_index.insert(*addr, i);
}
// 查找所有存在的地址的索引
// Find indices of all existing addresses
let mut indices_to_use = Vec::new();
let mut found_addresses = Vec::new();
let mut missing_addresses = Vec::new();
@@ -238,40 +223,35 @@ pub async fn send_transaction_with_addresses(
}
}
// 检查是否有地址未找到
// Check if any addresses were not found
if !missing_addresses.is_empty() {
println!("警告: {} 个地址未在查找表中找到", missing_addresses.len());
println!("Warning: {} addresses not found in lookup table", missing_addresses.len());
for (i, addr) in missing_addresses.iter().enumerate() {
println!("未找到的地址 {}: {}", i, addr);
println!("Address not found {}: {}", i, addr);
}
}
// 如果没有找到任何地址,返回错误
// Return error if no addresses were found
if indices_to_use.is_empty() {
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::NotFound,
"没有在查找表中找到任何指定的地址",
"No specified addresses found in lookup table",
)));
}
// 创建只包含选定地址的新查找表账户
// Create a new lookup table account containing only selected addresses
let filtered_addresses: Vec<Pubkey> = indices_to_use
.iter()
.filter_map(|&index| lookup_table.addresses.get(index).copied())
.collect();
println!(
"从查找表中选择了 {} 个地址用于交易",
filtered_addresses.len()
);
println!("Selected {} addresses from lookup table for transaction", filtered_addresses.len());
for (i, addr) in filtered_addresses.iter().enumerate() {
println!("使用地址 {}: {}", i, addr);
println!("Using address {}: {}", i, addr);
}
let filtered_lookup_table = AddressLookupTableAccount {
key: lookup_table.key,
addresses: filtered_addresses,
};
let filtered_lookup_table =
AddressLookupTableAccount { key: lookup_table.key, addresses: filtered_addresses };
let blockhash = client.get_latest_blockhash().await?;
@@ -286,7 +266,7 @@ pub async fn send_transaction_with_addresses(
let signature = client.send_and_confirm_transaction(&tx).await?;
println!("交易已确认: {}", signature);
println!("Transaction confirmed: {}", signature);
Ok(signature.to_string())
}
@@ -310,7 +290,7 @@ pub async fn create_pumpfun_lookup_table(
client.send_and_confirm_transaction(&transaction).await?;
Ok(lookup_table_address)
}
}
pub async fn add_pumpfun_address_to_lookup_table(
client: Arc<SolanaRpcClient>,
@@ -319,13 +299,7 @@ pub async fn add_pumpfun_address_to_lookup_table(
lookup_table_address: &Pubkey,
) -> Result<(), Box<dyn Error>> {
let addresses = get_pumpfun_addresses(payer.pubkey(), vec![]);
extend_lookup_table(
client,
payer,
authority,
lookup_table_address,
addresses
).await?;
extend_lookup_table(client, payer, authority, lookup_table_address, addresses).await?;
Ok(())
}
@@ -337,13 +311,7 @@ pub async fn extend_pumpfun_address_to_lookup_table(
lookup_table_address: &Pubkey,
addresses: Vec<Pubkey>,
) -> Result<(), Box<dyn Error>> {
extend_lookup_table(
client,
payer,
authority,
lookup_table_address,
addresses
).await?;
extend_lookup_table(client, payer, authority, lookup_table_address, addresses).await?;
Ok(())
}
@@ -362,14 +330,17 @@ pub fn get_pumpfun_addresses(payer: Pubkey, include_addresses: Vec<Pubkey>) -> V
];
addresses.extend(include_addresses);
addresses
}
pub fn get_pumpfun_filtered_addresses(payer: Pubkey, include_addresses: Vec<Pubkey>) -> Vec<Pubkey> {
pub fn get_pumpfun_filtered_addresses(
payer: Pubkey,
include_addresses: Vec<Pubkey>,
) -> Vec<Pubkey> {
let mut addresses = vec![
payer,
constants::pumpfun::accounts::PUMPFUN,
constants::pumpfun::accounts::PUMPFUN,
constants::pumpfun::accounts::SYSTEM_PROGRAM,
constants::pumpfun::accounts::TOKEN_PROGRAM,
constants::pumpfun::accounts::RENT,
@@ -388,6 +359,6 @@ pub fn get_pumpfun_filtered_addresses(payer: Pubkey, include_addresses: Vec<Pubk
];
addresses.extend(include_addresses);
addresses
}
+49 -86
View File
@@ -1,154 +1,117 @@
use dashmap::DashMap;
use solana_sdk::{message::AddressLookupTableAccount, pubkey::Pubkey};
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock};
use std::sync::{Arc, OnceLock};
/// AddressLookupTableInfo 结构体,存储地址表相关信息
/// 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>,
/// 锁定状态
pub lock: bool,
}
/// AddressLookupTableCache 单例,用于存储和管理地址表
/// AddressLookupTableCache singleton for storing and managing address lookup tables
pub struct AddressLookupTableCache {
/// 内部存储的地址表数据,键为地址表地址
tables: Mutex<HashMap<Pubkey, AddressLookupTableInfo>>,
/// Lock-free hash map supporting high concurrent access
tables: DashMap<Pubkey, AddressLookupTableInfo>,
}
// 使用静态 OnceLock 确保单例模式的线程安全性
// Use static OnceLock to ensure thread safety of singleton pattern
static ADDRESS_LOOKUP_TABLE_CACHE: OnceLock<Arc<AddressLookupTableCache>> = OnceLock::new();
impl AddressLookupTableCache {
/// 获取 AddressLookupTableCache 单例实例
/// Get AddressLookupTableCache singleton instance
pub fn get_instance() -> Arc<AddressLookupTableCache> {
ADDRESS_LOOKUP_TABLE_CACHE
.get_or_init(|| {
Arc::new(AddressLookupTableCache {
tables: Mutex::new(HashMap::new()),
})
})
.get_or_init(|| Arc::new(AddressLookupTableCache { tables: DashMap::new() }))
.clone()
}
/// 添加或更新地址表信息
/// Add or update address lookup table information - lock-free implementation
pub fn add_or_update_table(
&self,
lookup_table_address: Pubkey,
address_lookup_table: Option<AddressLookupTableAccount>,
lock: Option<bool>,
) {
let mut tables = self.tables.lock().unwrap();
if let Some(table_info) = tables.get_mut(&lookup_table_address) {
// 更新已存在的表
if let Some(mut entry) = self.tables.get_mut(&lookup_table_address) {
// Update existing table
if let Some(table) = address_lookup_table {
table_info.address_lookup_table = Some(table);
}
if let Some(l) = lock {
table_info.lock = l;
entry.address_lookup_table = Some(table);
}
} else {
// 添加新表
tables.insert(
// Add new table
self.tables.insert(
lookup_table_address,
AddressLookupTableInfo {
lookup_table_address: Some(lookup_table_address),
address_lookup_table,
lock: lock.unwrap_or(false),
},
);
}
}
/// 移除地址表
/// Remove address lookup table - lock-free implementation
pub fn remove_table(&self, lookup_table_address: &Pubkey) -> bool {
let mut tables = self.tables.lock().unwrap();
tables.remove(lookup_table_address).is_some()
self.tables.remove(lookup_table_address).is_some()
}
/// 获取地址表信息
/// Get address lookup table information - lock-free implementation
pub fn get_table(&self, lookup_table_address: &Pubkey) -> Option<AddressLookupTableInfo> {
let tables = self.tables.lock().unwrap();
tables.get(lookup_table_address).map(|info| AddressLookupTableInfo {
lookup_table_address: info.lookup_table_address,
address_lookup_table: info.address_lookup_table.clone(),
lock: info.lock,
})
self.tables.get(lookup_table_address).map(|entry| entry.value().clone())
}
/// 获取所有表地址
/// Get all table addresses - lock-free implementation
pub fn get_all_table_addresses(&self) -> Vec<Pubkey> {
let tables = self.tables.lock().unwrap();
tables.keys().cloned().collect()
self.tables.iter().map(|entry| *entry.key()).collect()
}
/// 检查表是否存在
/// Check if table exists - lock-free implementation
pub fn table_exists(&self, lookup_table_address: &Pubkey) -> bool {
let tables = self.tables.lock().unwrap();
tables.contains_key(lookup_table_address)
self.tables.contains_key(lookup_table_address)
}
/// 锁定地址表
pub fn lock_table(&self, lookup_table_address: &Pubkey) -> bool {
let mut tables = self.tables.lock().unwrap();
if let Some(table_info) = tables.get_mut(lookup_table_address) {
table_info.lock = true;
true
} else {
false
}
}
/// 解锁地址表
pub fn unlock_table(&self, lookup_table_address: &Pubkey) -> bool {
let mut tables = self.tables.lock().unwrap();
if let Some(table_info) = tables.get_mut(lookup_table_address) {
table_info.lock = false;
true
} else {
false
}
}
/// 更新地址表内容
/// Update address lookup table content - lock-free implementation
pub fn update_table_content(
&self,
lookup_table_address: &Pubkey,
address_lookup_table: AddressLookupTableAccount,
) -> bool {
let mut tables = self.tables.lock().unwrap();
if let Some(table_info) = tables.get_mut(lookup_table_address) {
table_info.address_lookup_table = Some(address_lookup_table);
if let Some(mut entry) = self.tables.get_mut(lookup_table_address) {
entry.address_lookup_table = Some(address_lookup_table);
true
} else {
false
}
}
/// 获取表的内容
/// Get table content - high-performance lock-free implementation
pub fn get_table_content(&self, lookup_table_address: &Pubkey) -> AddressLookupTableAccount {
let tables = self.tables.lock().unwrap();
tables
let result = self
.tables
.get(lookup_table_address)
.and_then(|info| info.address_lookup_table.clone())
.and_then(|entry| entry.address_lookup_table.clone())
.unwrap_or_else(|| AddressLookupTableAccount {
key: *lookup_table_address,
addresses: Vec::new(),
})
});
if result.addresses.len() == 0 {
eprintln!(" ❌ Address lookup table account {} not setup", lookup_table_address);
eprintln!(" ❌ Please update the address table account information using 【AddressLookupTableCache】 first");
eprintln!(
" ❌ The current transaction will not include this address lookup table account"
);
}
return result;
}
}
/// 获取地址表账户
pub async fn get_address_lookup_table_account(lookup_table_address: &Pubkey) -> AddressLookupTableAccount {
/// Get address lookup table account
pub async fn get_address_lookup_table_account(
lookup_table_address: &Pubkey,
) -> AddressLookupTableAccount {
let cache = AddressLookupTableCache::get_instance();
return cache.get_table_content(&lookup_table_address);
}
}
+55 -65
View File
@@ -1,33 +1,36 @@
use solana_hash::Hash;
use solana_sdk::account_utils::StateMut;
use solana_sdk::nonce::state::Versions;
use solana_sdk::nonce::State;
use solana_sdk::pubkey::Pubkey;
use solana_streamer_sdk::common::SolanaRpcClient;
use std::str::FromStr;
use std::sync::{Arc, Mutex, OnceLock};
use solana_hash::Hash;
use tracing::error;
/// NonceInfo 结构体,存储 nonce 相关信息
/// NonceInfo structure to store nonce-related information
pub struct NonceInfo {
/// nonce 账户地址
/// Nonce account address
pub nonce_account: Option<Pubkey>,
/// 当前 nonce
/// Current nonce value
pub current_nonce: Hash,
/// 下次可用时间(Unix 时间戳,秒)
/// Next available time (Unix timestamp in seconds)
pub next_buy_time: i64,
/// 锁定状态
pub lock: bool,
/// 是否已使用
/// Whether it has been used
pub used: bool,
}
/// NonceInfoStore 单例,用于存储和管理 NonceInfo
/// NonceInfoStore singleton for storing and managing NonceInfo
pub struct NonceCache {
/// 内部存储的 NonceInfo 数据
/// Internally stored NonceInfo data
nonce_info: Mutex<NonceInfo>,
}
// 使用静态 OnceLock 确保单例模式的线程安全性
// Use static OnceLock to ensure thread safety of singleton pattern
static NONCE_CACHE: OnceLock<Arc<NonceCache>> = OnceLock::new();
impl NonceCache {
/// 获取 NonceInfoStore 单例实例
/// Get NonceInfoStore singleton instance
pub fn get_instance() -> Arc<NonceCache> {
NONCE_CACHE
.get_or_init(|| {
@@ -36,7 +39,6 @@ impl NonceCache {
nonce_account: None,
current_nonce: Hash::default(),
next_buy_time: 0,
lock: false,
used: false,
}),
})
@@ -44,95 +46,83 @@ impl NonceCache {
.clone()
}
/// 初始化 nonce 信息
/// Initialize nonce information
pub fn init(&self, nonce_account_str: Option<String>) {
let nonce_account = nonce_account_str
.and_then(|s| Pubkey::from_str(&s).ok());
self.update_nonce_info_partial(
nonce_account,
None,
None,
Some(false),
Some(false),
);
let nonce_account = nonce_account_str.and_then(|s| Pubkey::from_str(&s).ok());
self.update_nonce_info_partial(nonce_account, None, None, Some(false));
}
/// 获取 NonceInfo 的副本
pub fn get_nonce_info(&self) -> NonceInfo {
/// Get a copy of NonceInfo
pub fn get_nonce_info(&self) -> NonceInfo {
let nonce_info = self.nonce_info.lock().unwrap();
NonceInfo {
nonce_account: nonce_info.nonce_account,
current_nonce: nonce_info.current_nonce,
next_buy_time: nonce_info.next_buy_time,
lock: nonce_info.lock,
used: nonce_info.used,
}
}
/// 部分更新 NonceInfo,只更新传入的字段
/// Partially update NonceInfo, only update the passed fields
pub fn update_nonce_info_partial(
&self,
nonce_account: Option<Pubkey>,
current_nonce: Option<Hash>,
next_buy_time: Option<i64>,
lock: Option<bool>,
used: Option<bool>,
) {
let mut current = self.nonce_info.lock().unwrap();
// 只更新传入的字段
// Only update the passed fields
if let Some(account) = nonce_account {
current.nonce_account = Some(account);
}
if let Some(nonce) = current_nonce {
current.current_nonce = nonce;
}
if let Some(time) = next_buy_time {
current.next_buy_time = time;
}
if let Some(l) = lock {
current.lock = l;
}
if let Some(u) = used {
current.used = u;
}
}
/// 标记 nonce 已使用
/// Mark nonce as used
pub fn mark_used(&self) {
self.update_nonce_info_partial(
None,
None,
None,
None,
Some(true),
);
self.update_nonce_info_partial(None, None, None, Some(true));
}
/// 锁定 nonce
pub fn lock(&self) {
self.update_nonce_info_partial(
None,
None,
None,
Some(true),
None,
);
}
/// 解锁 nonce
pub fn unlock(&self) {
self.update_nonce_info_partial(
None,
None,
None,
Some(false),
None,
);
/// Fetch nonce information using RPC
pub async fn fetch_nonce_info_use_rpc(
&self,
rpc: &SolanaRpcClient,
) -> Result<(), anyhow::Error> {
match rpc.get_account(&self.get_nonce_info().nonce_account.unwrap()).await {
Ok(account) => match account.state() {
Ok(Versions::Current(state)) => {
if let State::Initialized(data) = *state {
let blockhash = data.durable_nonce.as_hash();
let old_nonce_info = self.get_nonce_info();
if old_nonce_info.current_nonce != *blockhash {
self.update_nonce_info_partial(
None,
Some(*blockhash),
None,
Some(false),
);
}
}
}
_ => (),
},
Err(e) => {
error!("Failed to get nonce account information: {:?}", e);
}
}
Ok(())
}
}
+4 -7
View File
@@ -1,7 +1,4 @@
use solana_sdk::{
message::AddressLookupTableAccount,
pubkey::Pubkey,
};
use solana_sdk::{message::AddressLookupTableAccount, pubkey::Pubkey};
use crate::common::address_lookup_cache::get_address_lookup_table_account;
@@ -11,11 +8,11 @@ pub async fn get_address_lookup_table_accounts(
lookup_table_key: Option<Pubkey>,
) -> Vec<AddressLookupTableAccount> {
let mut address_lookup_table_accounts = vec![];
if let Some(lookup_table_key) = lookup_table_key {
let account = get_address_lookup_table_account(&lookup_table_key).await;
address_lookup_table_accounts.push(account);
}
address_lookup_table_accounts
}
}
+9 -18
View File
@@ -5,11 +5,11 @@ use solana_system_interface::instruction::advance_nonce_account;
use crate::common::nonce_cache::NonceCache;
/// 添加nonce消费指令到指令集合中
/// Add nonce advance instruction to the instruction set
///
/// 只有提供了nonce_pubkey时才使用nonce功能
/// 如果nonce被锁定、已使用或未准备好,将返回错误
/// 成功时会锁定并标记nonce为已使用
/// Nonce functionality is only used when nonce_pubkey is provided
/// Returns error if nonce is locked, already used, or not ready
/// On success, locks and marks nonce as used
pub fn add_nonce_instruction(
instructions: &mut Vec<Instruction>,
payer: &Keypair,
@@ -17,25 +17,16 @@ pub fn add_nonce_instruction(
let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info();
// 只检查nonce_account是否存在
// Only check if nonce_account exists
if let Some(nonce_pubkey) = nonce_info.nonce_account {
// 暂不加锁
// if nonce_info.lock {
// return Err(anyhow!("Nonce is locked"));
// }
if nonce_info.used {
return Err(anyhow!("Nonce is used"));
}
if nonce_info.current_nonce == Hash::default() {
return Err(anyhow!("Nonce is not ready"));
}
// if nonce_info.next_buy_time == 0 || chrono::Utc::now().timestamp() < nonce_info.next_buy_time {
// return Err(anyhow!("Nonce is not ready"));
// }
// 加锁 - 暂不加锁
// nonce_cache.lock();
// 创建Solana系统nonce推进指令 - 使用系统程序ID
// Create Solana system nonce advance instruction - using system program ID
let nonce_advance_ix = advance_nonce_account(&nonce_pubkey, &payer.pubkey());
instructions.push(nonce_advance_ix);
@@ -44,8 +35,8 @@ pub fn add_nonce_instruction(
Ok(())
}
/// 获取用于交易的blockhash
/// 如果使用了nonce账户,返回nonce中的blockhash,否则返回传入的recent_blockhash
/// Get blockhash for transaction
/// If nonce account is used, return blockhash from nonce, otherwise return the provided recent_blockhash
pub fn get_transaction_blockhash(recent_blockhash: Hash) -> Hash {
let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info();
@@ -57,7 +48,7 @@ pub fn get_transaction_blockhash(recent_blockhash: Hash) -> Hash {
}
}
/// 检查是否使用nonce账户
/// Check if using nonce account
pub fn is_using_nonce() -> bool {
let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info();