hopr_transport_probe/
types.rs1use hopr_api::PeerId;
2use hopr_crypto_random::Randomizable;
3use hopr_internal_types::{NodeId, protocol::HoprPseudonym};
4use hopr_network_types::types::{DestinationRouting, RoutingOptions};
5use hopr_primitive_types::{bounded::BoundedVec, errors::GeneralError};
6
7pub struct TaggedDestinationRouting {
8 pub destination: Box<NodeId>,
10 pub pseudonym: HoprPseudonym,
12 pub forward_options: RoutingOptions,
14 pub return_options: Option<RoutingOptions>,
16}
17
18impl TaggedDestinationRouting {
19 pub fn neighbor(destination: Box<NodeId>) -> Self {
20 Self {
21 destination,
22 pseudonym: HoprPseudonym::random(),
23 forward_options: RoutingOptions::Hops(0.try_into().expect("0 is a valid u8")),
24 return_options: Some(RoutingOptions::Hops(0.try_into().expect("0 is a valid u8"))),
25 }
26 }
27
28 pub fn loopback(me: Box<NodeId>, path: BoundedVec<NodeId, { RoutingOptions::MAX_INTERMEDIATE_HOPS }>) -> Self {
29 Self {
30 destination: me,
31 pseudonym: HoprPseudonym::random(),
32 forward_options: RoutingOptions::IntermediatePath(path),
33 return_options: None,
34 }
35 }
36}
37
38impl From<TaggedDestinationRouting> for DestinationRouting {
39 fn from(value: TaggedDestinationRouting) -> Self {
40 DestinationRouting::Forward {
41 destination: value.destination,
42 pseudonym: Some(value.pseudonym),
43 forward_options: value.forward_options,
44 return_options: value.return_options,
45 }
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::EnumDiscriminants)]
51#[strum_discriminants(vis(pub(crate)), derive(strum::FromRepr, strum::EnumCount), repr(u8))]
52pub enum NeighborProbe {
53 Ping([u8; Self::NONCE_SIZE]),
55 Pong([u8; Self::NONCE_SIZE]),
57}
58
59impl NeighborProbe {
60 pub const NONCE_SIZE: usize = 32;
61 pub const SIZE: usize = 1 + Self::NONCE_SIZE;
62
63 pub fn random_nonce() -> Self {
65 Self::Ping(hopr_crypto_random::random_bytes::<{ Self::NONCE_SIZE }>())
66 }
67
68 pub fn is_complement_to(&self, other: Self) -> bool {
69 match (self, &other) {
70 (Self::Ping(nonce1), Self::Pong(nonce2)) => nonce1 == nonce2,
71 (Self::Pong(nonce1), Self::Ping(nonce2)) => nonce1 == nonce2,
72 _ => false,
73 }
74 }
75
76 pub fn to_bytes(self) -> Box<[u8]> {
77 let mut out = Vec::with_capacity(1 + Self::NONCE_SIZE);
78 out.push(NeighborProbeDiscriminants::from(&self) as u8);
79 out.extend_from_slice(self.as_ref());
80 out.into_boxed_slice()
81 }
82}
83
84impl<'a> TryFrom<&'a [u8]> for NeighborProbe {
85 type Error = GeneralError;
86
87 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
88 if value.len() == 1 + Self::NONCE_SIZE {
89 match NeighborProbeDiscriminants::from_repr(value[0])
90 .ok_or(GeneralError::ParseError("NeighborProbe.disc".into()))?
91 {
92 NeighborProbeDiscriminants::Ping => {
93 Ok(Self::Ping((&value[1..]).try_into().map_err(|_| {
94 GeneralError::ParseError("NeighborProbe.ping_nonce".into())
95 })?))
96 }
97 NeighborProbeDiscriminants::Pong => {
98 Ok(Self::Pong((&value[1..]).try_into().map_err(|_| {
99 GeneralError::ParseError("NeighborProbe.pong_nonce".into())
100 })?))
101 }
102 }
103 } else {
104 Err(GeneralError::ParseError("NeighborProbe.size".into()))
105 }
106 }
107}
108
109impl std::fmt::Display for NeighborProbe {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self {
112 NeighborProbe::Ping(nonce) => write!(f, "Ping({})", hex::encode(nonce)),
113 NeighborProbe::Pong(nonce) => write!(f, "Pong({})", hex::encode(nonce)),
114 }
115 }
116}
117
118impl AsRef<[u8]> for NeighborProbe {
119 fn as_ref(&self) -> &[u8] {
120 match self {
121 NeighborProbe::Ping(nonce) | NeighborProbe::Pong(nonce) => nonce,
122 }
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131pub struct PathTelemetry {
132 pub id: [u8; Self::ID_SIZE],
134 pub path: [u8; Self::PATH_SIZE],
136 pub timestamp: u128,
138}
139
140impl PathTelemetry {
141 pub const ID_SIZE: usize = 10;
142 pub const PATH_SIZE: usize = 10;
143 pub const SIZE: usize = Self::ID_SIZE + Self::PATH_SIZE + size_of::<u128>();
144
145 pub fn to_bytes(self) -> Box<[u8]> {
146 let mut out = Vec::with_capacity(Self::SIZE);
147 out.extend_from_slice(&self.id);
148 out.extend_from_slice(&self.path);
149 out.extend_from_slice(&self.timestamp.to_be_bytes());
150 out.into_boxed_slice()
151 }
152}
153
154impl hopr_api::ct::MeasurablePath for PathTelemetry {
155 fn id(&self) -> &[u8] {
156 &self.id
157 }
158
159 fn path(&self) -> &[u8] {
160 &self.path
161 }
162
163 fn timestamp(&self) -> u128 {
164 self.timestamp
165 }
166}
167
168const _: () = assert!(size_of::<u128>() > PathTelemetry::ID_SIZE);
169
170impl std::fmt::Display for PathTelemetry {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 write!(
173 f,
174 "PathTelemetry(id: {}, path: {}, timestamp: {})",
175 hex::encode(self.id),
176 hex::encode(self.path),
177 self.timestamp
178 )
179 }
180}
181
182impl<'a> TryFrom<&'a [u8]> for PathTelemetry {
183 type Error = GeneralError;
184
185 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
186 if value.len() == Self::SIZE {
187 Ok(Self {
188 id: (&value[0..10])
189 .try_into()
190 .map_err(|_| GeneralError::ParseError("PathTelemetry.id".into()))?,
191 path: (&value[10..20])
192 .try_into()
193 .map_err(|_| GeneralError::ParseError("PathTelemetry.path".into()))?,
194 timestamp: u128::from_be_bytes(
195 (&value[20..36])
196 .try_into()
197 .map_err(|_| GeneralError::ParseError("PathTelemetry.timestamp".into()))?,
198 ),
199 })
200 } else {
201 Err(GeneralError::ParseError("PathTelemetry".into()))
202 }
203 }
204}
205
206#[derive(Debug, Clone)]
210pub struct NeighborTelemetry {
211 pub peer: PeerId,
212 pub rtt: std::time::Duration,
213}
214
215impl hopr_api::ct::MeasurableNeighbor for NeighborTelemetry {
216 fn peer(&self) -> &PeerId {
217 &self.peer
218 }
219
220 fn rtt(&self) -> std::time::Duration {
221 self.rtt
222 }
223}