1#![deny(
30 clippy::unwrap_used,
31 missing_docs,
32 missing_debug_implementations,
33 missing_copy_implementations,
34 trivial_casts,
35 trivial_numeric_casts,
36 unsafe_code,
37 unstable_features,
38 unused_import_braces,
39 unused_qualifications
40)]
41
42pub mod data;
43pub mod operations;
44
45pub use crate::data::{WebOfTrust, WotId};
46
47use once_cell::sync::OnceCell;
48
49pub static MAIN_WOT: OnceCell<parking_lot::RwLock<data::rusty::RustyWebOfTrust>> = OnceCell::new();
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::data::*;
56 use crate::operations::centrality::*;
57 use crate::operations::distance::*;
58 use crate::operations::path::*;
59 use std::{io::Read, io::Write, path::Path};
60
61 fn read_bin_file(file_path: &Path) -> Result<Vec<u8>, std::io::Error> {
62 let mut file = std::fs::File::open(file_path)?;
63 if file.metadata()?.len() == 0 {
64 Ok(vec![])
65 } else {
66 let mut bin_datas = Vec::new();
67 file.read_to_end(&mut bin_datas)?;
68
69 Ok(bin_datas)
70 }
71 }
72
73 fn write_bin_file(file_path: &Path, datas: &[u8]) -> Result<(), std::io::Error> {
74 let mut file = std::fs::File::create(file_path)?;
75 file.write_all(datas)?;
76
77 Ok(())
78 }
79
80 #[allow(clippy::cognitive_complexity)]
85 pub fn generic_wot_test<W>()
86 where
87 W: WebOfTrust + Sync,
88 {
89 let centralities_calculator = UlrikBrandesCentralityCalculator {};
90 let distance_calculator = RustyDistanceCalculator {};
91 let path_finder = RustyPathFinder {};
92 let mut wot = W::new(3);
93
94 assert_eq!(wot.size(), 0);
96
97 assert_eq!(wot.is_enabled(WotId(0)), None);
99 assert_eq!(wot.is_enabled(WotId(23)), None);
100
101 assert_eq!(wot.add_node(), WotId(0));
104 assert_eq!(wot.size(), 1);
105 assert_eq!(wot.get_disabled().len(), 0);
106
107 assert_eq!(wot.rem_node(), Some(WotId(0)));
109 assert_eq!(wot.size(), 0);
110
111 assert_eq!(wot.add_node(), WotId(0));
113
114 assert_eq!(wot.add_node(), WotId(1));
116 assert_eq!(wot.size(), 2);
117 assert_eq!(wot.get_disabled().len(), 0);
118
119 for i in 0..10 {
121 assert_eq!(wot.add_node(), WotId(i + 2));
122 }
123
124 assert_eq!(wot.size(), 12);
125
126 assert_eq!(
128 wot.add_link(WotId(0), WotId(0)),
129 NewLinkResult::SelfLinkingForbidden()
130 );
131
132 assert_eq!(wot.add_link(WotId(0), WotId(1)), NewLinkResult::Ok(1));
134 assert_eq!(wot.add_link(WotId(0), WotId(2)), NewLinkResult::Ok(1));
135 assert_eq!(wot.add_link(WotId(0), WotId(3)), NewLinkResult::Ok(1));
136 assert_eq!(
137 wot.add_link(WotId(0), WotId(4)),
138 NewLinkResult::AllCertificationsUsed(0)
139 );
140
141 assert_eq!(wot.get_max_link(), 3);
142 assert_eq!(wot.has_link(WotId(0), WotId(1)), HasLinkResult::Link(true));
143 assert_eq!(wot.has_link(WotId(0), WotId(2)), HasLinkResult::Link(true));
144 assert_eq!(wot.has_link(WotId(0), WotId(3)), HasLinkResult::Link(true));
145 assert_eq!(wot.has_link(WotId(0), WotId(4)), HasLinkResult::Link(false));
146
147 wot.set_max_link(4);
148 assert_eq!(wot.get_max_link(), 4);
149 assert_eq!(wot.has_link(WotId(0), WotId(4)), HasLinkResult::Link(false));
150 wot.add_link(WotId(0), WotId(4));
151 assert_eq!(wot.has_link(WotId(0), WotId(4)), HasLinkResult::Link(true));
152 wot.rem_link(WotId(0), WotId(1));
153 wot.rem_link(WotId(0), WotId(2));
154 wot.rem_link(WotId(0), WotId(3));
155 wot.rem_link(WotId(0), WotId(4));
156
157 assert_eq!(wot.has_link(WotId(0), WotId(6)), HasLinkResult::Link(false));
159 assert_eq!(
160 wot.has_link(WotId(23), WotId(0)),
161 HasLinkResult::UnknownSource()
162 );
163 assert_eq!(
164 wot.has_link(WotId(2), WotId(53)),
165 HasLinkResult::UnknownTarget()
166 );
167
168 assert_eq!(wot.is_enabled(WotId(0)), Some(true));
170 assert_eq!(wot.is_enabled(WotId(1)), Some(true));
171 assert_eq!(wot.is_enabled(WotId(2)), Some(true));
172 assert_eq!(wot.is_enabled(WotId(3)), Some(true));
173 assert_eq!(wot.is_enabled(WotId(11)), Some(true));
174
175 assert_eq!(wot.set_enabled(WotId(0), false), Some(false));
177 assert_eq!(wot.set_enabled(WotId(1), false), Some(false));
178 assert_eq!(wot.set_enabled(WotId(2), false), Some(false));
179 assert_eq!(wot.get_disabled().len(), 3);
180 assert_eq!(wot.set_enabled(WotId(1), true), Some(true));
181
182 assert_eq!(wot.is_enabled(WotId(0)), Some(false));
184 assert_eq!(wot.is_enabled(WotId(1)), Some(true));
185 assert_eq!(wot.is_enabled(WotId(2)), Some(false));
186 assert_eq!(wot.is_enabled(WotId(3)), Some(true));
187 assert_eq!(wot.set_enabled(WotId(0), true), Some(true));
189 assert_eq!(wot.set_enabled(WotId(1), true), Some(true));
190 assert_eq!(wot.set_enabled(WotId(2), true), Some(true));
191 assert_eq!(wot.set_enabled(WotId(1), true), Some(true));
192 assert_eq!(wot.get_disabled().len(), 0);
193
194 assert_eq!(wot.has_link(WotId(2), WotId(0)), HasLinkResult::Link(false));
196
197 assert_eq!(wot.add_link(WotId(2), WotId(0)), NewLinkResult::Ok(1));
199 assert_eq!(wot.add_link(WotId(4), WotId(0)), NewLinkResult::Ok(2));
200 assert_eq!(
202 wot.add_link(WotId(4), WotId(0)),
203 NewLinkResult::AlreadyExistingCertification(2)
204 );
205 assert_eq!(
207 wot.add_link(WotId(4), WotId(0)),
208 NewLinkResult::AlreadyExistingCertification(2)
209 );
210 assert_eq!(wot.add_link(WotId(5), WotId(0)), NewLinkResult::Ok(3));
211
212 assert_eq!(wot.has_link(WotId(2), WotId(0)), HasLinkResult::Link(true));
221 assert_eq!(wot.has_link(WotId(4), WotId(0)), HasLinkResult::Link(true));
222 assert_eq!(wot.has_link(WotId(5), WotId(0)), HasLinkResult::Link(true));
223 assert_eq!(wot.has_link(WotId(2), WotId(1)), HasLinkResult::Link(false));
224
225 assert_eq!(wot.rem_link(WotId(4), WotId(0)), RemLinkResult::Removed(2));
227 assert_eq!(wot.has_link(WotId(2), WotId(0)), HasLinkResult::Link(true));
236 assert_eq!(wot.has_link(WotId(4), WotId(0)), HasLinkResult::Link(false));
237 assert_eq!(wot.has_link(WotId(5), WotId(0)), HasLinkResult::Link(true));
238 assert_eq!(wot.has_link(WotId(2), WotId(1)), HasLinkResult::Link(false));
239
240 assert_eq!(
242 distance_calculator.is_outdistanced(
243 &wot,
244 WotDistanceParameters {
245 node: WotId(0),
246 sentry_requirement: 1,
247 step_max: 1,
248 x_percent: 1.0,
249 },
250 ),
251 Ok(false)
252 );
253 assert_eq!(
255 distance_calculator.is_outdistanced(
256 &wot,
257 WotDistanceParameters {
258 node: WotId(0),
259 sentry_requirement: 2,
260 step_max: 1,
261 x_percent: 1.0,
262 },
263 ),
264 Ok(false)
265 );
266 assert_eq!(
268 distance_calculator.is_outdistanced(
269 &wot,
270 WotDistanceParameters {
271 node: WotId(0),
272 sentry_requirement: 3,
273 step_max: 1,
274 x_percent: 1.0,
275 },
276 ),
277 Ok(false)
278 );
279 assert_eq!(wot.add_link(WotId(3), WotId(1)), NewLinkResult::Ok(1));
283 assert_eq!(wot.add_link(WotId(3), WotId(2)), NewLinkResult::Ok(1));
284 assert_eq!(wot.size(), 12);
293 assert_eq!(wot.get_sentries(1).len(), 1);
294 assert_eq!(wot.get_sentries(1)[0], WotId(2));
295 assert_eq!(wot.get_sentries(2).len(), 0);
296 assert_eq!(wot.get_sentries(3).len(), 0);
297 assert_eq!(wot.get_non_sentries(1).len(), 11); assert_eq!(wot.get_non_sentries(2).len(), 12); assert_eq!(wot.get_non_sentries(3).len(), 12); assert_eq!(path_finder.find_paths(&wot, WotId(3), WotId(0), 1).len(), 0); assert_eq!(path_finder.find_paths(&wot, WotId(3), WotId(0), 2).len(), 1); assert!(path_finder
303 .find_paths(&wot, WotId(3), WotId(0), 2)
304 .contains(&vec![WotId(3), WotId(2), WotId(0)]));
305
306 assert_eq!(
307 distance_calculator.is_outdistanced(
308 &wot,
309 WotDistanceParameters {
310 node: WotId(0),
311 sentry_requirement: 1,
312 step_max: 1,
313 x_percent: 1.0,
314 },
315 ),
316 Ok(false)
317 ); assert_eq!(
319 distance_calculator.is_outdistanced(
320 &wot,
321 WotDistanceParameters {
322 node: WotId(0),
323 sentry_requirement: 2,
324 step_max: 1,
325 x_percent: 1.0,
326 },
327 ),
328 Ok(false)
329 ); assert_eq!(
331 distance_calculator.is_outdistanced(
332 &wot,
333 WotDistanceParameters {
334 node: WotId(0),
335 sentry_requirement: 3,
336 step_max: 1,
337 x_percent: 1.0,
338 },
339 ),
340 Ok(false)
341 ); assert_eq!(
343 distance_calculator.is_outdistanced(
344 &wot,
345 WotDistanceParameters {
346 node: WotId(0),
347 sentry_requirement: 2,
348 step_max: 2,
349 x_percent: 1.0,
350 },
351 ),
352 Ok(false)
353 ); wot.add_link(WotId(1), WotId(3));
356 wot.add_link(WotId(2), WotId(3));
357
358 assert_eq!(wot.size(), 12);
359 assert_eq!(wot.get_sentries(1).len(), 3);
360 assert_eq!(wot.get_sentries(1)[0], WotId(1));
361 assert_eq!(wot.get_sentries(1)[1], WotId(2));
362 assert_eq!(wot.get_sentries(1)[2], WotId(3));
363
364 assert_eq!(wot.get_sentries(2).len(), 1);
365 assert_eq!(wot.get_sentries(2)[0], WotId(3));
366 assert_eq!(wot.get_sentries(3).len(), 0);
367 assert_eq!(wot.get_non_sentries(1).len(), 9); assert_eq!(wot.get_non_sentries(2).len(), 11); assert_eq!(wot.get_non_sentries(3).len(), 12); assert_eq!(path_finder.find_paths(&wot, WotId(3), WotId(0), 1).len(), 0); assert_eq!(path_finder.find_paths(&wot, WotId(3), WotId(0), 2).len(), 1); assert!(path_finder
373 .find_paths(&wot, WotId(3), WotId(0), 2)
374 .contains(&vec![WotId(3), WotId(2), WotId(0)]));
375
376 assert_eq!(
377 distance_calculator.is_outdistanced(
378 &wot,
379 WotDistanceParameters {
380 node: WotId(0),
381 sentry_requirement: 1,
382 step_max: 1,
383 x_percent: 1.0,
384 },
385 ),
386 Ok(true)
387 ); assert_eq!(
401 distance_calculator.is_outdistanced(
402 &wot,
403 WotDistanceParameters {
404 node: WotId(0),
405 sentry_requirement: 3,
406 step_max: 1,
407 x_percent: 1.0,
408 },
409 ),
410 Ok(false)
411 ); assert_eq!(
413 distance_calculator.is_outdistanced(
414 &wot,
415 WotDistanceParameters {
416 node: WotId(0),
417 sentry_requirement: 2,
418 step_max: 2,
419 x_percent: 1.0,
420 },
421 ),
422 Ok(false)
423 ); assert_eq!(wot.size(), 12);
427
428 assert_eq!(wot.rem_node(), Some(WotId(11)));
430
431 assert_eq!(wot.size(), 11);
433
434 assert_eq!(wot.set_enabled(WotId(3), false), Some(false));
437 assert_eq!(wot.get_disabled().len(), 1);
438 assert_eq!(
439 distance_calculator.is_outdistanced(
440 &wot,
441 WotDistanceParameters {
442 node: WotId(0),
443 sentry_requirement: 2,
444 step_max: 1,
445 x_percent: 1.0,
446 },
447 ),
448 Ok(false)
449 ); write_bin_file(
453 Path::new("test.wot"),
454 &bincode::serialize(&wot).expect("fail to serialize wot"),
455 )
456 .expect("fail to write wot file");
457
458 let wot2_bin = read_bin_file(Path::new("test.wot")).expect("fail to read wot file");
459 let wot2: W = bincode::deserialize(&wot2_bin).expect("fail to deserialize wot");
460
461 {
463 assert_eq!(wot.size(), wot2.size());
464 assert_eq!(
465 wot.get_non_sentries(1).len(),
466 wot2.get_non_sentries(1).len()
467 );
468 assert_eq!(wot.get_disabled().len(), wot2.get_disabled().len());
469 assert_eq!(wot2.get_disabled().len(), 1);
470 assert_eq!(wot2.is_enabled(WotId(3)), Some(false));
471 assert_eq!(
472 distance_calculator.is_outdistanced(
473 &wot2,
474 WotDistanceParameters {
475 node: WotId(0),
476 sentry_requirement: 2,
477 step_max: 1,
478 x_percent: 1.0,
479 },
480 ),
481 Ok(false)
482 );
483 }
484
485 let mut dump_wot2_chars = Vec::new();
487 wot2.dump(&mut dump_wot2_chars).expect("fail to dump wot2");
488 let dump_wot2_str = String::from_utf8(dump_wot2_chars).expect("invalid utf8 chars");
489 assert_eq!(
490 dump_wot2_str,
491 "max_links=4
492nodes_count=11
493000: [2, 5]
494001: [3]
495002: [3]
496003: disabled [1, 2]
497004: []
498005: []
499006: []
500007: []
501008: []
502009: []
503010: []
504"
505 );
506
507 let wot3_bin = read_bin_file(Path::new("tests/g1_genesis.bin"))
509 .expect("fail to read g1_genesis wot file");
510 let wot3: W = bincode::deserialize(&wot3_bin).expect("fail to deserialize g1_genesis wot");
511
512 let members_count = wot3.get_enabled().len() as u64;
514 assert_eq!(members_count, 59);
515
516 assert_eq!(
518 distance_calculator.compute_distance(
519 &wot3,
520 WotDistanceParameters {
521 node: WotId(37),
522 sentry_requirement: 3,
523 step_max: 5,
524 x_percent: 0.8,
525 },
526 ),
527 Ok(WotDistance {
528 sentries: 48,
529 success: 48,
530 success_at_border: 3,
531 reached: 51,
532 reached_at_border: 3,
533 outdistanced: false,
534 },)
535 );
536
537 let centralities = centralities_calculator.betweenness_centralities(&wot3);
539 assert_eq!(centralities.len(), 59);
540 assert_eq!(
541 centralities,
542 vec![
543 148, 30, 184, 11, 60, 51, 40, 115, 24, 140, 47, 69, 16, 34, 94, 126, 151, 0, 34,
544 133, 20, 103, 38, 144, 73, 523, 124, 23, 47, 17, 9, 64, 77, 281, 6, 105, 54, 0,
545 111, 21, 6, 2, 0, 1, 47, 59, 28, 236, 0, 0, 0, 0, 60, 6, 0, 1, 8, 33, 169,
546 ]
547 );
548
549 let stress_centralities = centralities_calculator.stress_centralities(&wot3);
551 assert_eq!(stress_centralities.len(), 59);
552 assert_eq!(
553 stress_centralities,
554 vec![
555 848, 240, 955, 80, 416, 203, 290, 645, 166, 908, 313, 231, 101, 202, 487, 769, 984,
556 0, 154, 534, 105, 697, 260, 700, 496, 1726, 711, 160, 217, 192, 89, 430, 636, 1276,
557 41, 420, 310, 0, 357, 125, 50, 15, 0, 12, 275, 170, 215, 1199, 0, 0, 0, 0, 201, 31,
558 0, 9, 55, 216, 865,
559 ]
560 );
561
562 let distance_stress_centralities =
564 centralities_calculator.distance_stress_centralities(&wot3, 5);
565 assert_eq!(distance_stress_centralities.len(), 59);
566 assert_eq!(
567 distance_stress_centralities,
568 vec![
569 848, 240, 955, 80, 416, 203, 290, 645, 166, 908, 313, 231, 101, 202, 487, 769, 984,
570 0, 154, 534, 105, 697, 260, 700, 496, 1726, 711, 160, 217, 192, 89, 430, 636, 1276,
571 41, 420, 310, 0, 357, 125, 50, 15, 0, 12, 275, 170, 215, 1199, 0, 0, 0, 0, 201, 31,
572 0, 9, 55, 216, 865,
573 ]
574 );
575 }
576}