Skip to main content

hopr_crypto_packet/
errors.rs

1use std::fmt::Debug;
2
3use hopr_types::{
4    crypto::{errors::CryptoError, prelude::SimplePseudonym},
5    internal::{
6        errors::CoreTypesError,
7        prelude::{ChannelId, Ticket, WinningProbability},
8    },
9    primitive::{
10        errors::GeneralError,
11        prelude::{Address, HoprBalance},
12    },
13};
14use thiserror::Error;
15
16#[derive(Error, Debug)]
17pub enum PacketError {
18    #[error("failed to decode packet: {0}")]
19    PacketDecodingError(String),
20
21    #[error("failed to construct packet: {0}")]
22    PacketConstructionError(String),
23
24    #[error("Proof of Relay challenge could not be verified")]
25    PoRVerificationError,
26
27    #[error("logic error during packet processing: {0}")]
28    LogicError(String),
29
30    #[error("underlying transport error while sending packet: {0}")]
31    TransportError(String),
32
33    #[error(transparent)]
34    CryptographicError(#[from] CryptoError),
35
36    #[error(transparent)]
37    CoreTypesError(#[from] CoreTypesError),
38
39    #[error(transparent)]
40    SphinxError(#[from] crate::sphinx::errors::SphinxError),
41
42    #[error(transparent)]
43    PixError(#[from] hopr_protocol_pix::errors::PixError<SimplePseudonym>),
44
45    #[error(transparent)]
46    Other(#[from] GeneralError),
47}
48
49pub type Result<T> = std::result::Result<T, PacketError>;
50
51/// Contains all possible validation errors that can occur during [ticket
52/// validation](crate::validation::validate_unacknowledged_ticket).
53#[derive(Debug, Clone, Copy, Error, strum::AsRefStr)]
54#[strum(serialize_all = "snake_case")]
55pub enum ValidationErrorKind {
56    /// Ticket signer does not match the sender.
57    #[error("ticket signer does not match the sender")]
58    InvalidSigner,
59    /// Ticket amount is lower than the given minimum value.
60    #[error("ticket amount is lower than {0}")]
61    LowValue(HoprBalance),
62    /// Ticket winning probability is lower than the given minimum value.
63    #[error("ticket winning probability is lower than {0}")]
64    LowWinProb(WinningProbability),
65    /// The given channel is closed or pending to close.
66    #[error("channel {0} is closed or pending to close")]
67    ChannelClosed(ChannelId),
68    /// Ticket epoch does not match the given channel epoch.
69    #[error("ticket epoch does not match channel epoch {0}")]
70    EpochMismatch(u32),
71    /// Ticket index is lower than the given channel ticket index.
72    #[error("ticket index is lower than channel index {0}")]
73    IndexTooLow(u64),
74    /// Not enough funds in the given channel to pay for the ticket.
75    #[error("ticket value is greater than remaining unrealized balance {1} in channel {0}")]
76    InsufficientFunds(ChannelId, HoprBalance),
77}
78
79/// Contains errors returned by [validate_unacknowledged_ticket](crate::validation::validate_unacknowledged_ticket).
80#[derive(Debug, Clone, Error)]
81#[error("validation error of {ticket}: {kind}")]
82pub struct TicketValidationError {
83    /// Error description.
84    pub kind: ValidationErrorKind,
85    /// Invalid ticket that failed to validate.
86    pub ticket: Box<Ticket>,
87    /// Issuer of the ticket.
88    ///
89    /// This value is present if at least the ticket signature validation succeeded.
90    pub issuer: Option<Address>,
91}
92
93#[cfg(test)]
94mod tests {
95    use hopr_types::{
96        crypto::prelude::{ChainKeypair, Keypair},
97        internal::prelude::TicketBuilder,
98    };
99
100    use super::*;
101
102    #[test]
103    fn test_validation_error_kind_display() {
104        let kind = ValidationErrorKind::LowWinProb(WinningProbability::ALWAYS);
105        assert_eq!(
106            kind.to_string(),
107            format!(
108                "ticket winning probability is lower than {}",
109                WinningProbability::ALWAYS
110            )
111        );
112        assert_eq!(kind.as_ref(), "low_win_prob");
113    }
114
115    #[test]
116    fn test_ticket_validation_error_display() {
117        let src = ChainKeypair::random();
118        let dst = ChainKeypair::random();
119
120        let ticket = TicketBuilder::zero_hop()
121            .counterparty(&dst)
122            .eth_challenge(Default::default())
123            .build_signed(&src, &Default::default())
124            .unwrap()
125            .leak();
126
127        let error = TicketValidationError {
128            kind: ValidationErrorKind::LowWinProb(WinningProbability::default()),
129            ticket: Box::new(ticket),
130            issuer: None,
131        };
132
133        assert_eq!(
134            error.to_string(),
135            format!(
136                "validation error of {ticket}: ticket winning probability is lower than {}",
137                WinningProbability::ALWAYS
138            )
139        );
140    }
141}