fix: WSOL ATA creation in background with retry/timeout; silence unused and deprecated warnings

- lib: WSOL ATA creation moved to background to avoid blocking startup; ensure_wsol_ata adds 3 retries and 10s timeout
- lib: cfg(feature = "perf-trace") for DEFAULT_SLIPPAGE usage
- gas_fee_strategy, bloxroute, transaction_builder, async_executor, executor: prefix unused vars/params with underscore or allow
- pumpswap: add allow(deprecated) for get_program_accounts_with_config

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Wood
2026-02-12 23:38:59 +08:00
co-authored by Cursor
parent 710a8d482f
commit feaac5ddd2
7 changed files with 90 additions and 27 deletions
+4 -4
View File
@@ -300,7 +300,7 @@ impl GasFeeStrategy {
pub fn update_buy_tip(&self, buy_tip: f64) { pub fn update_buy_tip(&self, buy_tip: f64) {
self.strategies.rcu(|current_map| { self.strategies.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
for ((swqos_type, trade_type, strategy_type), value) in new_map.iter_mut() { for ((_swqos_type, trade_type, _strategy_type), value) in new_map.iter_mut() {
if *trade_type == TradeType::Buy { if *trade_type == TradeType::Buy {
value.tip = buy_tip; value.tip = buy_tip;
} }
@@ -314,7 +314,7 @@ impl GasFeeStrategy {
pub fn update_sell_tip(&self, sell_tip: f64) { pub fn update_sell_tip(&self, sell_tip: f64) {
self.strategies.rcu(|current_map| { self.strategies.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
for ((swqos_type, trade_type, strategy_type), value) in new_map.iter_mut() { for ((_swqos_type, trade_type, _strategy_type), value) in new_map.iter_mut() {
if *trade_type == TradeType::Sell { if *trade_type == TradeType::Sell {
value.tip = sell_tip; value.tip = sell_tip;
} }
@@ -328,7 +328,7 @@ impl GasFeeStrategy {
pub fn update_buy_cu_price(&self, buy_cu_price: u64) { pub fn update_buy_cu_price(&self, buy_cu_price: u64) {
self.strategies.rcu(|current_map| { self.strategies.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
for ((swqos_type, trade_type, strategy_type), value) in new_map.iter_mut() { for ((_swqos_type, trade_type, _strategy_type), value) in new_map.iter_mut() {
if *trade_type == TradeType::Buy { if *trade_type == TradeType::Buy {
value.cu_price = buy_cu_price; value.cu_price = buy_cu_price;
} }
@@ -342,7 +342,7 @@ impl GasFeeStrategy {
pub fn update_sell_cu_price(&self, sell_cu_price: u64) { pub fn update_sell_cu_price(&self, sell_cu_price: u64) {
self.strategies.rcu(|current_map| { self.strategies.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
for ((swqos_type, trade_type, strategy_type), value) in new_map.iter_mut() { for ((_swqos_type, trade_type, _strategy_type), value) in new_map.iter_mut() {
if *trade_type == TradeType::Sell { if *trade_type == TradeType::Sell {
value.cu_price = sell_cu_price; value.cu_price = sell_cu_price;
} }
+2
View File
@@ -227,6 +227,7 @@ pub async fn find_by_base_mint(
sort_results: None, sort_results: None,
}; };
let program_id = accounts::AMM_PROGRAM; let program_id = accounts::AMM_PROGRAM;
#[allow(deprecated)]
let accounts = rpc.get_program_accounts_with_config(&program_id, config).await?; let accounts = rpc.get_program_accounts_with_config(&program_id, config).await?;
if accounts.is_empty() { if accounts.is_empty() {
return Err(anyhow!("No pool found for mint {}", base_mint)); return Err(anyhow!("No pool found for mint {}", base_mint));
@@ -277,6 +278,7 @@ pub async fn find_by_quote_mint(
sort_results: None, sort_results: None,
}; };
let program_id = accounts::AMM_PROGRAM; let program_id = accounts::AMM_PROGRAM;
#[allow(deprecated)]
let accounts = rpc.get_program_accounts_with_config(&program_id, config).await?; let accounts = rpc.get_program_accounts_with_config(&program_id, config).await?;
if accounts.is_empty() { if accounts.is_empty() {
return Err(anyhow!("No pool found for mint {}", quote_mint)); return Err(anyhow!("No pool found for mint {}", quote_mint));
+79 -19
View File
@@ -8,6 +8,7 @@ pub mod utils;
use crate::common::nonce_cache::DurableNonceInfo; use crate::common::nonce_cache::DurableNonceInfo;
use crate::common::GasFeeStrategy; use crate::common::GasFeeStrategy;
use crate::common::{TradeConfig, InfrastructureConfig}; use crate::common::{TradeConfig, InfrastructureConfig};
#[cfg(feature = "perf-trace")]
use crate::constants::trade::trade::DEFAULT_SLIPPAGE; use crate::constants::trade::trade::DEFAULT_SLIPPAGE;
use crate::constants::SOL_TOKEN_ACCOUNT; use crate::constants::SOL_TOKEN_ACCOUNT;
use crate::constants::USD1_TOKEN_ACCOUNT; use crate::constants::USD1_TOKEN_ACCOUNT;
@@ -286,7 +287,13 @@ impl TradingClient {
crate::common::fast_fn::fast_init(&payer.pubkey()); crate::common::fast_fn::fast_init(&payer.pubkey());
if create_wsol_ata { if create_wsol_ata {
Self::ensure_wsol_ata(&payer, &infrastructure.rpc).await; // 在后台异步创建 WSOL ATA,不阻塞启动
let payer_clone = payer.clone();
let rpc_clone = infrastructure.rpc.clone();
tokio::spawn(async move {
Self::ensure_wsol_ata(&payer_clone, &rpc_clone).await;
});
println!("ℹ️ WSOL ATA 创建已在后台启动,不阻塞机器人启动");
} }
Self { Self {
@@ -309,6 +316,7 @@ impl TradingClient {
match rpc.get_account(&wsol_ata).await { match rpc.get_account(&wsol_ata).await {
Ok(_) => { Ok(_) => {
println!("✅ WSOL ATA已存在: {}", wsol_ata); println!("✅ WSOL ATA已存在: {}", wsol_ata);
return;
} }
Err(_) => { Err(_) => {
println!("🔨 创建WSOL ATA: {}", wsol_ata); println!("🔨 创建WSOL ATA: {}", wsol_ata);
@@ -317,35 +325,87 @@ impl TradingClient {
if !create_ata_ixs.is_empty() { if !create_ata_ixs.is_empty() {
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
let recent_blockhash = rpc.get_latest_blockhash().await.unwrap();
let tx = Transaction::new_signed_with_payer(
&create_ata_ixs,
Some(&payer.pubkey()),
&[payer.as_ref()],
recent_blockhash,
);
match rpc.send_and_confirm_transaction(&tx).await { // 重试逻辑:最多尝试3次,每次超时10秒
Ok(signature) => { const MAX_RETRIES: usize = 3;
println!("✅ WSOL ATA创建成功: {}", signature); const TIMEOUT_SECS: u64 = 10;
let mut last_error = None;
for attempt in 1..=MAX_RETRIES {
if attempt > 1 {
println!("🔄 重试创建WSOL ATA (第{}/{}次)...", attempt, MAX_RETRIES);
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
} }
Err(e) => {
match rpc.get_account(&wsol_ata).await { let recent_blockhash = match rpc.get_latest_blockhash().await {
Ok(_) => { Ok(hash) => hash,
Err(e) => {
eprintln!("⚠️ 获取最新blockhash失败: {}", e);
last_error = Some(format!("获取blockhash失败: {}", e));
continue;
}
};
let tx = Transaction::new_signed_with_payer(
&create_ata_ixs,
Some(&payer.pubkey()),
&[payer.as_ref()],
recent_blockhash,
);
// 使用超时包装 send_and_confirm_transaction
let send_result = tokio::time::timeout(
tokio::time::Duration::from_secs(TIMEOUT_SECS),
rpc.send_and_confirm_transaction(&tx)
).await;
match send_result {
Ok(Ok(signature)) => {
println!("✅ WSOL ATA创建成功: {}", signature);
return;
}
Ok(Err(e)) => {
last_error = Some(format!("{}", e));
// 检查账户是否实际已存在
if let Ok(_) = rpc.get_account(&wsol_ata).await {
println!( println!(
"✅ WSOL ATA已存在(交易失败但账户存在): {}", "✅ WSOL ATA已存在(交易失败但账户存在): {}",
wsol_ata wsol_ata
); );
return;
} }
Err(_) => {
panic!( if attempt < MAX_RETRIES {
"❌ WSOL ATA创建失败且账户不存在: {}. 错误: {}", eprintln!("⚠️ 第{}次尝试失败: {}", attempt, e);
wsol_ata, e
);
} }
} }
Err(_) => {
last_error = Some(format!("交易确认超时({}秒)", TIMEOUT_SECS));
eprintln!("⚠️ 第{}次尝试超时", attempt);
}
} }
} }
// 所有重试都失败了
if let Some(err) = last_error {
eprintln!("❌ WSOL ATA创建失败(已重试{}次): {}", MAX_RETRIES, wsol_ata);
eprintln!(" 错误详情: {}", err);
eprintln!(" 💡 可能原因:");
eprintln!(" 1. 钱包SOL余额不足(需要约0.002 SOL用于租金豁免)");
eprintln!(" 2. RPC节点响应超时或网络拥堵");
eprintln!(" 3. 交易费用不足");
eprintln!(" 🔧 解决方案:");
eprintln!(" 1. 给钱包充值至少0.1 SOL");
eprintln!(" 2. 等待几秒后重试");
eprintln!(" 3. 检查RPC节点连接");
eprintln!(" ⚠️ 程序将在5秒后退出,请解决上述问题后重启");
std::thread::sleep(std::time::Duration::from_secs(5));
panic!(
"❌ WSOL ATA创建失败且账户不存在: {}. 错误: {}",
wsol_ata, err
);
}
} else { } else {
println!("ℹ️ WSOL ATA已存在(无需创建)"); println!("ℹ️ WSOL ATA已存在(无需创建)");
} }
+1 -1
View File
@@ -111,7 +111,7 @@ impl BloxrouteClient {
Ok(()) Ok(())
} }
pub async fn send_transactions(&self, trade_type: TradeType, transactions: &Vec<VersionedTransaction>, wait_confirmation: bool) -> Result<()> { pub async fn send_transactions(&self, trade_type: TradeType, transactions: &Vec<VersionedTransaction>, _wait_confirmation: bool) -> Result<()> {
let start_time = Instant::now(); let start_time = Instant::now();
let body = serde_json::json!({ let body = serde_json::json!({
+1 -2
View File
@@ -11,14 +11,13 @@ use super::{
}; };
use crate::{ use crate::{
common::{nonce_cache::DurableNonceInfo, SolanaRpcClient}, common::{nonce_cache::DurableNonceInfo, SolanaRpcClient},
constants::swqos::NODE1_TIP_ACCOUNTS,
trading::{MiddlewareManager, core::transaction_pool::{acquire_builder, release_builder}}, trading::{MiddlewareManager, core::transaction_pool::{acquire_builder, release_builder}},
}; };
/// Build standard RPC transaction /// Build standard RPC transaction
pub async fn build_transaction( pub async fn build_transaction(
payer: Arc<Keypair>, payer: Arc<Keypair>,
rpc: Option<Arc<SolanaRpcClient>>, _rpc: Option<Arc<SolanaRpcClient>>,
unit_limit: u32, unit_limit: u32,
unit_price: u64, unit_price: u64,
business_instructions: Vec<Instruction>, business_instructions: Vec<Instruction>,
+2
View File
@@ -38,6 +38,7 @@ struct TaskResult {
success: bool, success: bool,
signature: Signature, signature: Signature,
error: Option<anyhow::Error>, error: Option<anyhow::Error>,
#[allow(dead_code)]
swqos_type: SwqosType, // 🔧 增加:记录SWQOS类型 swqos_type: SwqosType, // 🔧 增加:记录SWQOS类型
landed_on_chain: bool, // 🔧 Whether tx landed on-chain (even if failed) landed_on_chain: bool, // 🔧 Whether tx landed on-chain (even if failed)
} }
@@ -349,6 +350,7 @@ pub async fn execute_parallel(
let _send_start = Instant::now(); let _send_start = Instant::now();
let mut err: Option<anyhow::Error> = None; let mut err: Option<anyhow::Error> = None;
#[allow(unused_assignments)]
let mut landed_on_chain = false; let mut landed_on_chain = false;
let success = match swqos_client let success = match swqos_client
.send_transaction( .send_transaction(
+1 -1
View File
@@ -11,7 +11,7 @@ use crate::{
perf::syscall_bypass::SystemCallBypassManager, perf::syscall_bypass::SystemCallBypassManager,
trading::core::{ trading::core::{
async_executor::execute_parallel, async_executor::execute_parallel,
execution::{ExecutionPath, InstructionProcessor, Prefetch}, execution::{InstructionProcessor, Prefetch},
traits::TradeExecutor, traits::TradeExecutor,
}, },
trading::MiddlewareManager, trading::MiddlewareManager,