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#[async_trait::async_trait]
61pub trait HoprDbProtocolOperations {
62    type Error: std::error::Error + Send + Sync + 'static;
63
64    /// Processes the acknowledgements for the pending tickets
65    ///
66    /// There are three cases:
67    /// 1. There is an unacknowledged ticket and we are awaiting a half key.
68    /// 2. We were the creator of the packet, hence we do not wait for any half key
69    /// 3. The acknowledgement is unexpected and stems from a protocol bug or an attacker
70    async fn handle_acknowledgement<R>(
71        &self,
72        ack: VerifiedAcknowledgement,
73        chain_resolver: &R,
74    ) -> Result<(), Self::Error>
75    where
76        R: ChainReadChannelOperations + ChainValues + Send + Sync;
77
78    /// Attempts to find SURB and its ID given the [`SurbMatcher`].
79    async fn find_surb(&self, matcher: SurbMatcher) -> Result<FoundSurb, Self::Error>;
80
81    /// Returns the SURB cache configuration.
82    fn get_surb_config(&self) -> SurbCacheConfig;
83
84    /// Process the data into an outgoing packet that is not going to be acknowledged.
85    async fn to_send_no_ack<R>(
86        &self,
87        data: Box<[u8]>,
88        destination: OffchainPublicKey,
89        resolver: &R,
90    ) -> Result<OutgoingPacket, Self::Error>
91    where
92        R: ChainKeyOperations + ChainValues + Send + Sync;
93
94    /// Process the data into an outgoing packet
95    async fn to_send<R>(
96        &self,
97        data: Box<[u8]>,
98        routing: ResolvedTransportRouting,
99        outgoing_ticket_win_prob: Option<WinningProbability>,
100        outgoing_ticket_price: Option<HoprBalance>,
101        signals: PacketSignals,
102        resolver: &R,
103    ) -> Result<OutgoingPacket, Self::Error>
104    where
105        R: ChainReadChannelOperations + ChainKeyOperations + ChainValues + Send + Sync;
106
107    /// Process the incoming packet into data
108    #[allow(clippy::wrong_self_convention)]
109    async fn from_recv<R>(
110        &self,
111        data: Box<[u8]>,
112        pkt_keypair: &OffchainKeypair,
113        sender: OffchainPublicKey,
114        outgoing_ticket_win_prob: Option<WinningProbability>,
115        outgoing_ticket_price: Option<HoprBalance>,
116        resolver: &R,
117    ) -> Result<IncomingPacket, IncomingPacketError<Self::Error>>
118    where
119        R: ChainReadChannelOperations + ChainKeyOperations + ChainValues + Send + Sync;
120}
121
122/// Contains some miscellaneous information about a received packet.
123#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
124pub struct AuxiliaryPacketInfo {
125    /// Packet signals that the packet carried.
126    ///
127    /// Zero if no signal flags were specified.
128    pub packet_signals: PacketSignals,
129    /// Number of SURBs that the packet carried.
130    pub num_surbs: usize,
131}
132
133#[allow(clippy::large_enum_variant)] // TODO: Uses too large objects
134pub enum IncomingPacket {
135    /// Packet is intended for us
136    Final {
137        packet_tag: PacketTag,
138        previous_hop: OffchainPublicKey,
139        sender: HoprPseudonym,
140        plain_text: Box<[u8]>,
141        ack_key: HalfKey,
142        info: AuxiliaryPacketInfo,
143    },
144    /// Packet must be forwarded
145    Forwarded {
146        packet_tag: PacketTag,
147        previous_hop: OffchainPublicKey,
148        next_hop: OffchainPublicKey,
149        data: Box<[u8]>,
150        /// Acknowledgement payload to be sent to the previous hop
151        ack_key: HalfKey,
152    },
153    /// The packet contains an acknowledgement of a delivered packet.
154    Acknowledgement {
155        packet_tag: PacketTag,
156        previous_hop: OffchainPublicKey,
157        ack: Acknowledgement,
158    },
159}
160
161/// Packet that is being sent out by us
162pub struct OutgoingPacket {
163    pub next_hop: OffchainPublicKey,
164    pub ack_challenge: HalfKeyChallenge,
165    pub data: Box<[u8]>,
166}
167
168impl std::fmt::Debug for OutgoingPacket {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        f.debug_struct("OutgoingPacket")
171            .field("next_hop", &self.next_hop)
172            .field("ack_challenge", &self.ack_challenge)
173            .finish_non_exhaustive()
174    }
175}
176
177#[allow(clippy::large_enum_variant)] // TODO: Uses too large objects
178pub enum ResolvedAcknowledgement {
179    Sending(VerifiedAcknowledgement),
180    RelayingWin(AcknowledgedTicket),
181    RelayingLoss(Hash),
182}