Compare commits

...
3 Commits
Author SHA1 Message Date
Wood 3d062279d9 chore: release v3.5.4
- Bump version to 3.5.4; update README and README_CN
- Astralane: irisb binary API (no Base64), POST /irisb with query api-key&method; constants use /irisb endpoints; ping POST getHealth
- BlockRazor: Send Transaction v2 (plain Base64 body, Content-Type text/plain, auth in URI only); ping POST /v2/health; use default_http_client_builder
- SWQOS: all clients use default_http_client_builder (nextblock, temporal, zeroslot, astralane, lightspeed, jito, flashblock); remove unused Duration imports

Made-with: Cursor
2026-02-27 02:30:52 +08:00
Wood 15e07e9130 docs: remove version release notes from README_CN, fix crates.io version to 3.5.3
Made-with: Cursor
2026-02-27 00:42:43 +08:00
Wood 6eaafde4fd docs: remove version release notes from README
Made-with: Cursor
2026-02-27 00:42:17 +08:00
12 changed files with 93 additions and 271 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "sol-trade-sdk" name = "sol-trade-sdk"
version = "3.5.3" version = "3.5.4"
edition = "2021" edition = "2021"
authors = [ authors = [
"William <byteblock6@gmail.com>", "William <byteblock6@gmail.com>",
+2 -27
View File
@@ -60,31 +60,6 @@
--- ---
## 🆕 What's new in 3.5.3
- **Full release**: Includes all updates (3.5.2 SWQoS perf + IDL/instruction changes). Use this version.
- **SWQoS submit latency**: Sync serialize + buffer-pool hot path; `format!` body for single/batch submit (Bloxroute); avoid status clone in confirmation polling.
- **First-submit & 5-min idle**: Immediate first ping + 30s keepalive; `pool_max_idle_per_host=4` and `pool_idle_timeout=300s` (BlockRazor, Temporal, Node1, Astralane, Stellium); ping consumes response body for connection reuse.
- **PumpFun / PumpSwap**: IDL updates (pump.json, pump_amm.json); instruction and utils updates for pumpfun and pumpswap; fast_fn and release notes.
## 🆕 What's new in 3.5.2
- **SWQoS submit latency**: Sync serialize + buffer-pool hot path; `format!` body for single/batch submit (Bloxroute); avoid status clone in confirmation polling.
- **First-submit & 5-min idle**: Immediate first ping + 30s keepalive; `pool_max_idle_per_host=4` and `pool_idle_timeout=300s` (BlockRazor, Temporal, Node1, Astralane, Stellium) so submit reuses the same connection; ping consumes response body for connection reuse.
- **Docs**: All SWQoS comments translated to English.
## 🆕 What's new in 3.5.1
- **SWQoS / executor**: Updates to common SWQoS logic and trading executor.
## 🆕 What's new in 3.5.0
- **Performance**: Hot-path timing only when logging; reduced clones (`execute_parallel` takes `&[Arc<SwqosClient>]`); shared HTTP client constants for SWQoS.
- **Code quality**: Extracted `validate_protocol_params` for buy/sell; constants for instruction/account sizes and HTTP timeouts; prefetch and branch-hint comments.
- **Documentation**: Bilingual (English + 中文) doc comments across execution, executor, perf, and swqos modules.
---
## ✨ Features ## ✨ Features
1. **PumpFun Trading**: Support for `buy` and `sell` operations 1. **PumpFun Trading**: Support for `buy` and `sell` operations
@@ -114,14 +89,14 @@ Add the dependency to your `Cargo.toml`:
```toml ```toml
# Add to your Cargo.toml # Add to your Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.5.3" } sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.5.4" }
``` ```
### Use crates.io ### Use crates.io
```toml ```toml
# Add to your Cargo.toml # Add to your Cargo.toml
sol-trade-sdk = "3.5.3" sol-trade-sdk = "3.5.4"
``` ```
## 🛠️ Usage Examples ## 🛠️ Usage Examples
+2 -10
View File
@@ -60,14 +60,6 @@
--- ---
## 🆕 3.5.0 更新说明
- **性能**:仅在打日志时做热路径计时;减少 clone(`execute_parallel` 改为接收 `&[Arc<SwqosClient>]`);SWQoS 共用 HTTP 客户端常量。
- **代码质量**:抽取 buy/sell 共用的 `validate_protocol_params`;指令/账户大小与 HTTP 超时常量化;预取与分支提示注释完善。
- **文档**execution、executor、perf、swqos 等模块增加中英双语文档注释。
---
## ✨ 项目特性 ## ✨ 项目特性
1. **PumpFun 交易**: 支持`购买``卖出`功能 1. **PumpFun 交易**: 支持`购买``卖出`功能
@@ -97,14 +89,14 @@ git clone https://github.com/0xfnzero/sol-trade-sdk
```toml ```toml
# 添加到您的 Cargo.toml # 添加到您的 Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.5.3" } sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.5.4" }
``` ```
### 使用 crates.io ### 使用 crates.io
```toml ```toml
# 添加到您的 Cargo.toml # 添加到您的 Cargo.toml
sol-trade-sdk = "3.5.0" sol-trade-sdk = "3.5.4"
``` ```
## 🛠️ 使用示例 ## 🛠️ 使用示例
+20 -16
View File
@@ -227,26 +227,30 @@ pub const SWQOS_ENDPOINTS_FLASHBLOCK: [&str; 8] = [
"http://ny.flashblock.trade", "http://ny.flashblock.trade",
]; ];
/// BlockRazor Send Transaction v2: plain-text Base64 body, auth in URI, Content-Type: text/plain. Keep-alive: POST /v2/health.
pub const SWQOS_ENDPOINTS_BLOCKRAZOR: [&str; 8] = [ pub const SWQOS_ENDPOINTS_BLOCKRAZOR: [&str; 8] = [
"http://newyork.solana.blockrazor.xyz:443/sendTransaction", "http://newyork.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/sendTransaction", "http://frankfurt.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://amsterdam.solana.blockrazor.xyz:443/sendTransaction", "http://amsterdam.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/sendTransaction", "http://newyork.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://tokyo.solana.blockrazor.xyz:443/sendTransaction", "http://tokyo.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/sendTransaction", "http://london.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/sendTransaction", "http://newyork.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/sendTransaction", "http://frankfurt.solana.blockrazor.xyz:443/v2/sendTransaction",
]; ];
/// Astralane binary API path (no Base64; use with ?api-key=...&method=sendTransaction|getHealth).
pub const ASTRALANE_PATH_IRISB: &str = "irisb";
pub const SWQOS_ENDPOINTS_ASTRALANE: [&str; 8] = [ pub const SWQOS_ENDPOINTS_ASTRALANE: [&str; 8] = [
"http://ny.gateway.astralane.io/iris", "http://ny.gateway.astralane.io/irisb",
"http://fr.gateway.astralane.io/iris", "http://fr.gateway.astralane.io/irisb",
"http://ams.gateway.astralane.io/iris", "http://ams.gateway.astralane.io/irisb",
"http://ny.gateway.astralane.io/iris", "http://ny.gateway.astralane.io/irisb",
"http://jp.gateway.astralane.io/iris", "http://jp.gateway.astralane.io/irisb",
"http://ny.gateway.astralane.io/iris", "http://ny.gateway.astralane.io/irisb",
"http://lax.gateway.astralane.io/iris", "http://lax.gateway.astralane.io/irisb",
"http://lim.gateway.astralane.io/iris", "http://lim.gateway.astralane.io/irisb",
]; ];
pub const SWQOS_ENDPOINTS_STELLIUM: [&str; 8] = [ pub const SWQOS_ENDPOINTS_STELLIUM: [&str; 8] = [
+30 -66
View File
@@ -1,13 +1,12 @@
use crate::swqos::common::{poll_transaction_confirmation, serialize_transaction_and_encode}; use crate::swqos::common::{default_http_client_builder, poll_transaction_confirmation};
use rand::seq::IndexedRandom; use rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration; use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result; use anyhow::Result;
use bincode::serialize as bincode_serialize;
use solana_client::rpc_client::SerializableTransaction;
use solana_sdk::transaction::VersionedTransaction; use solana_sdk::transaction::VersionedTransaction;
use crate::swqos::{SwqosType, TradeType}; use crate::swqos::{SwqosType, TradeType};
use crate::swqos::SwqosClientTrait; use crate::swqos::SwqosClientTrait;
@@ -17,6 +16,9 @@ use crate::{common::SolanaRpcClient, constants::swqos::ASTRALANE_TIP_ACCOUNTS};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
/// Empty body for getHealth POST; avoid per-request allocation.
static PING_BODY: &[u8] = &[];
#[derive(Clone)] #[derive(Clone)]
pub struct AstralaneClient { pub struct AstralaneClient {
pub endpoint: String, pub endpoint: String,
@@ -50,19 +52,7 @@ impl SwqosClientTrait for AstralaneClient {
impl AstralaneClient { impl AstralaneClient {
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self { pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// 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 client = Self { let client = Self {
rpc_client: Arc::new(rpc_client), rpc_client: Arc::new(rpc_client),
@@ -90,13 +80,9 @@ impl AstralaneClient {
let stop_ping = self.stop_ping.clone(); let stop_ping = self.stop_ping.clone();
let handle = tokio::spawn(async move { 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!("Astralane ping request failed: {}", e);
}
let mut interval = tokio::time::interval(Duration::from_secs(30)); let mut interval = tokio::time::interval(Duration::from_secs(30));
loop { loop {
interval.tick().await; interval.tick().await; // first tick completes immediately → one ping at start
if stop_ping.load(Ordering::Relaxed) { if stop_ping.load(Ordering::Relaxed) {
break; break;
} }
@@ -116,71 +102,49 @@ impl AstralaneClient {
} }
} }
/// Send ping request to /gethealth endpoint /// Send ping request: POST endpoint?api-key=...&method=getHealth (endpoint is irisb from constants).
async fn send_ping_request(http_client: &Client, endpoint: &str, auth_token: &str) -> Result<()> { async fn send_ping_request(http_client: &Client, endpoint: &str, auth_token: &str) -> Result<()> {
// Build ping URL by replacing /iris with /gethealth let response = http_client
let ping_url = if endpoint.ends_with("/iris") { .post(endpoint)
endpoint.replace("/iris", "/gethealth") .query(&[("api-key", auth_token), ("method", "getHealth")])
} else if endpoint.ends_with("/iris/") {
endpoint.replace("/iris/", "/gethealth")
} else if endpoint.ends_with('/') {
format!("{}gethealth", endpoint)
} else {
format!("{}/gethealth", endpoint)
};
// Short timeout for ping; consume body so connection is returned to pool for reuse by submit
let response = http_client.get(&ping_url)
.header("api_key", auth_token)
.timeout(Duration::from_millis(1500)) .timeout(Duration::from_millis(1500))
.body(PING_BODY)
.send() .send()
.await?; .await?;
let status = response.status(); let status = response.status();
let _ = response.bytes().await; let _ = response.bytes().await; // consume body so connection returns to pool
if !status.is_success() { if !status.is_success() {
eprintln!("Astralane ping request returned non-success status: {}", status); eprintln!("Astralane ping request returned non-success status: {}", status);
} }
Ok(()) Ok(())
} }
/// Send transaction via /irisb binary API (no Base64; lower latency).
pub async fn send_transaction(&self, trade_type: TradeType, transaction: &VersionedTransaction, wait_confirmation: bool) -> Result<()> { pub async fn send_transaction(&self, trade_type: TradeType, transaction: &VersionedTransaction, wait_confirmation: bool) -> Result<()> {
let start_time = Instant::now(); let start_time = Instant::now();
let (content, signature) = serialize_transaction_and_encode(transaction, UiTransactionEncoding::Base64)?; let signature = transaction.get_signature();
let request_body = serde_json::to_string(&json!({ let body_bytes = bincode_serialize(transaction).map_err(|e| anyhow::anyhow!("Astralane binary serialize failed: {}", e))?;
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
content,
{ "encoding": "base64", "skipPreflight": true },
{ "mevProtect": false }
]
}))?;
// Send request with api_key header let response = self.http_client
let response_text = self.http_client.post(&self.endpoint) .post(&self.endpoint)
.body(request_body) .query(&[("api-key", self.auth_token.as_str()), ("method", "sendTransaction")])
.header("Content-Type", "application/json") .header("Content-Type", "application/octet-stream")
.header("api_key", &self.auth_token) .body(body_bytes)
.send() .send()
.await?
.text()
.await?; .await?;
// Parse JSON response let status = response.status();
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) { let _ = response.bytes().await;
if response_json.get("result").is_some() { if status.is_success() {
println!(" [astralane] {} submitted: {:?}", trade_type, start_time.elapsed()); println!(" [astralane] {} submitted: {:?}", trade_type, start_time.elapsed());
} else if let Some(_error) = response_json.get("error") {
eprintln!(" [astralane] {} submission failed: {:?}", trade_type, _error);
}
} else { } else {
eprintln!(" [astralane] {} submission failed: {:?}", trade_type, response_text); eprintln!(" [astralane] {} submission failed: status {}", trade_type, status);
return Err(anyhow::anyhow!("Astralane sendTransaction failed: {}", status));
} }
let start_time: Instant = Instant::now(); let start_time = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await { match poll_transaction_confirmation(&self.rpc_client, *signature, wait_confirmation).await {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
println!(" signature: {:?}", signature); println!(" signature: {:?}", signature);
+26 -62
View File
@@ -1,7 +1,6 @@
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 rand::seq::IndexedRandom;
use reqwest::{Client, header::{HeaderMap, HeaderValue, CONTENT_TYPE}}; use reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration; use std::time::Duration;
@@ -50,19 +49,7 @@ impl SwqosClientTrait for BlockRazorClient {
impl BlockRazorClient { impl BlockRazorClient {
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self { pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// Optimized connection pool settings for high performance
.pool_idle_timeout(Duration::from_secs(300)) // 5min so ping-kept connection is not evicted early
.pool_max_idle_per_host(4) // Few connections so submit reuses same connection as ping, avoiding cold connection after ~5min server idle close
.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 client = Self { let client = Self {
rpc_client: Arc::new(rpc_client), rpc_client: Arc::new(rpc_client),
@@ -120,31 +107,15 @@ impl BlockRazorClient {
} }
} }
/// Send ping request to /health endpoint /// Send ping request: POST /v2/health?auth=... (Keep Alive). Only required param: auth.
async fn send_ping_request(http_client: &Client, endpoint: &str, auth_token: &str) -> Result<()> { async fn send_ping_request(http_client: &Client, endpoint: &str, auth_token: &str) -> Result<()> {
// Build health URL by replacing sendTransaction with health let ping_url = endpoint.replace("/v2/sendTransaction", "/v2/health");
let ping_url = if endpoint.ends_with("sendTransaction") { let response = http_client
endpoint.replace("sendTransaction", "health") .post(&ping_url)
} else if endpoint.ends_with("/sendTransaction") { .query(&[("auth", auth_token)])
endpoint.replace("/sendTransaction", "/health") .header("Content-Type", "text/plain")
} else {
// Fallback to original logic if endpoint doesn't end with sendTransaction
if endpoint.ends_with('/') {
format!("{}health", endpoint)
} else {
format!("{}/health", endpoint)
}
};
// Prepare headers
let mut headers = HeaderMap::new();
headers.insert("apikey", HeaderValue::from_str(auth_token)?);
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
// Short timeout for ping; consume body so connection is returned to pool for reuse by submit
let response = http_client.get(&ping_url)
.headers(headers)
.timeout(Duration::from_millis(1500)) .timeout(Duration::from_millis(1500))
.body(&[] as &[u8])
.send() .send()
.await?; .await?;
let status = response.status(); let status = response.status();
@@ -155,40 +126,33 @@ impl BlockRazorClient {
Ok(()) Ok(())
} }
/// Send transaction via v2 API: plain Base64 body, Content-Type: text/plain. Only required URI param: auth.
pub async fn send_transaction(&self, trade_type: TradeType, transaction: &VersionedTransaction, wait_confirmation: bool) -> Result<()> { pub async fn send_transaction(&self, trade_type: TradeType, transaction: &VersionedTransaction, wait_confirmation: bool) -> Result<()> {
let start_time = Instant::now(); let start_time = Instant::now();
let (content, signature) = serialize_transaction_and_encode(transaction, UiTransactionEncoding::Base64)?; let (content, signature) = serialize_transaction_and_encode(transaction, UiTransactionEncoding::Base64)?;
// BlockRazor fast-mode request format let response = self.http_client
let request_body = serde_json::to_string(&json!({ .post(&self.endpoint)
"transaction": content, .query(&[("auth", self.auth_token.as_str())])
"mode": "fast" .header("Content-Type", "text/plain")
}))?; .body(content)
// BlockRazor uses apikey header
let response_text = self.http_client.post(&self.endpoint)
.body(request_body)
.header("Content-Type", "application/json")
.header("apikey", &self.auth_token)
.send() .send()
.await?
.text()
.await?; .await?;
// Parse JSON response let status = response.status();
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) { let _ = response.bytes().await;
if status.is_success() {
if crate::common::sdk_log::sdk_log_enabled() { 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());
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 if crate::common::sdk_log::sdk_log_enabled() { } else {
eprintln!(" [blockrazor] {} submission failed: {:?}", trade_type, response_text); if crate::common::sdk_log::sdk_log_enabled() {
eprintln!(" [blockrazor] {} submission failed: status {}", trade_type, status);
}
return Err(anyhow::anyhow!("BlockRazor sendTransaction failed: {}", status));
} }
let start_time: Instant = Instant::now(); let start_time = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await { match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
+2 -15
View File
@@ -1,10 +1,9 @@
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 rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json; use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding; use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result; use anyhow::Result;
@@ -46,19 +45,7 @@ impl SwqosClientTrait for FlashBlockClient {
impl FlashBlockClient { impl FlashBlockClient {
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self { pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// Optimized connection pool settings for high performance
.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
.build()
.unwrap();
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client } Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
} }
+2 -15
View File
@@ -1,11 +1,10 @@
use crate::swqos::common::{poll_transaction_confirmation, serialize_transaction_and_encode, FormatBase64VersionedTransaction}; use crate::swqos::common::{default_http_client_builder, poll_transaction_confirmation, serialize_transaction_and_encode, FormatBase64VersionedTransaction};
use rand::seq::IndexedRandom; use rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json; use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding; use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result; use anyhow::Result;
@@ -49,19 +48,7 @@ impl SwqosClientTrait for JitoClient {
impl JitoClient { impl JitoClient {
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self { pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// Optimized connection pool settings for high performance
.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
.build()
.unwrap();
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client } Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
} }
+2 -15
View File
@@ -1,10 +1,9 @@
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 rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json; use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding; use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result; use anyhow::Result;
@@ -47,19 +46,7 @@ impl LightspeedClient {
// Lightspeed endpoint should already include /lightspeed path // Lightspeed endpoint should already include /lightspeed path
// Format: https://<tier>.rpc.solanavibestation.com/lightspeed?api_key=<key> // Format: https://<tier>.rpc.solanavibestation.com/lightspeed?api_key=<key>
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// Optimized connection pool settings for high performance
.pool_idle_timeout(Duration::from_secs(120))
.pool_max_idle_per_host(256)
.tcp_keepalive(Some(Duration::from_secs(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))
.connect_timeout(Duration::from_millis(2000))
.build()
.unwrap();
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client } Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
} }
+2 -15
View File
@@ -1,10 +1,9 @@
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 rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json; use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding; use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result; use anyhow::Result;
@@ -51,19 +50,7 @@ impl NextBlockClient {
format!("{}/api/v2/submit", endpoint.trim_end_matches('/')) format!("{}/api/v2/submit", endpoint.trim_end_matches('/'))
}; };
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// Optimized connection pool settings for high performance
.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
.build()
.unwrap();
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client } Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
} }
+2 -14
View File
@@ -1,5 +1,5 @@
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 rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json; use serde_json::json;
@@ -76,19 +76,7 @@ impl SwqosClientTrait for TemporalClient {
impl TemporalClient { impl TemporalClient {
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self { pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// 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 client = Self { let client = Self {
rpc_client: Arc::new(rpc_client), rpc_client: Arc::new(rpc_client),
+2 -15
View File
@@ -1,10 +1,9 @@
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 rand::seq::IndexedRandom;
use reqwest::Client; use reqwest::Client;
use serde_json::json; use serde_json::json;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding; use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result; use anyhow::Result;
@@ -46,19 +45,7 @@ impl SwqosClientTrait for ZeroSlotClient {
impl ZeroSlotClient { impl ZeroSlotClient {
pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self { pub fn new(rpc_url: String, endpoint: String, auth_token: String) -> Self {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let http_client = Client::builder() let http_client = default_http_client_builder().build().unwrap();
// Optimized connection pool settings for high performance
.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
.build()
.unwrap();
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client } Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
} }