hotshot_testing/
view_sync_task.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7use std::{collections::HashSet, marker::PhantomData, sync::Arc};
8
9use async_trait::async_trait;
10use hotshot_task_impls::events::HotShotEvent;
11use hotshot_types::traits::node_implementation::{NodeType, TestableNodeImplementation};
12use hotshot_utils::anytrace::*;
13use thiserror::Error;
14
15use crate::test_task::{TestResult, TestTaskState};
16
17/// `ViewSync` Task error
18#[derive(Error, Debug, Clone)]
19pub enum ViewSyncTaskError {
20    #[error("{} nodes hit view sync", hit_view_sync.len())]
21    HitViewSync { hit_view_sync: HashSet<usize> },
22}
23
24/// `ViewSync` task state
25pub struct ViewSyncTask<TYPES: NodeType, I: TestableNodeImplementation<TYPES>> {
26    /// nodes that hit view sync
27    pub(crate) hit_view_sync: HashSet<usize>,
28    /// properties of task
29    pub(crate) description: ViewSyncTaskDescription,
30    /// Phantom data for TYPES and I
31    pub(crate) _pd: PhantomData<(TYPES, I)>,
32}
33
34#[async_trait]
35impl<TYPES: NodeType, I: TestableNodeImplementation<TYPES>> TestTaskState
36    for ViewSyncTask<TYPES, I>
37{
38    type Event = Arc<HotShotEvent<TYPES>>;
39    type Error = Error;
40
41    /// Handles an event from one of multiple receivers.
42    async fn handle_event(&mut self, (event, id): (Self::Event, usize)) -> Result<()> {
43        match event.as_ref() {
44            // all the view sync events
45            HotShotEvent::ViewSyncTimeout(..)
46            | HotShotEvent::ViewSyncPreCommitVoteRecv(_)
47            | HotShotEvent::ViewSyncCommitVoteRecv(_)
48            | HotShotEvent::ViewSyncFinalizeVoteRecv(_)
49            | HotShotEvent::ViewSyncPreCommitVoteSend(_)
50            | HotShotEvent::ViewSyncCommitVoteSend(_)
51            | HotShotEvent::ViewSyncFinalizeVoteSend(_)
52            | HotShotEvent::ViewSyncPreCommitCertificateRecv(_)
53            | HotShotEvent::ViewSyncCommitCertificateRecv(_)
54            | HotShotEvent::ViewSyncFinalizeCertificateRecv(_)
55            | HotShotEvent::ViewSyncPreCommitCertificateSend(..)
56            | HotShotEvent::ViewSyncCommitCertificateSend(..)
57            | HotShotEvent::ViewSyncFinalizeCertificateSend(..)
58            | HotShotEvent::ViewSyncTrigger(_) => {
59                self.hit_view_sync.insert(id);
60            },
61            _ => (),
62        }
63
64        Ok(())
65    }
66
67    async fn check(&self) -> TestResult {
68        match self.description.clone() {
69            ViewSyncTaskDescription::Threshold(min, max) => {
70                let num_hits = self.hit_view_sync.len();
71                if min <= num_hits && num_hits <= max {
72                    TestResult::Pass
73                } else {
74                    TestResult::Fail(Box::new(ViewSyncTaskError::HitViewSync {
75                        hit_view_sync: self.hit_view_sync.clone(),
76                    }))
77                }
78            },
79        }
80    }
81}
82
83/// enum desecribing whether a node should hit view sync
84#[derive(Clone, Debug, Copy)]
85pub enum ShouldHitViewSync {
86    /// the node should hit view sync
87    Yes,
88    /// the node should not hit view sync
89    No,
90    /// don't care if the node should hit view sync
91    Ignore,
92}
93
94/// Description for a view sync task.
95#[derive(Clone, Debug)]
96pub enum ViewSyncTaskDescription {
97    /// (min, max) number nodes that may hit view sync, inclusive
98    Threshold(usize, usize),
99}