Skip to main content

primitives/errors/
mod.rs

1use serde::{de::DeserializeOwned, Deserialize, Serialize};
2
3use crate::types::{identifiers::FaultyPeer, PeerId, PeerIndex};
4
5mod builder_error;
6
7pub use builder_error::BuilderError;
8
9/// General trait
10pub trait Error:
11    std::error::Error + Clone + PartialEq + Eq + Serialize + DeserializeOwned + Send + Sync
12{
13}
14impl<T> Error for T where
15    T: std::error::Error + Clone + PartialEq + Eq + Serialize + DeserializeOwned + Send + Sync
16{
17}
18
19#[derive(thiserror::Error, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
20#[repr(C)]
21pub enum PrimitiveError {
22    // --- Serialization Errors ---
23    #[error("Serialization Failed: {0}.")]
24    SerializationFailed(String),
25    #[error("Deserialization Failed: {0}.")]
26    DeserializationFailed(String),
27
28    // --- Verification Errors (Wrong...) ---
29    #[error("Wrong Opening: Expected {0}, got {1}.")]
30    WrongOpening(String, String),
31    #[error("Wrong Opening for {0}: Expected {1}, got {2}.")]
32    WrongOpeningFor(FaultyPeer, String, String),
33    #[error("Wrong Echo from {0}.")]
34    WrongEcho(FaultyPeer),
35    #[error("Wrong signature: {0}.")]
36    WrongSignature(String),
37    #[error("Wrong MAC for {0}: got {1:?}.")]
38    WrongMACFor(FaultyPeer, String),
39    #[error("Wrong MAC: got {0:?}.")]
40    WrongMAC(String),
41    #[error("Wrong correlation. {0}")]
42    WrongCorrelation(String),
43
44    // --- Validation Errors ---
45    #[error("Invalid Size: expected {0} elements, got {1}")]
46    InvalidSize(usize, usize),
47    #[error("Minimum Length Error: expected at least {0} elements, got {1}")]
48    MinimumLength(usize, usize),
49    #[error("Invalid Parameters: {0}")]
50    InvalidParameters(String),
51    #[error("PeerIndex out of bounds: {0} ∉ [0, {1}].")]
52    InvalidPeerIndex(PeerIndex, usize),
53    #[error("Invalid peer ID: {0}")]
54    InvalidPeerId(PeerId),
55
56    // --- Other Errors ---
57    #[error("Zero value sampled for type {0}")]
58    ZeroValueSampled(String),
59}
60
61impl From<quinn::rustls::Error> for PrimitiveError {
62    fn from(err: quinn::rustls::Error) -> Self {
63        PrimitiveError::InvalidParameters(err.to_string())
64    }
65}
66
67impl From<Vec<PrimitiveError>> for PrimitiveError {
68    /// Aggregate multiple PrimitiveErrors into one. Only WrongMACFor and WrongEcho can be
69    /// aggregated, and all errors must be of the same type.
70    fn from(errors: Vec<PrimitiveError>) -> Self {
71        if errors.is_empty() {
72            return PrimitiveError::InvalidParameters(
73                "Cannot aggregate an empty list of errors.".to_owned(),
74            );
75        };
76        if errors.len() == 1 {
77            return errors.into_iter().next().unwrap();
78        }
79
80        let (peers, receiver, invalid_errs) = errors.into_iter().fold(
81            (vec![], vec![], vec![]),
82            |(mut peers, mut receiver, mut invalid_errors), e| {
83                match e {
84                    PrimitiveError::WrongMACFor(p, r) => {
85                        peers.push(p);
86                        receiver.push(r);
87                    }
88                    PrimitiveError::WrongEcho(p) => {
89                        peers.push(p);
90                    }
91                    _ => invalid_errors.push(e.to_string()),
92                }
93                (peers, receiver, invalid_errors)
94            },
95        );
96        if !invalid_errs.is_empty() {
97            return PrimitiveError::InvalidParameters(
98                "Only WrongMACFor|WrongEcho can be aggregated. Got: ".to_owned()
99                    + &invalid_errs.join(", "),
100            );
101        }
102        match (peers, receiver.as_slice()) {
103            (peers, []) => PrimitiveError::WrongEcho(FaultyPeer::Multiple(peers)),
104            (peers, receiver) if peers.len() == receiver.len() => {
105                PrimitiveError::WrongMACFor(FaultyPeer::Multiple(peers), receiver.join(", "))
106            }
107            _ => PrimitiveError::InvalidParameters(
108                "All errors must be of the same type to be aggregated".to_owned(),
109            ),
110        }
111    }
112}
113impl PrimitiveError {
114    /// Blames another peer for this error.
115    pub fn blame(self, peer_to_blame: PeerIndex) -> PrimitiveError {
116        match self {
117            PrimitiveError::WrongMAC(receiver) => {
118                PrimitiveError::WrongMACFor(FaultyPeer::Foreign(peer_to_blame), receiver)
119            }
120            PrimitiveError::WrongMACFor(peers, receiver) => {
121                PrimitiveError::WrongMACFor(peers.push(peer_to_blame), receiver)
122            }
123            PrimitiveError::WrongOpening(expected, got) => {
124                PrimitiveError::WrongOpeningFor(FaultyPeer::Foreign(peer_to_blame), expected, got)
125            }
126            PrimitiveError::WrongOpeningFor(peers, expected, got) => {
127                PrimitiveError::WrongOpeningFor(peers.push(peer_to_blame), expected, got)
128            }
129            _ => self,
130        }
131    }
132}