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}