feat: translate comments to English and add PumpSwap buy_exact_quote_in

- Translate all Chinese comments to English
- Add PumpSwap buy_exact_quote_in instruction and event support
- Update event parser to handle new buy_exact_quote_in event type
- Improve code readability across codebase
This commit is contained in:
Estereg
2025-12-17 20:06:14 -03:00
parent bec65dea21
commit e1c537554e
29 changed files with 533 additions and 351 deletions
+6 -6
View File
@@ -1,18 +1,18 @@
// 流处理相关的常量定义 // Constants related to stream processing
// 默认配置常量 // Default configuration constants
pub const DEFAULT_CONNECT_TIMEOUT: u64 = 10; pub const DEFAULT_CONNECT_TIMEOUT: u64 = 10;
pub const DEFAULT_REQUEST_TIMEOUT: u64 = 60; pub const DEFAULT_REQUEST_TIMEOUT: u64 = 60;
pub const DEFAULT_CHANNEL_SIZE: usize = 1000; pub const DEFAULT_CHANNEL_SIZE: usize = 1000;
pub const DEFAULT_MAX_DECODING_MESSAGE_SIZE: usize = 1024 * 1024 * 10; pub const DEFAULT_MAX_DECODING_MESSAGE_SIZE: usize = 1024 * 1024 * 10;
// 性能监控相关常量 // Performance monitoring related constants
pub const DEFAULT_METRICS_WINDOW_SECONDS: u64 = 5; pub const DEFAULT_METRICS_WINDOW_SECONDS: u64 = 5;
pub const DEFAULT_METRICS_PRINT_INTERVAL_SECONDS: u64 = 10; pub const DEFAULT_METRICS_PRINT_INTERVAL_SECONDS: u64 = 10;
pub const SLOW_PROCESSING_THRESHOLD_US: f64 = 3000.0; pub const SLOW_PROCESSING_THRESHOLD_US: f64 = 3000.0;
// gRPC 延迟监控 // gRPC latency monitoring
// Solana 不存储毫秒,所以我们用500ms来校准以获得更好的近似值 // Solana doesn't store milliseconds, so we use 500ms to calibrate for better approximation
pub const SOLANA_BLOCK_TIME_ADJUSTMENT_MS: i64 = 500; pub const SOLANA_BLOCK_TIME_ADJUSTMENT_MS: i64 = 500;
// 默认最大延迟阈值(毫秒) // Default maximum latency threshold (milliseconds)
pub const MAX_LATENCY_THRESHOLD_MS: i64 = 1000; pub const MAX_LATENCY_THRESHOLD_MS: i64 = 1000;
+2 -2
View File
@@ -10,9 +10,9 @@ use crate::streaming::shred::TransactionWithSlot;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use std::sync::Arc; use std::sync::Arc;
/// 创建带 metrics 统计的 callback 包装器 /// Create callback wrapper with metrics statistics
/// ///
/// 用于 Transaction 事件处理,在调用原始 callback 的同时更新 metrics /// Used for Transaction event processing, updates metrics while calling the original callback
#[inline] #[inline]
fn create_metrics_callback( fn create_metrics_callback(
callback: Arc<dyn Fn(DexEvent) + Send + Sync>, callback: Arc<dyn Fn(DexEvent) + Send + Sync>,
+36 -36
View File
@@ -200,7 +200,7 @@ pub struct HighPerformanceMetrics {
start_nanos: AtomicU64, start_nanos: AtomicU64,
event_metrics: [AtomicEventMetrics; 3], event_metrics: [AtomicEventMetrics; 3],
processing_stats: AtomicProcessingTimeStats, processing_stats: AtomicProcessingTimeStats,
// 丢弃事件指标 // Dropped events metrics
dropped_events_count: AtomicU64, dropped_events_count: AtomicU64,
} }
@@ -219,7 +219,7 @@ impl HighPerformanceMetrics {
} }
} }
/// 获取运行时长(秒) /// Get uptime (seconds)
#[inline] #[inline]
pub fn get_uptime_seconds(&self) -> f64 { pub fn get_uptime_seconds(&self) -> f64 {
let now_nanos = let now_nanos =
@@ -244,7 +244,7 @@ impl HighPerformanceMetrics {
(now_nanos - start) as f64 / 1_000_000_000.0 (now_nanos - start) as f64 / 1_000_000_000.0
} }
/// 获取事件指标快照 /// Get event metrics snapshot
#[inline] #[inline]
pub fn get_event_metrics(&self, event_type: EventType) -> EventMetricsSnapshot { pub fn get_event_metrics(&self, event_type: EventType) -> EventMetricsSnapshot {
let index = event_type.as_index(); let index = event_type.as_index();
@@ -254,19 +254,19 @@ impl HighPerformanceMetrics {
EventMetricsSnapshot { process_count, events_processed, processing_stats } EventMetricsSnapshot { process_count, events_processed, processing_stats }
} }
/// 获取处理时间统计 /// Get processing time statistics
#[inline] #[inline]
pub fn get_processing_stats(&self) -> ProcessingTimeStats { pub fn get_processing_stats(&self) -> ProcessingTimeStats {
self.processing_stats.get_stats() self.processing_stats.get_stats()
} }
/// 获取丢弃事件计数 /// Get dropped events count
#[inline] #[inline]
pub fn get_dropped_events_count(&self) -> u64 { pub fn get_dropped_events_count(&self) -> u64 {
self.dropped_events_count.load(Ordering::Relaxed) self.dropped_events_count.load(Ordering::Relaxed)
} }
/// 更新窗口指标(后台任务调用) /// Update window metrics (called by background task)
fn update_window_metrics(&self, event_type: EventType, window_duration_nanos: u64) { fn update_window_metrics(&self, event_type: EventType, window_duration_nanos: u64) {
let now_nanos = let now_nanos =
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos() std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
@@ -291,7 +291,7 @@ static BACKGROUND_TASK_STARTED: AtomicBool = AtomicBool::new(false);
/// Metrics enabled flag /// Metrics enabled flag
static METRICS_ENABLED: AtomicBool = AtomicBool::new(true); static METRICS_ENABLED: AtomicBool = AtomicBool::new(true);
/// 高性能指标管理器 (Singleton) /// High-performance metrics manager (Singleton)
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct MetricsManager; pub struct MetricsManager;
@@ -334,7 +334,7 @@ impl MetricsManager {
METRICS_ENABLED.load(Ordering::Relaxed) METRICS_ENABLED.load(Ordering::Relaxed)
} }
/// 记录处理次数(非阻塞) /// Record process count (non-blocking)
#[inline] #[inline]
pub fn record_process(&self, event_type: EventType) { pub fn record_process(&self, event_type: EventType) {
if self.is_enabled() { if self.is_enabled() {
@@ -342,7 +342,7 @@ impl MetricsManager {
} }
} }
/// 记录事件处理(非阻塞) /// Record event processing (non-blocking)
#[inline] #[inline]
pub fn record_events(&self, event_type: EventType, count: u64, processing_time_us: f64) { pub fn record_events(&self, event_type: EventType, count: u64, processing_time_us: f64) {
if !self.is_enabled() { if !self.is_enabled() {
@@ -351,17 +351,17 @@ impl MetricsManager {
let index = event_type.as_index(); let index = event_type.as_index();
// 原子更新事件计数 // Atomically update event count
GLOBAL_METRICS.event_metrics[index].add_events_processed(count); GLOBAL_METRICS.event_metrics[index].add_events_processed(count);
// 原子更新该事件类型的处理时间统计 // Atomically update processing time statistics for this event type
GLOBAL_METRICS.event_metrics[index].update_processing_stats(processing_time_us, count); GLOBAL_METRICS.event_metrics[index].update_processing_stats(processing_time_us, count);
// 保持全局处理时间统计的兼容性 // Maintain compatibility with global processing time statistics
GLOBAL_METRICS.processing_stats.update(processing_time_us, count); GLOBAL_METRICS.processing_stats.update(processing_time_us, count);
} }
/// 记录慢处理操作 /// Record slow processing operation
#[inline] #[inline]
pub fn log_slow_processing(&self, processing_time_us: f64, event_count: usize) { pub fn log_slow_processing(&self, processing_time_us: f64, event_count: usize) {
if processing_time_us > SLOW_PROCESSING_THRESHOLD_US { if processing_time_us > SLOW_PROCESSING_THRESHOLD_US {
@@ -369,12 +369,12 @@ impl MetricsManager {
} }
} }
/// 检查并警告高延迟 (校准后的 gRPC latency) /// Check and warn about high latency (calibrated gRPC latency)
/// latency = recv_time - (block_time + 500ms) /// latency = recv_time - (block_time + 500ms)
#[inline] #[inline]
pub fn check_and_warn_high_latency(&self, recv_us: i64, block_time_ms: i64) { pub fn check_and_warn_high_latency(&self, recv_us: i64, block_time_ms: i64) {
let recv_ms = recv_us / 1000; let recv_ms = recv_us / 1000;
// 校准延迟: recv_time - (block_time + 500ms) // Calibrate latency: recv_time - (block_time + 500ms)
let adjusted_latency_ms = recv_ms - (block_time_ms + SOLANA_BLOCK_TIME_ADJUSTMENT_MS); let adjusted_latency_ms = recv_ms - (block_time_ms + SOLANA_BLOCK_TIME_ADJUSTMENT_MS);
if adjusted_latency_ms > MAX_LATENCY_THRESHOLD_MS { if adjusted_latency_ms > MAX_LATENCY_THRESHOLD_MS {
@@ -388,38 +388,38 @@ impl MetricsManager {
} }
} }
/// 获取运行时长 /// Get uptime
pub fn get_uptime(&self) -> std::time::Duration { pub fn get_uptime(&self) -> std::time::Duration {
std::time::Duration::from_secs_f64(GLOBAL_METRICS.get_uptime_seconds()) std::time::Duration::from_secs_f64(GLOBAL_METRICS.get_uptime_seconds())
} }
/// 获取事件指标 /// Get event metrics
pub fn get_event_metrics(&self, event_type: EventType) -> EventMetricsSnapshot { pub fn get_event_metrics(&self, event_type: EventType) -> EventMetricsSnapshot {
GLOBAL_METRICS.get_event_metrics(event_type) GLOBAL_METRICS.get_event_metrics(event_type)
} }
/// 获取处理时间统计 /// Get processing time statistics
pub fn get_processing_stats(&self) -> ProcessingTimeStats { pub fn get_processing_stats(&self) -> ProcessingTimeStats {
GLOBAL_METRICS.get_processing_stats() GLOBAL_METRICS.get_processing_stats()
} }
/// 获取丢弃事件计数 /// Get dropped events count
pub fn get_dropped_events_count(&self) -> u64 { pub fn get_dropped_events_count(&self) -> u64 {
GLOBAL_METRICS.get_dropped_events_count() GLOBAL_METRICS.get_dropped_events_count()
} }
/// 打印性能指标(非阻塞) /// Print performance metrics (non-blocking)
pub fn print_metrics(&self) { pub fn print_metrics(&self) {
println!("\n📊 Performance Metrics"); println!("\n📊 Performance Metrics");
println!(" Run Time: {:?}", self.get_uptime()); println!(" Run Time: {:?}", self.get_uptime());
// 打印丢弃事件指标 // Print dropped events metrics
let dropped_count = self.get_dropped_events_count(); let dropped_count = self.get_dropped_events_count();
if dropped_count > 0 { if dropped_count > 0 {
println!("\n⚠️ Dropped Events: {}", dropped_count); println!("\n⚠️ Dropped Events: {}", dropped_count);
} }
// 打印事件指标表格(包含处理时间统计) // Print event metrics table (including processing time statistics)
println!("┌─────────────┬──────────────┬──────────────────┬─────────────┬─────────────┐"); println!("┌─────────────┬──────────────┬──────────────────┬─────────────┬─────────────┐");
println!("│ Event Type │ Process Count│ Events Processed │ Last(μs) │ Avg(μs) │"); println!("│ Event Type │ Process Count│ Events Processed │ Last(μs) │ Avg(μs) │");
println!("├─────────────┼──────────────┼──────────────────┼─────────────┼─────────────┤"); println!("├─────────────┼──────────────┼──────────────────┼─────────────┼─────────────┤");
@@ -440,7 +440,7 @@ impl MetricsManager {
println!(); println!();
} }
/// 启动自动性能监控任务 /// Start automatic performance monitoring task
pub async fn start_auto_monitoring(&self) -> Option<tokio::task::JoinHandle<()>> { pub async fn start_auto_monitoring(&self) -> Option<tokio::task::JoinHandle<()>> {
if !self.is_enabled() { if !self.is_enabled() {
return None; return None;
@@ -458,7 +458,7 @@ impl MetricsManager {
Some(handle) Some(handle)
} }
/// 获取完整的性能指标(兼容性方法) /// Get complete performance metrics (compatibility method)
pub fn get_metrics(&self) -> PerformanceMetrics { pub fn get_metrics(&self) -> PerformanceMetrics {
PerformanceMetrics { PerformanceMetrics {
uptime: self.get_uptime(), uptime: self.get_uptime(),
@@ -470,25 +470,25 @@ impl MetricsManager {
} }
} }
/// 兼容性方法 - 添加交易处理计数 /// Compatibility method - add transaction process count
#[inline] #[inline]
pub fn add_tx_process_count(&self) { pub fn add_tx_process_count(&self) {
self.record_process(EventType::Transaction); self.record_process(EventType::Transaction);
} }
/// 兼容性方法 - 添加账户处理计数 /// Compatibility method - add account process count
#[inline] #[inline]
pub fn add_account_process_count(&self) { pub fn add_account_process_count(&self) {
self.record_process(EventType::Account); self.record_process(EventType::Account);
} }
/// 兼容性方法 - 添加区块元数据处理计数 /// Compatibility method - add block meta process count
#[inline] #[inline]
pub fn add_block_meta_process_count(&self) { pub fn add_block_meta_process_count(&self) {
self.record_process(EventType::BlockMeta); self.record_process(EventType::BlockMeta);
} }
/// 兼容性方法 - 更新指标 /// Compatibility method - update metrics
#[inline] #[inline]
pub fn update_metrics( pub fn update_metrics(
&self, &self,
@@ -500,7 +500,7 @@ impl MetricsManager {
self.log_slow_processing(processing_time_us, events_processed as usize); self.log_slow_processing(processing_time_us, events_processed as usize);
} }
/// 更新指标并检查延迟 /// Update metrics and check latency
#[inline] #[inline]
pub fn update_metrics_with_latency( pub fn update_metrics_with_latency(
&self, &self,
@@ -514,39 +514,39 @@ impl MetricsManager {
self.update_metrics(event_type, events_processed, processing_time_us); self.update_metrics(event_type, events_processed, processing_time_us);
} }
/// 增加丢弃事件计数 /// Increment dropped events count
#[inline] #[inline]
pub fn increment_dropped_events(&self) { pub fn increment_dropped_events(&self) {
if !self.is_enabled() { if !self.is_enabled() {
return; return;
} }
// 原子地增加丢弃事件计数 // Atomically increment dropped events count
let new_count = GLOBAL_METRICS.dropped_events_count.fetch_add(1, Ordering::Relaxed) + 1; let new_count = GLOBAL_METRICS.dropped_events_count.fetch_add(1, Ordering::Relaxed) + 1;
// 每丢弃1000个事件记录一次警告日志 // Log warning every 1000 dropped events
if new_count % 1000 == 0 { if new_count % 1000 == 0 {
log::debug!("Dropped events count reached: {}", new_count); log::debug!("Dropped events count reached: {}", new_count);
} }
} }
/// 批量增加丢弃事件计数 /// Batch increment dropped events count
#[inline] #[inline]
pub fn increment_dropped_events_by(&self, count: u64) { pub fn increment_dropped_events_by(&self, count: u64) {
if !self.is_enabled() || count == 0 { if !self.is_enabled() || count == 0 {
return; return;
} }
// 原子地增加丢弃事件计数 // Atomically increment dropped events count
let new_count = let new_count =
GLOBAL_METRICS.dropped_events_count.fetch_add(count, Ordering::Relaxed) + count; GLOBAL_METRICS.dropped_events_count.fetch_add(count, Ordering::Relaxed) + count;
// 记录批量丢弃事件的日志 // Log batch dropped events
if count > 1 { if count > 1 {
log::debug!("Dropped batch of {} events, total dropped: {}", count, new_count); log::debug!("Dropped batch of {} events, total dropped: {}", count, new_count);
} }
// 每丢弃1000个事件记录一次警告日志 // Log warning every 1000 dropped events
if new_count % 1000 == 0 || (new_count / 1000) != ((new_count - count) / 1000) { if new_count % 1000 == 0 || (new_count / 1000) != ((new_count - count) / 1000) {
log::debug!("Dropped events count reached: {}", new_count); log::debug!("Dropped events count reached: {}", new_count);
} }
+2 -2
View File
@@ -1,4 +1,4 @@
// 公用模块 - 包含流处理相关的通用功能 // Common modules - contains common functionality related to stream processing
pub mod config; pub mod config;
pub mod metrics; pub mod metrics;
pub mod constants; pub mod constants;
@@ -6,7 +6,7 @@ pub mod subscription;
pub mod event_processor; pub mod event_processor;
pub mod simd_utils; pub mod simd_utils;
// 重新导出主要类型 // Re-export main types
pub use config::*; pub use config::*;
pub use metrics::*; pub use metrics::*;
pub use constants::*; pub use constants::*;
@@ -1,33 +1,33 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::time::Instant; use std::time::Instant;
/// 高性能时钟管理器,减少系统调用开销并最小化延迟 /// High-performance clock manager, reduces system call overhead and minimizes latency
#[derive(Debug)] #[derive(Debug)]
pub struct HighPerformanceClock { pub struct HighPerformanceClock {
/// 基准时间点(程序启动时的单调时钟时间) /// Base time point (monotonic clock time at program startup)
base_instant: Instant, base_instant: Instant,
/// 基准时间点对应的UTC时间戳(微秒) /// UTC timestamp (microseconds) corresponding to base time point
base_timestamp_us: i64, base_timestamp_us: i64,
/// 上次校准时间(用于检测是否需要重新校准) /// Last calibration time (used to detect if recalibration is needed)
last_calibration: Instant, last_calibration: Instant,
/// 校准间隔(秒) /// Calibration interval (seconds)
calibration_interval_secs: u64, calibration_interval_secs: u64,
} }
impl HighPerformanceClock { impl HighPerformanceClock {
/// 创建新的高性能时钟 /// Create new high-performance clock
pub fn new() -> Self { pub fn new() -> Self {
Self::new_with_calibration_interval(300) // 默认5分钟校准一次 Self::new_with_calibration_interval(300) // Default: calibrate every 5 minutes
} }
/// 创建带自定义校准间隔的高性能时钟 /// Create high-performance clock with custom calibration interval
pub fn new_with_calibration_interval(calibration_interval_secs: u64) -> Self { pub fn new_with_calibration_interval(calibration_interval_secs: u64) -> Self {
// 通过多次采样来减少初始化误差 // Reduce initialization error through multiple samples
let mut best_offset = i64::MAX; let mut best_offset = i64::MAX;
let mut best_instant = Instant::now(); let mut best_instant = Instant::now();
let mut best_timestamp = chrono::Utc::now().timestamp_micros(); let mut best_timestamp = chrono::Utc::now().timestamp_micros();
// 进行3次采样,选择延迟最小的 // Perform 3 samples, choose the one with minimum latency
for _ in 0..3 { for _ in 0..3 {
let instant_before = Instant::now(); let instant_before = Instant::now();
let timestamp = chrono::Utc::now().timestamp_micros(); let timestamp = chrono::Utc::now().timestamp_micros();
@@ -50,35 +50,35 @@ impl HighPerformanceClock {
} }
} }
/// 获取当前时间戳(微秒),使用单调时钟计算,避免系统调用 /// Get current timestamp (microseconds), calculated using monotonic clock to avoid system calls
#[inline(always)] #[inline(always)]
pub fn now_micros(&self) -> i64 { pub fn now_micros(&self) -> i64 {
let elapsed = self.base_instant.elapsed(); let elapsed = self.base_instant.elapsed();
self.base_timestamp_us + elapsed.as_micros() as i64 self.base_timestamp_us + elapsed.as_micros() as i64
} }
/// 获取高精度当前时间戳(微秒),在必要时进行校准 /// Get high-precision current timestamp (microseconds), calibrate when necessary
pub fn now_micros_with_calibration(&mut self) -> i64 { pub fn now_micros_with_calibration(&mut self) -> i64 {
// 检查是否需要重新校准 // Check if recalibration is needed
if self.last_calibration.elapsed().as_secs() >= self.calibration_interval_secs { if self.last_calibration.elapsed().as_secs() >= self.calibration_interval_secs {
self.recalibrate(); self.recalibrate();
} }
self.now_micros() self.now_micros()
} }
/// 重新校准时钟,减少累积漂移 /// Recalibrate clock to reduce accumulated drift
fn recalibrate(&mut self) { fn recalibrate(&mut self) {
let current_monotonic = Instant::now(); let current_monotonic = Instant::now();
let current_utc = chrono::Utc::now().timestamp_micros(); let current_utc = chrono::Utc::now().timestamp_micros();
// 计算预期的UTC时间戳(基于单调时钟) // Calculate expected UTC timestamp (based on monotonic clock)
let expected_utc = self.base_timestamp_us let expected_utc = self.base_timestamp_us
+ current_monotonic.duration_since(self.base_instant).as_micros() as i64; + current_monotonic.duration_since(self.base_instant).as_micros() as i64;
// 计算漂移量 // Calculate drift amount
let drift_us = current_utc - expected_utc; let drift_us = current_utc - expected_utc;
// 如果漂移超过1毫秒,进行校准 // If drift exceeds 1 millisecond, perform calibration
if drift_us.abs() > 1000 { if drift_us.abs() > 1000 {
self.base_instant = current_monotonic; self.base_instant = current_monotonic;
self.base_timestamp_us = current_utc; self.base_timestamp_us = current_utc;
@@ -87,20 +87,20 @@ impl HighPerformanceClock {
self.last_calibration = current_monotonic; self.last_calibration = current_monotonic;
} }
/// 计算从指定时间戳到现在的消耗时间(微秒) /// Calculate elapsed time (microseconds) from specified timestamp to now
#[inline(always)] #[inline(always)]
pub fn elapsed_micros_since(&self, start_timestamp_us: i64) -> i64 { pub fn elapsed_micros_since(&self, start_timestamp_us: i64) -> i64 {
self.now_micros() - start_timestamp_us self.now_micros() - start_timestamp_us
} }
/// 获取高精度纳秒时间戳 /// Get high-precision nanosecond timestamp
#[inline(always)] #[inline(always)]
pub fn now_nanos(&self) -> i128 { pub fn now_nanos(&self) -> i128 {
let elapsed = self.base_instant.elapsed(); let elapsed = self.base_instant.elapsed();
(self.base_timestamp_us as i128 * 1000) + elapsed.as_nanos() as i128 (self.base_timestamp_us as i128 * 1000) + elapsed.as_nanos() as i128
} }
/// 重置时钟(强制重新初始化) /// Reset clock (force re-initialization)
pub fn reset(&mut self) { pub fn reset(&mut self) {
*self = Self::new_with_calibration_interval(self.calibration_interval_secs); *self = Self::new_with_calibration_interval(self.calibration_interval_secs);
} }
@@ -112,11 +112,11 @@ impl Default for HighPerformanceClock {
} }
} }
/// 全局高性能时钟实例 /// Global high-performance clock instance
static HIGH_PERF_CLOCK: once_cell::sync::OnceCell<HighPerformanceClock> = static HIGH_PERF_CLOCK: once_cell::sync::OnceCell<HighPerformanceClock> =
once_cell::sync::OnceCell::new(); once_cell::sync::OnceCell::new();
/// 获取全局高性能时钟实例(最简单的实现) /// Get global high-performance clock instance (simplest implementation)
#[inline(always)] #[inline(always)]
pub fn get_high_perf_clock() -> i64 { pub fn get_high_perf_clock() -> i64 {
let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new); let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new);
+18 -8
View File
@@ -30,7 +30,7 @@ impl EventMetadataPool {
} }
pub fn release(&self, metadata: EventMetadata) { pub fn release(&self, metadata: EventMetadata) {
// 如果队列已满,push 会失败,但不会阻塞 // If queue is full, push will fail but won't block
let _ = self.pool.push(metadata); let _ = self.pool.push(metadata);
} }
} }
@@ -63,6 +63,7 @@ pub enum EventType {
// PumpSwap events // PumpSwap events
#[default] #[default]
PumpSwapBuy, PumpSwapBuy,
PumpSwapBuyExactQuoteIn,
PumpSwapSell, PumpSwapSell,
PumpSwapCreatePool, PumpSwapCreatePool,
PumpSwapDeposit, PumpSwapDeposit,
@@ -168,6 +169,7 @@ impl fmt::Display for EventType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
EventType::PumpSwapBuy => write!(f, "PumpSwapBuy"), EventType::PumpSwapBuy => write!(f, "PumpSwapBuy"),
EventType::PumpSwapBuyExactQuoteIn => write!(f, "PumpSwapBuyExactQuoteIn"),
EventType::PumpSwapSell => write!(f, "PumpSwapSell"), EventType::PumpSwapSell => write!(f, "PumpSwapSell"),
EventType::PumpSwapCreatePool => write!(f, "PumpSwapCreatePool"), EventType::PumpSwapCreatePool => write!(f, "PumpSwapCreatePool"),
EventType::PumpSwapDeposit => write!(f, "PumpSwapDeposit"), EventType::PumpSwapDeposit => write!(f, "PumpSwapDeposit"),
@@ -301,7 +303,7 @@ pub struct SwapData {
pub struct EventMetadata { pub struct EventMetadata {
pub signature: Signature, pub signature: Signature,
pub slot: u64, pub slot: u64,
pub transaction_index: Option<u64>, // 新增:交易在slot中的索引 pub transaction_index: Option<u64>, // New: transaction index within the slot
pub block_time: i64, pub block_time: i64,
pub block_time_ms: i64, pub block_time_ms: i64,
pub recv_us: i64, pub recv_us: i64,
@@ -380,7 +382,7 @@ pub fn parse_swap_data_from_next_instructions(
description: None, description: None,
}; };
// 先根据 event 取出关键信息 // First extract key information from event
// let mut user: Option<Pubkey> = None; // let mut user: Option<Pubkey> = None;
let mut from_mint: Option<Pubkey> = None; let mut from_mint: Option<Pubkey> = None;
let mut to_mint: Option<Pubkey> = None; let mut to_mint: Option<Pubkey> = None;
@@ -407,6 +409,10 @@ pub fn parse_swap_data_from_next_instructions(
swap_data.from_mint = e.quote_mint; swap_data.from_mint = e.quote_mint;
swap_data.to_mint = e.base_mint; swap_data.to_mint = e.base_mint;
} }
DexEvent::PumpSwapBuyExactQuoteInEvent(e) => {
swap_data.from_mint = e.quote_mint;
swap_data.to_mint = e.base_mint;
}
DexEvent::PumpSwapSellEvent(e) => { DexEvent::PumpSwapSellEvent(e) => {
swap_data.from_mint = e.base_mint; swap_data.from_mint = e.base_mint;
swap_data.to_mint = e.quote_mint; swap_data.to_mint = e.quote_mint;
@@ -457,7 +463,7 @@ pub fn parse_swap_data_from_next_instructions(
let to_mint = to_mint.unwrap_or_default(); let to_mint = to_mint.unwrap_or_default();
let from_mint = from_mint.unwrap_or_default(); let from_mint = from_mint.unwrap_or_default();
// 单次循环完成提取和判断 // Single loop to complete extraction and validation
for instruction in inner_instruction.instructions.iter().skip((current_index + 1) as usize) { for instruction in inner_instruction.instructions.iter().skip((current_index + 1) as usize) {
let compiled = &instruction.instruction; let compiled = &instruction.instruction;
let program_id = accounts[compiled.program_id_index as usize]; let program_id = accounts[compiled.program_id_index as usize];
@@ -466,7 +472,7 @@ pub fn parse_swap_data_from_next_instructions(
} }
let data = &compiled.data; let data = &compiled.data;
// 使用 SIMD 验证数据格式 // Use SIMD to validate data format
if !SimdUtils::validate_data_format(data, 8) { if !SimdUtils::validate_data_format(data, 8) {
continue; continue;
} }
@@ -550,7 +556,7 @@ pub fn parse_swap_data_from_next_grpc_instructions(
description: None, description: None,
}; };
// 先根据 event 取出关键信息 // First extract key information from event
// let mut user: Option<Pubkey> = None; // let mut user: Option<Pubkey> = None;
let mut from_mint: Option<Pubkey> = None; let mut from_mint: Option<Pubkey> = None;
let mut to_mint: Option<Pubkey> = None; let mut to_mint: Option<Pubkey> = None;
@@ -577,6 +583,10 @@ pub fn parse_swap_data_from_next_grpc_instructions(
swap_data.from_mint = e.quote_mint; swap_data.from_mint = e.quote_mint;
swap_data.to_mint = e.base_mint; swap_data.to_mint = e.base_mint;
} }
DexEvent::PumpSwapBuyExactQuoteInEvent(e) => {
swap_data.from_mint = e.quote_mint;
swap_data.to_mint = e.base_mint;
}
DexEvent::PumpSwapSellEvent(e) => { DexEvent::PumpSwapSellEvent(e) => {
swap_data.from_mint = e.base_mint; swap_data.from_mint = e.base_mint;
swap_data.to_mint = e.quote_mint; swap_data.to_mint = e.quote_mint;
@@ -627,7 +637,7 @@ pub fn parse_swap_data_from_next_grpc_instructions(
let to_mint = to_mint.unwrap_or_default(); let to_mint = to_mint.unwrap_or_default();
let from_mint = from_mint.unwrap_or_default(); let from_mint = from_mint.unwrap_or_default();
// 单次循环完成提取和判断 // Single loop to complete extraction and validation
for instruction in inner_instruction.instructions.iter().skip((current_index + 1) as usize) { for instruction in inner_instruction.instructions.iter().skip((current_index + 1) as usize) {
let compiled = &instruction; let compiled = &instruction;
let program_id = accounts[compiled.program_id_index as usize]; let program_id = accounts[compiled.program_id_index as usize];
@@ -636,7 +646,7 @@ pub fn parse_swap_data_from_next_grpc_instructions(
} }
let data = &compiled.data; let data = &compiled.data;
// 使用 SIMD 验证数据格式 // Use SIMD to validate data format
if !SimdUtils::validate_data_format(data, 8) { if !SimdUtils::validate_data_format(data, 8) {
continue; continue;
} }
+10 -10
View File
@@ -1,11 +1,11 @@
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
/// 获取当前时间戳 /// Get current timestamp
pub fn current_timestamp() -> i64 { pub fn current_timestamp() -> i64 {
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs() as i64 SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs() as i64
} }
/// 从字节数组中提取鉴别器和剩余数据 /// Extract discriminator and remaining data from byte array
pub fn extract_discriminator(length: usize, data: &[u8]) -> Option<(&[u8], &[u8])> { pub fn extract_discriminator(length: usize, data: &[u8]) -> Option<(&[u8], &[u8])> {
if data.len() < length { if data.len() < length {
return None; return None;
@@ -13,18 +13,18 @@ pub fn extract_discriminator(length: usize, data: &[u8]) -> Option<(&[u8], &[u8]
Some((&data[..length], &data[length..])) Some((&data[..length], &data[length..]))
} }
/// 从日志中提取程序数据 /// Extract program data from log
pub fn extract_program_data(log: &str) -> Option<&str> { pub fn extract_program_data(log: &str) -> Option<&str> {
const PROGRAM_DATA_PREFIX: &str = "Program data: "; const PROGRAM_DATA_PREFIX: &str = "Program data: ";
log.strip_prefix(PROGRAM_DATA_PREFIX) log.strip_prefix(PROGRAM_DATA_PREFIX)
} }
/// 从日志中提取程序日志 /// Extract program log from log
pub fn extract_program_log<'a>(log: &'a str, prefix: &str) -> Option<&'a str> { pub fn extract_program_log<'a>(log: &'a str, prefix: &str) -> Option<&'a str> {
log.strip_prefix(prefix) log.strip_prefix(prefix)
} }
/// 安全地从字节数组中读取u64 /// Safely read u64 from byte array
pub fn read_u64_le(data: &[u8], offset: usize) -> Option<u64> { pub fn read_u64_le(data: &[u8], offset: usize) -> Option<u64> {
if data.len() < offset + 8 { if data.len() < offset + 8 {
return None; return None;
@@ -71,7 +71,7 @@ pub fn read_option_bool(data: &[u8], offset: &mut usize) -> Option<Option<bool>>
Some(Some(value != 0)) Some(Some(value != 0))
} }
/// 安全地从字节数组中读取u32 /// Safely read u32 from byte array
pub fn read_u32_le(data: &[u8], offset: usize) -> Option<u32> { pub fn read_u32_le(data: &[u8], offset: usize) -> Option<u32> {
if data.len() < offset + 4 { if data.len() < offset + 4 {
return None; return None;
@@ -80,7 +80,7 @@ pub fn read_u32_le(data: &[u8], offset: usize) -> Option<u32> {
Some(u32::from_le_bytes(bytes)) Some(u32::from_le_bytes(bytes))
} }
/// 安全地从字节数组中读取u16 /// Safely read u16 from byte array
pub fn read_u16_le(data: &[u8], offset: usize) -> Option<u16> { pub fn read_u16_le(data: &[u8], offset: usize) -> Option<u16> {
if data.len() < offset + 2 { if data.len() < offset + 2 {
return None; return None;
@@ -89,17 +89,17 @@ pub fn read_u16_le(data: &[u8], offset: usize) -> Option<u16> {
Some(u16::from_le_bytes(bytes)) Some(u16::from_le_bytes(bytes))
} }
/// 安全地从字节数组中读取u8 /// Safely read u8 from byte array
pub fn read_u8(data: &[u8], offset: usize) -> Option<u8> { pub fn read_u8(data: &[u8], offset: usize) -> Option<u8> {
data.get(offset).copied() data.get(offset).copied()
} }
/// 验证账户索引的有效性 /// Validate account index validity
pub fn validate_account_indices(indices: &[u8], account_count: usize) -> bool { pub fn validate_account_indices(indices: &[u8], account_count: usize) -> bool {
indices.iter().all(|&idx| (idx as usize) < account_count) indices.iter().all(|&idx| (idx as usize) < account_count)
} }
/// 格式化公钥为短字符串 /// Format pubkey as short string
pub fn format_pubkey_short(pubkey: &solana_sdk::pubkey::Pubkey) -> String { pub fn format_pubkey_short(pubkey: &solana_sdk::pubkey::Pubkey) -> String {
let s = pubkey.to_string(); let s = pubkey.to_string();
if s.len() <= 8 { if s.len() <= 8 {
@@ -14,7 +14,7 @@ use spl_token_2022::{
state::{Account as Account2022, Mint as Mint2022}, state::{Account as Account2022, Mint as Mint2022},
}; };
/// 通用账户事件 /// Generic account event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct TokenAccountEvent { pub struct TokenAccountEvent {
pub metadata: EventMetadata, pub metadata: EventMetadata,
@@ -63,39 +63,39 @@ impl AccountEventParser {
) -> Option<DexEvent> { ) -> Option<DexEvent> {
use crate::streaming::event_parser::core::dispatcher::EventDispatcher; use crate::streaming::event_parser::core::dispatcher::EventDispatcher;
// 1. 尝试从账户 discriminator 解析(协议特定账户) // 1. Try to parse from account discriminator (protocol-specific accounts)
if account.data.len() >= 8 { if account.data.len() >= 8 {
let discriminator = &account.data[0..8]; let discriminator = &account.data[0..8];
// 尝试识别协议类型 // Try to identify protocol type
if let Some(protocol) = EventDispatcher::match_protocol_by_program_id(&account.owner) { if let Some(protocol) = EventDispatcher::match_protocol_by_program_id(&account.owner) {
// 检查是否在请求的协议列表中 // Check if in the requested protocol list
if protocols.contains(&protocol) { if protocols.contains(&protocol) {
// 构建临时元数据(protocol会被dispatcher设置,event_type会在parser中设置) // Build temporary metadata (protocol will be set by dispatcher, event_type will be set by parser)
let metadata = EventMetadata { let metadata = EventMetadata {
slot: account.slot, slot: account.slot,
signature: account.signature, signature: account.signature,
protocol: ProtocolType::Common, // 会被 EventDispatcher::dispatch_account 设置 protocol: ProtocolType::Common, // Will be set by EventDispatcher::dispatch_account
event_type: EventType::default(), // 会被具体 parser 设置 event_type: EventType::default(), // Will be set by specific parser
program_id: account.owner, program_id: account.owner,
recv_us: account.recv_us, recv_us: account.recv_us,
handle_us: elapsed_micros_since(account.recv_us), handle_us: elapsed_micros_since(account.recv_us),
..Default::default() ..Default::default()
}; };
// 使用 dispatcher 解析 // Use dispatcher to parse
if let Some(event) = EventDispatcher::dispatch_account( if let Some(event) = EventDispatcher::dispatch_account(
protocol, protocol,
discriminator, discriminator,
&account, &account,
metadata, metadata,
) { ) {
// 应用事件类型过滤 // Apply event type filter
if let Some(filter) = event_type_filter { if let Some(filter) = event_type_filter {
if filter.include.contains(&event.metadata().event_type) { if filter.include.contains(&event.metadata().event_type) {
return Some(event); return Some(event);
} }
// 不匹配过滤器,继续尝试其他解析方式 // Doesn't match filter, continue trying other parsing methods
} else { } else {
return Some(event); return Some(event);
} }
@@ -104,8 +104,8 @@ impl AccountEventParser {
} }
} }
// 2. 尝试解析特殊账户类型(TokenNonce等) // 2. Try to parse special account types (Token, Nonce, etc.)
// 这些是通用的,不属于特定协议 // These are generic and don't belong to specific protocols
let metadata = EventMetadata { let metadata = EventMetadata {
slot: account.slot, slot: account.slot,
signature: account.signature, signature: account.signature,
@@ -117,7 +117,7 @@ impl AccountEventParser {
..Default::default() ..Default::default()
}; };
// 尝试解析 Nonce 账户 // Try to parse Nonce account
if let Some(event) = Self::parse_nonce_account_event(&account, metadata.clone()) { if let Some(event) = Self::parse_nonce_account_event(&account, metadata.clone()) {
if let Some(filter) = event_type_filter { if let Some(filter) = event_type_filter {
if filter.include.contains(&event.metadata().event_type) { if filter.include.contains(&event.metadata().event_type) {
@@ -128,7 +128,7 @@ impl AccountEventParser {
} }
} }
// 尝试解析 Token 账户 // Try to parse Token account
if let Some(event) = Self::parse_token_account_event(&account, metadata) { if let Some(event) = Self::parse_token_account_event(&account, metadata) {
if let Some(filter) = event_type_filter { if let Some(filter) = event_type_filter {
if filter.include.contains(&event.metadata().event_type) { if filter.include.contains(&event.metadata().event_type) {
@@ -11,21 +11,21 @@ use solana_sdk::pubkey::Pubkey;
pub const COMPUTE_BUDGET_PROGRAM_ID: Pubkey = pub const COMPUTE_BUDGET_PROGRAM_ID: Pubkey =
solana_sdk::pubkey!("ComputeBudget111111111111111111111111111111"); solana_sdk::pubkey!("ComputeBudget111111111111111111111111111111");
/// SetComputeUnitLimit 事件 /// SetComputeUnitLimit event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct SetComputeUnitLimitEvent { pub struct SetComputeUnitLimitEvent {
#[borsh(skip)] #[borsh(skip)]
pub metadata: EventMetadata, pub metadata: EventMetadata,
/// 请求的计算单元数量 /// Number of compute units requested
pub units: u32, pub units: u32,
} }
/// SetComputeUnitPrice 事件 /// SetComputeUnitPrice event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct SetComputeUnitPriceEvent { pub struct SetComputeUnitPriceEvent {
#[borsh(skip)] #[borsh(skip)]
pub metadata: EventMetadata, pub metadata: EventMetadata,
/// 每个计算单元的价格 (micro-lamports) /// Price per compute unit (micro-lamports)
pub micro_lamports: u64, pub micro_lamports: u64,
} }
@@ -43,7 +43,7 @@ impl CommonEventParser {
DexEvent::BlockMetaEvent(block_meta_event) DexEvent::BlockMetaEvent(block_meta_event)
} }
/// 解析 Compute Budget 指令 /// Parse Compute Budget instruction
pub fn parse_compute_budget_instruction( pub fn parse_compute_budget_instruction(
instruction_data: &[u8], instruction_data: &[u8],
mut metadata: EventMetadata, mut metadata: EventMetadata,
@@ -52,10 +52,10 @@ impl CommonEventParser {
return None; return None;
} }
// 设置 protocol Common // Set protocol to Common
metadata.protocol = ProtocolType::Common; metadata.protocol = ProtocolType::Common;
// Compute Budget 指令使用单字节判别器 // Compute Budget instructions use single-byte discriminator
match instruction_data[0] { match instruction_data[0] {
// SetComputeUnitLimit: discriminator = 2 // SetComputeUnitLimit: discriminator = 2
2 => { 2 => {
+48 -48
View File
@@ -1,11 +1,11 @@
//! 中心事件解析调度器 //! Central event parsing dispatcher
//! //!
//! 根据协议类型路由到对应的解析函数,替代原有的静态 CONFIGS 数组架构 //! Routes to corresponding parsing functions based on protocol type, replacing the original static CONFIGS array architecture
//! //!
//! ## 设计原则 //! ## Design Principles
//! - **单一职责**: 每个函数只负责一件事(路由、解析、合并分离) //! - **Single Responsibility**: Each function is responsible for one thing (routing, parsing, merging separated)
//! - **灵活性**: 调用方可以选择是否合并,或自定义合并逻辑 //! - **Flexibility**: Callers can choose whether to merge or customize merge logic
//! - **可测试性**: 每个函数都可以独立测试 //! - **Testability**: Each function can be tested independently
use crate::streaming::event_parser::{ use crate::streaming::event_parser::{
common::EventMetadata, common::EventMetadata,
@@ -19,23 +19,23 @@ use crate::streaming::event_parser::{
}; };
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
/// 中心事件解析调度器 /// Central event parsing dispatcher
/// ///
/// 负责将解析请求路由到对应协议的解析函数 /// Responsible for routing parsing requests to corresponding protocol parsing functions
pub struct EventDispatcher; pub struct EventDispatcher;
impl EventDispatcher { impl EventDispatcher {
/// 解析 instruction 事件(只解析,不合并) /// Parse instruction event (parse only, no merging)
/// ///
/// # 参数 /// # Parameters
/// - `protocol`: 协议类型 /// - `protocol`: Protocol type
/// - `instruction_discriminator`: 指令判别器 (8 bytes) /// - `instruction_discriminator`: Instruction discriminator (8 bytes)
/// - `instruction_data`: 指令数据 /// - `instruction_data`: Instruction data
/// - `accounts`: 账户公钥列表 /// - `accounts`: Account public key list
/// - `metadata`: 事件元数据 /// - `metadata`: Event metadata
/// ///
/// # 返回 /// # Returns
/// 解析成功返回 `Some(DexEvent)`,否则返回 `None` /// Returns `Some(DexEvent)` on successful parsing, otherwise `None`
#[inline] #[inline]
pub fn dispatch_instruction( pub fn dispatch_instruction(
protocol: Protocol, protocol: Protocol,
@@ -44,7 +44,7 @@ impl EventDispatcher {
accounts: &[Pubkey], accounts: &[Pubkey],
mut metadata: EventMetadata, mut metadata: EventMetadata,
) -> Option<DexEvent> { ) -> Option<DexEvent> {
// 根据协议类型设置 metadata.protocol // Set metadata.protocol based on protocol type
use crate::streaming::event_parser::common::ProtocolType; use crate::streaming::event_parser::common::ProtocolType;
metadata.protocol = match protocol { metadata.protocol = match protocol {
Protocol::PumpFun => ProtocolType::PumpFun, Protocol::PumpFun => ProtocolType::PumpFun,
@@ -102,16 +102,16 @@ impl EventDispatcher {
} }
} }
/// 解析 inner instruction 事件(只解析,不合并) /// Parse inner instruction event (parse only, no merging)
/// ///
/// # 参数 /// # Parameters
/// - `protocol`: 协议类型 /// - `protocol`: Protocol type
/// - `inner_instruction_discriminator`: 内联指令判别器 (16 bytes) /// - `inner_instruction_discriminator`: Inner instruction discriminator (16 bytes)
/// - `inner_instruction_data`: 内联指令数据 /// - `inner_instruction_data`: Inner instruction data
/// - `metadata`: 事件元数据 /// - `metadata`: Event metadata
/// ///
/// # 返回 /// # Returns
/// 解析成功返回 `Some(DexEvent)`,否则返回 `None` /// Returns `Some(DexEvent)` on successful parsing, otherwise `None`
#[inline] #[inline]
pub fn dispatch_inner_instruction( pub fn dispatch_inner_instruction(
protocol: Protocol, protocol: Protocol,
@@ -119,7 +119,7 @@ impl EventDispatcher {
inner_instruction_data: &[u8], inner_instruction_data: &[u8],
mut metadata: EventMetadata, mut metadata: EventMetadata,
) -> Option<DexEvent> { ) -> Option<DexEvent> {
// 根据协议类型设置 metadata.protocol // Set metadata.protocol based on protocol type
use crate::streaming::event_parser::common::ProtocolType; use crate::streaming::event_parser::common::ProtocolType;
metadata.protocol = match protocol { metadata.protocol = match protocol {
Protocol::PumpFun => ProtocolType::PumpFun, Protocol::PumpFun => ProtocolType::PumpFun,
@@ -170,7 +170,7 @@ impl EventDispatcher {
} }
} }
/// 通过 program_id 匹配协议类型 /// Match protocol type by program_id
#[inline] #[inline]
pub fn match_protocol_by_program_id(program_id: &Pubkey) -> Option<Protocol> { pub fn match_protocol_by_program_id(program_id: &Pubkey) -> Option<Protocol> {
if program_id == &pumpfun::PUMPFUN_PROGRAM_ID { if program_id == &pumpfun::PUMPFUN_PROGRAM_ID {
@@ -192,20 +192,20 @@ impl EventDispatcher {
} }
} }
/// 检查是否为 Compute Budget Program /// Check if it's a Compute Budget Program
#[inline] #[inline]
pub fn is_compute_budget_program(program_id: &Pubkey) -> bool { pub fn is_compute_budget_program(program_id: &Pubkey) -> bool {
program_id == &COMPUTE_BUDGET_PROGRAM_ID program_id == &COMPUTE_BUDGET_PROGRAM_ID
} }
/// 解析 Compute Budget 指令 /// Parse Compute Budget instruction
/// ///
/// # 参数 /// # Parameters
/// - `instruction_data`: 指令数据 /// - `instruction_data`: Instruction data
/// - `metadata`: 事件元数据 /// - `metadata`: Event metadata
/// ///
/// # 返回 /// # Returns
/// 解析成功返回 `Some(DexEvent)`,否则返回 `None` /// Returns `Some(DexEvent)` on successful parsing, otherwise `None`
#[inline] #[inline]
pub fn dispatch_compute_budget_instruction( pub fn dispatch_compute_budget_instruction(
instruction_data: &[u8], instruction_data: &[u8],
@@ -214,7 +214,7 @@ impl EventDispatcher {
CommonEventParser::parse_compute_budget_instruction(instruction_data, metadata) CommonEventParser::parse_compute_budget_instruction(instruction_data, metadata)
} }
/// 获取指定协议的 program_id /// Get program_id for specified protocol
#[inline] #[inline]
pub fn get_program_id(protocol: Protocol) -> Pubkey { pub fn get_program_id(protocol: Protocol) -> Pubkey {
match protocol { match protocol {
@@ -228,30 +228,30 @@ impl EventDispatcher {
} }
} }
/// 批量获取 program_ids /// Batch get program_ids
pub fn get_program_ids(protocols: &[Protocol]) -> Vec<Pubkey> { pub fn get_program_ids(protocols: &[Protocol]) -> Vec<Pubkey> {
protocols.iter().map(|p| Self::get_program_id(p.clone())).collect() protocols.iter().map(|p| Self::get_program_id(p.clone())).collect()
} }
/// 解析账户数据 /// Parse account data
/// ///
/// 根据账户的 discriminator 路由到对应协议的账户解析函数 /// Route to corresponding protocol account parsing function based on account discriminator
/// ///
/// # 参数 /// # Parameters
/// - `protocol`: 协议类型 /// - `protocol`: Protocol type
/// - `discriminator`: 账户判别器 /// - `discriminator`: Account discriminator
/// - `account`: 账户信息 /// - `account`: Account information
/// - `metadata`: 事件元数据 /// - `metadata`: Event metadata
/// ///
/// # 返回 /// # Returns
/// 解析成功返回 `Some(DexEvent)`,否则返回 `None` /// Returns `Some(DexEvent)` on successful parsing, otherwise `None`
pub fn dispatch_account( pub fn dispatch_account(
protocol: Protocol, protocol: Protocol,
discriminator: &[u8], discriminator: &[u8],
account: &crate::streaming::grpc::AccountPretty, account: &crate::streaming::grpc::AccountPretty,
mut metadata: crate::streaming::event_parser::common::EventMetadata, mut metadata: crate::streaming::event_parser::common::EventMetadata,
) -> Option<DexEvent> { ) -> Option<DexEvent> {
// 根据协议类型设置 metadata.protocol // Set metadata.protocol based on protocol type
use crate::streaming::event_parser::common::ProtocolType; use crate::streaming::event_parser::common::ProtocolType;
metadata.protocol = match protocol { metadata.protocol = match protocol {
Protocol::PumpFun => ProtocolType::PumpFun, Protocol::PumpFun => ProtocolType::PumpFun,
@@ -281,7 +281,7 @@ impl EventDispatcher {
raydium_amm_v4::parse_raydium_amm_v4_account_data(discriminator, account, metadata) raydium_amm_v4::parse_raydium_amm_v4_account_data(discriminator, account, metadata)
} }
Protocol::MeteoraDammV2 => { Protocol::MeteoraDammV2 => {
// Meteora DAMM 目前不需要解析账户数据,返回 None // Meteora DAMM currently doesn't need to parse account data, return None
None None
} }
} }
+54 -47
View File
@@ -42,7 +42,7 @@ impl EventParser {
transaction_index: Option<u64>, transaction_index: Option<u64>,
callback: Arc<dyn Fn(DexEvent) + Send + Sync>, callback: Arc<dyn Fn(DexEvent) + Send + Sync>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// 创建适配器回调,将所有权回调转换为引用回调 // Create adapter callback to convert ownership callback to reference callback
let adapter_callback = Arc::new(move |event: &DexEvent| { let adapter_callback = Arc::new(move |event: &DexEvent| {
callback(event.clone()); callback(event.clone());
}); });
@@ -69,7 +69,7 @@ impl EventParser {
Vec::with_capacity(message.account_keys.len() + address_table_lookups.len()); Vec::with_capacity(message.account_keys.len() + address_table_lookups.len());
accounts_bytes.extend_from_slice(&message.account_keys); accounts_bytes.extend_from_slice(&message.account_keys);
accounts_bytes.extend(address_table_lookups); accounts_bytes.extend(address_table_lookups);
// 转换为 Pubkey // Convert to Pubkey
let accounts: Vec<Pubkey> = accounts_bytes let accounts: Vec<Pubkey> = accounts_bytes
.iter() .iter()
.filter_map(|account| { .filter_map(|account| {
@@ -80,7 +80,7 @@ impl EventParser {
} }
}) })
.collect(); .collect();
// 解析指令事件 // Parse instruction events
let instructions = &message.instructions; let instructions = &message.instructions;
Self::parse_instruction_events_from_grpc_transaction( Self::parse_instruction_events_from_grpc_transaction(
protocols, protocols,
@@ -122,28 +122,28 @@ impl EventParser {
transaction_index: Option<u64>, transaction_index: Option<u64>,
callback: Arc<dyn Fn(DexEvent) + Send + Sync>, callback: Arc<dyn Fn(DexEvent) + Send + Sync>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// 创建适配器回调,将所有权回调转换为引用回调 // Create adapter callback to convert ownership callback to reference callback
let adapter_callback = Arc::new(move |event: &DexEvent| { let adapter_callback = Arc::new(move |event: &DexEvent| {
callback(event.clone()); callback(event.clone());
}); });
// 获取交易的指令和账户 // Get transaction instructions and accounts
let compiled_instructions = transaction.message.instructions(); let compiled_instructions = transaction.message.instructions();
let mut accounts: Vec<Pubkey> = accounts.to_vec(); let mut accounts: Vec<Pubkey> = accounts.to_vec();
// 检查交易中是否包含程序 // Check if transaction contains the program
let has_program = accounts let has_program = accounts
.iter() .iter()
.any(|account| Self::should_handle(protocols, event_type_filter, account)); .any(|account| Self::should_handle(protocols, event_type_filter, account));
if has_program { if has_program {
// 解析每个指令 // Parse each instruction
for (index, instruction) in compiled_instructions.iter().enumerate() { for (index, instruction) in compiled_instructions.iter().enumerate() {
if let Some(program_id) = accounts.get(instruction.program_id_index as usize) { if let Some(program_id) = accounts.get(instruction.program_id_index as usize) {
let program_id = *program_id; // 克隆程序ID,避免借用冲突 let program_id = *program_id; // Clone program ID to avoid borrow conflicts
let inner_instructions = inner_instructions let inner_instructions = inner_instructions
.iter() .iter()
.find(|inner_instruction| inner_instruction.index == index as u8); .find(|inner_instruction| inner_instruction.index == index as u8);
if Self::should_handle(protocols, event_type_filter, &program_id) { if Self::should_handle(protocols, event_type_filter, &program_id) {
let max_idx = instruction.accounts.iter().max().unwrap_or(&0); let max_idx = instruction.accounts.iter().max().unwrap_or(&0);
// 补齐accounts(使用Pubkey::default()) // Pad accounts (using Pubkey::default())
if *max_idx as usize >= accounts.len() { if *max_idx as usize >= accounts.len() {
accounts.resize(*max_idx as usize + 1, Pubkey::default()); accounts.resize(*max_idx as usize + 1, Pubkey::default());
} }
@@ -216,22 +216,22 @@ impl EventParser {
transaction_index: Option<u64>, transaction_index: Option<u64>,
callback: Arc<dyn for<'a> Fn(&'a DexEvent) + Send + Sync>, callback: Arc<dyn for<'a> Fn(&'a DexEvent) + Send + Sync>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// 获取交易的指令和账户 // Get transaction instructions and accounts
let mut accounts = accounts.to_vec(); let mut accounts = accounts.to_vec();
// 检查交易中是否包含程序 // Check if transaction contains the program
let has_program = accounts let has_program = accounts
.iter() .iter()
.any(|account| Self::should_handle(protocols, event_type_filter, account)); .any(|account| Self::should_handle(protocols, event_type_filter, account));
if has_program { if has_program {
// 解析每个指令 // Parse each instruction
for (index, instruction) in compiled_instructions.iter().enumerate() { for (index, instruction) in compiled_instructions.iter().enumerate() {
if let Some(program_id) = accounts.get(instruction.program_id_index as usize) { if let Some(program_id) = accounts.get(instruction.program_id_index as usize) {
let program_id = *program_id; // 克隆程序ID,避免借用冲突 let program_id = *program_id; // Clone program ID to avoid borrow conflicts
let inner_instructions = inner_instructions let inner_instructions = inner_instructions
.iter() .iter()
.find(|inner_instruction| inner_instruction.index == index as u32); .find(|inner_instruction| inner_instruction.index == index as u32);
let max_idx = instruction.accounts.iter().max().unwrap_or(&0); let max_idx = instruction.accounts.iter().max().unwrap_or(&0);
// 补齐accounts(使用Pubkey::default()) // Pad accounts (using Pubkey::default())
if *max_idx as usize >= accounts.len() { if *max_idx as usize >= accounts.len() {
accounts.resize(*max_idx as usize + 1, Pubkey::default()); accounts.resize(*max_idx as usize + 1, Pubkey::default());
} }
@@ -311,7 +311,7 @@ impl EventParser {
inner_instructions: Option<&yellowstone_grpc_proto::prelude::InnerInstructions>, inner_instructions: Option<&yellowstone_grpc_proto::prelude::InnerInstructions>,
callback: Arc<dyn for<'a> Fn(&'a DexEvent) + Send + Sync>, callback: Arc<dyn for<'a> Fn(&'a DexEvent) + Send + Sync>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// 添加边界检查以防止越界访问 // Add bounds check to prevent out-of-bounds access
let program_id_index = instruction.program_id_index as usize; let program_id_index = instruction.program_id_index as usize;
if program_id_index >= accounts.len() { if program_id_index >= accounts.len() {
return Ok(()); return Ok(());
@@ -328,11 +328,11 @@ impl EventParser {
_ => 8, _ => 8,
}; };
// 检查指令数据长度(至少需要 disc_len 字节的 discriminator // Check instruction data length (at least disc_len bytes for discriminator)
if !is_cu_program && instruction.data.len() < disc_len { if !is_cu_program && instruction.data.len() < disc_len {
return Ok(()); return Ok(());
} }
// 创建元数据 // Create metadata
let timestamp = block_time.unwrap_or(Timestamp { seconds: 0, nanos: 0 }); let timestamp = block_time.unwrap_or(Timestamp { seconds: 0, nanos: 0 });
let block_time_ms = timestamp.seconds * 1000 + (timestamp.nanos as i64) / 1_000_000; let block_time_ms = timestamp.seconds * 1000 + (timestamp.nanos as i64) / 1_000_000;
let metadata = EventMetadata::new( let metadata = EventMetadata::new(
@@ -359,24 +359,24 @@ impl EventParser {
return Ok(()); return Ok(());
} }
// 使用 EventDispatcher 匹配协议 // Use EventDispatcher to match protocol
let protocol = match EventDispatcher::match_protocol_by_program_id(&program_id) { let protocol = match EventDispatcher::match_protocol_by_program_id(&program_id) {
Some(p) => p, Some(p) => p,
None => return Ok(()), None => return Ok(()),
}; };
// 提取 discriminator 和数据 // Extract discriminator and data
let instruction_discriminator = &instruction.data[..disc_len]; let instruction_discriminator = &instruction.data[..disc_len];
let instruction_data = &instruction.data[disc_len..]; let instruction_data = &instruction.data[disc_len..];
// 构建账户公钥列表 // Build account pubkey list
let account_pubkeys: Vec<Pubkey> = instruction let account_pubkeys: Vec<Pubkey> = instruction
.accounts .accounts
.iter() .iter()
.filter_map(|&idx| accounts.get(idx as usize).copied()) .filter_map(|&idx| accounts.get(idx as usize).copied())
.collect(); .collect();
// 使用 EventDispatcher 解析 instruction 事件 // Use EventDispatcher to parse instruction event
let mut event = match EventDispatcher::dispatch_instruction( let mut event = match EventDispatcher::dispatch_instruction(
protocol.clone(), protocol.clone(),
instruction_discriminator, instruction_discriminator,
@@ -388,23 +388,23 @@ impl EventParser {
None => return Ok(()), None => return Ok(()),
}; };
// 处理 inner instructions - 查找对应的 CPI log 进行 merge // Process inner instructions - find corresponding CPI log for merge
// inner_index 有值时,只查找索引大于当前 inner_index 的 CPI log // When inner_index has a value, only search for CPI logs with index greater than current inner_index
let mut inner_instruction_event: Option<DexEvent> = None; let mut inner_instruction_event: Option<DexEvent> = None;
if let Some(inner_instructions_ref) = inner_instructions { if let Some(inner_instructions_ref) = inner_instructions {
let current_inner_idx = inner_index.unwrap_or(-1) as i32; let current_inner_idx = inner_index.unwrap_or(-1) as i32;
// 并行执行两个任务: 解析 inner event 和提取 swap_data // Execute two tasks in parallel: parse inner event and extract swap_data
let (inner_event_result, swap_data_result) = std::thread::scope(|s| { let (inner_event_result, swap_data_result) = std::thread::scope(|s| {
let inner_event_handle = s.spawn(|| { let inner_event_handle = s.spawn(|| {
for (idx, inner_instruction) in inner_instructions_ref.instructions.iter().enumerate() { for (idx, inner_instruction) in inner_instructions_ref.instructions.iter().enumerate() {
// 只查找索引大于当前 inner_index 的 CPI log // Only search for CPI logs with index greater than current inner_index
if (idx as i32) <= current_inner_idx { if (idx as i32) <= current_inner_idx {
continue; continue;
} }
let inner_data = &inner_instruction.data; let inner_data = &inner_instruction.data;
// 检查长度(需要 16 字节的 discriminator // Check length (needs 16 bytes for discriminator)
if inner_data.len() < 16 { if inner_data.len() < 16 {
continue; continue;
} }
@@ -436,7 +436,7 @@ impl EventParser {
} }
}); });
// 等待两个任务完成 // Wait for both tasks to complete
(inner_event_handle.join().unwrap(), swap_data_handle.join().unwrap()) (inner_event_handle.join().unwrap(), swap_data_handle.join().unwrap())
}); });
@@ -446,7 +446,7 @@ impl EventParser {
} }
} }
// 特殊处理: PumpFun MIGRATE 指令需要 inner instruction data // Special handling: PumpFun MIGRATE instruction requires inner instruction data
if matches!(protocol, Protocol::PumpFun) { if matches!(protocol, Protocol::PumpFun) {
const PUMPFUN_MIGRATE_IX: &[u8] = &[155, 234, 231, 146, 236, 158, 162, 30]; const PUMPFUN_MIGRATE_IX: &[u8] = &[155, 234, 231, 146, 236, 158, 162, 30];
if instruction_discriminator == PUMPFUN_MIGRATE_IX && inner_instruction_event.is_none() if instruction_discriminator == PUMPFUN_MIGRATE_IX && inner_instruction_event.is_none()
@@ -455,12 +455,12 @@ impl EventParser {
} }
} }
// 合并事件 // Merge events
if let Some(inner_instruction_event) = inner_instruction_event { if let Some(inner_instruction_event) = inner_instruction_event {
merge(&mut event, inner_instruction_event); merge(&mut event, inner_instruction_event);
} }
// 设置处理时间(使用高性能时钟) // Set processing time (using high-performance clock)
event.metadata_mut().handle_us = elapsed_micros_since(recv_us); event.metadata_mut().handle_us = elapsed_micros_since(recv_us);
event = Self::process_event(event, bot_wallet); event = Self::process_event(event, bot_wallet);
callback(&event); callback(&event);
@@ -493,7 +493,7 @@ impl EventParser {
inner_instructions: Option<&InnerInstructions>, inner_instructions: Option<&InnerInstructions>,
callback: Arc<dyn for<'a> Fn(&'a DexEvent) + Send + Sync>, callback: Arc<dyn for<'a> Fn(&'a DexEvent) + Send + Sync>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// 添加边界检查以防止越界访问 // Add bounds check to prevent out-of-bounds access
let program_id_index = instruction.program_id_index as usize; let program_id_index = instruction.program_id_index as usize;
if program_id_index >= accounts.len() { if program_id_index >= accounts.len() {
return Ok(()); return Ok(());
@@ -510,12 +510,12 @@ impl EventParser {
_ => 8, _ => 8,
}; };
// 检查指令数据长度(至少需要 8 字节的 discriminator // Check instruction data length (at least 8 bytes for discriminator)
if !is_cu_program && instruction.data.len() < disc_len { if !is_cu_program && instruction.data.len() < disc_len {
return Ok(()); return Ok(());
} }
// 创建元数据 // Create metadata
let timestamp = block_time.unwrap_or(Timestamp { seconds: 0, nanos: 0 }); let timestamp = block_time.unwrap_or(Timestamp { seconds: 0, nanos: 0 });
let block_time_ms = timestamp.seconds * 1000 + (timestamp.nanos as i64) / 1_000_000; let block_time_ms = timestamp.seconds * 1000 + (timestamp.nanos as i64) / 1_000_000;
let metadata = EventMetadata::new( let metadata = EventMetadata::new(
@@ -542,24 +542,24 @@ impl EventParser {
return Ok(()); return Ok(());
} }
// 使用 EventDispatcher 匹配协议 // Use EventDispatcher to match protocol
let protocol = match EventDispatcher::match_protocol_by_program_id(&program_id) { let protocol = match EventDispatcher::match_protocol_by_program_id(&program_id) {
Some(p) => p, Some(p) => p,
None => return Ok(()), None => return Ok(()),
}; };
// 提取 discriminator 和数据 // Extract discriminator and data
let instruction_discriminator = &instruction.data[..disc_len]; let instruction_discriminator = &instruction.data[..disc_len];
let instruction_data = &instruction.data[disc_len..]; let instruction_data = &instruction.data[disc_len..];
// 构建账户公钥列表 // Build account pubkey list
let account_pubkeys: Vec<Pubkey> = instruction let account_pubkeys: Vec<Pubkey> = instruction
.accounts .accounts
.iter() .iter()
.filter_map(|&idx| accounts.get(idx as usize).copied()) .filter_map(|&idx| accounts.get(idx as usize).copied())
.collect(); .collect();
// 使用 EventDispatcher 解析 instruction 事件 // Use EventDispatcher to parse instruction event
let mut event = match EventDispatcher::dispatch_instruction( let mut event = match EventDispatcher::dispatch_instruction(
protocol.clone(), protocol.clone(),
instruction_discriminator, instruction_discriminator,
@@ -571,23 +571,23 @@ impl EventParser {
None => return Ok(()), None => return Ok(()),
}; };
// 处理 inner instructions - 查找对应的 CPI log 进行 merge // Process inner instructions - find corresponding CPI log for merge
// inner_index 有值时,只查找索引大于当前 inner_index 的 CPI log // When inner_index has a value, only search for CPI logs with index greater than current inner_index
let mut inner_instruction_event: Option<DexEvent> = None; let mut inner_instruction_event: Option<DexEvent> = None;
if let Some(inner_instructions_ref) = inner_instructions { if let Some(inner_instructions_ref) = inner_instructions {
let current_inner_idx = inner_index.unwrap_or(-1) as i32; let current_inner_idx = inner_index.unwrap_or(-1) as i32;
// 并行执行两个任务: 解析 inner event 和提取 swap_data // Execute two tasks in parallel: parse inner event and extract swap_data
let (inner_event_result, swap_data_result) = std::thread::scope(|s| { let (inner_event_result, swap_data_result) = std::thread::scope(|s| {
let inner_event_handle = s.spawn(|| { let inner_event_handle = s.spawn(|| {
for (idx, inner_instruction) in inner_instructions_ref.instructions.iter().enumerate() { for (idx, inner_instruction) in inner_instructions_ref.instructions.iter().enumerate() {
// 只查找索引大于当前 inner_index 的 CPI log // Only search for CPI logs with index greater than current inner_index
if (idx as i32) <= current_inner_idx { if (idx as i32) <= current_inner_idx {
continue; continue;
} }
let inner_data = &inner_instruction.instruction.data; let inner_data = &inner_instruction.instruction.data;
// 检查长度(需要 16 字节的 discriminator // Check length (needs 16 bytes for discriminator)
if inner_data.len() < 16 { if inner_data.len() < 16 {
continue; continue;
} }
@@ -619,7 +619,7 @@ impl EventParser {
} }
}); });
// 等待两个任务完成 // Wait for both tasks to complete
(inner_event_handle.join().unwrap(), swap_data_handle.join().unwrap()) (inner_event_handle.join().unwrap(), swap_data_handle.join().unwrap())
}); });
@@ -629,7 +629,7 @@ impl EventParser {
} }
} }
// 特殊处理: PumpFun MIGRATE 指令需要 inner instruction data // Special handling: PumpFun MIGRATE instruction requires inner instruction data
if matches!(protocol, Protocol::PumpFun) { if matches!(protocol, Protocol::PumpFun) {
const PUMPFUN_MIGRATE_IX: &[u8] = &[155, 234, 231, 146, 236, 158, 162, 30]; const PUMPFUN_MIGRATE_IX: &[u8] = &[155, 234, 231, 146, 236, 158, 162, 30];
if instruction_discriminator == PUMPFUN_MIGRATE_IX && inner_instruction_event.is_none() if instruction_discriminator == PUMPFUN_MIGRATE_IX && inner_instruction_event.is_none()
@@ -638,12 +638,12 @@ impl EventParser {
} }
} }
// 合并事件 // Merge events
if let Some(inner_instruction_event) = inner_instruction_event { if let Some(inner_instruction_event) = inner_instruction_event {
merge(&mut event, inner_instruction_event); merge(&mut event, inner_instruction_event);
} }
// 设置处理时间(使用高性能时钟) // Set processing time (using high-performance clock)
event.metadata_mut().handle_us = elapsed_micros_since(recv_us); event.metadata_mut().handle_us = elapsed_micros_since(recv_us);
event = Self::process_event(event, bot_wallet); event = Self::process_event(event, bot_wallet);
callback(&event); callback(&event);
@@ -663,7 +663,7 @@ impl EventParser {
_event_type_filter: Option<&EventTypeFilter>, _event_type_filter: Option<&EventTypeFilter>,
program_id: &Pubkey, program_id: &Pubkey,
) -> bool { ) -> bool {
// 使用 EventDispatcher 来匹配协议 // Use EventDispatcher to match protocol
if let Some(protocol) = EventDispatcher::match_protocol_by_program_id(program_id) { if let Some(protocol) = EventDispatcher::match_protocol_by_program_id(program_id) {
protocols.contains(&protocol) protocols.contains(&protocol)
} else if EventDispatcher::is_compute_budget_program(program_id) { } else if EventDispatcher::is_compute_budget_program(program_id) {
@@ -730,6 +730,13 @@ impl EventParser {
} }
DexEvent::PumpSwapBuyEvent(trade_info) DexEvent::PumpSwapBuyEvent(trade_info)
} }
DexEvent::PumpSwapBuyExactQuoteInEvent(mut trade_info) => {
if let Some(swap_data) = trade_info.metadata.swap_data.as_mut() {
swap_data.from_amount = trade_info.user_quote_amount_in;
swap_data.to_amount = trade_info.base_amount_out;
}
DexEvent::PumpSwapBuyExactQuoteInEvent(trade_info)
}
DexEvent::PumpSwapSellEvent(mut trade_info) => { DexEvent::PumpSwapSellEvent(mut trade_info) => {
if let Some(swap_data) = trade_info.metadata.swap_data.as_mut() { if let Some(swap_data) = trade_info.metadata.swap_data.as_mut() {
swap_data.from_amount = trade_info.base_amount_in; swap_data.from_amount = trade_info.base_amount_in;
@@ -140,6 +140,48 @@ pub fn merge(instruction_event: &mut DexEvent, cpi_log_event: DexEvent) {
e.coin_creator = cpie.coin_creator; e.coin_creator = cpie.coin_creator;
e.coin_creator_fee_basis_points = cpie.coin_creator_fee_basis_points; e.coin_creator_fee_basis_points = cpie.coin_creator_fee_basis_points;
e.coin_creator_fee = cpie.coin_creator_fee; e.coin_creator_fee = cpie.coin_creator_fee;
e.track_volume = cpie.track_volume;
e.total_unclaimed_tokens = cpie.total_unclaimed_tokens;
e.total_claimed_tokens = cpie.total_claimed_tokens;
e.current_sol_volume = cpie.current_sol_volume;
e.last_update_timestamp = cpie.last_update_timestamp;
e.min_base_amount_out = cpie.min_base_amount_out;
e.ix_name = cpie.ix_name;
}
_ => {}
},
DexEvent::PumpSwapBuyExactQuoteInEvent(e) => match cpi_log_event {
DexEvent::PumpSwapBuyExactQuoteInEvent(cpie) => {
e.timestamp = cpie.timestamp;
e.base_amount_out = cpie.base_amount_out;
e.max_quote_amount_in = cpie.max_quote_amount_in;
e.user_base_token_reserves = cpie.user_base_token_reserves;
e.user_quote_token_reserves = cpie.user_quote_token_reserves;
e.pool_base_token_reserves = cpie.pool_base_token_reserves;
e.pool_quote_token_reserves = cpie.pool_quote_token_reserves;
e.quote_amount_in = cpie.quote_amount_in;
e.lp_fee_basis_points = cpie.lp_fee_basis_points;
e.lp_fee = cpie.lp_fee;
e.protocol_fee_basis_points = cpie.protocol_fee_basis_points;
e.protocol_fee = cpie.protocol_fee;
e.quote_amount_in_with_lp_fee = cpie.quote_amount_in_with_lp_fee;
e.user_quote_amount_in = cpie.user_quote_amount_in;
e.pool = cpie.pool;
e.user = cpie.user;
e.user_base_token_account = cpie.user_base_token_account;
e.user_quote_token_account = cpie.user_quote_token_account;
e.protocol_fee_recipient = cpie.protocol_fee_recipient;
e.protocol_fee_recipient_token_account = cpie.protocol_fee_recipient_token_account;
e.coin_creator = cpie.coin_creator;
e.coin_creator_fee_basis_points = cpie.coin_creator_fee_basis_points;
e.coin_creator_fee = cpie.coin_creator_fee;
e.track_volume = cpie.track_volume;
e.total_unclaimed_tokens = cpie.total_unclaimed_tokens;
e.total_claimed_tokens = cpie.total_claimed_tokens;
e.current_sol_volume = cpie.current_sol_volume;
e.last_update_timestamp = cpie.last_update_timestamp;
e.min_base_amount_out = cpie.min_base_amount_out;
e.ix_name = cpie.ix_name;
} }
_ => {} _ => {}
}, },
@@ -38,6 +38,7 @@ pub enum DexEvent {
// PumpSwap events // PumpSwap events
PumpSwapBuyEvent(PumpSwapBuyEvent), PumpSwapBuyEvent(PumpSwapBuyEvent),
PumpSwapBuyExactQuoteInEvent(PumpSwapBuyExactQuoteInEvent),
PumpSwapSellEvent(PumpSwapSellEvent), PumpSwapSellEvent(PumpSwapSellEvent),
PumpSwapCreatePoolEvent(PumpSwapCreatePoolEvent), PumpSwapCreatePoolEvent(PumpSwapCreatePoolEvent),
PumpSwapDepositEvent(PumpSwapDepositEvent), PumpSwapDepositEvent(PumpSwapDepositEvent),
@@ -107,6 +108,7 @@ impl DexEvent {
DexEvent::PumpFunBondingCurveAccountEvent(e) => &e.metadata, DexEvent::PumpFunBondingCurveAccountEvent(e) => &e.metadata,
DexEvent::PumpFunGlobalAccountEvent(e) => &e.metadata, DexEvent::PumpFunGlobalAccountEvent(e) => &e.metadata,
DexEvent::PumpSwapBuyEvent(e) => &e.metadata, DexEvent::PumpSwapBuyEvent(e) => &e.metadata,
DexEvent::PumpSwapBuyExactQuoteInEvent(e) => &e.metadata,
DexEvent::PumpSwapSellEvent(e) => &e.metadata, DexEvent::PumpSwapSellEvent(e) => &e.metadata,
DexEvent::PumpSwapCreatePoolEvent(e) => &e.metadata, DexEvent::PumpSwapCreatePoolEvent(e) => &e.metadata,
DexEvent::PumpSwapDepositEvent(e) => &e.metadata, DexEvent::PumpSwapDepositEvent(e) => &e.metadata,
@@ -166,6 +168,7 @@ impl DexEvent {
DexEvent::PumpFunBondingCurveAccountEvent(e) => &mut e.metadata, DexEvent::PumpFunBondingCurveAccountEvent(e) => &mut e.metadata,
DexEvent::PumpFunGlobalAccountEvent(e) => &mut e.metadata, DexEvent::PumpFunGlobalAccountEvent(e) => &mut e.metadata,
DexEvent::PumpSwapBuyEvent(e) => &mut e.metadata, DexEvent::PumpSwapBuyEvent(e) => &mut e.metadata,
DexEvent::PumpSwapBuyExactQuoteInEvent(e) => &mut e.metadata,
DexEvent::PumpSwapSellEvent(e) => &mut e.metadata, DexEvent::PumpSwapSellEvent(e) => &mut e.metadata,
DexEvent::PumpSwapCreatePoolEvent(e) => &mut e.metadata, DexEvent::PumpSwapCreatePoolEvent(e) => &mut e.metadata,
DexEvent::PumpSwapDepositEvent(e) => &mut e.metadata, DexEvent::PumpSwapDepositEvent(e) => &mut e.metadata,
@@ -3,7 +3,7 @@ use borsh::BorshDeserialize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use solana_sdk::signature::Signature; use solana_sdk::signature::Signature;
/// Block元数据事件 /// Block metadata event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct BlockMetaEvent { pub struct BlockMetaEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -15,9 +15,9 @@ use crate::streaming::event_parser::{
pub const BONK_PROGRAM_ID: Pubkey = pub const BONK_PROGRAM_ID: Pubkey =
solana_sdk::pubkey!("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"); solana_sdk::pubkey!("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj");
/// 解析 Bonk instruction data /// Parse Bonk instruction data
/// ///
/// 根据判别器路由到具体的 instruction 解析函数 /// Route to specific instruction parser based on discriminator
pub fn parse_bonk_instruction_data( pub fn parse_bonk_instruction_data(
discriminator: &[u8], discriminator: &[u8],
data: &[u8], data: &[u8],
@@ -56,9 +56,9 @@ pub fn parse_bonk_instruction_data(
} }
} }
/// 解析 Bonk inner instruction data /// Parse Bonk inner instruction data
/// ///
/// 根据判别器路由到具体的 inner instruction 解析函数 /// Route to specific inner instruction parser based on discriminator
pub fn parse_bonk_inner_instruction_data( pub fn parse_bonk_inner_instruction_data(
discriminator: &[u8], discriminator: &[u8],
data: &[u8], data: &[u8],
@@ -75,9 +75,9 @@ pub fn parse_bonk_inner_instruction_data(
} }
} }
/// 解析 Bonk 账户数据 /// Parse Bonk account data
/// ///
/// 根据判别器路由到具体的账户解析函数 /// Route to specific account parser based on discriminator
pub fn parse_bonk_account_data( pub fn parse_bonk_account_data(
discriminator: &[u8], discriminator: &[u8],
account: &crate::streaming::grpc::AccountPretty, account: &crate::streaming::grpc::AccountPretty,
@@ -9,13 +9,13 @@ use crate::streaming::event_parser::{
}; };
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
/// PumpFun程序ID /// PumpFun program ID
pub const PUMPFUN_PROGRAM_ID: Pubkey = pub const PUMPFUN_PROGRAM_ID: Pubkey =
solana_sdk::pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); solana_sdk::pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");
/// 解析 PumpFun instruction data /// Parse PumpFun instruction data
/// ///
/// 根据判别器路由到具体的 instruction 解析函数 /// Route to specific instruction parser based on discriminator
pub fn parse_pumpfun_instruction_data( pub fn parse_pumpfun_instruction_data(
discriminator: &[u8], discriminator: &[u8],
data: &[u8], data: &[u8],
@@ -34,9 +34,9 @@ pub fn parse_pumpfun_instruction_data(
} }
} }
/// 解析 PumpFun inner instruction data /// Parse PumpFun inner instruction data
/// ///
/// 根据判别器路由到具体的 inner instruction 解析函数 /// Route to specific inner instruction parser based on discriminator
pub fn parse_pumpfun_inner_instruction_data( pub fn parse_pumpfun_inner_instruction_data(
discriminator: &[u8], discriminator: &[u8],
data: &[u8], data: &[u8],
@@ -52,9 +52,9 @@ pub fn parse_pumpfun_inner_instruction_data(
} }
} }
/// 解析 PumpFun 账户数据 /// Parse PumpFun account data
/// ///
/// 根据判别器路由到具体的账户解析函数 /// Route to specific account parser based on discriminator
pub fn parse_pumpfun_account_data( pub fn parse_pumpfun_account_data(
discriminator: &[u8], discriminator: &[u8],
account: &crate::streaming::grpc::AccountPretty, account: &crate::streaming::grpc::AccountPretty,
@@ -5,7 +5,7 @@ use solana_sdk::pubkey::Pubkey;
use crate::streaming::event_parser::common::EventMetadata; use crate::streaming::event_parser::common::EventMetadata;
use crate::streaming::event_parser::protocols::pumpswap::types::{GlobalConfig, Pool}; use crate::streaming::event_parser::protocols::pumpswap::types::{GlobalConfig, Pool};
/// 买入事件 /// Buy event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapBuyEvent { pub struct PumpSwapBuyEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -38,6 +38,66 @@ pub struct PumpSwapBuyEvent {
pub total_claimed_tokens: u64, pub total_claimed_tokens: u64,
pub current_sol_volume: u64, pub current_sol_volume: u64,
pub last_update_timestamp: i64, pub last_update_timestamp: i64,
pub min_base_amount_out: u64,
pub ix_name: String,
#[borsh(skip)]
pub base_mint: Pubkey,
#[borsh(skip)]
pub quote_mint: Pubkey,
#[borsh(skip)]
pub pool_base_token_account: Pubkey,
#[borsh(skip)]
pub pool_quote_token_account: Pubkey,
#[borsh(skip)]
pub coin_creator_vault_ata: Pubkey,
#[borsh(skip)]
pub coin_creator_vault_authority: Pubkey,
#[borsh(skip)]
pub base_token_program: Pubkey,
#[borsh(skip)]
pub quote_token_program: Pubkey,
}
/// Buy event (ix: `buy_exact_quote_in`)
///
/// Same on-chain layout as `PumpSwapBuyEvent` (IDL `BuyEvent`),
/// but represented as a different type to distinguish in the streamer.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapBuyExactQuoteInEvent {
#[borsh(skip)]
pub metadata: EventMetadata,
pub timestamp: i64,
pub base_amount_out: u64,
pub max_quote_amount_in: u64,
pub user_base_token_reserves: u64,
pub user_quote_token_reserves: u64,
pub pool_base_token_reserves: u64,
pub pool_quote_token_reserves: u64,
pub quote_amount_in: u64,
pub lp_fee_basis_points: u64,
pub lp_fee: u64,
pub protocol_fee_basis_points: u64,
pub protocol_fee: u64,
pub quote_amount_in_with_lp_fee: u64,
pub user_quote_amount_in: u64,
pub pool: Pubkey,
pub user: Pubkey,
pub user_base_token_account: Pubkey,
pub user_quote_token_account: Pubkey,
pub protocol_fee_recipient: Pubkey,
pub protocol_fee_recipient_token_account: Pubkey,
pub coin_creator: Pubkey,
pub coin_creator_fee_basis_points: u64,
pub coin_creator_fee: u64,
pub track_volume: bool,
pub total_unclaimed_tokens: u64,
pub total_claimed_tokens: u64,
pub current_sol_volume: u64,
pub last_update_timestamp: i64,
pub min_base_amount_out: u64,
pub ix_name: String,
#[borsh(skip)]
pub spendable_quote_in: u64,
#[borsh(skip)] #[borsh(skip)]
pub base_mint: Pubkey, pub base_mint: Pubkey,
#[borsh(skip)] #[borsh(skip)]
@@ -62,10 +122,19 @@ pub fn pump_swap_buy_event_log_decode(data: &[u8]) -> Option<PumpSwapBuyEvent> {
if data.len() < PUMP_SWAP_BUY_EVENT_LOG_SIZE { if data.len() < PUMP_SWAP_BUY_EVENT_LOG_SIZE {
return None; return None;
} }
borsh::from_slice::<PumpSwapBuyEvent>(&data[..PUMP_SWAP_BUY_EVENT_LOG_SIZE]).ok() // Use the entire buffer to correctly deserialize the String ix_name field
borsh::from_slice::<PumpSwapBuyEvent>(data).ok()
} }
/// 卖出事件 pub fn pump_swap_buy_exact_quote_in_event_log_decode(data: &[u8]) -> Option<PumpSwapBuyExactQuoteInEvent> {
if data.len() < PUMP_SWAP_BUY_EVENT_LOG_SIZE {
return None;
}
// Use the entire buffer to correctly deserialize the String ix_name field
borsh::from_slice::<PumpSwapBuyExactQuoteInEvent>(data).ok()
}
/// Sell event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapSellEvent { pub struct PumpSwapSellEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -120,7 +189,7 @@ pub fn pump_swap_sell_event_log_decode(data: &[u8]) -> Option<PumpSwapSellEvent>
borsh::from_slice::<PumpSwapSellEvent>(&data[..PUMP_SWAP_SELL_EVENT_LOG_SIZE]).ok() borsh::from_slice::<PumpSwapSellEvent>(&data[..PUMP_SWAP_SELL_EVENT_LOG_SIZE]).ok()
} }
/// 创建池子事件 /// Create pool event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapCreatePoolEvent { pub struct PumpSwapCreatePoolEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -162,7 +231,7 @@ pub fn pump_swap_create_pool_event_log_decode(data: &[u8]) -> Option<PumpSwapCre
borsh::from_slice::<PumpSwapCreatePoolEvent>(&data[..PUMP_SWAP_CREATE_POOL_EVENT_LOG_SIZE]).ok() borsh::from_slice::<PumpSwapCreatePoolEvent>(&data[..PUMP_SWAP_CREATE_POOL_EVENT_LOG_SIZE]).ok()
} }
/// 存款事件 /// Deposit event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapDepositEvent { pub struct PumpSwapDepositEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -202,7 +271,7 @@ pub fn pump_swap_deposit_event_log_decode(data: &[u8]) -> Option<PumpSwapDeposit
borsh::from_slice::<PumpSwapDepositEvent>(&data[..PUMP_SWAP_DEPOSIT_EVENT_LOG_SIZE]).ok() borsh::from_slice::<PumpSwapDepositEvent>(&data[..PUMP_SWAP_DEPOSIT_EVENT_LOG_SIZE]).ok()
} }
/// 提款事件 /// Withdraw event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapWithdrawEvent { pub struct PumpSwapWithdrawEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -242,7 +311,7 @@ pub fn pump_swap_withdraw_event_log_decode(data: &[u8]) -> Option<PumpSwapWithdr
borsh::from_slice::<PumpSwapWithdrawEvent>(&data[..PUMP_SWAP_WITHDRAW_EVENT_LOG_SIZE]).ok() borsh::from_slice::<PumpSwapWithdrawEvent>(&data[..PUMP_SWAP_WITHDRAW_EVENT_LOG_SIZE]).ok()
} }
/// 全局配置 /// Global config account event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapGlobalConfigAccountEvent { pub struct PumpSwapGlobalConfigAccountEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -255,7 +324,7 @@ pub struct PumpSwapGlobalConfigAccountEvent {
pub global_config: GlobalConfig, pub global_config: GlobalConfig,
} }
/// /// Pool account event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpSwapPoolAccountEvent { pub struct PumpSwapPoolAccountEvent {
#[borsh(skip)] #[borsh(skip)]
@@ -268,9 +337,9 @@ pub struct PumpSwapPoolAccountEvent {
pub pool: Pool, pub pool: Pool,
} }
/// 事件鉴别器常量 /// Event discriminator constants
pub mod discriminators { pub mod discriminators {
// 事件鉴别器 // Event discriminators
// pub const BUY_EVENT: &str = "0xe445a52e51cb9a1d67f4521f2cf57777"; // pub const BUY_EVENT: &str = "0xe445a52e51cb9a1d67f4521f2cf57777";
pub const BUY_EVENT: &[u8] = pub const BUY_EVENT: &[u8] =
&[228, 69, 165, 46, 81, 203, 154, 29, 103, 244, 82, 31, 44, 245, 119, 119]; &[228, 69, 165, 46, 81, 203, 154, 29, 103, 244, 82, 31, 44, 245, 119, 119];
@@ -287,14 +356,15 @@ pub mod discriminators {
pub const WITHDRAW_EVENT: &[u8] = pub const WITHDRAW_EVENT: &[u8] =
&[228, 69, 165, 46, 81, 203, 154, 29, 22, 9, 133, 26, 160, 44, 71, 192]; &[228, 69, 165, 46, 81, 203, 154, 29, 22, 9, 133, 26, 160, 44, 71, 192];
// 指令鉴别器 // Instruction discriminators
pub const BUY_IX: &[u8] = &[102, 6, 61, 18, 1, 218, 235, 234]; pub const BUY_IX: &[u8] = &[102, 6, 61, 18, 1, 218, 235, 234];
pub const BUY_EXACT_QUOTE_IN_IX: &[u8] = &[198, 46, 21, 82, 180, 217, 232, 112];
pub const SELL_IX: &[u8] = &[51, 230, 133, 164, 1, 127, 131, 173]; pub const SELL_IX: &[u8] = &[51, 230, 133, 164, 1, 127, 131, 173];
pub const CREATE_POOL_IX: &[u8] = &[233, 146, 209, 142, 207, 104, 64, 188]; pub const CREATE_POOL_IX: &[u8] = &[233, 146, 209, 142, 207, 104, 64, 188];
pub const DEPOSIT_IX: &[u8] = &[242, 35, 198, 137, 82, 225, 242, 182]; pub const DEPOSIT_IX: &[u8] = &[242, 35, 198, 137, 82, 225, 242, 182];
pub const WITHDRAW_IX: &[u8] = &[183, 18, 70, 156, 148, 109, 161, 34]; pub const WITHDRAW_IX: &[u8] = &[183, 18, 70, 156, 148, 109, 161, 34];
// 账户鉴别器 // Account discriminators
pub const GLOBAL_CONFIG_ACCOUNT: &[u8] = &[149, 8, 156, 202, 160, 252, 176, 217]; pub const GLOBAL_CONFIG_ACCOUNT: &[u8] = &[149, 8, 156, 202, 160, 252, 176, 217];
pub const POOL_ACCOUNT: &[u8] = &[241, 154, 109, 4, 17, 177, 109, 188]; pub const POOL_ACCOUNT: &[u8] = &[241, 154, 109, 4, 17, 177, 109, 188];
} }
@@ -1,22 +1,24 @@
use crate::streaming::event_parser::{ use crate::streaming::event_parser::{
common::{read_u64_le, EventMetadata, EventType}, common::{read_u64_le, EventMetadata, EventType},
protocols::pumpswap::{ protocols::pumpswap::{
discriminators, pump_swap_buy_event_log_decode, pump_swap_create_pool_event_log_decode, discriminators, pump_swap_buy_event_log_decode,
pump_swap_deposit_event_log_decode, pump_swap_sell_event_log_decode, pump_swap_buy_exact_quote_in_event_log_decode,
pump_swap_withdraw_event_log_decode, PumpSwapBuyEvent, PumpSwapCreatePoolEvent, pump_swap_create_pool_event_log_decode, pump_swap_deposit_event_log_decode,
PumpSwapDepositEvent, PumpSwapSellEvent, PumpSwapWithdrawEvent, pump_swap_sell_event_log_decode, pump_swap_withdraw_event_log_decode, PumpSwapBuyEvent,
PumpSwapBuyExactQuoteInEvent, PumpSwapCreatePoolEvent, PumpSwapDepositEvent,
PumpSwapSellEvent, PumpSwapWithdrawEvent,
}, },
DexEvent, DexEvent,
}; };
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
/// PumpSwap程序ID /// PumpSwap program ID
pub const PUMPSWAP_PROGRAM_ID: Pubkey = pub const PUMPSWAP_PROGRAM_ID: Pubkey =
solana_sdk::pubkey!("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"); solana_sdk::pubkey!("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA");
/// 解析 PumpSwap instruction data /// Parse PumpSwap instruction data
/// ///
/// 根据判别器路由到具体的 instruction 解析函数 /// Routes to specific instruction parser based on discriminator
pub fn parse_pumpswap_instruction_data( pub fn parse_pumpswap_instruction_data(
discriminator: &[u8], discriminator: &[u8],
data: &[u8], data: &[u8],
@@ -25,6 +27,7 @@ pub fn parse_pumpswap_instruction_data(
) -> Option<DexEvent> { ) -> Option<DexEvent> {
match discriminator { match discriminator {
discriminators::BUY_IX => parse_buy_instruction(data, accounts, metadata), discriminators::BUY_IX => parse_buy_instruction(data, accounts, metadata),
discriminators::BUY_EXACT_QUOTE_IN_IX => parse_buy_exact_quote_in_instruction(data, accounts, metadata),
discriminators::SELL_IX => parse_sell_instruction(data, accounts, metadata), discriminators::SELL_IX => parse_sell_instruction(data, accounts, metadata),
discriminators::CREATE_POOL_IX => { discriminators::CREATE_POOL_IX => {
parse_create_pool_instruction(data, accounts, metadata) parse_create_pool_instruction(data, accounts, metadata)
@@ -35,9 +38,9 @@ pub fn parse_pumpswap_instruction_data(
} }
} }
/// 解析 PumpSwap inner instruction data /// Parse PumpSwap inner instruction data
/// ///
/// 根据判别器路由到具体的 inner instruction 解析函数 /// Routes to specific inner instruction parser based on discriminator
pub fn parse_pumpswap_inner_instruction_data( pub fn parse_pumpswap_inner_instruction_data(
discriminator: &[u8], discriminator: &[u8],
data: &[u8], data: &[u8],
@@ -56,9 +59,9 @@ pub fn parse_pumpswap_inner_instruction_data(
} }
/// 解析 PumpSwap 账户数据 /// Parse PumpSwap account data
/// ///
/// 根据判别器路由到具体的账户解析函数 /// Routes to specific account parser based on discriminator
pub fn parse_pumpswap_account_data( pub fn parse_pumpswap_account_data(
discriminator: &[u8], discriminator: &[u8],
account: &crate::streaming::grpc::AccountPretty, account: &crate::streaming::grpc::AccountPretty,
@@ -75,17 +78,25 @@ pub fn parse_pumpswap_account_data(
} }
} }
/// 解析买入日志事件 /// Parse buy event log
fn parse_buy_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> { fn parse_buy_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
// Note: event_type will be set by instruction parser // First try to decode as buy_exact_quote_in to read ix_name
if let Some(event) = pump_swap_buy_event_log_decode(data) { if let Some(event) = pump_swap_buy_exact_quote_in_event_log_decode(data) {
Some(DexEvent::PumpSwapBuyEvent(PumpSwapBuyEvent { metadata, ..event })) if event.ix_name == "buy_exact_quote_in" {
} else { return Some(DexEvent::PumpSwapBuyExactQuoteInEvent(PumpSwapBuyExactQuoteInEvent {
None metadata,
..event
}));
}
} }
// If not buy_exact_quote_in, decode as normal buy
pump_swap_buy_event_log_decode(data).map(|event| {
DexEvent::PumpSwapBuyEvent(PumpSwapBuyEvent { metadata, ..event })
})
} }
/// 解析卖出日志事件 /// Parse sell event log
fn parse_sell_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> { fn parse_sell_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
// Note: event_type will be set by instruction parser // Note: event_type will be set by instruction parser
if let Some(event) = pump_swap_sell_event_log_decode(data) { if let Some(event) = pump_swap_sell_event_log_decode(data) {
@@ -95,7 +106,7 @@ fn parse_sell_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<
} }
} }
/// 解析创建池子日志事件 /// Parse create pool event log
fn parse_create_pool_inner_instruction( fn parse_create_pool_inner_instruction(
data: &[u8], data: &[u8],
metadata: EventMetadata, metadata: EventMetadata,
@@ -108,7 +119,7 @@ fn parse_create_pool_inner_instruction(
} }
} }
/// 解析存款日志事件 /// Parse deposit event log
fn parse_deposit_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> { fn parse_deposit_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
// Note: event_type will be set by instruction parser // Note: event_type will be set by instruction parser
if let Some(event) = pump_swap_deposit_event_log_decode(data) { if let Some(event) = pump_swap_deposit_event_log_decode(data) {
@@ -118,7 +129,7 @@ fn parse_deposit_inner_instruction(data: &[u8], metadata: EventMetadata) -> Opti
} }
} }
/// 解析提款日志事件 /// Parse withdraw event log
fn parse_withdraw_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> { fn parse_withdraw_inner_instruction(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
// Note: event_type will be set by instruction parser // Note: event_type will be set by instruction parser
if let Some(event) = pump_swap_withdraw_event_log_decode(data) { if let Some(event) = pump_swap_withdraw_event_log_decode(data) {
@@ -128,7 +139,7 @@ fn parse_withdraw_inner_instruction(data: &[u8], metadata: EventMetadata) -> Opt
} }
} }
/// 解析买入指令事件 /// Parse buy instruction
fn parse_buy_instruction( fn parse_buy_instruction(
data: &[u8], data: &[u8],
accounts: &[Pubkey], accounts: &[Pubkey],
@@ -165,7 +176,46 @@ fn parse_buy_instruction(
})) }))
} }
/// 解析卖出指令事件 /// Parse `buy_exact_quote_in` instruction
fn parse_buy_exact_quote_in_instruction(
data: &[u8],
accounts: &[Pubkey],
mut metadata: EventMetadata,
) -> Option<DexEvent> {
metadata.event_type = EventType::PumpSwapBuyExactQuoteIn;
if data.len() < 16 || accounts.len() < 13 {
return None;
}
let spendable_quote_in = read_u64_le(data, 0)?;
let min_base_amount_out = read_u64_le(data, 8)?;
Some(DexEvent::PumpSwapBuyExactQuoteInEvent(
PumpSwapBuyExactQuoteInEvent {
metadata,
spendable_quote_in,
min_base_amount_out,
pool: accounts[0],
user: accounts[1],
base_mint: accounts[3],
quote_mint: accounts[4],
user_base_token_account: accounts[5],
user_quote_token_account: accounts[6],
pool_base_token_account: accounts[7],
pool_quote_token_account: accounts[8],
protocol_fee_recipient: accounts[9],
protocol_fee_recipient_token_account: accounts[10],
base_token_program: accounts[11],
quote_token_program: accounts[12],
coin_creator_vault_ata: accounts.get(17).copied().unwrap_or_default(),
coin_creator_vault_authority: accounts.get(18).copied().unwrap_or_default(),
..Default::default()
},
))
}
/// Parse sell instruction
fn parse_sell_instruction( fn parse_sell_instruction(
data: &[u8], data: &[u8],
accounts: &[Pubkey], accounts: &[Pubkey],
@@ -202,7 +252,7 @@ fn parse_sell_instruction(
})) }))
} }
/// 解析创建池子指令事件 /// Parse create pool instruction
fn parse_create_pool_instruction( fn parse_create_pool_instruction(
data: &[u8], data: &[u8],
accounts: &[Pubkey], accounts: &[Pubkey],
@@ -243,7 +293,7 @@ fn parse_create_pool_instruction(
})) }))
} }
/// 解析存款指令事件 /// Parse deposit instruction
fn parse_deposit_instruction( fn parse_deposit_instruction(
data: &[u8], data: &[u8],
accounts: &[Pubkey], accounts: &[Pubkey],
@@ -277,7 +327,7 @@ fn parse_deposit_instruction(
})) }))
} }
/// 解析提款指令事件 /// Parse withdraw instruction
fn parse_withdraw_instruction( fn parse_withdraw_instruction(
data: &[u8], data: &[u8],
accounts: &[Pubkey], accounts: &[Pubkey],
@@ -7,7 +7,7 @@ use crate::streaming::event_parser::protocols::{
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
/// 支持的协议 /// Supported protocols
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Protocol { pub enum Protocol {
PumpSwap, PumpSwap,
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::streaming::common::constants::{
DEFAULT_CONNECT_TIMEOUT, DEFAULT_REQUEST_TIMEOUT, DEFAULT_MAX_DECODING_MESSAGE_SIZE DEFAULT_CONNECT_TIMEOUT, DEFAULT_REQUEST_TIMEOUT, DEFAULT_MAX_DECODING_MESSAGE_SIZE
}; };
/// gRPC连接池 - 简化版本 /// gRPC connection pool - simplified version
pub struct GrpcConnectionPool { pub struct GrpcConnectionPool {
endpoint: String, endpoint: String,
x_token: Option<String>, x_token: Option<String>,
+3 -3
View File
@@ -1,16 +1,16 @@
// gRPC 相关模块 // gRPC related modules
pub mod connection; pub mod connection;
pub mod pool; pub mod pool;
pub mod subscription; pub mod subscription;
pub mod types; pub mod types;
// 重新导出主要类型 // Re-export main types
pub use connection::*; pub use connection::*;
pub use pool::*; pub use pool::*;
pub use subscription::*; pub use subscription::*;
pub use types::*; pub use types::*;
// 从公用模块重新导出 // Re-export from common modules
pub use crate::streaming::common::{ pub use crate::streaming::common::{
ConnectionConfig, MetricsManager, PerformanceMetrics, StreamClientConfig as ClientConfig, ConnectionConfig, MetricsManager, PerformanceMetrics, StreamClientConfig as ClientConfig,
}; };
+37 -37
View File
@@ -9,13 +9,13 @@ use yellowstone_grpc_proto::{
prost_types::Timestamp, prost_types::Timestamp,
}; };
/// 通用对象池特征 /// Generic object pool trait
pub trait ObjectPool<T> { pub trait ObjectPool<T> {
fn acquire(&self) -> PooledObject<T>; fn acquire(&self) -> PooledObject<T>;
fn return_object(&self, obj: Box<T>); fn return_object(&self, obj: Box<T>);
} }
/// 带自动归还的智能指针 /// Smart pointer with automatic return
pub struct PooledObject<T> { pub struct PooledObject<T> {
object: Option<Box<T>>, object: Option<Box<T>>,
pool: Arc<Mutex<VecDeque<Box<T>>>>, pool: Arc<Mutex<VecDeque<Box<T>>>>,
@@ -36,7 +36,7 @@ impl<T> Drop for PooledObject<T> {
if pool.len() < self.max_size { if pool.len() < self.max_size {
pool.push_back(obj); pool.push_back(obj);
} }
// 超过最大容量时直接丢弃 // Discard when exceeding max capacity
} }
} }
} }
@@ -55,7 +55,7 @@ impl<T> std::ops::DerefMut for PooledObject<T> {
} }
} }
/// AccountPretty 对象池 /// AccountPretty object pool
pub struct AccountPrettyPool { pub struct AccountPrettyPool {
pool: Arc<Mutex<VecDeque<Box<AccountPretty>>>>, pool: Arc<Mutex<VecDeque<Box<AccountPretty>>>>,
max_size: usize, max_size: usize,
@@ -65,7 +65,7 @@ impl AccountPrettyPool {
pub fn new(initial_size: usize, max_size: usize) -> Self { pub fn new(initial_size: usize, max_size: usize) -> Self {
let mut pool = VecDeque::with_capacity(initial_size); let mut pool = VecDeque::with_capacity(initial_size);
// 预分配对象 // Pre-allocate objects
for _ in 0..initial_size { for _ in 0..initial_size {
pool.push_back(Box::new(AccountPretty::default())); pool.push_back(Box::new(AccountPretty::default()));
} }
@@ -84,7 +84,7 @@ impl AccountPrettyPool {
} }
} }
/// 带自动归还的 AccountPretty /// AccountPretty with automatic return
pub struct PooledAccountPretty { pub struct PooledAccountPretty {
account: Box<AccountPretty>, account: Box<AccountPretty>,
pool: Arc<Mutex<VecDeque<Box<AccountPretty>>>>, pool: Arc<Mutex<VecDeque<Box<AccountPretty>>>>,
@@ -92,7 +92,7 @@ pub struct PooledAccountPretty {
} }
impl PooledAccountPretty { impl PooledAccountPretty {
/// 从 gRPC 更新重置数据 /// Reset data from gRPC update
pub fn reset_from_update(&mut self, account_update: SubscribeUpdateAccount) { pub fn reset_from_update(&mut self, account_update: SubscribeUpdateAccount) {
let account_info = account_update.account.unwrap(); let account_info = account_update.account.unwrap();
@@ -109,7 +109,7 @@ impl PooledAccountPretty {
self.account.owner = Pubkey::try_from(account_info.owner.as_slice()).expect("valid pubkey"); self.account.owner = Pubkey::try_from(account_info.owner.as_slice()).expect("valid pubkey");
self.account.rent_epoch = account_info.rent_epoch; self.account.rent_epoch = account_info.rent_epoch;
// 优化数据字段的重用 // Optimize data field reuse
let new_data = account_info.data; let new_data = account_info.data;
if self.account.data.capacity() >= new_data.len() { if self.account.data.capacity() >= new_data.len() {
self.account.data.clear(); self.account.data.clear();
@@ -126,7 +126,7 @@ impl Drop for PooledAccountPretty {
fn drop(&mut self) { fn drop(&mut self) {
let mut pool = self.pool.lock().unwrap(); let mut pool = self.pool.lock().unwrap();
if pool.len() < self.max_size { if pool.len() < self.max_size {
// 清理敏感数据 // Clear sensitive data
self.account.data.clear(); self.account.data.clear();
self.account.signature = Signature::default(); self.account.signature = Signature::default();
self.account.pubkey = Pubkey::default(); self.account.pubkey = Pubkey::default();
@@ -150,7 +150,7 @@ impl std::ops::DerefMut for PooledAccountPretty {
} }
} }
/// BlockMetaPretty 对象池 /// BlockMetaPretty object pool
pub struct BlockMetaPrettyPool { pub struct BlockMetaPrettyPool {
pool: Arc<Mutex<VecDeque<Box<BlockMetaPretty>>>>, pool: Arc<Mutex<VecDeque<Box<BlockMetaPretty>>>>,
max_size: usize, max_size: usize,
@@ -160,7 +160,7 @@ impl BlockMetaPrettyPool {
pub fn new(initial_size: usize, max_size: usize) -> Self { pub fn new(initial_size: usize, max_size: usize) -> Self {
let mut pool = VecDeque::with_capacity(initial_size); let mut pool = VecDeque::with_capacity(initial_size);
// 预分配对象 // Pre-allocate objects
for _ in 0..initial_size { for _ in 0..initial_size {
pool.push_back(Box::new(BlockMetaPretty::default())); pool.push_back(Box::new(BlockMetaPretty::default()));
} }
@@ -179,7 +179,7 @@ impl BlockMetaPrettyPool {
} }
} }
/// 带自动归还的 BlockMetaPretty /// BlockMetaPretty with automatic return
pub struct PooledBlockMetaPretty { pub struct PooledBlockMetaPretty {
block_meta: Box<BlockMetaPretty>, block_meta: Box<BlockMetaPretty>,
pool: Arc<Mutex<VecDeque<Box<BlockMetaPretty>>>>, pool: Arc<Mutex<VecDeque<Box<BlockMetaPretty>>>>,
@@ -187,7 +187,7 @@ pub struct PooledBlockMetaPretty {
} }
impl PooledBlockMetaPretty { impl PooledBlockMetaPretty {
/// 从 gRPC 更新重置数据 /// Reset data from gRPC update
pub fn reset_from_update( pub fn reset_from_update(
&mut self, &mut self,
block_update: SubscribeUpdateBlockMeta, block_update: SubscribeUpdateBlockMeta,
@@ -204,7 +204,7 @@ impl Drop for PooledBlockMetaPretty {
fn drop(&mut self) { fn drop(&mut self) {
let mut pool = self.pool.lock().unwrap(); let mut pool = self.pool.lock().unwrap();
if pool.len() < self.max_size { if pool.len() < self.max_size {
// 清理数据 // Clear data
self.block_meta.block_hash.clear(); self.block_meta.block_hash.clear();
self.block_meta.block_time = None; self.block_meta.block_time = None;
pool.push_back(std::mem::take(&mut self.block_meta)); pool.push_back(std::mem::take(&mut self.block_meta));
@@ -226,7 +226,7 @@ impl std::ops::DerefMut for PooledBlockMetaPretty {
} }
} }
/// TransactionPretty 对象池 /// TransactionPretty object pool
pub struct TransactionPrettyPool { pub struct TransactionPrettyPool {
pool: Arc<Mutex<VecDeque<Box<TransactionPretty>>>>, pool: Arc<Mutex<VecDeque<Box<TransactionPretty>>>>,
max_size: usize, max_size: usize,
@@ -236,7 +236,7 @@ impl TransactionPrettyPool {
pub fn new(initial_size: usize, max_size: usize) -> Self { pub fn new(initial_size: usize, max_size: usize) -> Self {
let mut pool = VecDeque::with_capacity(initial_size); let mut pool = VecDeque::with_capacity(initial_size);
// 预分配对象 // Pre-allocate objects
for _ in 0..initial_size { for _ in 0..initial_size {
pool.push_back(Box::new(TransactionPretty::default())); pool.push_back(Box::new(TransactionPretty::default()));
} }
@@ -259,7 +259,7 @@ impl TransactionPrettyPool {
} }
} }
/// 带自动归还的 TransactionPretty /// TransactionPretty with automatic return
pub struct PooledTransactionPretty { pub struct PooledTransactionPretty {
transaction: Box<TransactionPretty>, transaction: Box<TransactionPretty>,
pool: Arc<Mutex<VecDeque<Box<TransactionPretty>>>>, pool: Arc<Mutex<VecDeque<Box<TransactionPretty>>>>,
@@ -267,7 +267,7 @@ pub struct PooledTransactionPretty {
} }
impl PooledTransactionPretty { impl PooledTransactionPretty {
/// 从 gRPC 更新重置数据 /// Reset data from gRPC update
pub fn reset_from_update( pub fn reset_from_update(
&mut self, &mut self,
tx_update: SubscribeUpdateTransaction, tx_update: SubscribeUpdateTransaction,
@@ -278,7 +278,7 @@ impl PooledTransactionPretty {
self.transaction.slot = tx_update.slot; self.transaction.slot = tx_update.slot;
self.transaction.transaction_index = Some(tx.index); self.transaction.transaction_index = Some(tx.index);
self.transaction.block_time = block_time; self.transaction.block_time = block_time;
self.transaction.block_hash.clear(); // 重置 block_hash self.transaction.block_hash.clear(); // Reset block_hash
self.transaction.signature = self.transaction.signature =
Signature::try_from(tx.signature.as_slice()).expect("valid signature"); Signature::try_from(tx.signature.as_slice()).expect("valid signature");
self.transaction.is_vote = tx.is_vote; self.transaction.is_vote = tx.is_vote;
@@ -291,7 +291,7 @@ impl Drop for PooledTransactionPretty {
fn drop(&mut self) { fn drop(&mut self) {
let mut pool = self.pool.lock().unwrap(); let mut pool = self.pool.lock().unwrap();
if pool.len() < self.max_size { if pool.len() < self.max_size {
// 清理数据 // Clear data
self.transaction.block_hash.clear(); self.transaction.block_hash.clear();
self.transaction.block_time = None; self.transaction.block_time = None;
self.transaction.signature = Signature::default(); self.transaction.signature = Signature::default();
@@ -314,7 +314,7 @@ impl std::ops::DerefMut for PooledTransactionPretty {
} }
} }
/// EventPretty 对象池(组合池) /// EventPretty object pool (composite pool)
pub struct EventPrettyPool { pub struct EventPrettyPool {
account_pool: AccountPrettyPool, account_pool: AccountPrettyPool,
block_pool: BlockMetaPrettyPool, block_pool: BlockMetaPrettyPool,
@@ -330,23 +330,23 @@ impl EventPrettyPool {
} }
} }
/// 获取账户事件对象 /// Get account event object
pub fn acquire_account(&self) -> PooledAccountPretty { pub fn acquire_account(&self) -> PooledAccountPretty {
self.account_pool.acquire() self.account_pool.acquire()
} }
/// 获取区块事件对象 /// Get block event object
pub fn acquire_block(&self) -> PooledBlockMetaPretty { pub fn acquire_block(&self) -> PooledBlockMetaPretty {
self.block_pool.acquire() self.block_pool.acquire()
} }
/// 获取交易事件对象 /// Get transaction event object
pub fn acquire_transaction(&self) -> PooledTransactionPretty { pub fn acquire_transaction(&self) -> PooledTransactionPretty {
self.transaction_pool.acquire() self.transaction_pool.acquire()
} }
} }
/// 对象池管理器(单例) /// Object pool manager (singleton)
pub struct PoolManager { pub struct PoolManager {
event_pool: EventPrettyPool, event_pool: EventPrettyPool,
} }
@@ -367,18 +367,18 @@ impl Default for PoolManager {
} }
} }
/// 工厂函数用于创建优化的 EventPretty /// Factory functions for creating optimized EventPretty
impl EventPrettyPool { impl EventPrettyPool {
/// 创建账户事件 - 使用对象池优化 /// Create account event - optimized with object pool
pub fn create_account_event_optimized(&self, update: SubscribeUpdateAccount) -> AccountPretty { pub fn create_account_event_optimized(&self, update: SubscribeUpdateAccount) -> AccountPretty {
let mut pooled_account = self.acquire_account(); let mut pooled_account = self.acquire_account();
pooled_account.reset_from_update(update); pooled_account.reset_from_update(update);
// 移动数据而不是克隆,避免多余的内存分配 // Move data instead of cloning to avoid unnecessary memory allocation
let result = std::mem::replace(pooled_account.deref_mut(), AccountPretty::default()); let result = std::mem::replace(pooled_account.deref_mut(), AccountPretty::default());
result result
} }
/// 创建区块事件 - 使用对象池优化 /// Create block event - optimized with object pool
pub fn create_block_event_optimized( pub fn create_block_event_optimized(
&self, &self,
update: SubscribeUpdateBlockMeta, update: SubscribeUpdateBlockMeta,
@@ -386,12 +386,12 @@ impl EventPrettyPool {
) -> BlockMetaPretty { ) -> BlockMetaPretty {
let mut pooled_block = self.acquire_block(); let mut pooled_block = self.acquire_block();
pooled_block.reset_from_update(update, block_time); pooled_block.reset_from_update(update, block_time);
// 移动数据而不是克隆 // Move data instead of cloning
let result = std::mem::replace(pooled_block.deref_mut(), BlockMetaPretty::default()); let result = std::mem::replace(pooled_block.deref_mut(), BlockMetaPretty::default());
result result
} }
/// 创建交易事件 - 使用对象池优化 /// Create transaction event - optimized with object pool
pub fn create_transaction_event_optimized( pub fn create_transaction_event_optimized(
&self, &self,
update: SubscribeUpdateTransaction, update: SubscribeUpdateTransaction,
@@ -399,27 +399,27 @@ impl EventPrettyPool {
) -> TransactionPretty { ) -> TransactionPretty {
let mut pooled_tx = self.acquire_transaction(); let mut pooled_tx = self.acquire_transaction();
pooled_tx.reset_from_update(update, block_time); pooled_tx.reset_from_update(update, block_time);
// 移动数据而不是克隆 // Move data instead of cloning
let result = std::mem::replace(pooled_tx.deref_mut(), TransactionPretty::default()); let result = std::mem::replace(pooled_tx.deref_mut(), TransactionPretty::default());
result result
} }
} }
// 全局池管理器实例 // Global pool manager instance
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref GLOBAL_POOL_MANAGER: PoolManager = PoolManager::new(); pub static ref GLOBAL_POOL_MANAGER: PoolManager = PoolManager::new();
} }
/// 便捷的全局工厂函数 /// Convenient global factory functions
pub mod factory { pub mod factory {
use super::*; use super::*;
/// 使用对象池创建账户事件(推荐用于高性能场景) /// Create account event using object pool (recommended for high-performance scenarios)
pub fn create_account_pretty_pooled(update: SubscribeUpdateAccount) -> AccountPretty { pub fn create_account_pretty_pooled(update: SubscribeUpdateAccount) -> AccountPretty {
GLOBAL_POOL_MANAGER.get_event_pool().create_account_event_optimized(update) GLOBAL_POOL_MANAGER.get_event_pool().create_account_event_optimized(update)
} }
/// 使用对象池创建区块事件(推荐用于高性能场景) /// Create block event using object pool (recommended for high-performance scenarios)
pub fn create_block_meta_pretty_pooled( pub fn create_block_meta_pretty_pooled(
update: SubscribeUpdateBlockMeta, update: SubscribeUpdateBlockMeta,
block_time: Option<Timestamp>, block_time: Option<Timestamp>,
@@ -427,7 +427,7 @@ pub mod factory {
GLOBAL_POOL_MANAGER.get_event_pool().create_block_event_optimized(update, block_time) GLOBAL_POOL_MANAGER.get_event_pool().create_block_event_optimized(update, block_time)
} }
/// 使用对象池创建交易事件(推荐用于高性能场景) /// Create transaction event using object pool (recommended for high-performance scenarios)
pub fn create_transaction_pretty_pooled( pub fn create_transaction_pretty_pooled(
update: SubscribeUpdateTransaction, update: SubscribeUpdateTransaction,
block_time: Option<Timestamp>, block_time: Option<Timestamp>,
+3 -3
View File
@@ -68,7 +68,7 @@ impl fmt::Debug for BlockMetaPretty {
#[derive(Clone)] #[derive(Clone)]
pub struct TransactionPretty { pub struct TransactionPretty {
pub slot: u64, pub slot: u64,
pub transaction_index: Option<u64>, // 新增:交易在slot中的索引 pub transaction_index: Option<u64>, // New: transaction index within the slot
pub block_hash: String, pub block_hash: String,
pub block_time: Option<Timestamp>, pub block_time: Option<Timestamp>,
pub signature: Signature, pub signature: Signature,
@@ -149,11 +149,11 @@ impl Default for TransactionPretty {
// ), // ),
// ) -> Self { // ) -> Self {
// let tx = transaction.expect("should be defined"); // let tx = transaction.expect("should be defined");
// // 根据用户说明,交易索引在 transaction.index // // According to user notes, transaction index is in transaction.index
// let transaction_index = tx.index; // let transaction_index = tx.index;
// Self { // Self {
// slot, // slot,
// transaction_index: Some(transaction_index), // 提取交易索引 // transaction_index: Some(transaction_index), // Extract transaction index
// block_time, // block_time,
// block_hash: String::new(), // block_hash: String::new(),
// signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"), // signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"),
+10 -10
View File
@@ -8,7 +8,7 @@ use crate::streaming::common::{
MetricsManager, PerformanceMetrics, StreamClientConfig, SubscriptionHandle, MetricsManager, PerformanceMetrics, StreamClientConfig, SubscriptionHandle,
}; };
/// ShredStream gRPC 客户端 /// ShredStream gRPC client
#[derive(Clone)] #[derive(Clone)]
pub struct ShredStreamGrpc { pub struct ShredStreamGrpc {
pub shredstream_client: Arc<ShredstreamProxyClient<Channel>>, pub shredstream_client: Arc<ShredstreamProxyClient<Channel>>,
@@ -17,12 +17,12 @@ pub struct ShredStreamGrpc {
} }
impl ShredStreamGrpc { impl ShredStreamGrpc {
/// 创建客户端,使用默认配置 /// Create client with default configuration
pub async fn new(endpoint: String) -> AnyResult<Self> { pub async fn new(endpoint: String) -> AnyResult<Self> {
Self::new_with_config(endpoint, StreamClientConfig::default()).await Self::new_with_config(endpoint, StreamClientConfig::default()).await
} }
/// 创建客户端,使用自定义配置 /// Create client with custom configuration
pub async fn new_with_config(endpoint: String, config: StreamClientConfig) -> AnyResult<Self> { pub async fn new_with_config(endpoint: String, config: StreamClientConfig) -> AnyResult<Self> {
let shredstream_client = ShredstreamProxyClient::connect(endpoint.clone()).await?; let shredstream_client = ShredstreamProxyClient::connect(endpoint.clone()).await?;
MetricsManager::init(config.enable_metrics); MetricsManager::init(config.enable_metrics);
@@ -33,37 +33,37 @@ impl ShredStreamGrpc {
}) })
} }
/// 获取当前配置 /// Get current configuration
pub fn get_config(&self) -> &StreamClientConfig { pub fn get_config(&self) -> &StreamClientConfig {
&self.config &self.config
} }
/// 更新配置 /// Update configuration
pub fn update_config(&mut self, config: StreamClientConfig) { pub fn update_config(&mut self, config: StreamClientConfig) {
self.config = config; self.config = config;
} }
/// 获取性能指标 /// Get performance metrics
pub fn get_metrics(&self) -> PerformanceMetrics { pub fn get_metrics(&self) -> PerformanceMetrics {
MetricsManager::global().get_metrics() MetricsManager::global().get_metrics()
} }
/// 启用或禁用性能监控 /// Enable or disable performance monitoring
pub fn set_enable_metrics(&mut self, enabled: bool) { pub fn set_enable_metrics(&mut self, enabled: bool) {
self.config.enable_metrics = enabled; self.config.enable_metrics = enabled;
} }
/// 打印性能指标 /// Print performance metrics
pub fn print_metrics(&self) { pub fn print_metrics(&self) {
MetricsManager::global().print_metrics(); MetricsManager::global().print_metrics();
} }
/// 启动自动性能监控任务 /// Start automatic performance monitoring task
pub async fn start_auto_metrics_monitoring(&self) { pub async fn start_auto_metrics_monitoring(&self) {
MetricsManager::global().start_auto_monitoring().await; MetricsManager::global().start_auto_monitoring().await;
} }
/// 停止当前订阅 /// Stop current subscription
pub async fn stop(&self) { pub async fn stop(&self) {
let mut handle_guard = self.subscription_handle.lock().await; let mut handle_guard = self.subscription_handle.lock().await;
if let Some(handle) = handle_guard.take() { if let Some(handle) = handle_guard.take() {
+3 -3
View File
@@ -1,14 +1,14 @@
// ShredStream 相关模块 // ShredStream related modules
pub mod connection; pub mod connection;
pub mod pool; pub mod pool;
pub mod types; pub mod types;
// 重新导出主要类型 // Re-export main types
pub use connection::*; pub use connection::*;
pub use pool::*; pub use pool::*;
pub use types::*; pub use types::*;
// 从公用模块重新导出 // Re-export from common modules
pub use crate::streaming::common::{ pub use crate::streaming::common::{
ConnectionConfig, MetricsEventType, MetricsManager, PerformanceMetrics, StreamClientConfig, ConnectionConfig, MetricsEventType, MetricsManager, PerformanceMetrics, StreamClientConfig,
}; };
+15 -15
View File
@@ -6,7 +6,7 @@ use solana_sdk::transaction::VersionedTransaction;
use super::TransactionWithSlot; use super::TransactionWithSlot;
/// TransactionWithSlot 对象池 /// TransactionWithSlot object pool
pub struct TransactionWithSlotPool { pub struct TransactionWithSlotPool {
pool: Arc<Mutex<VecDeque<Box<TransactionWithSlot>>>>, pool: Arc<Mutex<VecDeque<Box<TransactionWithSlot>>>>,
max_size: usize, max_size: usize,
@@ -16,7 +16,7 @@ impl TransactionWithSlotPool {
pub fn new(initial_size: usize, max_size: usize) -> Self { pub fn new(initial_size: usize, max_size: usize) -> Self {
let mut pool = VecDeque::with_capacity(initial_size); let mut pool = VecDeque::with_capacity(initial_size);
// 预分配对象 // Pre-allocate objects
for _ in 0..initial_size { for _ in 0..initial_size {
pool.push_back(Box::new(TransactionWithSlot::default())); pool.push_back(Box::new(TransactionWithSlot::default()));
} }
@@ -39,7 +39,7 @@ impl TransactionWithSlotPool {
} }
} }
/// 带自动归还的 TransactionWithSlot /// TransactionWithSlot with automatic return
pub struct PooledTransactionWithSlot { pub struct PooledTransactionWithSlot {
transaction: Box<TransactionWithSlot>, transaction: Box<TransactionWithSlot>,
pool: Arc<Mutex<VecDeque<Box<TransactionWithSlot>>>>, pool: Arc<Mutex<VecDeque<Box<TransactionWithSlot>>>>,
@@ -47,7 +47,7 @@ pub struct PooledTransactionWithSlot {
} }
impl PooledTransactionWithSlot { impl PooledTransactionWithSlot {
/// 从原始数据重置 /// Reset from raw data
pub fn reset_from_data( pub fn reset_from_data(
&mut self, &mut self,
transaction: VersionedTransaction, transaction: VersionedTransaction,
@@ -59,9 +59,9 @@ impl PooledTransactionWithSlot {
self.transaction.recv_us = recv_us; self.transaction.recv_us = recv_us;
} }
/// 使用优化的工厂方法创建 TransactionWithSlot(移动数据而不是克隆) /// Create TransactionWithSlot using optimized factory method (move data instead of cloning)
pub fn into_transaction_with_slot(mut self) -> TransactionWithSlot { pub fn into_transaction_with_slot(mut self) -> TransactionWithSlot {
// 移动数据而不是克隆,避免多余的内存分配 // Move data instead of cloning to avoid unnecessary memory allocation
std::mem::replace(self.deref_mut(), TransactionWithSlot::default()) std::mem::replace(self.deref_mut(), TransactionWithSlot::default())
} }
} }
@@ -70,10 +70,10 @@ impl Drop for PooledTransactionWithSlot {
fn drop(&mut self) { fn drop(&mut self) {
let mut pool = self.pool.lock().unwrap(); let mut pool = self.pool.lock().unwrap();
if pool.len() < self.max_size { if pool.len() < self.max_size {
// 清理敏感数据 // Clear sensitive data
self.transaction.slot = 0; self.transaction.slot = 0;
self.transaction.recv_us = 0; self.transaction.recv_us = 0;
// 重置交易为默认值以清理敏感数据 // Reset transaction to default to clear sensitive data
self.transaction.transaction = VersionedTransaction::default(); self.transaction.transaction = VersionedTransaction::default();
pool.push_back(std::mem::take(&mut self.transaction)); pool.push_back(std::mem::take(&mut self.transaction));
} }
@@ -94,7 +94,7 @@ impl std::ops::DerefMut for PooledTransactionWithSlot {
} }
} }
/// Shred 对象池管理器 /// Shred object pool manager
pub struct ShredPoolManager { pub struct ShredPoolManager {
transaction_pool: TransactionWithSlotPool, transaction_pool: TransactionWithSlotPool,
} }
@@ -103,8 +103,8 @@ impl ShredPoolManager {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
transaction_pool: TransactionWithSlotPool::new( transaction_pool: TransactionWithSlotPool::new(
5000, // 初始大小 - Shred 事件通常较多 5000, // Initial size - Shred events are usually numerous
15000, // 最大大小 15000, // Max size
), ),
} }
} }
@@ -113,7 +113,7 @@ impl ShredPoolManager {
&self.transaction_pool &self.transaction_pool
} }
/// 创建优化的 TransactionWithSlot /// Create optimized TransactionWithSlot
pub fn create_transaction_with_slot_optimized( pub fn create_transaction_with_slot_optimized(
&self, &self,
transaction: VersionedTransaction, transaction: VersionedTransaction,
@@ -132,16 +132,16 @@ impl Default for ShredPoolManager {
} }
} }
// 全局 Shred 池管理器实例 // Global Shred pool manager instance
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref GLOBAL_SHRED_POOL_MANAGER: ShredPoolManager = ShredPoolManager::new(); pub static ref GLOBAL_SHRED_POOL_MANAGER: ShredPoolManager = ShredPoolManager::new();
} }
/// 便捷的全局工厂函数 /// Convenient global factory functions
pub mod factory { pub mod factory {
use super::*; use super::*;
/// 使用对象池创建 TransactionWithSlot(推荐用于高性能场景) /// Create TransactionWithSlot using object pool (recommended for high-performance scenarios)
pub fn create_transaction_with_slot_pooled( pub fn create_transaction_with_slot_pooled(
transaction: VersionedTransaction, transaction: VersionedTransaction,
slot: u64, slot: u64,
+2 -2
View File
@@ -1,6 +1,6 @@
use solana_sdk::transaction::VersionedTransaction; use solana_sdk::transaction::VersionedTransaction;
/// 携带槽位信息的交易 /// Transaction with slot information
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct TransactionWithSlot { pub struct TransactionWithSlot {
pub transaction: VersionedTransaction, pub transaction: VersionedTransaction,
@@ -9,7 +9,7 @@ pub struct TransactionWithSlot {
} }
impl TransactionWithSlot { impl TransactionWithSlot {
/// 创建新的带槽位的交易 /// Create new transaction with slot
pub fn new( pub fn new(
transaction: VersionedTransaction, transaction: VersionedTransaction,
slot: u64, slot: u64,
+5 -5
View File
@@ -17,7 +17,7 @@ use solana_entry::entry::Entry;
use super::ShredStreamGrpc; use super::ShredStreamGrpc;
impl ShredStreamGrpc { impl ShredStreamGrpc {
/// 订阅ShredStream事件(支持批处理和即时处理) /// Subscribe to ShredStream events (supports batch and real-time processing)
pub async fn shredstream_subscribe<F>( pub async fn shredstream_subscribe<F>(
&self, &self,
protocols: Vec<Protocol>, protocols: Vec<Protocol>,
@@ -28,16 +28,16 @@ impl ShredStreamGrpc {
where where
F: Fn(DexEvent) + Send + Sync + 'static, F: Fn(DexEvent) + Send + Sync + 'static,
{ {
// 如果已有活跃订阅,先停止它 // If there's an active subscription, stop it first
self.stop().await; self.stop().await;
let mut metrics_handle = None; let mut metrics_handle = None;
// 启动自动性能监控(如果启用) // Start automatic performance monitoring (if enabled)
if self.config.enable_metrics { if self.config.enable_metrics {
metrics_handle = MetricsManager::global().start_auto_monitoring().await; metrics_handle = MetricsManager::global().start_auto_monitoring().await;
} }
// 启动流处理 // Start stream processing
let mut client = (*self.shredstream_client).clone(); let mut client = (*self.shredstream_client).clone();
let request = tonic::Request::new(SubscribeEntriesRequest {}); let request = tonic::Request::new(SubscribeEntriesRequest {});
let mut stream = client.subscribe_entries(request).await?.into_inner(); let mut stream = client.subscribe_entries(request).await?.into_inner();
@@ -83,7 +83,7 @@ impl ShredStreamGrpc {
} }
}); });
// 保存订阅句柄 // Save subscription handle
let subscription_handle = SubscriptionHandle::new(stream_task, None, metrics_handle); let subscription_handle = SubscriptionHandle::new(stream_task, None, metrics_handle);
let mut handle_guard = self.subscription_handle.lock().await; let mut handle_guard = self.subscription_handle.lock().await;
*handle_guard = Some(subscription_handle); *handle_guard = Some(subscription_handle);
+17 -17
View File
@@ -21,7 +21,7 @@ use yellowstone_grpc_proto::geyser::{
CommitmentLevel, SubscribeRequest, SubscribeRequestFilterAccountsFilter, SubscribeRequestPing, CommitmentLevel, SubscribeRequest, SubscribeRequestFilterAccountsFilter, SubscribeRequestPing,
}; };
/// 交易过滤器 /// Transaction filter
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TransactionFilter { pub struct TransactionFilter {
pub account_include: Vec<String>, pub account_include: Vec<String>,
@@ -29,7 +29,7 @@ pub struct TransactionFilter {
pub account_required: Vec<String>, pub account_required: Vec<String>,
} }
/// 账户过滤器 /// Account filter
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AccountFilter { pub struct AccountFilter {
pub account: Vec<String>, pub account: Vec<String>,
@@ -52,12 +52,12 @@ pub struct YellowstoneGrpc {
} }
impl YellowstoneGrpc { impl YellowstoneGrpc {
/// 创建客户端,使用默认配置 /// Create client with default configuration
pub fn new(endpoint: String, x_token: Option<String>) -> AnyResult<Self> { pub fn new(endpoint: String, x_token: Option<String>) -> AnyResult<Self> {
Self::new_with_config(endpoint, x_token, StreamClientConfig::default()) Self::new_with_config(endpoint, x_token, StreamClientConfig::default())
} }
/// 创建客户端,使用自定义配置 /// Create client with custom configuration
pub fn new_with_config( pub fn new_with_config(
endpoint: String, endpoint: String,
x_token: Option<String>, x_token: Option<String>,
@@ -81,32 +81,32 @@ impl YellowstoneGrpc {
}) })
} }
/// 获取配置 /// Get configuration
pub fn get_config(&self) -> &StreamClientConfig { pub fn get_config(&self) -> &StreamClientConfig {
&self.config &self.config
} }
/// 更新配置 /// Update configuration
pub fn update_config(&mut self, config: StreamClientConfig) { pub fn update_config(&mut self, config: StreamClientConfig) {
self.config = config; self.config = config;
} }
/// 获取性能指标 /// Get performance metrics
pub fn get_metrics(&self) -> PerformanceMetrics { pub fn get_metrics(&self) -> PerformanceMetrics {
MetricsManager::global().get_metrics() MetricsManager::global().get_metrics()
} }
/// 打印性能指标 /// Print performance metrics
pub fn print_metrics(&self) { pub fn print_metrics(&self) {
MetricsManager::global().print_metrics(); MetricsManager::global().print_metrics();
} }
/// 启用或禁用性能监控 /// Enable or disable performance monitoring
pub fn set_enable_metrics(&mut self, enabled: bool) { pub fn set_enable_metrics(&mut self, enabled: bool) {
self.config.enable_metrics = enabled; self.config.enable_metrics = enabled;
} }
/// 停止当前订阅 /// Stop current subscription
pub async fn stop(&self) { pub async fn stop(&self) {
let mut handle_guard = self.subscription_handle.lock().await; let mut handle_guard = self.subscription_handle.lock().await;
if let Some(handle) = handle_guard.take() { if let Some(handle) = handle_guard.take() {
@@ -153,7 +153,7 @@ impl YellowstoneGrpc {
} }
let mut metrics_handle = None; let mut metrics_handle = None;
// 启动自动性能监控(如果启用) // Start automatic performance monitoring (if enabled)
if self.config.enable_metrics { if self.config.enable_metrics {
metrics_handle = MetricsManager::global().start_auto_monitoring().await; metrics_handle = MetricsManager::global().start_auto_monitoring().await;
} }
@@ -165,13 +165,13 @@ impl YellowstoneGrpc {
.subscription_manager .subscription_manager
.subscribe_with_account_request(account_filter, event_type_filter.as_ref()); .subscribe_with_account_request(account_filter, event_type_filter.as_ref());
// 订阅事件 // Subscribe to events
let (subscribe_tx, mut stream, subscribe_request) = self let (subscribe_tx, mut stream, subscribe_request) = self
.subscription_manager .subscription_manager
.subscribe_with_request(transactions, accounts, commitment, event_type_filter.as_ref()) .subscribe_with_request(transactions, accounts, commitment, event_type_filter.as_ref())
.await?; .await?;
// Arc<Mutex<>> 包装 subscribe_tx 以支持多线程共享 // Wrap subscribe_tx with Arc<Mutex<>> to support multi-threaded sharing
let subscribe_tx = Arc::new(Mutex::new(subscribe_tx)); let subscribe_tx = Arc::new(Mutex::new(subscribe_tx));
*self.current_request.write().await = Some(subscribe_request); *self.current_request.write().await = Some(subscribe_request);
let (control_tx, mut control_rx) = mpsc::channel(100); let (control_tx, mut control_rx) = mpsc::channel(100);
@@ -238,7 +238,7 @@ impl YellowstoneGrpc {
} }
} }
Some(UpdateOneof::Ping(_)) => { Some(UpdateOneof::Ping(_)) => {
// 只在需要时获取锁,并立即释放 // Only acquire lock when needed and release immediately
if let Ok(mut tx_guard) = subscribe_tx.try_lock() { if let Ok(mut tx_guard) = subscribe_tx.try_lock() {
let _ = tx_guard let _ = tx_guard
.send(SubscribeRequest { .send(SubscribeRequest {
@@ -274,7 +274,7 @@ impl YellowstoneGrpc {
} }
}); });
// 保存订阅句柄 // Save subscription handle
let subscription_handle = SubscriptionHandle::new(stream_handle, None, metrics_handle); let subscription_handle = SubscriptionHandle::new(stream_handle, None, metrics_handle);
let mut handle_guard = self.subscription_handle.lock().await; let mut handle_guard = self.subscription_handle.lock().await;
*handle_guard = Some(subscription_handle); *handle_guard = Some(subscription_handle);
@@ -343,7 +343,7 @@ impl YellowstoneGrpc {
} }
} }
// 实现 Clone trait 以支持模块间共享 // Implement Clone trait to support sharing between modules
impl Clone for YellowstoneGrpc { impl Clone for YellowstoneGrpc {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@@ -351,7 +351,7 @@ impl Clone for YellowstoneGrpc {
x_token: self.x_token.clone(), x_token: self.x_token.clone(),
config: self.config.clone(), config: self.config.clone(),
subscription_manager: self.subscription_manager.clone(), subscription_manager: self.subscription_manager.clone(),
subscription_handle: self.subscription_handle.clone(), // 共享同一个 Arc<Mutex<>> subscription_handle: self.subscription_handle.clone(), // Share the same Arc<Mutex<>>
active_subscription: self.active_subscription.clone(), active_subscription: self.active_subscription.clone(),
control_tx: self.control_tx.clone(), control_tx: self.control_tx.clone(),
event_type_filter: self.event_type_filter.clone(), event_type_filter: self.event_type_filter.clone(),