solana-leader 0.4.0

solana leader library
Documentation
use crate::leader_buffer::SLOTS_PER_LEADER;
use crate::leader_entry::LeaderEntry;

#[derive(Debug, Clone)]
pub struct ScheduleSnapshot {
    epoch: u64,
    epoch_start_slot: u64,
    first_leader_index: u64,
    leaders: Box<[LeaderEntry]>,
}

impl ScheduleSnapshot {
    #[inline]
    pub fn new(epoch: u64, epoch_start_slot: u64, leaders: Box<[LeaderEntry]>) -> Self {
        Self {
            epoch,
            epoch_start_slot,
            first_leader_index: epoch_start_slot / SLOTS_PER_LEADER,
            leaders,
        }
    }

    #[inline]
    pub fn epoch(&self) -> u64 {
        self.epoch
    }

    #[inline]
    pub fn epoch_start_slot(&self) -> u64 {
        self.epoch_start_slot
    }

    #[inline]
    pub fn leaders_len(&self) -> usize {
        self.leaders.len()
    }

    #[inline]
    pub fn leaders(&self) -> &[LeaderEntry] {
        &self.leaders
    }

    #[inline]
    pub fn covers_slot(&self, slot: u64) -> bool {
        let leader_index = slot / SLOTS_PER_LEADER;
        leader_index >= self.first_leader_index
            && leader_index < self.first_leader_index + self.leaders.len() as u64
    }

    #[inline]
    pub fn get_leader_at_slot(&self, slot: u64) -> Option<LeaderEntry> {
        let index = self.index_for_slot(slot)?;
        Some(self.leaders[index])
    }

    #[inline]
    pub fn get_next_leaders_into(&self, start_slot: u64, buffer: &mut [LeaderEntry]) -> usize {
        let mut written = 0usize;
        let mut leader_index = (start_slot / SLOTS_PER_LEADER).max(self.first_leader_index);

        while written < buffer.len() {
            let offset = leader_index.saturating_sub(self.first_leader_index) as usize;
            if offset >= self.leaders.len() {
                break;
            }

            buffer[written] = self.leaders[offset];
            written += 1;
            leader_index += 1;
        }

        written
    }

    #[inline]
    fn index_for_slot(&self, slot: u64) -> Option<usize> {
        let leader_index = slot / SLOTS_PER_LEADER;
        if leader_index < self.first_leader_index {
            return None;
        }

        let offset = leader_index - self.first_leader_index;
        (offset < self.leaders.len() as u64).then_some(offset as usize)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::leader_entry::LeaderPubkey;

    #[test]
    fn schedule_snapshot_indexes_by_leader() {
        let leader = LeaderEntry::new_ipv4(
            LeaderPubkey::new([1; 32]),
            [127, 0, 0, 1],
            8000,
            [127, 0, 0, 1],
            8001,
        );
        let snapshot = ScheduleSnapshot::new(1, 100, vec![leader, LeaderEntry::EMPTY].into());

        assert!(snapshot.covers_slot(100));
        assert_eq!(
            snapshot.get_leader_at_slot(103).unwrap().pubkey.to_bytes()[0],
            1
        );
        assert!(snapshot.get_leader_at_slot(108).is_none());
    }
}