Skip to main content

primitives/errors/
mod.rs

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