style: run rustfmt

This commit is contained in:
hookenful
2026-03-14 18:16:55 +02:00
parent 0ec826fcbd
commit 2abcf3839e
76 changed files with 1763 additions and 1352 deletions
+1 -1
View File
@@ -1,8 +1,8 @@
use dashmap::DashMap;
use once_cell::sync::Lazy;
use smallvec::SmallVec;
use solana_sdk::instruction::Instruction;
use solana_compute_budget_interface::ComputeBudgetInstruction;
use solana_sdk::instruction::Instruction;
use std::sync::Arc;
/// Cache key containing all parameters for compute budget instructions
+3 -3
View File
@@ -1,12 +1,12 @@
pub mod compute_budget_manager;
pub mod nonce_manager;
pub mod transaction_builder;
pub mod compute_budget_manager;
pub mod utils;
pub mod wsol_manager;
// Re-export commonly used functions
pub use compute_budget_manager::*;
pub use nonce_manager::*;
pub use transaction_builder::*;
pub use compute_budget_manager::*;
pub use utils::*;
pub use wsol_manager::*;
pub use wsol_manager::*;
+3 -2
View File
@@ -15,10 +15,11 @@ pub fn add_nonce_instruction(
durable_nonce: Option<&DurableNonceInfo>,
) -> Result<(), anyhow::Error> {
if let Some(durable_nonce) = durable_nonce {
let nonce_advance_ix = advance_nonce_account(&durable_nonce.nonce_account.unwrap(), &payer.pubkey());
let nonce_advance_ix =
advance_nonce_account(&durable_nonce.nonce_account.unwrap(), &payer.pubkey());
instructions.push(nonce_advance_ix);
}
Ok(())
}
+4 -1
View File
@@ -9,7 +9,10 @@ use std::sync::Arc;
use super::nonce_manager::{add_nonce_instruction, get_transaction_blockhash};
use crate::{
common::{nonce_cache::DurableNonceInfo, SolanaRpcClient},
trading::{MiddlewareManager, core::transaction_pool::{acquire_builder, release_builder}},
trading::{
core::transaction_pool::{acquire_builder, release_builder},
MiddlewareManager,
},
};
/// Convert SOL amount (f64) to lamports without string allocation (hot path).
+1 -8
View File
@@ -40,14 +40,7 @@ pub async fn get_token_balance(
payer: &Pubkey,
mint: &Pubkey,
) -> Result<u64, anyhow::Error> {
get_token_balance_with_options(
rpc,
payer,
mint,
&crate::constants::TOKEN_PROGRAM,
false,
)
.await
get_token_balance_with_options(rpc, payer, mint, &crate::constants::TOKEN_PROGRAM, false).await
}
/// 使用与交易指令一致的 ATA 推导(可选 seed)查询余额;卖出/余额查询应与买入使用同一 ATA 地址。
+11 -21
View File
@@ -1,7 +1,10 @@
use crate::common::{
fast_fn::create_associated_token_account_idempotent_fast,
seed::{
create_associated_token_account_use_seed,
get_associated_token_address_with_program_id_use_seed,
},
spl_token::close_account,
seed::{create_associated_token_account_use_seed, get_associated_token_address_with_program_id_use_seed},
};
use smallvec::SmallVec;
use solana_sdk::{instruction::Instruction, message::AccountMeta, pubkey::Pubkey};
@@ -38,7 +41,7 @@ pub fn handle_wsol(payer: &Pubkey, amount_in: u64) -> SmallVec<[Instruction; 3]>
pub fn close_wsol(payer: &Pubkey) -> Vec<Instruction> {
use std::sync::Arc;
let wsol_token_account =
crate::common::fast_fn::get_associated_token_address_with_program_id_fast(
&payer,
@@ -61,7 +64,7 @@ pub fn close_wsol(payer: &Pubkey) -> Vec<Instruction> {
.unwrap()]
},
);
// 🚀 性能优化:尝试零开销解包 Arc
Arc::try_unwrap(arc_instructions).unwrap_or_else(|arc| (*arc).clone())
}
@@ -109,10 +112,7 @@ pub fn wrap_sol_only(payer: &Pubkey, amount_in: u64) -> SmallVec<[Instruction; 2
///
/// 注意:此函数只生成指令,不检查账户是否存在(需要调用方在发送交易前检查)
/// 如果临时账户已存在,可以安全地跳过创建步骤,直接转账并关闭
pub fn wrap_wsol_to_sol(
payer: &Pubkey,
amount: u64,
) -> Result<Vec<Instruction>, anyhow::Error> {
pub fn wrap_wsol_to_sol(payer: &Pubkey, amount: u64) -> Result<Vec<Instruction>, anyhow::Error> {
let mut instructions = Vec::new();
// 1. 创建 WSOL seed 账户(注意:如果账户已存在会失败)
@@ -151,13 +151,8 @@ pub fn wrap_wsol_to_sol(
instructions.push(transfer_instruction);
// 5. 添加关闭 WSOL seed 账户的指令
let close_instruction = close_account(
&crate::constants::TOKEN_PROGRAM,
&seed_ata_address,
payer,
payer,
&[],
)?;
let close_instruction =
close_account(&crate::constants::TOKEN_PROGRAM, &seed_ata_address, payer, payer, &[])?;
instructions.push(close_instruction);
Ok(instructions)
@@ -197,13 +192,8 @@ pub fn wrap_wsol_to_sol_without_create(
instructions.push(transfer_instruction);
// 4. 添加关闭 WSOL seed 账户的指令
let close_instruction = close_account(
&crate::constants::TOKEN_PROGRAM,
&seed_ata_address,
payer,
payer,
&[],
)?;
let close_instruction =
close_account(&crate::constants::TOKEN_PROGRAM, &seed_ata_address, payer, payer, &[])?;
instructions.push(close_instruction);
Ok(instructions)
+20 -19
View File
@@ -106,11 +106,7 @@ async fn run_one_swqos_job(job: SwqosJob) {
let (success, err, landed_on_chain) = match job
.swqos_client
.send_transaction(
if s.is_buy {
TradeType::Buy
} else {
TradeType::Sell
},
if s.is_buy { TradeType::Buy } else { TradeType::Sell },
&transaction,
s.wait_transaction_confirmed,
)
@@ -196,7 +192,7 @@ fn is_landed_error(error: &anyhow::Error) -> bool {
struct ResultCollector {
results: Arc<ArrayQueue<TaskResult>>,
success_flag: Arc<AtomicBool>,
landed_failed_flag: Arc<AtomicBool>, // 🔧 Tx landed on-chain but failed (nonce consumed)
landed_failed_flag: Arc<AtomicBool>, // 🔧 Tx landed on-chain but failed (nonce consumed)
completed_count: Arc<AtomicUsize>,
total_tasks: usize,
}
@@ -229,7 +225,9 @@ impl ResultCollector {
self.completed_count.fetch_add(1, Ordering::Release);
}
async fn wait_for_success(&self) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>, Vec<(SwqosType, i64)>)> {
async fn wait_for_success(
&self,
) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>, Vec<(SwqosType, i64)>)> {
let start = Instant::now();
let timeout = std::time::Duration::from_secs(5);
let poll_interval = std::time::Duration::from_millis(1000);
@@ -271,7 +269,7 @@ impl ResultCollector {
}
let completed = self.completed_count.load(Ordering::Acquire);
if completed >= self.total_tasks {
if completed >= self.total_tasks {
let mut signatures = Vec::new();
let mut last_error = None;
let mut any_success = false;
@@ -299,7 +297,9 @@ impl ResultCollector {
}
}
fn get_first(&self) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>, Vec<(SwqosType, i64)>)> {
fn get_first(
&self,
) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>, Vec<(SwqosType, i64)>)> {
let mut signatures = Vec::new();
let mut has_success = false;
let mut last_error = None;
@@ -325,7 +325,10 @@ impl ResultCollector {
/// 等待全部任务完成(不等待链上确认),然后收集并返回所有签名。用于「多路提交」时返回多笔签名。
/// 轮询间隔 2ms,避免 50ms 间隔在最后一笔返回时多等几十 ms 拉高 submit 耗时。
async fn wait_for_all_submitted(&self, timeout_secs: u64) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>, Vec<(SwqosType, i64)>)> {
async fn wait_for_all_submitted(
&self,
timeout_secs: u64,
) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>, Vec<(SwqosType, i64)>)> {
let start = Instant::now();
let timeout = std::time::Duration::from_secs(timeout_secs);
let poll_interval = std::time::Duration::from_millis(2);
@@ -390,11 +393,7 @@ pub async fn execute_parallel(
TradeType::Sell
});
let check_tip = with_tip && !matches!(swqos_type, SwqosType::Default) && check_min_tip;
let min_tip = if check_tip {
swqos_client.min_tip_sol()
} else {
0.0
};
let min_tip = if check_tip { swqos_client.min_tip_sol() } else { 0.0 };
gas_fee_strategy_configs
.into_iter()
.filter(move |config| config.0 == swqos_type)
@@ -489,10 +488,12 @@ pub async fn execute_parallel(
if !wait_transaction_confirmed {
const SUBMIT_TIMEOUT_SECS: u64 = 30;
let ret = collector
.wait_for_all_submitted(SUBMIT_TIMEOUT_SECS)
.await
.unwrap_or((false, vec![], Some(anyhow!("No SWQOS result within {}s", SUBMIT_TIMEOUT_SECS)), vec![]));
let ret = collector.wait_for_all_submitted(SUBMIT_TIMEOUT_SECS).await.unwrap_or((
false,
vec![],
Some(anyhow!("No SWQOS result within {}s", SUBMIT_TIMEOUT_SECS)),
vec![],
));
let (success, signatures, last_error, submit_timings) = ret;
return Ok((success, signatures, last_error, submit_timings));
}
+3 -10
View File
@@ -2,16 +2,9 @@
//! 执行模块:指令预处理、缓存预取、分支提示。
use anyhow::Result;
use solana_sdk::{
instruction::Instruction,
pubkey::Pubkey,
signature::Keypair,
};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signature::Keypair};
use crate::perf::{
hardware_optimizations::BranchOptimizer,
simd::SIMDMemory,
};
use crate::perf::{hardware_optimizations::BranchOptimizer, simd::SIMDMemory};
/// Solana account key size in bytes (Pubkey). 每个账户(Pubkey)的字节数。
pub const BYTES_PER_ACCOUNT: usize = 32;
@@ -150,4 +143,4 @@ impl ExecutionPath {
slow_path()
}
}
}
}
+66 -29
View File
@@ -4,10 +4,15 @@ use solana_sdk::{
instruction::Instruction, message::AddressLookupTableAccount, pubkey::Pubkey,
signature::Keypair, signature::Signature,
};
use std::{sync::Arc, time::{Duration, Instant}};
use std::{
sync::Arc,
time::{Duration, Instant},
};
#[allow(unused_imports)]
use tracing::{info, trace, warn};
use super::{params::SwapParams, traits::InstructionBuilder};
use crate::swqos::TradeType;
use crate::{
common::{nonce_cache::DurableNonceInfo, GasFeeStrategy, SolanaRpcClient},
perf::syscall_bypass::SystemCallBypassManager,
@@ -20,8 +25,6 @@ use crate::{
trading::MiddlewareManager,
};
use once_cell::sync::Lazy;
use crate::swqos::TradeType;
use super::{params::SwapParams, traits::InstructionBuilder};
/// Global syscall bypass manager (reserved for future time/IO optimizations).
/// 全局系统调用绕过管理器(预留,后续可接入时间/IO 等优化)。
@@ -49,7 +52,10 @@ impl GenericTradeExecutor {
#[async_trait::async_trait]
impl TradeExecutor for GenericTradeExecutor {
async fn swap(&self, params: SwapParams) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)> {
async fn swap(
&self,
params: SwapParams,
) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)> {
// Sample total start only when logging or simulate. 仅在有日志或 simulate 时取起点。
let total_start = (params.log_enabled || params.simulate).then(Instant::now);
let timing_start_us: Option<i64> = if params.log_enabled {
@@ -58,7 +64,8 @@ impl TradeExecutor for GenericTradeExecutor {
None
};
let is_buy = params.trade_type == TradeType::Buy || params.trade_type == TradeType::CreateAndBuy;
let is_buy =
params.trade_type == TradeType::Buy || params.trade_type == TradeType::CreateAndBuy;
Prefetch::keypair(&params.payer);
@@ -85,7 +92,8 @@ impl TradeExecutor for GenericTradeExecutor {
let build_end_us = (params.log_enabled && crate::common::sdk_log::sdk_log_enabled())
.then(crate::common::clock::now_micros);
let _before_submit_elapsed = total_start.as_ref().map(|s| s.elapsed()).unwrap_or(Duration::ZERO);
let _before_submit_elapsed =
total_start.as_ref().map(|s| s.elapsed()).unwrap_or(Duration::ZERO);
let before_submit_us = (params.log_enabled && crate::common::sdk_log::sdk_log_enabled())
.then(crate::common::clock::now_micros);
@@ -111,12 +119,24 @@ impl TradeExecutor for GenericTradeExecutor {
if crate::common::sdk_log::sdk_log_enabled() {
let dir = if is_buy { "Buy" } else { "Sell" };
if let (Some(start_us), Some(end_us)) = (timing_start_us, build_end_us) {
println!(" [SDK] {} build_instructions: {:.4} ms", dir, (end_us - start_us) as f64 / 1000.0);
println!(
" [SDK] {} build_instructions: {:.4} ms",
dir,
(end_us - start_us) as f64 / 1000.0
);
}
if let (Some(start_us), Some(end_us)) = (timing_start_us, before_submit_us) {
println!(" [SDK] {} before_submit: {:.4} ms", dir, (end_us - start_us) as f64 / 1000.0);
println!(
" [SDK] {} before_submit: {:.4} ms",
dir,
(end_us - start_us) as f64 / 1000.0
);
}
println!(" [SDK] {} simulate (dry-run): {:.4} ms", dir, send_elapsed.as_secs_f64() * 1000.0);
println!(
" [SDK] {} simulate (dry-run): {:.4} ms",
dir,
send_elapsed.as_secs_f64() * 1000.0
);
println!(" [SDK] {} total: {:.4} ms", dir, total_elapsed.as_secs_f64() * 1000.0);
}
@@ -146,12 +166,9 @@ impl TradeExecutor for GenericTradeExecutor {
let log_enabled = params.log_enabled && crate::common::sdk_log::sdk_log_enabled();
let (ok, signatures, err, submit_timings) = match result {
Ok((success, sigs, last_error, timings)) => (
success,
sigs,
last_error.map(|e| anyhow::anyhow!("{}", e)),
timings,
),
Ok((success, sigs, last_error, timings)) => {
(success, sigs, last_error.map(|e| anyhow::anyhow!("{}", e)), timings)
}
Err(e) => (false, vec![], Some(anyhow::anyhow!("{}", e)), vec![]),
};
let submit_timings_ref: &[(crate::swqos::SwqosType, i64)] = submit_timings.as_slice();
@@ -167,16 +184,26 @@ impl TradeExecutor for GenericTradeExecutor {
let dir = if is_buy { "Buy" } else { "Sell" };
if let Some(start_us) = timing_start_us {
if let Some(end_us) = build_end_us {
println!(" [SDK] {} build_instructions: {:.4} ms", dir, (end_us - start_us) as f64 / 1000.0);
println!(
" [SDK] {} build_instructions: {:.4} ms",
dir,
(end_us - start_us) as f64 / 1000.0
);
}
if let Some(end_us) = before_submit_us {
println!(" [SDK] {} before_submit: {:.4} ms", dir, (end_us - start_us) as f64 / 1000.0);
println!(
" [SDK] {} before_submit: {:.4} ms",
dir,
(end_us - start_us) as f64 / 1000.0
);
}
if let Some(confirm_us) = confirm_done_us {
let total_ms = (confirm_us - start_us) as f64 / 1000.0;
for (swqos_type, submit_done_us) in submit_timings_ref {
let submit_ms = (*submit_done_us - start_us).max(0) as f64 / 1000.0;
let confirmed_ms = (confirm_us - *submit_done_us).max(0) as f64 / 1000.0;
let submit_ms =
(*submit_done_us - start_us).max(0) as f64 / 1000.0;
let confirmed_ms =
(confirm_us - *submit_done_us).max(0) as f64 / 1000.0;
println!(" [SDK] {} {:?} submit: {:.4} ms, confirmed: {:.4} ms, total: {:.4} ms", dir, swqos_type, submit_ms, confirmed_ms, total_ms);
}
}
@@ -196,14 +223,25 @@ impl TradeExecutor for GenericTradeExecutor {
let dir = if is_buy { "Buy" } else { "Sell" };
if let Some(start_us) = timing_start_us {
if let Some(end_us) = build_end_us {
println!(" [SDK] {} build_instructions: {:.4} ms", dir, (end_us - start_us) as f64 / 1000.0);
println!(
" [SDK] {} build_instructions: {:.4} ms",
dir,
(end_us - start_us) as f64 / 1000.0
);
}
if let Some(end_us) = before_submit_us {
println!(" [SDK] {} before_submit: {:.4} ms", dir, (end_us - start_us) as f64 / 1000.0);
println!(
" [SDK] {} before_submit: {:.4} ms",
dir,
(end_us - start_us) as f64 / 1000.0
);
}
for (swqos_type, submit_done_us) in submit_timings_ref {
let submit_ms = (*submit_done_us - start_us).max(0) as f64 / 1000.0;
println!(" [SDK] {} {:?} submit: {:.4} ms, confirmed: -, total: {:.4} ms", dir, swqos_type, submit_ms, submit_ms);
println!(
" [SDK] {} {:?} submit: {:.4} ms, confirmed: -, total: {:.4} ms",
dir, swqos_type, submit_ms, submit_ms
);
}
}
}
@@ -278,14 +316,14 @@ async fn simulate_transaction(
.simulate_transaction_with_config(
&transaction,
RpcSimulateTransactionConfig {
sig_verify: false, // Don't verify signature during simulation for speed
sig_verify: false, // Don't verify signature during simulation for speed
replace_recent_blockhash: false, // Use actual blockhash from transaction
commitment: Some(CommitmentConfig {
commitment: CommitmentLevel::Processed, // Use Processed level to get latest state
}),
encoding: Some(UiTransactionEncoding::Base64), // Base64 encoding
accounts: None, // Don't return specific account states (can be specified if needed)
min_context_slot: None, // Don't specify minimum context slot
accounts: None, // Don't return specific account states (can be specified if needed)
min_context_slot: None, // Don't specify minimum context slot
inner_instructions: true, // Enable inner instructions for debugging and detailed execution flow
},
)
@@ -353,10 +391,9 @@ mod tests {
}
println!("\n--- 3. 不等待链上确认时:每行 total = 该通道 submit 耗时(独立)---\n");
for (swqos_type, submit_ms, total_ms) in [
(SwqosType::Jito, 44.20, 44.20),
(SwqosType::Helius, 51.80, 51.80),
] {
for (swqos_type, submit_ms, total_ms) in
[(SwqosType::Jito, 44.20, 44.20), (SwqosType::Helius, 51.80, 51.80)]
{
println!(
" [SDK] {} {:?} submit: {:.4} ms, confirmed: -, total: {:.4} ms",
dir, swqos_type, submit_ms, total_ms
+3 -3
View File
@@ -1,6 +1,6 @@
pub mod async_executor;
pub mod execution;
pub mod executor;
pub mod params;
pub mod traits;
pub mod executor;
pub mod async_executor;
pub mod transaction_pool;
pub mod execution;
+4 -1
View File
@@ -9,7 +9,10 @@ pub trait TradeExecutor: Send + Sync {
/// - bool: 是否至少有一个交易成功
/// - Vec<Signature>: 所有提交的交易签名(按SWQOS顺序)
/// - Option<anyhow::Error>: 最后一个错误(如果全部失败)
async fn swap(&self, params: SwapParams) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)>;
async fn swap(
&self,
params: SwapParams,
) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)>;
/// 获取协议名称
fn protocol_name(&self) -> &'static str;
}
+9 -13
View File
@@ -18,7 +18,10 @@ const TX_BUILDER_POOL_PREFILL: usize = 100;
use crossbeam_queue::ArrayQueue;
use once_cell::sync::Lazy;
use solana_sdk::{
hash::Hash, instruction::Instruction, message::{v0, AddressLookupTableAccount, Message, VersionedMessage}, pubkey::Pubkey
hash::Hash,
instruction::Instruction,
message::{v0, AddressLookupTableAccount, Message, VersionedMessage},
pubkey::Pubkey,
};
use std::sync::Arc;
/// 预分配的交易构建器
@@ -91,11 +94,8 @@ impl PreallocatedTxBuilder {
VersionedMessage::V0(message)
} else {
// ✅ 没有查找表,使用 Legacy 消息(兼容所有 RPC
let message = Message::new_with_blockhash(
&self.instructions,
Some(payer),
&recent_blockhash,
);
let message =
Message::new_with_blockhash(&self.instructions, Some(payer), &recent_blockhash);
VersionedMessage::Legacy(message)
}
}
@@ -115,9 +115,7 @@ static TX_BUILDER_POOL: Lazy<Arc<ArrayQueue<PreallocatedTxBuilder>>> = Lazy::new
/// 🚀 从池中获取构建器
#[inline(always)]
pub fn acquire_builder() -> PreallocatedTxBuilder {
TX_BUILDER_POOL
.pop()
.unwrap_or_else(|| PreallocatedTxBuilder::new())
TX_BUILDER_POOL.pop().unwrap_or_else(|| PreallocatedTxBuilder::new())
}
/// 🚀 归还构建器到池
@@ -139,9 +137,7 @@ pub struct TxBuilderGuard {
impl TxBuilderGuard {
pub fn new() -> Self {
Self {
builder: Some(acquire_builder()),
}
Self { builder: Some(acquire_builder()) }
}
pub fn get_mut(&mut self) -> &mut PreallocatedTxBuilder {
@@ -155,4 +151,4 @@ impl Drop for TxBuilderGuard {
release_builder(builder);
}
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
pub mod traits;
pub mod builtin;
pub mod traits;
pub use traits::{InstructionMiddleware, MiddlewareManager};
+2 -5
View File
@@ -76,11 +76,8 @@ impl MiddlewareManager {
is_buy: bool,
) -> Result<Vec<Instruction>> {
for middleware in &self.middlewares {
full_instructions = middleware.process_full_instructions(
full_instructions,
protocol_name,
is_buy,
)?;
full_instructions =
middleware.process_full_instructions(full_instructions, protocol_name, is_buy)?;
if full_instructions.is_empty() {
break;
}