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