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, SurbInsertOutcome},
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, along with how many had to be dropped to make room. The eviction count must not be
30 /// discarded lightly: it is the only evidence that the sender is over-producing.
31 fn insert_surbs(&self, pseudonym: HoprPseudonym, surbs: Vec<(HoprSurbId, HoprSurb)>) -> SurbInsertOutcome;
32
33 /// Stores the given [`opener`](ReplyOpener) for the given [`sender_id`](HoprSenderId).
34 ///
35 /// This is done by the sending side, when it creates a packet containing a SURB to be delivered
36 /// to the replying side.
37 ///
38 /// The operation should happen reasonably fast, as it is called from the packet processing code.
39 fn insert_reply_opener(&self, sender_id: HoprSenderId, opener: ReplyOpener);
40
41 /// Tries to find a [`ReplyOpener`] given the [`sender_id`](HoprSenderId).
42 ///
43 /// This is done by the sending side of the original packet when the reply to that
44 /// packet is received and needs to be decrypted.
45 ///
46 /// The operation should happen reasonably fast, as it is called from the packet processing code.
47 fn find_reply_opener(&self, sender_id: &HoprSenderId) -> Option<ReplyOpener>;
48
49 /// Marks the edge from this node to `relayer` as unusable, so stored SURBs whose return path
50 /// starts there are no longer handed out.
51 ///
52 /// Used by the replying side once the payment channel towards `relayer` is closing or closed:
53 /// replying over it would only burn the SURB. SURBs with a direct return path are unaffected —
54 /// their first relayer is the final recipient and needs no channel.
55 ///
56 /// Defaults to a no-op, for stores that do not track edge validity.
57 fn invalidate_relayer(&self, _relayer: &HoprKeyIdent) {}
58
59 /// Reverts [`SurbStore::invalidate_relayer`] once the channel towards `relayer` re-opens.
60 ///
61 /// Defaults to a no-op, for stores that do not track edge validity.
62 fn revalidate_relayer(&self, _relayer: &HoprKeyIdent) {}
63}
64
65/// Trait defining encoder for [outgoing HOPR packets](OutgoingPacket).
66///
67/// These operations are done directly by the packet processing pipeline before
68/// the outgoing packet is handled to the underlying p2p transport.
69#[auto_impl::auto_impl(&, Box, Arc)]
70pub trait PacketEncoder {
71 type Error: std::error::Error + Send + Sync + 'static;
72
73 /// Encodes the given `data` and [`signals`](PacketSignals) for sending.
74 ///
75 /// The `data` MUST be already correctly sized for HOPR packets, otherwise the operation
76 /// must fail.
77 fn encode_packet<T: AsRef<[u8]> + Send + 'static, S: Into<PacketSignals> + Send + 'static>(
78 &self,
79 data: T,
80 routing: ResolvedTransportRouting<HoprSurb>,
81 signals: S,
82 ) -> Result<OutgoingPacket, Self::Error>;
83
84 /// Encodes the given vector of [`VerifiedAcknowledgements`](VerifiedAcknowledgement) as an outgoing packet to be
85 /// sent to the given [`destination`](OffchainPublicKey).
86 fn encode_acknowledgements(
87 &self,
88 acks: &[VerifiedAcknowledgement],
89 destination: &OffchainPublicKey,
90 ) -> Result<OutgoingPacket, Self::Error>;
91}
92
93/// Trait defining decoder HOPR packets.
94///
95/// This operation is done directly by the packet processing pipeline after
96/// the underlying p2p transport hands over incoming data packets.
97#[auto_impl::auto_impl(&, Box, Arc)]
98pub trait PacketDecoder {
99 type Error: std::error::Error + Send + Sync + 'static;
100
101 /// Decodes the `data` received from the given [`sender`](PeerId)
102 /// returns the corresponding [`IncomingPacket`] if the decoding into a HOPR packet was successful.
103 fn decode(&self, sender: PeerId, data: Bytes) -> Result<IncomingPacket, IncomingPacketError<Self::Error>>;
104}
105
106/// Defines errors returned by `UnacknowledgedTicketProcessor::acknowledge_ticket`.
107#[derive(Debug, thiserror::Error)]
108pub enum TicketAcknowledgementError<E> {
109 /// An acknowledgement from a peer was not expected.
110 #[error("acknowledgement from the peer was not expected")]
111 UnexpectedAcknowledgement,
112 /// An error occurred while processing the acknowledgement.
113 #[error(transparent)]
114 Inner(E),
115}
116
117impl<E> TicketAcknowledgementError<E> {
118 pub fn inner<F: Into<E>>(e: F) -> Self {
119 Self::Inner(e.into())
120 }
121}
122
123/// Performs necessary processing of unacknowledged tickets in the HOPR packet processing pipeline.
124#[auto_impl::auto_impl(&, Box, Arc)]
125pub trait UnacknowledgedTicketProcessor {
126 type Error: std::error::Error + Send + Sync + 'static;
127
128 /// Inserts a verified unacknowledged ticket from a delivered packet into the internal storage.
129 ///
130 /// The [`ticket`](UnacknowledgedTicket) corresponds to the given [`challenge`](HalfKeyChallenge)
131 /// and awaits to be [acknowledged](UnacknowledgedTicketProcessor::acknowledge_tickets)
132 /// once an [`Acknowledgement`] is received from the `next_hop`.
133 ///
134 /// This operation should be reasonably fast and should not block the main processing pipeline.
135 fn insert_unacknowledged_ticket(
136 &self,
137 next_hop: &OffchainPublicKey,
138 challenge: HalfKeyChallenge,
139 ticket: UnacknowledgedTicket,
140 ) -> Result<(), Self::Error>;
141
142 /// Finds and acknowledges previously inserted tickets, using incoming [`Acknowledgements`](Acknowledgement) from
143 /// the upstream [`peer`](OffchainPublicKey).
144 ///
145 /// Function should first check if any acknowledgements are expected from the given `peer`.
146 ///
147 /// Furthermore, the function must verify each given acknowledgement and find if it evaluates to any solutions
148 /// to challenges of previously [inserted tickets](UnacknowledgedTicketProcessor::insert_unacknowledged_ticket).
149 ///
150 /// On success, the [resolutions](ResolvedAcknowledgement) contain decisions whether the previously
151 /// stored ticket with a matching challenge was found, and whether it is winning (and thus also redeemable) or
152 /// losing.
153 /// Challenges for which tickets were not found are skipped.
154 ///
155 /// Must return [`TicketAcknowledgementError::UnexpectedAcknowledgement`] if no `Acknowledgements` from the given
156 /// `peer` was expected.
157 ///
158 /// This operation is expected to be somewhat long-running and significantly blocking.
159 fn acknowledge_tickets(
160 &self,
161 peer: OffchainPublicKey,
162 acks: Vec<Acknowledgement>,
163 ) -> Result<Vec<ResolvedAcknowledgement>, TicketAcknowledgementError<Self::Error>>;
164}