feat: optimize cache systems and add examples
This commit is contained in:
+55
-65
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user