fix: align Lunar Lander with official client

This commit is contained in:
0xfnzero
2026-07-12 18:03:08 +08:00
parent 1c78b3cab2
commit 1d224770d8
3 changed files with 48 additions and 38 deletions
+1 -1
View File
@@ -112,7 +112,7 @@ sha2 = "0.10"
tonic-prost = "0.14.2" tonic-prost = "0.14.2"
# 须含 runtime-tokio,否则 quinn::Endpoint::client 报 no async runtime foundQUICSpeedlanding/Soyas)无法初始化 # 须含 runtime-tokio,否则 quinn::Endpoint::client 报 no async runtime foundQUICSpeedlanding/Soyas)无法初始化
quinn = { version = "0.11", default-features = false, features = ["rustls", "runtime-tokio"] } quinn = { version = "0.11", default-features = false, features = ["rustls", "runtime-tokio"] }
lunar-lander-quic-client = "0.1" lunar-lander-quic-client = "0.4"
rcgen = "0.13" rcgen = "0.13"
uuid = "1.11" uuid = "1.11"
+40 -34
View File
@@ -15,8 +15,7 @@ use crate::{common::SolanaRpcClient, constants::swqos::LUNARLANDER_TIP_ACCOUNTS}
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use lunar_lander_quic_client::LunarLanderQuicClient; use lunar_lander_quic_client::{ClientOptions, LunarLanderQuicClient};
use tokio::sync::Mutex;
#[derive(Clone)] #[derive(Clone)]
pub enum LunarLanderBackend { pub enum LunarLanderBackend {
@@ -27,7 +26,7 @@ pub enum LunarLanderBackend {
ping_handle: Arc<tokio::sync::Mutex<Option<JoinHandle<()>>>>, ping_handle: Arc<tokio::sync::Mutex<Option<JoinHandle<()>>>>,
stop_ping: Arc<AtomicBool>, stop_ping: Arc<AtomicBool>,
}, },
Quic(Arc<Mutex<LunarLanderQuicClient>>), Quic(Arc<LunarLanderQuicClient>),
} }
#[derive(Clone)] #[derive(Clone)]
@@ -98,12 +97,22 @@ impl LunarLanderClient {
} }
/// Create a QUIC client (port 16888, cert CN = api_key, fire-and-forget unidirectional streams). /// Create a QUIC client (port 16888, cert CN = api_key, fire-and-forget unidirectional streams).
pub async fn new_quic(rpc_url: String, quic_endpoint: &str, api_key: String) -> Result<Self> { pub async fn new_quic(
rpc_url: String,
quic_endpoint: &str,
api_key: String,
mev_protection: bool,
) -> Result<Self> {
let rpc_client = SolanaRpcClient::new(rpc_url); let rpc_client = SolanaRpcClient::new(rpc_url);
let quic_client = LunarLanderQuicClient::connect(quic_endpoint, &api_key).await?; let quic_client = LunarLanderQuicClient::connect_with_options(
quic_endpoint,
api_key,
quic_client_options(mev_protection),
)
.await?;
Ok(Self { Ok(Self {
rpc_client: Arc::new(rpc_client), rpc_client: Arc::new(rpc_client),
backend: LunarLanderBackend::Quic(Arc::new(Mutex::new(quic_client))), backend: LunarLanderBackend::Quic(Arc::new(quic_client)),
}) })
} }
@@ -155,7 +164,7 @@ impl LunarLanderClient {
endpoint: &str, endpoint: &str,
auth_token: &str, auth_token: &str,
) -> Result<()> { ) -> Result<()> {
let url = format!("{}/ping", endpoint); let url = format!("{}/ping", endpoint.trim_end_matches('/'));
let response = http_client let response = http_client
.get(&url) .get(&url)
.header("x-api-key", auth_token) .header("x-api-key", auth_token)
@@ -173,13 +182,16 @@ impl LunarLanderClient {
wait_confirmation: bool, wait_confirmation: bool,
) -> Result<()> { ) -> Result<()> {
let start_time = Instant::now(); let start_time = Instant::now();
let signature = transaction.signatures[0]; let signature = *transaction
.signatures
.first()
.ok_or_else(|| anyhow::anyhow!("LunarLander transaction has no signature"))?;
let body_bytes = bincode_serialize(transaction) let body_bytes = bincode_serialize(transaction)
.map_err(|e| anyhow::anyhow!("LunarLander binary serialize failed: {}", e))?; .map_err(|e| anyhow::anyhow!("LunarLander binary serialize failed: {}", e))?;
match &self.backend { match &self.backend {
LunarLanderBackend::Http { endpoint, auth_token, http_client, .. } => { LunarLanderBackend::Http { endpoint, auth_token, http_client, .. } => {
let url = format!("{}/send-bin", endpoint); let url = format!("{}/send-bin", endpoint.trim_end_matches('/'));
let response = http_client let response = http_client
.post(&url) .post(&url)
.header("x-api-key", auth_token) .header("x-api-key", auth_token)
@@ -210,25 +222,7 @@ impl LunarLanderClient {
} }
} }
LunarLanderBackend::Quic(quic) => { LunarLanderBackend::Quic(quic) => {
let send_result = { quic.send_transaction(&body_bytes).await?;
let client = quic.lock().await;
client.send_transaction(&body_bytes).await
};
if let Err(e) = send_result {
// Attempt reconnect on failure.
let mut client = quic.lock().await;
if let Err(re) = client.reconnect().await {
if crate::common::sdk_log::sdk_log_enabled() {
crate::common::sdk_log::log_swqos_submission_failed(
"LunarLander",
trade_type,
start_time.elapsed(),
format!("QUIC send failed: {}, reconnect failed: {}", e, re),
);
}
}
return Err(anyhow::anyhow!("LunarLander QUIC send failed: {}", e));
}
if crate::common::sdk_log::sdk_log_enabled() { if crate::common::sdk_log::sdk_log_enabled() {
crate::common::sdk_log::log_swqos_submitted( crate::common::sdk_log::log_swqos_submitted(
"LunarLander", "LunarLander",
@@ -275,16 +269,28 @@ impl Drop for LunarLanderClient {
match &self.backend { match &self.backend {
LunarLanderBackend::Http { stop_ping, ping_handle, .. } => { LunarLanderBackend::Http { stop_ping, ping_handle, .. } => {
stop_ping.store(true, Ordering::Relaxed); stop_ping.store(true, Ordering::Relaxed);
let ping_handle = ping_handle.clone(); if let Ok(mut guard) = ping_handle.try_lock() {
tokio::spawn(async move { if let Some(handle) = guard.take() {
let mut guard = ping_handle.lock().await;
if let Some(handle) = guard.as_ref() {
handle.abort(); handle.abort();
} }
*guard = None; }
});
} }
LunarLanderBackend::Quic(_) => {} LunarLanderBackend::Quic(_) => {}
} }
} }
} }
fn quic_client_options(mev_protection: bool) -> ClientOptions {
ClientOptions { mev_protect: mev_protection, ..ClientOptions::default() }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn quic_options_follow_sdk_mev_protection() {
assert!(!quic_client_options(false).mev_protect);
assert!(quic_client_options(true).mev_protect);
}
}
+7 -3
View File
@@ -553,9 +553,13 @@ impl SwqosConfig {
let quic_endpoint = url.unwrap_or_else(|| { let quic_endpoint = url.unwrap_or_else(|| {
SWQOS_ENDPOINTS_LUNARLANDER_QUIC[region as usize].to_string() SWQOS_ENDPOINTS_LUNARLANDER_QUIC[region as usize].to_string()
}); });
let lunarlander_client = let lunarlander_client = LunarLanderClient::new_quic(
LunarLanderClient::new_quic(rpc_url.clone(), &quic_endpoint, api_key) rpc_url.clone(),
.await?; &quic_endpoint,
api_key,
mev_protection,
)
.await?;
Ok(Arc::new(lunarlander_client)) Ok(Arc::new(lunarlander_client))
} else { } else {
let endpoint = SwqosConfig::get_endpoint(SwqosType::LunarLander, region, url); let endpoint = SwqosConfig::get_endpoint(SwqosType::LunarLander, region, url);