sof 0.17.1

Solana Observer Framework for low-latency shred ingestion and plugin-driven transaction observation
Documentation
use std::fmt;

use thiserror::Error;

use crate::protocol::shred_wire::{
    DATA_COMPLETE_SHRED_MASK, LAST_SHRED_IN_SLOT_MASK, SHRED_KIND_MASK, SHRED_PROOF_SIZE_MASK,
    SHRED_TICK_REFERENCE_MASK, VARIANT_MERKLE_CODE, VARIANT_MERKLE_CODE_RESIGNED,
    VARIANT_MERKLE_DATA, VARIANT_MERKLE_DATA_RESIGNED,
};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ShredType {
    Data,
    Code,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ShredVariant {
    pub shred_type: ShredType,
    pub proof_size: u8,
    pub resigned: bool,
}

impl ShredVariant {
    pub(super) const fn parse(byte: u8) -> Result<Self, ParseError> {
        let proof_size = byte & SHRED_PROOF_SIZE_MASK;
        let kind = byte & SHRED_KIND_MASK;
        match kind {
            VARIANT_MERKLE_CODE => Ok(Self {
                shred_type: ShredType::Code,
                proof_size,
                resigned: false,
            }),
            VARIANT_MERKLE_CODE_RESIGNED => Ok(Self {
                shred_type: ShredType::Code,
                proof_size,
                resigned: true,
            }),
            VARIANT_MERKLE_DATA => Ok(Self {
                shred_type: ShredType::Data,
                proof_size,
                resigned: false,
            }),
            VARIANT_MERKLE_DATA_RESIGNED => Ok(Self {
                shred_type: ShredType::Data,
                proof_size,
                resigned: true,
            }),
            _ => Err(ParseError::InvalidShredVariant(byte)),
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct CommonHeader {
    pub shred_variant: ShredVariant,
    pub slot: u64,
    pub index: u32,
    pub version: u16,
    pub fec_set_index: u32,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct DataHeader {
    pub parent_offset: u16,
    pub flags: u8,
    pub size: u16,
}

impl DataHeader {
    #[must_use]
    pub const fn reference_tick(self) -> u8 {
        self.flags & SHRED_TICK_REFERENCE_MASK
    }

    #[must_use]
    pub const fn data_complete(self) -> bool {
        self.flags & DATA_COMPLETE_SHRED_MASK == DATA_COMPLETE_SHRED_MASK
    }

    #[must_use]
    pub const fn last_in_slot(self) -> bool {
        self.flags & LAST_SHRED_IN_SLOT_MASK == LAST_SHRED_IN_SLOT_MASK
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodingHeader {
    pub num_data_shreds: u16,
    pub num_coding_shreds: u16,
    pub position: u16,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ParsedShred {
    Data(ParsedDataShred),
    Code(ParsedCodeShred),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ParsedShredHeader {
    Data(ParsedDataShredHeader),
    Code(ParsedCodeShred),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParsedDataShred {
    pub common: CommonHeader,
    pub data_header: DataHeader,
    pub payload: Vec<u8>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParsedDataShredHeader {
    pub common: CommonHeader,
    pub data_header: DataHeader,
    pub payload_offset: usize,
    pub payload_len: usize,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParsedCodeShred {
    pub common: CommonHeader,
    pub coding_header: CodingHeader,
}

#[derive(Debug, Error, Clone, Eq, PartialEq)]
pub enum ParseError {
    #[error("packet too short: {actual} bytes (expected at least {minimum})")]
    PacketTooShort { actual: usize, minimum: usize },
    #[error("invalid shred variant: 0x{0:02x}")]
    InvalidShredVariant(u8),
    #[error("invalid data shred size: {0}")]
    InvalidDataSize(u16),
    #[error(
        "invalid coding header: num_data={num_data_shreds} num_coding={num_coding_shreds} position={position}"
    )]
    InvalidCodingHeader {
        num_data_shreds: u16,
        num_coding_shreds: u16,
        position: u16,
    },
}

impl fmt::Display for ParsedShred {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Data(data) => write!(
                f,
                "data(slot={}, index={}, fec_set={}, payload_len={}, flags=0x{:02x})",
                data.common.slot,
                data.common.index,
                data.common.fec_set_index,
                data.payload.len(),
                data.data_header.flags
            ),
            Self::Code(code) => write!(
                f,
                "code(slot={}, index={}, fec_set={}, num_data={}, num_code={}, pos={})",
                code.common.slot,
                code.common.index,
                code.common.fec_set_index,
                code.coding_header.num_data_shreds,
                code.coding_header.num_coding_shreds,
                code.coding_header.position
            ),
        }
    }
}