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]
name = "sol-trade-sdk"
version = "3.5.3"
version = "3.5.4"
edition = "2021"
authors = [
"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
1. **PumpFun Trading**: Support for `buy` and `sell` operations
@@ -114,14 +89,14 @@ Add the dependency to your `Cargo.toml`:
```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
```toml
# Add to your Cargo.toml
sol-trade-sdk = "3.5.3"
sol-trade-sdk = "3.5.4"
```
## 🛠️ 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 交易**: 支持`购买``卖出`功能
@@ -97,14 +89,14 @@ git clone https://github.com/0xfnzero/sol-trade-sdk
```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
```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",
];
/// 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] = [
"http://newyork.solana.blockrazor.xyz:443/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/sendTransaction",
"http://amsterdam.solana.blockrazor.xyz:443/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/sendTransaction",
"http://tokyo.solana.blockrazor.xyz:443/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://frankfurt.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://amsterdam.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://tokyo.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://london.solana.blockrazor.xyz:443/v2/sendTransaction",
"http://newyork.solana.blockrazor.xyz:443/v2/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] = [
"http://ny.gateway.astralane.io/iris",
"http://fr.gateway.astralane.io/iris",
"http://ams.gateway.astralane.io/iris",
"http://ny.gateway.astralane.io/iris",
"http://jp.gateway.astralane.io/iris",
"http://ny.gateway.astralane.io/iris",
"http://lax.gateway.astralane.io/iris",
"http://lim.gateway.astralane.io/iris",
"http://ny.gateway.astralane.io/irisb",
"http://fr.gateway.astralane.io/irisb",
"http://ams.gateway.astralane.io/irisb",
"http://ny.gateway.astralane.io/irisb",
"http://jp.gateway.astralane.io/irisb",
"http://ny.gateway.astralane.io/irisb",
"http://lax.gateway.astralane.io/irisb",
"http://lim.gateway.astralane.io/irisb",
];
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 reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result;
use bincode::serialize as bincode_serialize;
use solana_client::rpc_client::SerializableTransaction;
use solana_sdk::transaction::VersionedTransaction;
use crate::swqos::{SwqosType, TradeType};
use crate::swqos::SwqosClientTrait;
@@ -17,6 +16,9 @@ use crate::{common::SolanaRpcClient, constants::swqos::ASTRALANE_TIP_ACCOUNTS};
use tokio::task::JoinHandle;
use std::sync::atomic::{AtomicBool, Ordering};
/// Empty body for getHealth POST; avoid per-request allocation.
static PING_BODY: &[u8] = &[];
#[derive(Clone)]
pub struct AstralaneClient {
pub endpoint: String,
@@ -50,19 +52,7 @@ impl SwqosClientTrait for AstralaneClient {
impl AstralaneClient {
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),
@@ -90,13 +80,9 @@ impl AstralaneClient {
let stop_ping = self.stop_ping.clone();
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));
loop {
interval.tick().await;
interval.tick().await; // first tick completes immediately → one ping at start
if stop_ping.load(Ordering::Relaxed) {
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<()> {
// Build ping URL by replacing /iris with /gethealth
let ping_url = if endpoint.ends_with("/iris") {
endpoint.replace("/iris", "/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)
let response = http_client
.post(endpoint)
.query(&[("api-key", auth_token), ("method", "getHealth")])
.timeout(Duration::from_millis(1500))
.body(PING_BODY)
.send()
.await?;
let status = response.status();
let _ = response.bytes().await;
let _ = response.bytes().await; // consume body so connection returns to pool
if !status.is_success() {
eprintln!("Astralane ping request returned non-success status: {}", status);
}
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<()> {
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!({
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
content,
{ "encoding": "base64", "skipPreflight": true },
{ "mevProtect": false }
]
}))?;
let body_bytes = bincode_serialize(transaction).map_err(|e| anyhow::anyhow!("Astralane binary serialize failed: {}", e))?;
// Send request with api_key header
let response_text = self.http_client.post(&self.endpoint)
.body(request_body)
.header("Content-Type", "application/json")
.header("api_key", &self.auth_token)
let response = self.http_client
.post(&self.endpoint)
.query(&[("api-key", self.auth_token.as_str()), ("method", "sendTransaction")])
.header("Content-Type", "application/octet-stream")
.body(body_bytes)
.send()
.await?
.text()
.await?;
// 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!(" [astralane] {} submitted: {:?}", trade_type, start_time.elapsed());
} else if let Some(_error) = response_json.get("error") {
eprintln!(" [astralane] {} submission failed: {:?}", trade_type, _error);
}
let status = response.status();
let _ = response.bytes().await;
if status.is_success() {
println!(" [astralane] {} submitted: {:?}", trade_type, start_time.elapsed());
} 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();
match poll_transaction_confirmation(&self.rpc_client, signature, wait_confirmation).await {
let start_time = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, *signature, wait_confirmation).await {
Ok(_) => (),
Err(e) => {
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 reqwest::{Client, header::{HeaderMap, HeaderValue, CONTENT_TYPE}};
use serde_json::json;
use reqwest::Client;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
@@ -50,19 +49,7 @@ impl SwqosClientTrait for BlockRazorClient {
impl BlockRazorClient {
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)) // 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 http_client = default_http_client_builder().build().unwrap();
let client = Self {
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<()> {
// Build health URL by replacing sendTransaction with health
let ping_url = if endpoint.ends_with("sendTransaction") {
endpoint.replace("sendTransaction", "health")
} else if endpoint.ends_with("/sendTransaction") {
endpoint.replace("/sendTransaction", "/health")
} 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)
let ping_url = endpoint.replace("/v2/sendTransaction", "/v2/health");
let response = http_client
.post(&ping_url)
.query(&[("auth", auth_token)])
.header("Content-Type", "text/plain")
.timeout(Duration::from_millis(1500))
.body(&[] as &[u8])
.send()
.await?;
let status = response.status();
@@ -155,40 +126,33 @@ impl BlockRazorClient {
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<()> {
let start_time = Instant::now();
let (content, signature) = serialize_transaction_and_encode(transaction, UiTransactionEncoding::Base64)?;
// BlockRazor fast-mode request format
let request_body = serde_json::to_string(&json!({
"transaction": content,
"mode": "fast"
}))?;
// 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)
let response = self.http_client
.post(&self.endpoint)
.query(&[("auth", self.auth_token.as_str())])
.header("Content-Type", "text/plain")
.body(content)
.send()
.await?
.text()
.await?;
// Parse JSON response
if let Ok(response_json) = serde_json::from_str::<serde_json::Value>(&response_text) {
let status = response.status();
let _ = response.bytes().await;
if status.is_success() {
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);
}
println!(" [blockrazor] {} submitted: {:?}", trade_type, start_time.elapsed());
}
} else if crate::common::sdk_log::sdk_log_enabled() {
eprintln!(" [blockrazor] {} submission failed: {:?}", trade_type, response_text);
} else {
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 {
Ok(_) => (),
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 reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result;
@@ -46,19 +45,7 @@ impl SwqosClientTrait for FlashBlockClient {
impl FlashBlockClient {
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(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();
let http_client = default_http_client_builder().build().unwrap();
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 reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result;
@@ -49,19 +48,7 @@ impl SwqosClientTrait for JitoClient {
impl JitoClient {
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(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();
let http_client = default_http_client_builder().build().unwrap();
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 reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result;
@@ -47,19 +46,7 @@ impl LightspeedClient {
// Lightspeed endpoint should already include /lightspeed path
// Format: https://<tier>.rpc.solanavibestation.com/lightspeed?api_key=<key>
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(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();
let http_client = default_http_client_builder().build().unwrap();
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 reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result;
@@ -51,19 +50,7 @@ impl NextBlockClient {
format!("{}/api/v2/submit", endpoint.trim_end_matches('/'))
};
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(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();
let http_client = default_http_client_builder().build().unwrap();
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 reqwest::Client;
use serde_json::json;
@@ -76,19 +76,7 @@ impl SwqosClientTrait for TemporalClient {
impl TemporalClient {
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),
+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 reqwest::Client;
use serde_json::json;
use std::{sync::Arc, time::Instant};
use std::time::Duration;
use solana_transaction_status::UiTransactionEncoding;
use anyhow::Result;
@@ -46,19 +45,7 @@ impl SwqosClientTrait for ZeroSlotClient {
impl ZeroSlotClient {
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(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();
let http_client = default_http_client_builder().build().unwrap();
Self { rpc_client: Arc::new(rpc_client), endpoint, auth_token, http_client }
}