Skip to main content

hopr_protocol_hopr/
traits.rs

1use bytes::Bytes;
2use hopr_api::types::{crypto::prelude::*, internal::prelude::*};
3use hopr_crypto_packet::prelude::*;
4
5pub use crate::{
6    errors::IncomingPacketError,
7    types::{FoundSurb, IncomingPacket, OutgoingPacket, ResolvedAcknowledgement},
8};
9
10/// A trait defining the operations required to store and retrieve SURBs (Single Use Reply Blocks) and their reply
11/// openers.
12///
13/// The sending side stores the reply openers, whereas the SURBs are stored by the replying side
14/// of the communication.
15#[auto_impl::auto_impl(&, Box, Arc)]
16pub trait SurbStore {
17    /// Tries to find SURB using the given [`matcher`](SurbMatcher).
18    ///
19    /// This is used by the replying side when it is about to send a reply packet back
20    /// to the sender.
21    fn find_surb(&self, matcher: SurbMatcher) -> Option<FoundSurb>;
22
23    /// Stores the `surbs` and associates them with the given [`pseudonym`](HoprPseudonym).
24    ///
25    /// This is used by the replying side when it receives packets containing SURBs from the sender
26    /// with the given `pseudonym`.
27    ///
28    /// Returns the total number of SURBs available for that `pseudonym`, including the newly inserted
29    /// ones.
30    fn insert_surbs(&self, pseudonym: HoprPseudonym, surbs: Vec<(HoprSurbId, HoprSurb)>) -> usize;
31
32    /// Stores the given [`opener`](ReplyOpener) for the given [`sender_id`](HoprSenderId).
33    ///
34    /// This is done by the sending side, when it creates a packet containing a SURB to be delivered
35    /// to the replying side.
36    ///
37    /// The operation should happen reasonably fast, as it is called from the packet processing code.
38    fn insert_reply_opener(&self, sender_id: HoprSenderId, opener: ReplyOpener);
39
40    /// Tries to find a [`ReplyOpener`] given the [`sender_id`](HoprSenderId).
41    ///
42    /// This is done by the sending side of the original packet when the reply to that
43    /// packet is received and needs to be decrypted.
44    ///
45    /// The operation should happen reasonably fast, as it is called from the packet processing code.
46    fn find_reply_opener(&self, sender_id: &HoprSenderId) -> Option<ReplyOpener>;
47}
48
49/// Trait defining encoder for [outgoing HOPR packets](OutgoingPacket).
50///
51/// These operations are done directly by the packet processing pipeline before
52/// the outgoing packet is handled to the underlying p2p transport.
53#[auto_impl::auto_impl(&, Box, Arc)]
54pub trait PacketEncoder {
55    type Error: std::error::Error + Send + Sync + 'static;
56
57    /// Encodes the given `data` and [`signals`](PacketSignals) for sending.
58    ///
59    /// The `data` MUST be already correctly sized for HOPR packets, otherwise the operation
60    /// must fail.
61    fn encode_packet<T: AsRef<[u8]> + Send + 'static, S: Into<PacketSignals> + Send + 'static>(
62        &self,
63        data: T,
64        routing: ResolvedTransportRouting<HoprSurb>,
65        signals: S,
66    ) -> Result<OutgoingPacket, Self::Error>;
67
68    /// Encodes the given vector of [`VerifiedAcknowledgements`](VerifiedAcknowledgement) as an outgoing packet to be
69    /// sent to the given [`destination`](OffchainPublicKey).
70    fn encode_acknowledgements(
71        &self,
72        acks: &[VerifiedAcknowledgement],
73        destination: &OffchainPublicKey,
74    ) -> Result<OutgoingPacket, Self::Error>;
75}
76
77/// Trait defining decoder HOPR packets.
78///
79/// This operation is done directly by the packet processing pipeline after
80/// the underlying p2p transport hands over incoming data packets.
81#[auto_impl::auto_impl(&, Box, Arc)]
82pub trait PacketDecoder {
83    type Error: std::error::Error + Send + Sync + 'static;
84
85    /// Decodes the `data` received from the given [`sender`](PeerId)
86    /// returns the corresponding [`IncomingPacket`] if the decoding into a HOPR packet was successful.
87    fn decode(&self, sender: PeerId, data: Bytes) -> Result<IncomingPacket, IncomingPacketError<Self::Error>>;
88}
89
90/// Defines errors returned by `UnacknowledgedTicketProcessor::acknowledge_ticket`.
91#[derive(Debug, thiserror::Error)]
92pub enum TicketAcknowledgementError<E> {
93    /// An acknowledgement from a peer was not expected.
94    #[error("acknowledgement from the peer was not expected")]
95    UnexpectedAcknowledgement,
96    /// An error occurred while processing the acknowledgement.
97    #[error(transparent)]
98    Inner(E),
99}
100
101impl<E> TicketAcknowledgementError<E> {
102    pub fn inner<F: Into<E>>(e: F) -> Self {
103        Self::Inner(e.into())
104    }
105}
106
107/// Performs necessary processing of unacknowledged tickets in the HOPR packet processing pipeline.
108#[auto_impl::auto_impl(&, Box, Arc)]
109pub trait UnacknowledgedTicketProcessor {
110    type Error: std::error::Error + Send + Sync + 'static;
111
112    /// Inserts a verified unacknowledged ticket from a delivered packet into the internal storage.
113    ///
114    /// The [`ticket`](UnacknowledgedTicket) corresponds to the given [`challenge`](HalfKeyChallenge)
115    /// and awaits to be [acknowledged](UnacknowledgedTicketProcessor::acknowledge_tickets)
116    /// once an [`Acknowledgement`] is received from the `next_hop`.
117    ///
118    /// This operation should be reasonably fast and should not block the main processing pipeline.
119    fn insert_unacknowledged_ticket(
120        &self,
121        next_hop: &OffchainPublicKey,
122        challenge: HalfKeyChallenge,
123        ticket: UnacknowledgedTicket,
124    ) -> Result<(), Self::Error>;
125
126    /// Finds and acknowledges previously inserted tickets, using incoming [`Acknowledgements`](Acknowledgement) from
127    /// the upstream [`peer`](OffchainPublicKey).
128    ///
129    /// Function should first check if any acknowledgements are expected from the given `peer`.
130    ///
131    /// Furthermore, the function must verify each given acknowledgement and find if it evaluates to any solutions
132    /// to challenges of previously [inserted tickets](UnacknowledgedTicketProcessor::insert_unacknowledged_ticket).
133    ///
134    /// On success, the [resolutions](ResolvedAcknowledgement) contain decisions whether the previously
135    /// stored ticket with a matching challenge was found, and whether it is winning (and thus also redeemable) or
136    /// losing.
137    /// Challenges for which tickets were not found are skipped.
138    ///
139    /// Must return [`TicketAcknowledgementError::UnexpectedAcknowledgement`] if no `Acknowledgements` from the given
140    /// `peer` was expected.
141    ///
142    /// This operation is expected to be somewhat long-running and significantly blocking.
143    fn acknowledge_tickets(
144        &self,
145        peer: OffchainPublicKey,
146        acks: Vec<Acknowledgement>,
147    ) -> Result<Vec<ResolvedAcknowledgement>, TicketAcknowledgementError<Self::Error>>;
148}