hopr_api/db/
protocol.rs

1use std::fmt::Formatter;
2
3pub use hopr_crypto_packet::{
4    HoprSurb,
5    prelude::{HoprSenderId, PacketSignals},
6};
7use hopr_crypto_types::prelude::*;
8use hopr_internal_types::prelude::*;
9use hopr_network_types::prelude::{ResolvedTransportRouting, SurbMatcher};
10use hopr_primitive_types::balance::HoprBalance;
11
12use crate::chain::{ChainKeyOperations, ChainReadChannelOperations, ChainValues};
13
14/// Contains a SURB found in the SURB ring buffer via [`HoprDbProtocolOperations::find_surb`].
15#[derive(Debug)]
16pub struct FoundSurb {
17    /// Complete sender ID of the SURB.
18    pub sender_id: HoprSenderId,
19    /// The SURB itself.
20    pub surb: HoprSurb,
21    /// Number of SURBs remaining in the ring buffer with the same pseudonym.
22    pub remaining: usize,
23}
24
25/// Configuration for the SURB cache.
26#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
27pub struct SurbCacheConfig {
28    /// Size of the SURB ring buffer per pseudonym.
29    pub rb_capacity: usize,
30    /// Threshold for the number of SURBs in the ring buffer, below which it is
31    /// considered low ("SURB distress").
32    pub distress_threshold: usize,
33}
34
35/// Error that can occur when processing an incoming packet.
36#[derive(Debug, strum::EnumIs, strum::EnumTryAs)]
37pub enum IncomingPacketError<E> {
38    /// Packet is not decodable.
39    ///
40    /// Such errors are fatal and therefore the packet cannot be acknowledged.
41    Undecodable(E),
42    /// Packet is decodable but cannot be processed due to other reasons.
43    ///
44    /// Such errors are protocol-related and packets must be acknowledged.
45    ProcessingError(E),
46}
47
48impl<E: std::fmt::Display> std::fmt::Display for IncomingPacketError<E> {
49    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50        match self {
51            IncomingPacketError::Undecodable(e) => write!(f, "undecodable packet: {e}"),
52            IncomingPacketError::ProcessingError(e) => write!(f, "packet processing error: {e}"),
53        }
54    }
55}
56
57impl<E: std::error::Error> std::error::Error for IncomingPacketError<E> {}
58
59/// Trait defining all DB functionality needed by a packet/acknowledgement processing pipeline.
60// TODO: to be removed and dissolved in hopr-transport crates (see #7575)
61#[async_trait::async_trait]
62#[auto_impl::auto_impl(&, Box, Arc)]
63pub trait HoprDbProtocolOperations {
64    type Error: std::error::Error + Send + Sync + 'static;
65
66    /// Processes the acknowledgements for the pending tickets
67    ///
68    /// There are three cases:
69    /// 1. There is an unacknowledged ticket and we are awaiting a half key.
70    /// 2. We were the creator of the packet, hence we do not wait for any half key
71    /// 3. The acknowledgement is unexpected and stems from a protocol bug or an attacker
72    async fn handle_acknowledgement<R>(
73        &self,
74        ack: VerifiedAcknowledgement,
75        chain_resolver: &R,
76    ) -> Result<(), Self::Error>
77    where
78        R: ChainReadChannelOperations + ChainValues + Send + Sync;
79
80    /// Attempts to find SURB and its ID given the [`SurbMatcher`].
81    async fn find_surb(&self, matcher: SurbMatcher) -> Result<FoundSurb, Self::Error>;
82
83    /// Returns the SURB cache configuration.
84    fn get_surb_config(&self) -> SurbCacheConfig;
85
86    /// Process the data into an outgoing packet that is not going to be acknowledged.
87    async fn to_send_no_ack<R>(
88        &self,
89        data: Box<[u8]>,
90        destination: OffchainPublicKey,
91        resolver: &R,
92    ) -> Result<OutgoingPacket, Self::Error>
93    where
94        R: ChainKeyOperations + ChainValues + Send + Sync;
95
96    /// Process the data into an outgoing packet
97    async fn to_send<R>(
98        &self,
99        data: Box<[u8]>,
100        routing: ResolvedTransportRouting,
101        outgoing_ticket_win_prob: Option<WinningProbability>,
102        outgoing_ticket_price: Option<HoprBalance>,
103        signals: PacketSignals,
104        resolver: &R,
105    ) -> Result<OutgoingPacket, Self::Error>
106    where
107        R: ChainReadChannelOperations + ChainKeyOperations + ChainValues + Send + Sync;
108
109    /// Process the incoming packet into data
110    #[allow(clippy::wrong_self_convention)]
111    async fn from_recv<R>(
112        &self,
113        data: Box<[u8]>,
114        pkt_keypair: &OffchainKeypair,
115        sender: OffchainPublicKey,
116        outgoing_ticket_win_prob: Option<WinningProbability>,
117        outgoing_ticket_price: Option<HoprBalance>,
118        resolver: &R,
119    ) -> Result<IncomingPacket, IncomingPacketError<Self::Error>>
120    where
121        R: ChainReadChannelOperations + ChainKeyOperations + ChainValues + Send + Sync;
122}
123
124/// Contains some miscellaneous information about a received packet.
125#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
126pub struct AuxiliaryPacketInfo {
127    /// Packet signals that the packet carried.
128    ///
129    /// Zero if no signal flags were specified.
130    pub packet_signals: PacketSignals,
131    /// Number of SURBs that the packet carried.
132    pub num_surbs: usize,
133}
134
135#[allow(clippy::large_enum_variant)] // TODO: Uses too large objects
136pub enum IncomingPacket {
137    /// Packet is intended for us
138    Final {
139        packet_tag: PacketTag,
140        previous_hop: OffchainPublicKey,
141        sender: HoprPseudonym,
142        plain_text: Box<[u8]>,
143        ack_key: HalfKey,
144        info: AuxiliaryPacketInfo,
145    },
146    /// Packet must be forwarded
147    Forwarded {
148        packet_tag: PacketTag,
149        previous_hop: OffchainPublicKey,
150        next_hop: OffchainPublicKey,
151        data: Box<[u8]>,
152        /// Acknowledgement payload to be sent to the previous hop
153        ack_key: HalfKey,
154    },
155    /// The packet contains an acknowledgement of a delivered packet.
156    Acknowledgement {
157        packet_tag: PacketTag,
158        previous_hop: OffchainPublicKey,
159        ack: Acknowledgement,
160    },
161}
162
163/// Packet that is being sent out by us
164pub struct OutgoingPacket {
165    pub next_hop: OffchainPublicKey,
166    pub ack_challenge: HalfKeyChallenge,
167    pub data: Box<[u8]>,
168}
169
170impl std::fmt::Debug for OutgoingPacket {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        f.debug_struct("OutgoingPacket")
173            .field("next_hop", &self.next_hop)
174            .field("ack_challenge", &self.ack_challenge)
175            .finish_non_exhaustive()
176    }
177}
178
179#[allow(clippy::large_enum_variant)] // TODO: Uses too large objects
180pub enum ResolvedAcknowledgement {
181    Sending(VerifiedAcknowledgement),
182    RelayingWin(RedeemableTicket),
183    RelayingLoss(Hash),
184}