1#![warn(missing_docs)]
2
3use serde::Deserialize;
4use serde::Serialize;
5
6use crate::dht::Did;
7use crate::error::Error;
8use crate::error::Result;
9
10#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
17pub struct MessageRelay {
18 pub path: Vec<Did>,
20
21 pub next_hop: Did,
24
25 pub destination: Did,
28}
29
30impl MessageRelay {
31 pub fn new(path: Vec<Did>, next_hop: Did, destination: Did) -> Self {
33 Self {
34 path,
35 next_hop,
36 destination,
37 }
38 }
39
40 pub fn forward(&self, current: Did, next_hop: Did) -> Result<Self> {
43 self.validate(current)?;
44
45 if self.next_hop != current {
46 return Err(Error::InvalidNextHop);
47 }
48
49 let mut path = self.path.clone();
50 path.push(current);
51
52 Ok(Self {
53 path,
54 next_hop,
55 destination: self.destination,
56 })
57 }
58
59 pub fn report(&self, current: Did) -> Result<Self> {
63 self.validate(current)?;
64
65 if self.path.is_empty() {
66 return Err(Error::CannotInferNextHop);
67 }
68
69 Ok(Self {
70 path: vec![current],
71 next_hop: self.path.last().copied().ok_or(Error::CannotInferNextHop)?,
72 destination: self.try_origin_sender()?,
73 })
74 }
75
76 pub fn reset_destination(&self, destination: Did) -> Self {
79 let mut relay = self.clone();
80 relay.destination = destination;
81 relay
82 }
83
84 pub fn validate(&self, current: Did) -> Result<()> {
86 if self.next_hop != current {
87 return Err(Error::InvalidNextHop);
88 }
89
90 if self
92 .path
93 .windows(2)
94 .any(|window| matches!(window, [left, right] if left == right))
95 {
96 return Err(Error::InvalidRelayPath);
97 }
98
99 if has_infinite_loop(&self.path) {
101 tracing::error!("Infinite path detected {:?}", self.path);
102 return Err(Error::InfiniteRelayPath);
103 }
104
105 Ok(())
106 }
107
108 #[deprecated(note = "please use `origin_sender` instead")]
111 pub fn sender(&self) -> Did {
112 self.origin_sender()
113 }
114
115 pub fn try_origin_sender(&self) -> Result<Did> {
117 self.path.first().copied().ok_or(Error::CannotInferNextHop)
118 }
119
120 pub fn origin_sender(&self) -> Did {
127 self.path.first().copied().unwrap_or(self.destination)
128 }
129}
130
131const INFINITE_LOOP_TOLERANCE: usize = 3;
134
135fn has_infinite_loop<T>(path: &[T]) -> bool
136where T: PartialEq {
137 for period in 1..=path.len() / INFINITE_LOOP_TOLERANCE {
140 let repeated_len = period * INFINITE_LOOP_TOLERANCE;
141 let start = path.len() - repeated_len;
142 let Some(suffix) = path.get(start..) else {
143 continue;
144 };
145 let mut chunks = suffix.chunks_exact(period);
146 let Some(first) = chunks.next() else {
147 continue;
148 };
149 if chunks.all(|chunk| chunk == first) {
150 return true;
151 }
152 }
153
154 false
155}
156
157#[cfg(test)]
158mod test {
159 use super::*;
160
161 #[test]
162 #[rustfmt::skip]
163 fn test_has_infinite_loop() {
164 assert!(!has_infinite_loop(&Vec::<u8>::new()));
165
166 assert!(!has_infinite_loop(&[
167 1, 2, 3,
168 ]));
169
170 assert!(!has_infinite_loop(&[
171 1, 2, 3,
172 1, 2, 3,
173 ]));
174
175 assert!(has_infinite_loop(&[
176 1, 2, 3,
177 1, 2, 3,
178 1, 2, 3,
179 ]));
180
181 assert!(has_infinite_loop(&[
182 1, 1, 2, 3,
183 1, 2, 3,
184 1, 2, 3,
185 ]));
186
187 assert!(!has_infinite_loop(&[
188 1, 2, 3,
189 1, 1, 2, 3,
190 1, 2, 3,
191 ]));
192
193 assert!(has_infinite_loop(&[
194 1, 2, 1, 2, 3,
195 1, 2, 3,
196 1, 2, 3,
197 ]));
198
199 assert!(has_infinite_loop(&[
200 4, 5, 1, 2, 3,
201 1, 2, 3,
202 1, 2, 3,
203 ]));
204
205 assert!(!has_infinite_loop(&[
206 1, 2, 3,
207 3,
208 1, 2, 3,
209 3,
210 1, 2, 3,
211 ]));
212
213 assert!(!has_infinite_loop(&[
214 1,
215 1, 2, 3,
216 3,
217 1, 2, 3,
218 3,
219 1, 2, 3,
220 ]));
221
222 assert!(has_infinite_loop(&[
223 3,
224 1, 2, 3,
225 3,
226 1, 2, 3,
227 3,
228 1, 2, 3,
229 ]));
230
231 assert!(has_infinite_loop(&[
232 1, 2, 3,
233 1, 2, 3,
234 3,
235 1, 2, 3,
236 3,
237 1, 2, 3,
238 ]));
239
240 assert!(has_infinite_loop(&[
241 1, 2,
242 3, 1, 2,
243 3, 3, 1, 2,
244 3, 3, 1, 2,
245 3, 3, 1, 2,
246 ]));
247
248 assert!(!has_infinite_loop(&[
249 2, 3,
250 4, 3,
251 1, 2, 3,
252 4, 3,
253 1, 2, 3,
254 4, 3,
255 ]));
256
257 assert!(has_infinite_loop(&[
258 1, 2, 3,
259 4, 3,
260 1, 2, 3,
261 4, 3,
262 1, 2, 3,
263 4, 3,
264 ]));
265
266 assert!(has_infinite_loop(&[
267 1, 2, 3, 4,
268 3, 1, 2, 3, 4,
269 3, 1, 2, 3, 4,
270 3, 1, 2, 3, 4,
271 ]));
272 }
273
274 #[test]
275 fn empty_path_origin_sender_is_checked() {
276 let fallback_destination = Did::from(2);
277 let relay = MessageRelay::new(vec![], Did::from(1), fallback_destination);
278
279 assert!(matches!(
280 relay.try_origin_sender(),
281 Err(Error::CannotInferNextHop)
282 ));
283 assert_eq!(relay.origin_sender(), fallback_destination);
284 }
285}