mirror of
https://github.com/0xfnzero/solana-streamer.git
synced 2026-08-25 23:08:05 +00:00
add block_time and block_time_ms
This commit is contained in:
+7
-7
@@ -22,7 +22,7 @@ use solana_streamer_sdk::{
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
test_grpc().await?;
|
test_grpc().await?;
|
||||||
test_shreds().await?;
|
// test_shreds().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,11 +36,11 @@ async fn test_grpc() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let callback = create_event_callback();
|
let callback = create_event_callback();
|
||||||
let protocols = vec![
|
let protocols = vec![
|
||||||
Protocol::PumpFun,
|
// Protocol::PumpFun,
|
||||||
Protocol::PumpSwap,
|
// Protocol::PumpSwap,
|
||||||
Protocol::Bonk,
|
Protocol::Bonk,
|
||||||
Protocol::RaydiumCpmm,
|
// Protocol::RaydiumCpmm,
|
||||||
Protocol::RaydiumClmm,
|
// Protocol::RaydiumClmm,
|
||||||
];
|
];
|
||||||
|
|
||||||
println!("开始监听事件,按 Ctrl+C 停止...");
|
println!("开始监听事件,按 Ctrl+C 停止...");
|
||||||
@@ -75,10 +75,10 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
|
|||||||
|event: Box<dyn UnifiedEvent>| {
|
|event: Box<dyn UnifiedEvent>| {
|
||||||
match_event!(event, {
|
match_event!(event, {
|
||||||
BlockMetaEvent => |e: BlockMetaEvent| {
|
BlockMetaEvent => |e: BlockMetaEvent| {
|
||||||
println!("BlockMetaEvent: {:?}", e.slot);
|
// println!("BlockMetaEvent: {:?}", e.slot);
|
||||||
},
|
},
|
||||||
BonkPoolCreateEvent => |e: BonkPoolCreateEvent| {
|
BonkPoolCreateEvent => |e: BonkPoolCreateEvent| {
|
||||||
println!("BonkPoolCreateEvent: {:?}", e.base_mint_param.symbol);
|
// println!("BonkPoolCreateEvent: {:?}", e.base_mint_param.symbol);
|
||||||
},
|
},
|
||||||
BonkTradeEvent => |e: BonkTradeEvent| {
|
BonkTradeEvent => |e: BonkTradeEvent| {
|
||||||
println!("BonkTradeEvent: {:?}", e);
|
println!("BonkTradeEvent: {:?}", e);
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
use borsh::{BorshDeserialize, BorshSerialize};
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::instruction::CompiledInstruction;
|
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::UiInstruction;
|
||||||
UiCompiledInstruction, UiInstruction, UiTransactionStatusMeta, UiTransactionTokenBalance,
|
|
||||||
};
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
@@ -158,6 +155,8 @@ pub struct EventMetadata {
|
|||||||
pub id: String,
|
pub id: String,
|
||||||
pub signature: String,
|
pub signature: String,
|
||||||
pub slot: u64,
|
pub slot: u64,
|
||||||
|
pub block_time: i64,
|
||||||
|
pub block_time_ms: i64,
|
||||||
pub program_received_time_ms: i64,
|
pub program_received_time_ms: i64,
|
||||||
pub protocol: ProtocolType,
|
pub protocol: ProtocolType,
|
||||||
pub event_type: EventType,
|
pub event_type: EventType,
|
||||||
@@ -170,6 +169,8 @@ impl EventMetadata {
|
|||||||
id: String,
|
id: String,
|
||||||
signature: String,
|
signature: String,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: i64,
|
||||||
|
block_time_ms: i64,
|
||||||
protocol: ProtocolType,
|
protocol: ProtocolType,
|
||||||
event_type: EventType,
|
event_type: EventType,
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
@@ -178,6 +179,8 @@ impl EventMetadata {
|
|||||||
id,
|
id,
|
||||||
signature,
|
signature,
|
||||||
slot,
|
slot,
|
||||||
|
block_time,
|
||||||
|
block_time_ms,
|
||||||
program_received_time_ms: chrono::Utc::now().timestamp_millis(),
|
program_received_time_ms: chrono::Utc::now().timestamp_millis(),
|
||||||
protocol,
|
protocol,
|
||||||
event_type,
|
event_type,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use borsh::BorshDeserialize;
|
use borsh::BorshDeserialize;
|
||||||
|
use prost_types::Timestamp;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
instruction::CompiledInstruction, pubkey::Pubkey, transaction::VersionedTransaction,
|
instruction::CompiledInstruction, pubkey::Pubkey, transaction::VersionedTransaction,
|
||||||
@@ -7,6 +8,7 @@ use solana_sdk::{
|
|||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
EncodedTransactionWithStatusMeta, UiCompiledInstruction, UiInnerInstructions, UiInstruction,
|
EncodedTransactionWithStatusMeta, UiCompiledInstruction, UiInnerInstructions, UiInstruction,
|
||||||
};
|
};
|
||||||
|
use yellowstone_grpc_proto::prelude::UnixTimestamp;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{collections::HashMap, str::FromStr};
|
||||||
use yellowstone_grpc_proto::geyser::SubscribeUpdateBlockMeta;
|
use yellowstone_grpc_proto::geyser::SubscribeUpdateBlockMeta;
|
||||||
@@ -78,6 +80,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
instruction: &UiCompiledInstruction,
|
instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>>;
|
) -> Vec<Box<dyn UnifiedEvent>>;
|
||||||
|
|
||||||
/// 从指令中解析事件数据
|
/// 从指令中解析事件数据
|
||||||
@@ -87,6 +90,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>>;
|
) -> Vec<Box<dyn UnifiedEvent>>;
|
||||||
|
|
||||||
/// 从VersionedTransaction中解析指令事件的通用方法
|
/// 从VersionedTransaction中解析指令事件的通用方法
|
||||||
@@ -95,6 +99,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
versioned_tx: &VersionedTransaction,
|
versioned_tx: &VersionedTransaction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: Option<u64>,
|
slot: Option<u64>,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
inner_instructions: &[UiInnerInstructions],
|
inner_instructions: &[UiInnerInstructions],
|
||||||
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
||||||
@@ -118,7 +123,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(mut events) = self
|
if let Ok(mut events) = self
|
||||||
.parse_instruction(instruction, &accounts, signature, slot)
|
.parse_instruction(instruction, &accounts, signature, slot, block_time)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
if events.len() > 0 {
|
if events.len() > 0 {
|
||||||
@@ -153,6 +158,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
versioned_tx: &VersionedTransaction,
|
versioned_tx: &VersionedTransaction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: Option<u64>,
|
slot: Option<u64>,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
bot_wallet: Option<Pubkey>,
|
bot_wallet: Option<Pubkey>,
|
||||||
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
||||||
let accounts: Vec<Pubkey> = versioned_tx.message.static_account_keys().to_vec();
|
let accounts: Vec<Pubkey> = versioned_tx.message.static_account_keys().to_vec();
|
||||||
@@ -161,6 +167,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
versioned_tx,
|
versioned_tx,
|
||||||
signature,
|
signature,
|
||||||
slot,
|
slot,
|
||||||
|
block_time,
|
||||||
&accounts,
|
&accounts,
|
||||||
&vec![],
|
&vec![],
|
||||||
)
|
)
|
||||||
@@ -174,6 +181,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
tx: EncodedTransactionWithStatusMeta,
|
tx: EncodedTransactionWithStatusMeta,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: Option<u64>,
|
slot: Option<u64>,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
bot_wallet: Option<Pubkey>,
|
bot_wallet: Option<Pubkey>,
|
||||||
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
||||||
let transaction = tx.transaction;
|
let transaction = tx.transaction;
|
||||||
@@ -209,6 +217,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
&versioned_tx,
|
&versioned_tx,
|
||||||
signature,
|
signature,
|
||||||
slot,
|
slot,
|
||||||
|
block_time,
|
||||||
&accounts,
|
&accounts,
|
||||||
&inner_instructions,
|
&inner_instructions,
|
||||||
)
|
)
|
||||||
@@ -238,6 +247,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
&accounts,
|
&accounts,
|
||||||
signature,
|
signature,
|
||||||
slot,
|
slot,
|
||||||
|
block_time,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -256,7 +266,7 @@ pub trait EventParser: Send + Sync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(mut events) = self
|
if let Ok(mut events) = self
|
||||||
.parse_inner_instruction(compiled, signature, slot)
|
.parse_inner_instruction(compiled, signature, slot, block_time)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
if events.len() > 0 {
|
if events.len() > 0 {
|
||||||
@@ -335,9 +345,10 @@ pub trait EventParser: Send + Sync {
|
|||||||
instruction: &UiCompiledInstruction,
|
instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: Option<u64>,
|
slot: Option<u64>,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
||||||
let slot = slot.unwrap_or(0);
|
let slot = slot.unwrap_or(0);
|
||||||
let events = self.parse_events_from_inner_instruction(instruction, signature, slot);
|
let events = self.parse_events_from_inner_instruction(instruction, signature, slot, block_time);
|
||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +358,10 @@ pub trait EventParser: Send + Sync {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: Option<u64>,
|
slot: Option<u64>,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
) -> Result<Vec<Box<dyn UnifiedEvent>>> {
|
||||||
let slot = slot.unwrap_or(0);
|
let slot = slot.unwrap_or(0);
|
||||||
let events = self.parse_events_from_instruction(instruction, accounts, signature, slot);
|
let events = self.parse_events_from_instruction(instruction, accounts, signature, slot, block_time);
|
||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,11 +441,16 @@ impl GenericEventParser {
|
|||||||
data: &[u8],
|
data: &[u8],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Option<Box<dyn UnifiedEvent>> {
|
) -> Option<Box<dyn UnifiedEvent>> {
|
||||||
|
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 metadata = EventMetadata::new(
|
let metadata = EventMetadata::new(
|
||||||
signature.to_string(),
|
signature.to_string(),
|
||||||
signature.to_string(),
|
signature.to_string(),
|
||||||
slot,
|
slot,
|
||||||
|
timestamp.seconds,
|
||||||
|
block_time_ms,
|
||||||
self.protocol_type.clone(),
|
self.protocol_type.clone(),
|
||||||
config.event_type.clone(),
|
config.event_type.clone(),
|
||||||
self.program_id,
|
self.program_id,
|
||||||
@@ -449,11 +466,16 @@ impl GenericEventParser {
|
|||||||
account_pubkeys: &[Pubkey],
|
account_pubkeys: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Option<Box<dyn UnifiedEvent>> {
|
) -> Option<Box<dyn UnifiedEvent>> {
|
||||||
|
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 metadata = EventMetadata::new(
|
let metadata = EventMetadata::new(
|
||||||
signature.to_string(),
|
signature.to_string(),
|
||||||
signature.to_string(),
|
signature.to_string(),
|
||||||
slot,
|
slot,
|
||||||
|
timestamp.seconds,
|
||||||
|
block_time_ms,
|
||||||
self.protocol_type.clone(),
|
self.protocol_type.clone(),
|
||||||
config.event_type.clone(),
|
config.event_type.clone(),
|
||||||
self.program_id,
|
self.program_id,
|
||||||
@@ -470,6 +492,7 @@ impl EventParser for GenericEventParser {
|
|||||||
inner_instruction: &UiCompiledInstruction,
|
inner_instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
let inner_instruction_data = inner_instruction.data.clone();
|
let inner_instruction_data = inner_instruction.data.clone();
|
||||||
let inner_instruction_data_decoded =
|
let inner_instruction_data_decoded =
|
||||||
@@ -485,7 +508,7 @@ impl EventParser for GenericEventParser {
|
|||||||
if discriminator_matches(&inner_instruction_data_decoded_str, disc) {
|
if discriminator_matches(&inner_instruction_data_decoded_str, disc) {
|
||||||
for config in configs {
|
for config in configs {
|
||||||
if let Some(event) =
|
if let Some(event) =
|
||||||
self.parse_inner_instruction_event(config, data, signature, slot)
|
self.parse_inner_instruction_event(config, data, signature, slot, block_time)
|
||||||
{
|
{
|
||||||
events.push(event);
|
events.push(event);
|
||||||
}
|
}
|
||||||
@@ -502,6 +525,7 @@ impl EventParser for GenericEventParser {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
let program_id = accounts[instruction.program_id_index as usize];
|
let program_id = accounts[instruction.program_id_index as usize];
|
||||||
if !self.should_handle(&program_id) {
|
if !self.should_handle(&program_id) {
|
||||||
@@ -532,6 +556,7 @@ impl EventParser for GenericEventParser {
|
|||||||
&account_pubkeys,
|
&account_pubkeys,
|
||||||
signature,
|
signature,
|
||||||
slot,
|
slot,
|
||||||
|
block_time,
|
||||||
) {
|
) {
|
||||||
events.push(event);
|
events.push(event);
|
||||||
}
|
}
|
||||||
@@ -554,11 +579,14 @@ impl EventParser for GenericEventParser {
|
|||||||
pub struct SDKSystemEventParser {}
|
pub struct SDKSystemEventParser {}
|
||||||
impl SDKSystemEventParser {
|
impl SDKSystemEventParser {
|
||||||
pub fn parse_block(block: SubscribeUpdateBlockMeta) -> Box<dyn UnifiedEvent> {
|
pub fn parse_block(block: SubscribeUpdateBlockMeta) -> Box<dyn UnifiedEvent> {
|
||||||
|
let block_time = block.block_time.unwrap_or(UnixTimestamp { timestamp: 0 });
|
||||||
Box::new(BlockMetaEvent {
|
Box::new(BlockMetaEvent {
|
||||||
metadata: EventMetadata::new(
|
metadata: EventMetadata::new(
|
||||||
block.blockhash.to_string(),
|
block.blockhash.to_string(),
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
block.slot,
|
block.slot,
|
||||||
|
block_time.timestamp,
|
||||||
|
block_time.timestamp * 1000,
|
||||||
ProtocolType::SDKSystem,
|
ProtocolType::SDKSystem,
|
||||||
EventType::SDKSystem,
|
EventType::SDKSystem,
|
||||||
Pubkey::default(),
|
Pubkey::default(),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use prost_types::Timestamp;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use solana_transaction_status::UiCompiledInstruction;
|
use solana_transaction_status::UiCompiledInstruction;
|
||||||
|
|
||||||
@@ -419,9 +420,10 @@ impl EventParser for BonkEventParser {
|
|||||||
inner_instruction: &UiCompiledInstruction,
|
inner_instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_inner_instruction(inner_instruction, signature, slot)
|
.parse_events_from_inner_instruction(inner_instruction, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_events_from_instruction(
|
fn parse_events_from_instruction(
|
||||||
@@ -430,9 +432,10 @@ impl EventParser for BonkEventParser {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_instruction(instruction, accounts, signature, slot)
|
.parse_events_from_instruction(instruction, accounts, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use prost_types::Timestamp;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use solana_transaction_status::UiCompiledInstruction;
|
use solana_transaction_status::UiCompiledInstruction;
|
||||||
|
|
||||||
@@ -224,9 +225,10 @@ impl EventParser for PumpFunEventParser {
|
|||||||
inner_instruction: &UiCompiledInstruction,
|
inner_instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_inner_instruction(inner_instruction, signature, slot)
|
.parse_events_from_inner_instruction(inner_instruction, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_events_from_instruction(
|
fn parse_events_from_instruction(
|
||||||
@@ -235,9 +237,10 @@ impl EventParser for PumpFunEventParser {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_instruction(instruction, accounts, signature, slot)
|
.parse_events_from_instruction(instruction, accounts, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use prost_types::Timestamp;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use solana_transaction_status::UiCompiledInstruction;
|
use solana_transaction_status::UiCompiledInstruction;
|
||||||
|
|
||||||
@@ -360,9 +361,10 @@ impl EventParser for PumpSwapEventParser {
|
|||||||
inner_instruction: &UiCompiledInstruction,
|
inner_instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_inner_instruction(inner_instruction, signature, slot)
|
.parse_events_from_inner_instruction(inner_instruction, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_events_from_instruction(
|
fn parse_events_from_instruction(
|
||||||
@@ -371,9 +373,10 @@ impl EventParser for PumpSwapEventParser {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_instruction(instruction, accounts, signature, slot)
|
.parse_events_from_instruction(instruction, accounts, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use prost_types::Timestamp;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use solana_transaction_status::UiCompiledInstruction;
|
use solana_transaction_status::UiCompiledInstruction;
|
||||||
|
|
||||||
@@ -144,9 +145,10 @@ impl EventParser for RaydiumClmmEventParser {
|
|||||||
inner_instruction: &UiCompiledInstruction,
|
inner_instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_inner_instruction(inner_instruction, signature, slot)
|
.parse_events_from_inner_instruction(inner_instruction, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_events_from_instruction(
|
fn parse_events_from_instruction(
|
||||||
@@ -155,9 +157,10 @@ impl EventParser for RaydiumClmmEventParser {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_instruction(instruction, accounts, signature, slot)
|
.parse_events_from_instruction(instruction, accounts, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use prost_types::Timestamp;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use solana_transaction_status::UiCompiledInstruction;
|
use solana_transaction_status::UiCompiledInstruction;
|
||||||
|
|
||||||
@@ -133,9 +134,10 @@ impl EventParser for RaydiumCpmmEventParser {
|
|||||||
inner_instruction: &UiCompiledInstruction,
|
inner_instruction: &UiCompiledInstruction,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_inner_instruction(inner_instruction, signature, slot)
|
.parse_events_from_inner_instruction(inner_instruction, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_events_from_instruction(
|
fn parse_events_from_instruction(
|
||||||
@@ -144,9 +146,10 @@ impl EventParser for RaydiumCpmmEventParser {
|
|||||||
accounts: &[Pubkey],
|
accounts: &[Pubkey],
|
||||||
signature: &str,
|
signature: &str,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
block_time: Option<Timestamp>,
|
||||||
) -> Vec<Box<dyn UnifiedEvent>> {
|
) -> Vec<Box<dyn UnifiedEvent>> {
|
||||||
self.inner
|
self.inner
|
||||||
.parse_events_from_instruction(instruction, accounts, signature, slot)
|
.parse_events_from_instruction(instruction, accounts, signature, slot, block_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
fn should_handle(&self, program_id: &Pubkey) -> bool {
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ impl ShredStreamGrpc {
|
|||||||
&versioned_tx,
|
&versioned_tx,
|
||||||
&signature.to_string(),
|
&signature.to_string(),
|
||||||
Some(slot),
|
Some(slot),
|
||||||
|
None,
|
||||||
bot_wallet.clone(),
|
bot_wallet.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::{collections::HashMap, fmt, time::Duration};
|
|||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use futures::{channel::mpsc, sink::Sink, SinkExt, Stream, StreamExt};
|
use futures::{channel::mpsc, sink::Sink, SinkExt, Stream, StreamExt};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
use prost_types::Timestamp;
|
||||||
use rustls::crypto::{ring::default_provider, CryptoProvider};
|
use rustls::crypto::{ring::default_provider, CryptoProvider};
|
||||||
use solana_sdk::{pubkey::Pubkey, signature::Signature};
|
use solana_sdk::{pubkey::Pubkey, signature::Signature};
|
||||||
use solana_transaction_status::{EncodedTransactionWithStatusMeta, UiTransactionEncoding};
|
use solana_transaction_status::{EncodedTransactionWithStatusMeta, UiTransactionEncoding};
|
||||||
@@ -30,6 +31,7 @@ const MAX_DECODING_MESSAGE_SIZE: usize = 1024 * 1024 * 10;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TransactionPretty {
|
pub struct TransactionPretty {
|
||||||
pub slot: u64,
|
pub slot: u64,
|
||||||
|
pub block_time: Option<Timestamp>,
|
||||||
pub signature: Signature,
|
pub signature: Signature,
|
||||||
pub is_vote: bool,
|
pub is_vote: bool,
|
||||||
pub tx: EncodedTransactionWithStatusMeta,
|
pub tx: EncodedTransactionWithStatusMeta,
|
||||||
@@ -54,11 +56,12 @@ impl fmt::Debug for TransactionPretty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SubscribeUpdateTransaction> for TransactionPretty {
|
impl From<(SubscribeUpdateTransaction, Option<Timestamp>)> for TransactionPretty {
|
||||||
fn from(SubscribeUpdateTransaction { transaction, slot }: SubscribeUpdateTransaction) -> Self {
|
fn from((SubscribeUpdateTransaction { transaction, slot }, block_time): (SubscribeUpdateTransaction, Option<Timestamp>)) -> Self {
|
||||||
let tx = transaction.expect("should be defined");
|
let tx = transaction.expect("should be defined");
|
||||||
Self {
|
Self {
|
||||||
slot,
|
slot,
|
||||||
|
block_time: block_time,
|
||||||
signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"),
|
signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"),
|
||||||
is_vote: tx.is_vote,
|
is_vote: tx.is_vote,
|
||||||
tx: yellowstone_grpc_proto::convert_from::create_tx_with_meta(tx)
|
tx: yellowstone_grpc_proto::convert_from::create_tx_with_meta(tx)
|
||||||
@@ -149,17 +152,12 @@ impl YellowstoneGrpc {
|
|||||||
pub async fn handle_stream_message(
|
pub async fn handle_stream_message(
|
||||||
msg: SubscribeUpdate,
|
msg: SubscribeUpdate,
|
||||||
tx: &mut mpsc::Sender<TransactionPretty>,
|
tx: &mut mpsc::Sender<TransactionPretty>,
|
||||||
block: Option<&mut mpsc::Sender<SubscribeUpdateBlockMeta>>,
|
|
||||||
subscribe_tx: &mut (impl Sink<SubscribeRequest, Error = mpsc::SendError> + Unpin),
|
subscribe_tx: &mut (impl Sink<SubscribeRequest, Error = mpsc::SendError> + Unpin),
|
||||||
) -> AnyResult<()> {
|
) -> AnyResult<()> {
|
||||||
|
let created_at = msg.created_at;
|
||||||
match msg.update_oneof {
|
match msg.update_oneof {
|
||||||
Some(UpdateOneof::BlockMeta(sut)) => {
|
|
||||||
if let Some(block) = block {
|
|
||||||
block.try_send(sut)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(UpdateOneof::Transaction(sut)) => {
|
Some(UpdateOneof::Transaction(sut)) => {
|
||||||
let transaction_pretty = TransactionPretty::from(sut.clone());
|
let transaction_pretty = TransactionPretty::from((sut, created_at));
|
||||||
tx.try_send(transaction_pretty)?;
|
tx.try_send(transaction_pretty)?;
|
||||||
}
|
}
|
||||||
Some(UpdateOneof::Ping(_)) => {
|
Some(UpdateOneof::Ping(_)) => {
|
||||||
@@ -216,7 +214,6 @@ impl YellowstoneGrpc {
|
|||||||
|
|
||||||
// 创建通道
|
// 创建通道
|
||||||
let (mut tx, mut rx) = mpsc::channel::<TransactionPretty>(CHANNEL_SIZE);
|
let (mut tx, mut rx) = mpsc::channel::<TransactionPretty>(CHANNEL_SIZE);
|
||||||
let (mut block, mut rblock) = mpsc::channel::<SubscribeUpdateBlockMeta>(CHANNEL_SIZE);
|
|
||||||
|
|
||||||
// 创建回调函数,使用 Arc 包装以便在多个任务中共享
|
// 创建回调函数,使用 Arc 包装以便在多个任务中共享
|
||||||
let callback = std::sync::Arc::new(Box::new(callback));
|
let callback = std::sync::Arc::new(Box::new(callback));
|
||||||
@@ -229,7 +226,6 @@ impl YellowstoneGrpc {
|
|||||||
if let Err(e) = Self::handle_stream_message(
|
if let Err(e) = Self::handle_stream_message(
|
||||||
msg,
|
msg,
|
||||||
&mut tx,
|
&mut tx,
|
||||||
Some(&mut block),
|
|
||||||
&mut subscribe_tx,
|
&mut subscribe_tx,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -246,16 +242,12 @@ impl YellowstoneGrpc {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 为交易处理和区块处理克隆 Arc<Box<F>>
|
|
||||||
let callback_tx = callback.clone();
|
|
||||||
let callback_block = callback;
|
|
||||||
|
|
||||||
// 处理交易
|
// 处理交易
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(transaction_pretty) = rx.next().await {
|
while let Some(transaction_pretty) = rx.next().await {
|
||||||
if let Err(e) = Self::process_event_transaction(
|
if let Err(e) = Self::process_event_transaction(
|
||||||
transaction_pretty,
|
transaction_pretty,
|
||||||
&**callback_tx,
|
&**callback,
|
||||||
bot_wallet,
|
bot_wallet,
|
||||||
protocols.clone(),
|
protocols.clone(),
|
||||||
)
|
)
|
||||||
@@ -265,14 +257,7 @@ impl YellowstoneGrpc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 处理block
|
|
||||||
tokio::spawn(async move {
|
|
||||||
while let Some(block) = rblock.next().await {
|
|
||||||
if let Err(e) = Self::process_block(block, &**callback_block).await {
|
|
||||||
error!("Error processing block: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tokio::signal::ctrl_c().await?;
|
tokio::signal::ctrl_c().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -296,6 +281,7 @@ impl YellowstoneGrpc {
|
|||||||
transaction_pretty.tx.clone(),
|
transaction_pretty.tx.clone(),
|
||||||
&signature,
|
&signature,
|
||||||
Some(slot),
|
Some(slot),
|
||||||
|
transaction_pretty.block_time,
|
||||||
bot_wallet.clone(),
|
bot_wallet.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -307,14 +293,4 @@ impl YellowstoneGrpc {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 处理区块
|
|
||||||
async fn process_block<F>(block: SubscribeUpdateBlockMeta, callback: &F) -> AnyResult<()>
|
|
||||||
where
|
|
||||||
F: Fn(Box<dyn UnifiedEvent>) + Send + Sync,
|
|
||||||
{
|
|
||||||
let event = SDKSystemEventParser::parse_block(block);
|
|
||||||
callback(event);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ impl YellowstoneGrpc {
|
|||||||
match message {
|
match message {
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
Self::handle_stream_message(msg, &mut tx, None, &mut subscribe_tx).await
|
Self::handle_stream_message(msg, &mut tx, &mut subscribe_tx).await
|
||||||
{
|
{
|
||||||
error!("Error handling message: {:?}", e);
|
error!("Error handling message: {:?}", e);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user