Release v3.5.0: performance, constants, bilingual docs
- Bump version to 3.5.0 - Performance: hot-path timing only when log_enabled/simulate; execute_parallel takes &[Arc<SwqosClient>]; shared HTTP client constants for SWQoS - Code quality: validate_protocol_params extracted for buy/sell; BYTES_PER_ACCOUNT, MAX_INSTRUCTIONS_WARN, HTTP timeout constants; prefetch/syscall bypass comments - Documentation: bilingual (EN + 中文) doc comments in execution, executor, perf, swqos; README/README_CN version and What's new in 3.5.0 - Add release_notes_v3.5.0.md Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+18
-10
@@ -92,7 +92,9 @@ impl BlockRazorClient {
|
||||
let handle = tokio::spawn(async move {
|
||||
// Immediate first ping to warm connection and reduce first-submit cold start latency
|
||||
if let Err(e) = Self::send_ping_request(&http_client, &endpoint, &auth_token).await {
|
||||
eprintln!("BlockRazor ping request failed: {}", e);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!("BlockRazor ping request failed: {}", e);
|
||||
}
|
||||
}
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(30)); // 30s keepalive to avoid server ~5min idle close
|
||||
loop {
|
||||
@@ -101,7 +103,9 @@ impl BlockRazorClient {
|
||||
break;
|
||||
}
|
||||
if let Err(e) = Self::send_ping_request(&http_client, &endpoint, &auth_token).await {
|
||||
eprintln!("BlockRazor ping request failed: {}", e);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!("BlockRazor ping request failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -173,12 +177,14 @@ impl BlockRazorClient {
|
||||
|
||||
// Parse JSON response
|
||||
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
|
||||
if response_json.get("result").is_some() || response_json.get("signature").is_some() {
|
||||
println!(" [blockrazor] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [blockrazor] {} submission failed: {:?}", trade_type, _error);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
if response_json.get("result").is_some() || response_json.get("signature").is_some() {
|
||||
println!(" [blockrazor] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [blockrazor] {} submission failed: {:?}", trade_type, _error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [blockrazor] {} submission failed: {:?}", trade_type, response_text);
|
||||
}
|
||||
|
||||
@@ -186,12 +192,14 @@ impl BlockRazorClient {
|
||||
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [blockrazor] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [blockrazor] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
if wait_confirmation {
|
||||
if wait_confirmation && crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [blockrazor] {} confirmed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
|
||||
+22
-23
@@ -1,3 +1,4 @@
|
||||
use crate::swqos::common::default_http_client_builder;
|
||||
use crate::swqos::common::poll_transaction_confirmation;
|
||||
use crate::swqos::common::serialize_transaction_and_encode;
|
||||
use crate::swqos::serialization;
|
||||
@@ -47,17 +48,9 @@ impl SwqosClientTrait for BloxrouteClient {
|
||||
impl BloxrouteClient {
|
||||
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
|
||||
let rpc_client = SolanaRpcClient::new(rpc_url);
|
||||
let http_client = Client::builder()
|
||||
// Optimized connection pool settings for high performance
|
||||
let http_client = default_http_client_builder()
|
||||
.pool_idle_timeout(Duration::from_secs(120))
|
||||
.pool_max_idle_per_host(256) // Increased from 64 to 256
|
||||
.tcp_keepalive(Some(Duration::from_secs(60))) // Reduced from 1200 to 60
|
||||
.tcp_nodelay(true) // Disable Nagle's algorithm for lower latency
|
||||
.http2_keep_alive_interval(Duration::from_secs(10))
|
||||
.http2_keep_alive_timeout(Duration::from_secs(5))
|
||||
.http2_adaptive_window(true) // Enable adaptive flow control
|
||||
.timeout(Duration::from_millis(3000)) // Reduced from 10s to 3s
|
||||
.connect_timeout(Duration::from_millis(2000)) // Reduced from 5s to 2s
|
||||
.pool_max_idle_per_host(256)
|
||||
.build()
|
||||
.unwrap();
|
||||
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
|
||||
@@ -85,12 +78,14 @@ impl BloxrouteClient {
|
||||
|
||||
// Parse with from_str to avoid extra wait from .json().await
|
||||
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" [bloxroute] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [bloxroute] {} submission failed: {:?}", trade_type, _error);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" [bloxroute] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [bloxroute] {} submission failed: {:?}", trade_type, _error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [bloxroute] {} submission failed: {:?}", trade_type, response_text);
|
||||
}
|
||||
|
||||
@@ -98,12 +93,14 @@ impl BloxrouteClient {
|
||||
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [bloxroute] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [bloxroute] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
if wait_confirmation {
|
||||
if wait_confirmation && crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [bloxroute] {} confirmed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
@@ -135,11 +132,13 @@ impl BloxrouteClient {
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" bloxroute {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" bloxroute {} submission failed: {:?}", trade_type, _error);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" bloxroute {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" bloxroute {} submission failed: {:?}", trade_type, _error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,36 @@ use std::str::FromStr;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::time::sleep;
|
||||
|
||||
/// Default pool idle timeout for SWQOS HTTP client (seconds). 连接池空闲超时(秒)。
|
||||
const HTTP_POOL_IDLE_TIMEOUT_SECS: u64 = 300;
|
||||
/// Max idle connections per host. 每主机最大空闲连接数。
|
||||
const HTTP_POOL_MAX_IDLE_PER_HOST: usize = 4;
|
||||
/// TCP keepalive interval (seconds). TCP 保活间隔(秒)。
|
||||
const HTTP_TCP_KEEPALIVE_SECS: u64 = 60;
|
||||
/// HTTP/2 keepalive interval (seconds). HTTP/2 保活间隔(秒)。
|
||||
const HTTP2_KEEPALIVE_INTERVAL_SECS: u64 = 10;
|
||||
/// HTTP/2 keepalive timeout (seconds). HTTP/2 保活超时(秒)。
|
||||
const HTTP2_KEEPALIVE_TIMEOUT_SECS: u64 = 5;
|
||||
/// Request timeout (milliseconds). 请求超时(毫秒)。
|
||||
const HTTP_TIMEOUT_MS: u64 = 3000;
|
||||
/// Connect timeout (milliseconds). 连接超时(毫秒)。
|
||||
const HTTP_CONNECT_TIMEOUT_MS: u64 = 2000;
|
||||
|
||||
/// Shared HTTP client builder for SWQOS clients; call `.build().unwrap()` or override pool first. SWQOS 共用 HTTP 客户端构建器。
|
||||
pub fn default_http_client_builder() -> reqwest::ClientBuilder {
|
||||
Client::builder()
|
||||
.pool_idle_timeout(Duration::from_secs(HTTP_POOL_IDLE_TIMEOUT_SECS))
|
||||
.pool_max_idle_per_host(HTTP_POOL_MAX_IDLE_PER_HOST)
|
||||
.tcp_keepalive(Some(Duration::from_secs(HTTP_TCP_KEEPALIVE_SECS)))
|
||||
.tcp_nodelay(true)
|
||||
.http2_keep_alive_interval(Duration::from_secs(HTTP2_KEEPALIVE_INTERVAL_SECS))
|
||||
.http2_keep_alive_timeout(Duration::from_secs(HTTP2_KEEPALIVE_TIMEOUT_SECS))
|
||||
.http2_adaptive_window(true)
|
||||
.timeout(Duration::from_millis(HTTP_TIMEOUT_MS))
|
||||
.connect_timeout(Duration::from_millis(HTTP_CONNECT_TIMEOUT_MS))
|
||||
}
|
||||
|
||||
/// Trade/on-chain error with code and optional instruction index. 交易/链上错误,含错误码与可选指令下标。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TradeError {
|
||||
pub code: u32,
|
||||
|
||||
+21
-25
@@ -1,4 +1,4 @@
|
||||
use crate::swqos::common::{poll_transaction_confirmation, serialize_transaction_and_encode};
|
||||
use crate::swqos::common::{default_http_client_builder, poll_transaction_confirmation, serialize_transaction_and_encode};
|
||||
use rand::seq::IndexedRandom;
|
||||
use reqwest::Client;
|
||||
use serde_json::json;
|
||||
@@ -50,19 +50,7 @@ impl SwqosClientTrait for Node1Client {
|
||||
impl Node1Client {
|
||||
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
|
||||
let rpc_client = SolanaRpcClient::new(rpc_url);
|
||||
let http_client = Client::builder()
|
||||
// Optimized connection pool settings for high performance
|
||||
.pool_idle_timeout(Duration::from_secs(300))
|
||||
.pool_max_idle_per_host(4)
|
||||
.tcp_keepalive(Some(Duration::from_secs(60))) // Reduced from 1200 to 60
|
||||
.tcp_nodelay(true) // Disable Nagle's algorithm for lower latency
|
||||
.http2_keep_alive_interval(Duration::from_secs(10))
|
||||
.http2_keep_alive_timeout(Duration::from_secs(5))
|
||||
.http2_adaptive_window(true) // Enable adaptive flow control
|
||||
.timeout(Duration::from_millis(3000)) // Reduced from 10s to 3s
|
||||
.connect_timeout(Duration::from_millis(2000)) // Reduced from 5s to 2s
|
||||
.build()
|
||||
.unwrap();
|
||||
let http_client = default_http_client_builder().build().unwrap();
|
||||
|
||||
let client = Self {
|
||||
rpc_client: Arc::new(rpc_client),
|
||||
@@ -92,7 +80,9 @@ impl Node1Client {
|
||||
let handle = tokio::spawn(async move {
|
||||
// Immediate first ping to warm connection and reduce first-submit cold start latency
|
||||
if let Err(e) = Self::send_ping_request(&http_client, &endpoint, &auth_token).await {
|
||||
eprintln!("Node1 ping request failed: {}", e);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!("Node1 ping request failed: {}", e);
|
||||
}
|
||||
}
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(30));
|
||||
loop {
|
||||
@@ -101,7 +91,9 @@ impl Node1Client {
|
||||
break;
|
||||
}
|
||||
if let Err(e) = Self::send_ping_request(&http_client, &endpoint, &auth_token).await {
|
||||
eprintln!("Node1 ping request failed: {}", e);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!("Node1 ping request failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -132,7 +124,7 @@ impl Node1Client {
|
||||
.await?;
|
||||
let status = response.status();
|
||||
let _ = response.bytes().await;
|
||||
if !status.is_success() {
|
||||
if !status.is_success() && crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!("Node1 ping request returned non-success status: {}", status);
|
||||
}
|
||||
Ok(())
|
||||
@@ -164,12 +156,14 @@ impl Node1Client {
|
||||
|
||||
// Parse JSON response
|
||||
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" [node1] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [node1] {} submission failed: {:?}", trade_type, _error);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" [node1] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [node1] {} submission failed: {:?}", trade_type, _error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [node1] {} submission failed: {:?}", trade_type, response_text);
|
||||
}
|
||||
|
||||
@@ -177,12 +171,14 @@ impl Node1Client {
|
||||
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [node1] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [node1] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
if wait_confirmation {
|
||||
if wait_confirmation && crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [node1] {} confirmed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
|
||||
@@ -105,7 +105,41 @@ impl Base64Encoder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Guard that returns the serialization buffer to the pool on drop.
|
||||
pub struct PooledTxBufGuard(pub Vec<u8>);
|
||||
|
||||
impl std::ops::Deref for PooledTxBufGuard {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PooledTxBufGuard {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_empty() {
|
||||
SERIALIZER.return_buffer(std::mem::take(&mut self.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize transaction to bincode bytes using buffer pool. The returned guard returns the buffer
|
||||
/// to the pool when dropped; use `&*guard` or `guard.as_ref()` for `&[u8]`.
|
||||
pub fn serialize_transaction_bincode_sync(
|
||||
transaction: &impl SerializableTransaction,
|
||||
) -> Result<(PooledTxBufGuard, Signature)> {
|
||||
let signature = transaction.get_signature();
|
||||
let serialized_tx = SERIALIZER.serialize_zero_alloc(transaction, "transaction")?;
|
||||
Ok((PooledTxBufGuard(serialized_tx), *signature))
|
||||
}
|
||||
|
||||
/// Return a buffer to the pool (for manual use when not using `PooledTxBufGuard`).
|
||||
pub fn return_serialization_buffer(buffer: Vec<u8>) {
|
||||
SERIALIZER.return_buffer(buffer);
|
||||
}
|
||||
|
||||
/// Sync serialize + encode using buffer pool; use in hot path to reduce allocs.
|
||||
/// Base64 path uses SIMD-accelerated encoding.
|
||||
pub fn serialize_transaction_sync(
|
||||
transaction: &impl SerializableTransaction,
|
||||
encoding: UiTransactionEncoding,
|
||||
@@ -114,7 +148,7 @@ pub fn serialize_transaction_sync(
|
||||
let serialized_tx = SERIALIZER.serialize_zero_alloc(transaction, "transaction")?;
|
||||
let serialized = match encoding {
|
||||
UiTransactionEncoding::Base58 => bs58::encode(&serialized_tx).into_string(),
|
||||
UiTransactionEncoding::Base64 => STANDARD.encode(&serialized_tx),
|
||||
UiTransactionEncoding::Base64 => SIMDSerializer::encode_base64_simd(&serialized_tx),
|
||||
_ => return Err(anyhow::anyhow!("Unsupported encoding")),
|
||||
};
|
||||
SERIALIZER.return_buffer(serialized_tx);
|
||||
@@ -133,10 +167,7 @@ pub async fn serialize_transaction(
|
||||
|
||||
let serialized = match encoding {
|
||||
UiTransactionEncoding::Base58 => bs58::encode(&serialized_tx).into_string(),
|
||||
UiTransactionEncoding::Base64 => {
|
||||
// Use SIMD-optimized Base64 encoding
|
||||
STANDARD.encode(&serialized_tx)
|
||||
}
|
||||
UiTransactionEncoding::Base64 => SIMDSerializer::encode_base64_simd(&serialized_tx),
|
||||
_ => return Err(anyhow::anyhow!("Unsupported encoding")),
|
||||
};
|
||||
|
||||
@@ -156,7 +187,7 @@ pub fn serialize_transactions_batch_sync(
|
||||
let serialized_tx = SERIALIZER.serialize_zero_alloc(tx, "transaction")?;
|
||||
let encoded = match encoding {
|
||||
UiTransactionEncoding::Base58 => bs58::encode(&serialized_tx).into_string(),
|
||||
UiTransactionEncoding::Base64 => STANDARD.encode(&serialized_tx),
|
||||
UiTransactionEncoding::Base64 => SIMDSerializer::encode_base64_simd(&serialized_tx),
|
||||
_ => return Err(anyhow::anyhow!("Unsupported encoding")),
|
||||
};
|
||||
SERIALIZER.return_buffer(serialized_tx);
|
||||
@@ -177,7 +208,7 @@ pub async fn serialize_transactions_batch(
|
||||
|
||||
let encoded = match encoding {
|
||||
UiTransactionEncoding::Base58 => bs58::encode(&serialized_tx).into_string(),
|
||||
UiTransactionEncoding::Base64 => STANDARD.encode(&serialized_tx),
|
||||
UiTransactionEncoding::Base64 => SIMDSerializer::encode_base64_simd(&serialized_tx),
|
||||
_ => return Err(anyhow::anyhow!("Unsupported encoding")),
|
||||
};
|
||||
|
||||
|
||||
+16
-11
@@ -6,7 +6,6 @@ use quinn::{
|
||||
TransportConfig,
|
||||
};
|
||||
use rand::seq::IndexedRandom as _;
|
||||
use solana_rpc_client::rpc_client::SerializableTransaction;
|
||||
use solana_sdk::{signature::Keypair, transaction::VersionedTransaction};
|
||||
use solana_tls_utils::{new_dummy_x509_certificate, SkipServerVerification};
|
||||
use std::time::Instant;
|
||||
@@ -19,6 +18,7 @@ use tokio::sync::Mutex;
|
||||
|
||||
use crate::common::SolanaRpcClient;
|
||||
use crate::swqos::common::poll_transaction_confirmation;
|
||||
use crate::swqos::serialization::serialize_transaction_bincode_sync;
|
||||
use crate::swqos::SwqosClientTrait;
|
||||
use crate::{
|
||||
constants::swqos::SPEEDLANDING_TIP_ACCOUNTS,
|
||||
@@ -105,27 +105,32 @@ impl SwqosClientTrait for SpeedlandingClient {
|
||||
wait_confirmation: bool,
|
||||
) -> Result<()> {
|
||||
let start_time = Instant::now();
|
||||
let signature = transaction.get_signature();
|
||||
let serialized_tx = bincode::serialize(transaction)?;
|
||||
let (buf_guard, signature) = serialize_transaction_bincode_sync(transaction)?;
|
||||
let connection = self.connection.load_full();
|
||||
if Self::try_send_bytes(&connection, &serialized_tx).await.is_err() {
|
||||
eprintln!(" [speedlanding] {} submission failed, reconnecting", trade_type);
|
||||
if Self::try_send_bytes(&connection, &*buf_guard).await.is_err() {
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [speedlanding] {} submission failed, reconnecting", trade_type);
|
||||
}
|
||||
self.reconnect().await?;
|
||||
let connection = self.connection.load_full();
|
||||
if let Err(e) = Self::try_send_bytes(&connection, &serialized_tx).await {
|
||||
eprintln!(" [speedlanding] {} submission failed: {:?}", trade_type, e);
|
||||
if let Err(e) = Self::try_send_bytes(&connection, &*buf_guard).await {
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [speedlanding] {} submission failed: {:?}", trade_type, e);
|
||||
}
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
match poll_transaction_confirmation(&self.rpc_client, *signature, wait_confirmation).await {
|
||||
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [speedlanding] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [speedlanding] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
if wait_confirmation {
|
||||
if wait_confirmation && crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [speedlanding] {} confirmed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
|
||||
+19
-25
@@ -1,4 +1,4 @@
|
||||
use crate::swqos::common::{poll_transaction_confirmation, serialize_transaction_and_encode};
|
||||
use crate::swqos::common::{default_http_client_builder, poll_transaction_confirmation, serialize_transaction_and_encode};
|
||||
use rand::seq::IndexedRandom;
|
||||
use reqwest::Client;
|
||||
use serde_json::json;
|
||||
@@ -48,19 +48,7 @@ impl SwqosClientTrait for StelliumClient {
|
||||
impl StelliumClient {
|
||||
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
|
||||
let rpc_client = SolanaRpcClient::new(rpc_url);
|
||||
let http_client = Client::builder()
|
||||
// Optimized connection pool settings for high performance
|
||||
.pool_idle_timeout(Duration::from_secs(300))
|
||||
.pool_max_idle_per_host(4)
|
||||
.tcp_keepalive(Some(Duration::from_secs(60))) // Reduced from 1200 to 60
|
||||
.tcp_nodelay(true) // Disable Nagle's algorithm for lower latency
|
||||
.http2_keep_alive_interval(Duration::from_secs(10))
|
||||
.http2_keep_alive_timeout(Duration::from_secs(5))
|
||||
.http2_adaptive_window(true) // Enable adaptive flow control
|
||||
.timeout(Duration::from_millis(3000)) // Reduced from 10s to 3s
|
||||
.connect_timeout(Duration::from_millis(2000)) // Reduced from 5s to 2s
|
||||
.build()
|
||||
.unwrap();
|
||||
let http_client = default_http_client_builder().build().unwrap();
|
||||
|
||||
let keep_alive_running = Arc::new(AtomicBool::new(true));
|
||||
|
||||
@@ -94,7 +82,7 @@ impl StelliumClient {
|
||||
if let Ok(resp) = http_client.get(&url).timeout(Duration::from_millis(1500)).send().await {
|
||||
let status = resp.status();
|
||||
let _ = resp.bytes().await;
|
||||
if !status.is_success() {
|
||||
if !status.is_success() && crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [Stellium] Ping failed with status: {}", status);
|
||||
}
|
||||
}
|
||||
@@ -109,12 +97,14 @@ impl StelliumClient {
|
||||
Ok(response) => {
|
||||
let status = response.status();
|
||||
let _ = response.bytes().await;
|
||||
if !status.is_success() {
|
||||
if !status.is_success() && crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [Stellium] Ping failed with status: {}", status);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(" [Stellium] Ping request error: {:?}", e);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [Stellium] Ping request error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,12 +142,14 @@ impl StelliumClient {
|
||||
|
||||
// Parse response
|
||||
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" [Stellium] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [Stellium] {} submission failed: {:?}", trade_type, _error);
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
if response_json.get("result").is_some() {
|
||||
println!(" [Stellium] {} submitted: {:?}", trade_type, start_time.elapsed());
|
||||
} else if let Some(_error) = response_json.get("error") {
|
||||
eprintln!(" [Stellium] {} submission failed: {:?}", trade_type, _error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if crate::common::sdk_log::sdk_log_enabled() {
|
||||
eprintln!(" [Stellium] {} submission failed: {:?}", trade_type, response_text);
|
||||
}
|
||||
|
||||
@@ -165,12 +157,14 @@ impl StelliumClient {
|
||||
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [Stellium] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
if crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [Stellium] {} confirmation failed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
if wait_confirmation {
|
||||
if wait_confirmation && crate::common::sdk_log::sdk_log_enabled() {
|
||||
println!(" signature: {:?}", signature);
|
||||
println!(" [Stellium] {} confirmed: {:?}", trade_type, start_time.elapsed());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user