use std::{net::SocketAddr, sync::Arc};
use agave_transaction_view::transaction_view::SanitizedTransactionView;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use sof_types::{PubkeyBytes, SignatureBytes};
use solana_pubkey::Pubkey;
use solana_transaction::versioned::VersionedTransaction;
use crate::{
event::{ForkSlotStatus, TxCommitmentStatus, TxKind},
provider_stream::ProviderSourceRef,
shred::wire::ParsedShredHeader,
};
#[derive(Debug, Clone)]
pub struct RawPacketEvent {
pub source: SocketAddr,
pub bytes: Arc<[u8]>,
}
#[derive(Debug, Clone)]
pub struct ShredEvent {
pub source: SocketAddr,
pub packet: Arc<[u8]>,
pub parsed: Arc<ParsedShredHeader>,
}
#[derive(Debug, Clone, Copy)]
pub struct DatasetEvent {
pub slot: u64,
pub start_index: u32,
pub end_index: u32,
pub last_in_slot: bool,
pub shreds: usize,
pub payload_len: usize,
pub tx_count: u64,
}
#[derive(Debug, Clone)]
pub struct TransactionEvent {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub signature: Option<SignatureBytes>,
pub provider_source: Option<ProviderSourceRef>,
pub tx: Arc<VersionedTransaction>,
pub kind: TxKind,
}
#[derive(Debug, Clone)]
pub struct TransactionLogEvent {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub signature: SignatureBytes,
pub err: Option<JsonValue>,
pub logs: Arc<[String]>,
pub matched_filter: Option<PubkeyBytes>,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TransactionStatusEvent {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub signature: SignatureBytes,
pub is_vote: bool,
pub index: Option<u64>,
pub err: Option<String>,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct BlockMetaEvent {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub blockhash: [u8; 32],
pub parent_slot: u64,
pub parent_blockhash: [u8; 32],
pub block_time: Option<i64>,
pub block_height: Option<u64>,
pub executed_transaction_count: u64,
pub entries_count: u64,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone)]
pub struct TransactionBatchEvent {
pub slot: u64,
pub start_index: u32,
pub end_index: u32,
pub last_in_slot: bool,
pub shreds: usize,
pub payload_len: usize,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub transactions: Arc<[VersionedTransaction]>,
}
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub struct SerializedTransactionRange {
start: u32,
end: u32,
}
impl SerializedTransactionRange {
#[must_use]
pub const fn new(start: u32, end: u32) -> Self {
Self { start, end }
}
#[must_use]
pub const fn start(self) -> u32 {
self.start
}
#[must_use]
pub const fn end(self) -> u32 {
self.end
}
#[must_use]
pub const fn len(self) -> u32 {
self.end.saturating_sub(self.start)
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.start == self.end
}
}
#[derive(Debug, Clone)]
pub struct TransactionViewBatchEvent {
pub slot: u64,
pub start_index: u32,
pub end_index: u32,
pub last_in_slot: bool,
pub shreds: usize,
pub payload_len: usize,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub provider_source: Option<ProviderSourceRef>,
pub payload: Arc<[u8]>,
pub transactions: Arc<[SerializedTransactionRange]>,
}
impl TransactionViewBatchEvent {
#[must_use]
pub fn len(&self) -> usize {
self.transactions.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.transactions.is_empty()
}
#[must_use]
pub fn transaction_bytes(&self, index: usize) -> Option<&[u8]> {
let range = *self.transactions.get(index)?;
let start = usize::try_from(range.start()).ok()?;
let end = usize::try_from(range.end()).ok()?;
self.payload.get(start..end)
}
pub fn transaction_views(
&self,
) -> impl Iterator<Item = agave_transaction_view::result::Result<SanitizedTransactionView<&[u8]>>> + '_
{
self.transactions
.iter()
.filter_map(|range| {
let start = usize::try_from(range.start()).ok()?;
let end = usize::try_from(range.end()).ok()?;
self.payload.get(start..end)
})
.map(|bytes| SanitizedTransactionView::try_new_sanitized(bytes, true))
}
}
#[derive(Debug, Clone, Copy)]
pub struct TransactionEventRef<'event> {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub signature: Option<SignatureBytes>,
pub tx: &'event VersionedTransaction,
pub kind: TxKind,
}
impl TransactionEventRef<'_> {
#[must_use]
pub fn to_owned(&self) -> TransactionEvent {
TransactionEvent {
slot: self.slot,
commitment_status: self.commitment_status,
confirmed_slot: self.confirmed_slot,
finalized_slot: self.finalized_slot,
signature: self.signature,
provider_source: None,
tx: Arc::new(self.tx.clone()),
kind: self.kind,
}
}
}
#[derive(Debug, Clone)]
pub struct AccountTouchEvent {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub signature: Option<SignatureBytes>,
pub account_keys: Arc<[PubkeyBytes]>,
pub writable_account_keys: Arc<[PubkeyBytes]>,
pub readonly_account_keys: Arc<[PubkeyBytes]>,
pub lookup_table_account_keys: Arc<[PubkeyBytes]>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct AccountUpdateEvent {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub pubkey: PubkeyBytes,
pub owner: PubkeyBytes,
pub lamports: u64,
pub executable: bool,
pub rent_epoch: u64,
pub data: Arc<[u8]>,
pub write_version: Option<u64>,
pub txn_signature: Option<SignatureBytes>,
pub is_startup: bool,
pub matched_filter: Option<PubkeyBytes>,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Copy)]
pub struct AccountTouchEventRef<'event> {
pub slot: u64,
pub commitment_status: TxCommitmentStatus,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub signature: Option<SignatureBytes>,
pub account_keys: &'event [Pubkey],
pub lookup_table_account_key_count: usize,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct SlotStatusEvent {
pub slot: u64,
pub parent_slot: Option<u64>,
pub previous_status: Option<ForkSlotStatus>,
pub status: ForkSlotStatus,
pub tip_slot: Option<u64>,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ReorgEvent {
pub old_tip: u64,
pub new_tip: u64,
pub common_ancestor: Option<u64>,
pub detached_slots: Vec<u64>,
pub attached_slots: Vec<u64>,
pub confirmed_slot: Option<u64>,
pub finalized_slot: Option<u64>,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ObservedRecentBlockhashEvent {
pub slot: u64,
pub recent_blockhash: [u8; 32],
pub dataset_tx_count: u64,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum ControlPlaneSource {
GossipBootstrap,
Direct,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ClusterNodeInfo {
pub pubkey: PubkeyBytes,
pub wallclock: u64,
pub shred_version: u16,
pub gossip: Option<SocketAddr>,
pub tpu: Option<SocketAddr>,
pub tpu_quic: Option<SocketAddr>,
pub tpu_forwards: Option<SocketAddr>,
pub tpu_forwards_quic: Option<SocketAddr>,
pub tpu_vote: Option<SocketAddr>,
pub tvu: Option<SocketAddr>,
pub rpc: Option<SocketAddr>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ClusterTopologyEvent {
pub source: ControlPlaneSource,
pub slot: Option<u64>,
pub epoch: Option<u64>,
pub active_entrypoint: Option<String>,
pub total_nodes: usize,
pub added_nodes: Vec<ClusterNodeInfo>,
pub removed_pubkeys: Vec<PubkeyBytes>,
pub updated_nodes: Vec<ClusterNodeInfo>,
pub snapshot_nodes: Vec<ClusterNodeInfo>,
pub provider_source: Option<ProviderSourceRef>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct LeaderScheduleEntry {
pub slot: u64,
pub leader: PubkeyBytes,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct LeaderScheduleEvent {
pub source: ControlPlaneSource,
pub slot: Option<u64>,
pub epoch: Option<u64>,
pub added_leaders: Vec<LeaderScheduleEntry>,
pub removed_slots: Vec<u64>,
pub updated_leaders: Vec<LeaderScheduleEntry>,
pub snapshot_leaders: Vec<LeaderScheduleEntry>,
pub provider_source: Option<ProviderSourceRef>,
}
#[must_use]
pub(crate) fn signature_bytes(value: solana_signature::Signature) -> SignatureBytes {
SignatureBytes::from_solana(value)
}
#[must_use]
pub(crate) fn signature_bytes_opt(
value: Option<solana_signature::Signature>,
) -> Option<SignatureBytes> {
value.map(SignatureBytes::from_solana)
}
#[must_use]
pub(crate) const fn pubkey_bytes(value: solana_pubkey::Pubkey) -> PubkeyBytes {
PubkeyBytes::from_solana(value)
}
#[must_use]
pub(crate) fn collect_pubkey_bytes<I>(iter: I) -> Vec<PubkeyBytes>
where
I: IntoIterator<Item = solana_pubkey::Pubkey>,
{
iter.into_iter().map(PubkeyBytes::from_solana).collect()
}
#[must_use]
pub(crate) fn arc_pubkey_bytes<I>(iter: I) -> Arc<[PubkeyBytes]>
where
I: IntoIterator<Item = solana_pubkey::Pubkey>,
{
Arc::from(collect_pubkey_bytes(iter))
}