Skip to main content

primitives/errors/
mod.rs

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