hopr_protocol_hopr/codec/
mod.rs1mod decoder;
2mod encoder;
3
4pub use decoder::HoprDecoder;
5pub use encoder::{HoprEncoder, MAX_ACKNOWLEDGEMENTS_BATCH_SIZE};
6
7fn default_outgoing_win_prob() -> Option<hopr_internal_types::prelude::WinningProbability> {
8 Some(hopr_internal_types::prelude::WinningProbability::ALWAYS)
9}
10
11#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_with::serde_as)]
13#[derive(Clone, Copy, Debug, smart_default::SmartDefault, validator::Validate)]
14#[cfg_attr(
15 feature = "serde",
16 derive(serde::Serialize, serde::Deserialize),
17 serde(deny_unknown_fields)
18)]
19pub struct HoprCodecConfig {
20 #[cfg_attr(
24 feature = "serde",
25 serde(default),
26 serde_as(as = "Option<serde_with::DisplayFromStr>")
27 )]
28 pub outgoing_ticket_price: Option<hopr_primitive_types::balance::HoprBalance>,
29 #[cfg_attr(
36 feature = "serde",
37 serde(default = "default_outgoing_win_prob"),
38 serde_as(as = "Option<serde_with::DisplayFromStr>")
39 )]
40 #[default(default_outgoing_win_prob())]
41 pub outgoing_win_prob: Option<hopr_internal_types::prelude::WinningProbability>,
42}
43
44impl PartialEq for HoprCodecConfig {
45 fn eq(&self, other: &Self) -> bool {
46 self.outgoing_ticket_price.eq(&other.outgoing_ticket_price)
47 && match (self.outgoing_win_prob, other.outgoing_win_prob) {
48 (Some(a), Some(b)) => a.approx_eq(&b),
49 (None, None) => true,
50 _ => false,
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use std::sync::Arc;
58
59 use hopr_chain_connector::{
60 HoprBlockchainSafeConnector,
61 testing::{BlokliTestClient, StaticState},
62 };
63 use hopr_crypto_random::Randomizable;
64 use hopr_crypto_types::prelude::*;
65 use hopr_db_node::HoprNodeDb;
66 use hopr_internal_types::prelude::*;
67 use hopr_network_types::prelude::ResolvedTransportRouting;
68
69 use crate::{
70 HoprCodecConfig, HoprDecoder, HoprEncoder, HoprTicketProcessor, HoprTicketProcessorConfig, MemorySurbStore,
71 PacketDecoder, PacketEncoder, SurbStoreConfig, codec::encoder::MAX_ACKNOWLEDGEMENTS_BATCH_SIZE, utils::*,
72 };
73
74 type TestEncoder = HoprEncoder<
75 Arc<HoprBlockchainSafeConnector<BlokliTestClient<StaticState>>>,
76 MemorySurbStore,
77 HoprTicketProcessor<Arc<HoprBlockchainSafeConnector<BlokliTestClient<StaticState>>>, HoprNodeDb>,
78 >;
79
80 type TestDecoder = HoprDecoder<
81 Arc<HoprBlockchainSafeConnector<BlokliTestClient<StaticState>>>,
82 MemorySurbStore,
83 HoprTicketProcessor<Arc<HoprBlockchainSafeConnector<BlokliTestClient<StaticState>>>, HoprNodeDb>,
84 >;
85
86 pub fn create_encoder(sender: &Node) -> TestEncoder {
87 HoprEncoder::new(
88 sender.chain_key.clone(),
89 sender.chain_api.clone(),
90 MemorySurbStore::new(SurbStoreConfig::default()),
91 HoprTicketProcessor::new(
92 sender.chain_api.clone(),
93 sender.node_db.clone(),
94 sender.chain_key.clone(),
95 Hash::default(),
96 HoprTicketProcessorConfig::default(),
97 ),
98 Hash::default(),
99 HoprCodecConfig::default(),
100 )
101 }
102
103 pub fn create_decoder(receiver: &Node) -> TestDecoder {
104 HoprDecoder::new(
105 (receiver.offchain_key.clone(), receiver.chain_key.clone()),
106 receiver.chain_api.clone(),
107 MemorySurbStore::new(SurbStoreConfig::default()),
108 HoprTicketProcessor::new(
109 receiver.chain_api.clone(),
110 receiver.node_db.clone(),
111 receiver.chain_key.clone(),
112 Hash::default(),
113 HoprTicketProcessorConfig::default(),
114 ),
115 Hash::default(),
116 HoprCodecConfig::default(),
117 )
118 }
119
120 #[tokio::test]
121 async fn encode_decode_packet() -> anyhow::Result<()> {
122 let blokli_client = create_blokli_client()?;
123 let sender = create_node(0, &blokli_client).await?;
124 let receiver = create_node(1, &blokli_client).await?;
125
126 let encoder = create_encoder(&sender);
127 let decoder = create_decoder(&receiver);
128
129 let data = b"some random message to encode and decode";
130
131 let out_packet = encoder
132 .encode_packet(
133 data,
134 ResolvedTransportRouting::Forward {
135 pseudonym: HoprPseudonym::random(),
136 forward_path: ValidatedPath::direct(
137 *receiver.offchain_key.public(),
138 receiver.chain_key.public().to_address(),
139 ),
140 return_paths: vec![],
141 },
142 None,
143 )
144 .await?;
145
146 let in_packet = decoder
147 .decode(sender.offchain_key.public().into(), out_packet.data)
148 .await?;
149 let in_packet = in_packet.try_as_final().ok_or(anyhow::anyhow!("packet is not final"))?;
150
151 assert_eq!(data, in_packet.plain_text.as_ref());
152 Ok(())
153 }
154
155 #[tokio::test]
156 async fn encode_decode_packet_should_fail_for_too_long_messages() -> anyhow::Result<()> {
157 let blokli_client = create_blokli_client()?;
158 let sender = create_node(0, &blokli_client).await?;
159 let receiver = create_node(1, &blokli_client).await?;
160
161 let encoder = create_encoder(&sender);
162
163 let data = hopr_crypto_random::random_bytes::<2048>();
164
165 assert!(
166 encoder
167 .encode_packet(
168 data,
169 ResolvedTransportRouting::Forward {
170 pseudonym: HoprPseudonym::random(),
171 forward_path: ValidatedPath::direct(
172 *receiver.offchain_key.public(),
173 receiver.chain_key.public().to_address(),
174 ),
175 return_paths: vec![],
176 },
177 None,
178 )
179 .await
180 .is_err()
181 );
182
183 Ok(())
184 }
185
186 #[tokio::test]
187 async fn encode_decode_packet_on_relay() -> anyhow::Result<()> {
188 let blokli_client = create_blokli_client()?;
189 let sender = create_node(0, &blokli_client).await?;
190 let relay = create_node(1, &blokli_client).await?;
191 let receiver = create_node(2, &blokli_client).await?;
192
193 let sender_encoder = create_encoder(&sender);
194 let relay_decoder = create_decoder(&relay);
195 let receiver_decoder = create_decoder(&receiver);
196
197 let data = b"some random message to encode and decode";
198
199 let out_packet = sender_encoder
200 .encode_packet(
201 data,
202 ResolvedTransportRouting::Forward {
203 pseudonym: HoprPseudonym::random(),
204 forward_path: ValidatedPath::new(
205 sender.chain_key.public().to_address(),
206 vec![
207 relay.chain_key.public().to_address(),
208 receiver.chain_key.public().to_address(),
209 ],
210 &sender.chain_api.as_path_resolver(),
211 )
212 .await?,
213 return_paths: vec![],
214 },
215 None,
216 )
217 .await?;
218
219 let fwd_packet = relay_decoder
220 .decode(sender.offchain_key.public().into(), out_packet.data)
221 .await?;
222 let fwd_packet = fwd_packet
223 .try_as_forwarded()
224 .ok_or(anyhow::anyhow!("packet is not forwarded"))?;
225
226 let in_packet = receiver_decoder
227 .decode(relay.offchain_key.public().into(), fwd_packet.data)
228 .await?;
229 let in_packet = in_packet.try_as_final().ok_or(anyhow::anyhow!("packet is not final"))?;
230
231 assert_eq!(data, in_packet.plain_text.as_ref());
232 Ok(())
233 }
234
235 #[tokio::test]
236 async fn encode_decode_acknowledgements() -> anyhow::Result<()> {
237 let blokli_client = create_blokli_client()?;
238 let sender = create_node(0, &blokli_client).await?;
239 let receiver = create_node(1, &blokli_client).await?;
240
241 let encoder = create_encoder(&sender);
242 let decoder = create_decoder(&receiver);
243
244 let acks = (0..MAX_ACKNOWLEDGEMENTS_BATCH_SIZE)
245 .map(|_| VerifiedAcknowledgement::random(&PEERS[0].1))
246 .collect::<Vec<_>>();
247 let out_packet = encoder.encode_acknowledgements(&acks, PEERS[1].1.public()).await?;
248
249 let in_packet = decoder
250 .decode(sender.offchain_key.public().into(), out_packet.data)
251 .await?;
252 let in_packet = in_packet
253 .try_as_acknowledgement()
254 .ok_or(anyhow::anyhow!("packet is not acknowledgement"))?;
255
256 assert_eq!(acks.len(), in_packet.received_acks.len());
257
258 for (i, ack) in in_packet.received_acks.into_iter().enumerate() {
259 let verified = ack.verify(PEERS[0].1.public())?;
260 assert_eq!(acks[i], verified);
261 }
262
263 Ok(())
264 }
265
266 #[tokio::test]
267 async fn encode_should_fail_on_too_many_acknowledgements() -> anyhow::Result<()> {
268 let blokli_client = create_blokli_client()?;
269 let sender = create_node(0, &blokli_client).await?;
270
271 let encoder = create_encoder(&sender);
272 let acks = (0..MAX_ACKNOWLEDGEMENTS_BATCH_SIZE + 1)
273 .map(|_| VerifiedAcknowledgement::random(&PEERS[0].1))
274 .collect::<Vec<_>>();
275
276 assert!(
277 encoder
278 .encode_acknowledgements(&acks, PEERS[1].1.public())
279 .await
280 .is_err()
281 );
282
283 Ok(())
284 }
285}