Skip to main content

hotshot_new_protocol/coordinator/
error.rs

1use std::fmt;
2
3use crate::{
4    block::BlockError,
5    epoch::EpochManagerError,
6    network::NetworkError,
7    proposal::ValidationError,
8    vid::{VidDisperseError, VidReconstructError},
9};
10
11#[derive(Debug, thiserror::Error)]
12#[error("{severity} coordinator error ({context}): source: {source}")]
13pub struct CoordinatorError {
14    pub severity: Severity,
15    pub source: ErrorSource,
16    pub context: &'static str,
17}
18
19impl CoordinatorError {
20    pub fn regular<E: Into<ErrorSource>>(e: E) -> Self {
21        Self {
22            context: "",
23            severity: Severity::Regular,
24            source: e.into(),
25        }
26    }
27
28    pub fn critical<E: Into<ErrorSource>>(e: E) -> Self {
29        Self {
30            context: "",
31            severity: Severity::Critical,
32            source: e.into(),
33        }
34    }
35
36    pub fn unspecified() -> Self {
37        Self {
38            context: "",
39            severity: Severity::Unspecified,
40            source: ErrorSource::Unspecified,
41        }
42    }
43
44    pub fn context(mut self, m: &'static str) -> Self {
45        self.context = m;
46        self
47    }
48}
49
50#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
51pub enum Severity {
52    Unspecified,
53    Regular,
54    Critical,
55}
56
57impl fmt::Display for Severity {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            Self::Unspecified => f.write_str("unspecified"),
61            Self::Regular => f.write_str("regular"),
62            Self::Critical => f.write_str("critical"),
63        }
64    }
65}
66
67#[derive(Debug, thiserror::Error)]
68#[non_exhaustive]
69pub enum ErrorSource {
70    #[error("network error: {0}")]
71    Network(#[from] NetworkError),
72
73    #[error("proposal validation error: {0}")]
74    Proposal(#[from] ValidationError),
75
76    #[error("unspecified error")]
77    Unspecified,
78
79    #[error("coordinator has no inputs")]
80    NoInput,
81
82    #[error("{0}")]
83    StaticMessage(&'static str),
84
85    #[error("{0}")]
86    Message(String),
87
88    #[error("block builder error: {0}")]
89    Block(#[from] BlockError),
90
91    #[error("epoch manager error: {0}")]
92    EpochManager(#[from] EpochManagerError),
93
94    #[error("vid reconstruction error: {0}")]
95    VidReconstruct(String),
96
97    #[error("vid disperse error: {0}")]
98    VidDisperse(#[from] VidDisperseError),
99}
100
101impl From<NetworkError> for CoordinatorError {
102    fn from(e: NetworkError) -> Self {
103        if e.is_critical() {
104            Self::critical(e)
105        } else {
106            Self::regular(e)
107        }
108    }
109}
110
111impl From<VidDisperseError> for CoordinatorError {
112    fn from(e: VidDisperseError) -> Self {
113        if e.is_critical() {
114            Self::critical(e)
115        } else {
116            Self::regular(e)
117        }
118    }
119}
120
121// `VidReconstructError<K>` is generic over the signature key type, but
122// `ErrorSource` is not parameterized by it, so flatten to the error's
123// `Display` (view + kind). The attributable `bad_share_keys` are consumed by
124// the reconstructor itself, not by this error boundary.
125impl<K> From<VidReconstructError<K>> for ErrorSource {
126    fn from(e: VidReconstructError<K>) -> Self {
127        Self::VidReconstruct(e.to_string())
128    }
129}
130
131impl From<&'static str> for ErrorSource {
132    fn from(msg: &'static str) -> Self {
133        Self::StaticMessage(msg)
134    }
135}
136
137impl From<String> for ErrorSource {
138    fn from(msg: String) -> Self {
139        Self::Message(msg)
140    }
141}