hopr_protocol_hopr/codec/
encoder.rs1use hopr_api::chain::*;
2use hopr_crypto_packet::prelude::*;
3use hopr_crypto_types::{crypto_traits::Randomizable, prelude::*};
4use hopr_internal_types::prelude::*;
5use hopr_network_types::prelude::*;
6use hopr_primitive_types::prelude::*;
7
8use crate::{
9 HoprCodecConfig, OutgoingPacket, PacketEncoder, SurbStore, TicketCreationError, TicketTracker,
10 errors::HoprProtocolError,
11};
12
13pub struct HoprEncoder<Chain, S, T> {
15 chain_api: Chain,
16 surb_store: S,
17 tracker: T,
18 chain_key: ChainKeypair,
19 channels_dst: Hash,
20 cfg: HoprCodecConfig,
21}
22
23impl<Chain, S, T> HoprEncoder<Chain, S, T> {
24 pub fn new(
26 chain_key: ChainKeypair,
27 chain_api: Chain,
28 surb_store: S,
29 tracker: T,
30 channels_dst: Hash,
31 cfg: HoprCodecConfig,
32 ) -> Self {
33 Self {
34 chain_api,
35 surb_store,
36 tracker,
37 chain_key,
38 channels_dst,
39 cfg,
40 }
41 }
42}
43
44impl<Chain, S, T> HoprEncoder<Chain, S, T>
45where
46 Chain: ChainKeyOperations + ChainReadChannelOperations + ChainValues + Sync,
47 S: SurbStore,
48 T: TicketTracker + Sync,
49{
50 async fn encode_packet_internal<D: AsRef<[u8]> + Send + 'static, Sig: Into<PacketSignals> + Send + 'static>(
51 &self,
52 next_peer: OffchainPublicKey,
53 data: D,
54 num_hops: usize,
55 signals: Sig,
56 routing: PacketRouting<ValidatedPath>,
57 pseudonym: HoprPseudonym,
58 ) -> Result<OutgoingPacket, HoprProtocolError> {
59 let next_peer = self
60 .chain_api
61 .packet_key_to_chain_key(&next_peer)
62 .await
63 .map_err(|e| HoprProtocolError::ResolverError(e.into()))?
64 .ok_or(HoprProtocolError::KeyNotFound)?;
65
66 let next_ticket = if num_hops > 1 {
68 let channel = self
69 .chain_api
70 .channel_by_parties(self.chain_key.as_ref(), &next_peer)
71 .await
72 .map_err(|e| HoprProtocolError::ResolverError(e.into()))?
73 .ok_or_else(|| HoprProtocolError::ChannelNotFound(*self.chain_key.as_ref(), next_peer))?;
74
75 let (outgoing_ticket_win_prob, outgoing_ticket_price) = self
76 .chain_api
77 .outgoing_ticket_values(self.cfg.outgoing_win_prob, self.cfg.outgoing_ticket_price)
78 .await
79 .map_err(|e| HoprProtocolError::ResolverError(e.into()))?;
80
81 self.tracker
82 .create_multihop_ticket(
83 &channel,
84 num_hops as u8,
85 outgoing_ticket_win_prob,
86 outgoing_ticket_price,
87 )
88 .await
89 .map_err(|e| match e {
90 TicketCreationError::OutOfFunds(id, a) => HoprProtocolError::OutOfFunds(id, a),
91 e => HoprProtocolError::TicketTrackerError(e.into()),
92 })?
93 } else {
94 TicketBuilder::zero_hop().counterparty(next_peer)
95 };
96
97 let chain_key = self.chain_key.clone();
99 let mapper = self.chain_api.key_id_mapper_ref().clone();
100 let domain_separator = self.channels_dst;
101 let (packet, openers) = hopr_parallelize::cpu::spawn_fifo_blocking(move || {
102 HoprPacket::into_outgoing(
103 data.as_ref(),
104 &pseudonym,
105 routing,
106 &chain_key,
107 next_ticket,
108 &mapper,
109 &domain_separator,
110 signals,
111 )
112 })
113 .await?;
114
115 openers.into_iter().for_each(|(surb_id, opener)| {
118 self.surb_store
119 .insert_reply_opener(HoprSenderId::from_pseudonym_and_id(&pseudonym, surb_id), opener);
120 });
121
122 let out = packet.try_as_outgoing().ok_or(HoprProtocolError::InvalidState(
123 "cannot send out packet that is not outgoing",
124 ))?;
125
126 let mut transport_payload = Vec::with_capacity(HoprPacket::SIZE);
127 transport_payload.extend_from_slice(out.packet.as_ref());
128 transport_payload.extend_from_slice(&out.ticket.into_encoded());
129
130 Ok(OutgoingPacket {
131 next_hop: out.next_hop,
132 ack_challenge: out.ack_challenge,
133 data: transport_payload.into_boxed_slice(),
134 })
135 }
136}
137
138#[async_trait::async_trait]
139impl<Chain, S, T> PacketEncoder for HoprEncoder<Chain, S, T>
140where
141 Chain: ChainKeyOperations + ChainReadChannelOperations + ChainValues + Send + Sync,
142 S: SurbStore + Send + Sync,
143 T: TicketTracker + Send + Sync,
144{
145 type Error = HoprProtocolError;
146
147 async fn encode_packet<D: AsRef<[u8]> + Send + 'static, Sig: Into<PacketSignals> + Send + 'static>(
148 &self,
149 data: D,
150 routing: ResolvedTransportRouting,
151 signals: Sig,
152 ) -> Result<OutgoingPacket, Self::Error> {
153 let (next_peer, num_hops, pseudonym, routing) = match routing {
155 ResolvedTransportRouting::Forward {
156 pseudonym,
157 forward_path,
158 return_paths,
159 } => (
160 forward_path[0],
161 forward_path.num_hops(),
162 pseudonym,
163 PacketRouting::ForwardPath {
164 forward_path,
165 return_paths,
166 },
167 ),
168 ResolvedTransportRouting::Return(sender_id, surb) => {
169 let next = self
170 .chain_api
171 .key_id_mapper_ref()
172 .map_id_to_public(&surb.first_relayer)
173 .ok_or(HoprProtocolError::KeyNotFound)?;
174
175 (
176 next,
177 surb.additional_data_receiver.proof_of_relay_values().chain_length() as usize,
178 sender_id.pseudonym(),
179 PacketRouting::Surb(sender_id.surb_id(), surb),
180 )
181 }
182 };
183
184 self.encode_packet_internal(next_peer, data, num_hops, signals, routing, pseudonym)
185 .await
186 }
187
188 async fn encode_acknowledgement(
189 &self,
190 ack: VerifiedAcknowledgement,
191 peer: &OffchainPublicKey,
192 ) -> Result<OutgoingPacket, Self::Error> {
193 self.encode_packet_internal(
194 *peer,
195 ack.leak(),
196 0,
197 None,
198 PacketRouting::NoAck(*peer),
199 HoprPseudonym::random(),
200 )
201 .await
202 }
203}