casper-node 2.0.3

The Casper blockchain node
Documentation
use std::fmt::{Display, Formatter};

use datasize::DataSize;

use crate::types::{NodeId, SyncLeap, SyncLeapIdentifier};

use super::LeapActivityError;

#[derive(Debug, DataSize)]
pub(crate) enum LeapState {
    Idle,
    Awaiting {
        sync_leap_identifier: SyncLeapIdentifier,
        in_flight: usize,
    },
    Received {
        best_available: Box<SyncLeap>,
        from_peers: Vec<NodeId>,
        in_flight: usize,
    },
    Failed {
        sync_leap_identifier: SyncLeapIdentifier,
        error: LeapActivityError,
        from_peers: Vec<NodeId>,
        in_flight: usize,
    },
}

impl Display for LeapState {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            LeapState::Idle => {
                write!(f, "Idle")
            }
            LeapState::Awaiting {
                sync_leap_identifier,
                in_flight,
            } => {
                write!(
                    f,
                    "Awaiting {} responses for {}",
                    in_flight,
                    sync_leap_identifier.block_hash(),
                )
            }
            LeapState::Received {
                best_available,
                from_peers,
                in_flight,
            } => {
                write!(
                    f,
                    "Received {} from {} peers, awaiting {} responses",
                    best_available.highest_block_hash(),
                    from_peers.len(),
                    in_flight
                )
            }
            LeapState::Failed {
                sync_leap_identifier,
                error,
                ..
            } => {
                write!(
                    f,
                    "Failed leap for {} {}",
                    sync_leap_identifier.block_hash(),
                    error
                )
            }
        }
    }
}

impl LeapState {
    pub(super) fn in_flight(&self) -> usize {
        match self {
            LeapState::Idle => 0,
            LeapState::Awaiting { in_flight, .. }
            | LeapState::Received { in_flight, .. }
            | LeapState::Failed { in_flight, .. } => *in_flight,
        }
    }

    pub(super) fn active(&self) -> bool {
        self.in_flight() > 0
    }
}

#[cfg(test)]
mod tests {
    use casper_types::{testing::TestRng, BlockHash};

    use crate::{
        components::sync_leaper::{tests::make_test_sync_leap, LeapActivityError, LeapState},
        types::SyncLeapIdentifier,
    };

    #[test]
    fn leap_state() {
        let mut rng = TestRng::new();

        let leap_state = LeapState::Idle;
        assert!(!leap_state.active());

        let sync_leap_identifier = SyncLeapIdentifier::sync_to_tip(BlockHash::random(&mut rng));
        let leap_state = LeapState::Awaiting {
            sync_leap_identifier,
            in_flight: 0,
        };
        assert!(!leap_state.active());
        assert_eq!(leap_state.in_flight(), 0);

        let leap_state = LeapState::Awaiting {
            sync_leap_identifier,
            in_flight: 1,
        };
        assert!(leap_state.active());
        assert_eq!(leap_state.in_flight(), 1);

        let leap_state = LeapState::Failed {
            sync_leap_identifier,
            in_flight: 0,
            error: LeapActivityError::NoPeers(sync_leap_identifier),
            from_peers: vec![],
        };
        assert!(!leap_state.active());
        assert_eq!(leap_state.in_flight(), 0);

        let leap_state = LeapState::Failed {
            sync_leap_identifier,
            in_flight: 1,
            error: LeapActivityError::NoPeers(sync_leap_identifier),
            from_peers: vec![],
        };
        assert!(leap_state.active());
        assert_eq!(leap_state.in_flight(), 1);

        let sync_leap = make_test_sync_leap(&mut rng);
        let leap_state = LeapState::Received {
            best_available: Box::new(sync_leap.clone()),
            from_peers: vec![],
            in_flight: 0,
        };
        assert!(!leap_state.active());
        assert_eq!(leap_state.in_flight(), 0);

        let leap_state = LeapState::Received {
            best_available: Box::new(sync_leap),
            from_peers: vec![],
            in_flight: 1,
        };
        assert!(leap_state.active());
        assert_eq!(leap_state.in_flight(), 1);
    }
}