Skip to content
Snippets Groups Projects
Commit 8d1ca53a authored by nanocryk's avatar nanocryk
Browse files

Merge branch '28-implement-web-of-trust-in-a-more-rusty-way' into 'dev'

Resolve "Implement Web of Trust in a more "rusty" way"

Closes #28

See merge request !20
parents 914e71a3 77592f49
Branches
Tags wotb/v0.6.1
1 merge request!20Resolve "Implement Web of Trust in a more "rusty" way"
......@@ -3,3 +3,4 @@
**/*.rs.bk
*.wot
*.bin
......@@ -6,6 +6,14 @@ dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayvec"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base58"
version = "0.1.0"
......@@ -39,6 +47,42 @@ name = "byteorder"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crossbeam-deque"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-epoch"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-utils"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "duniter-crypto"
version = "0.1.0"
......@@ -63,14 +107,20 @@ dependencies = [
[[package]]
name = "duniter-wotb"
version = "0.6.0"
version = "0.6.1"
dependencies = [
"bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "either"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
......@@ -90,6 +140,11 @@ name = "gcc"
version = "0.3.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.0.0"
......@@ -113,6 +168,24 @@ dependencies = [
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memoffset"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nodrop"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.3.15"
......@@ -127,6 +200,27 @@ dependencies = [
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon-core"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.37"
......@@ -171,6 +265,11 @@ name = "safemem"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.27"
......@@ -276,26 +375,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
"checksum base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4a342b450b268e1be8036311e2c613d7f8a7ed31214dff1cc3b60852a3168d"
"checksum bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9a6301db0b49fb63551bc15b5ae348147101cdf323242b93ec7546d5002ff1af"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59796cc6cbbdc6bb319161349db0c3250ec73ec7fcb763a51065ec4e2e158552"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "96264e9b293e95d25bfcbbf8a88ffd1aedc85b754eba8b7d78012f638ba220eb"
"checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
"checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d"
"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0"
"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5"
......
[package]
name = "duniter-wotb"
version = "0.6.0"
version = "0.6.1"
authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@duniter.org>"]
description = "Makes Web of Trust computations for the Duniter project."
repository = "https://git.duniter.org/nodes/rust/duniter-rs"
......@@ -16,3 +16,4 @@ serde = "1.0.24"
serde_derive = "1.0.24"
bincode = "0.9.2"
byteorder = "1.2.1"
rayon = "1.0.0"
......@@ -32,11 +32,14 @@
extern crate bincode;
extern crate byteorder;
extern crate rayon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
pub mod legacy;
pub mod rusty;
pub use legacy::LegacyWebOfTrust;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
......@@ -167,7 +170,7 @@ pub trait WebOfTrust {
fn add_node(&mut self) -> NodeId;
/// Remove the last node.
/// Returns `None` if the WoT was empty.
/// Returns `None` if the WoT was empty, otherwise new top node id.
fn rem_node(&mut self) -> Option<NodeId>;
/// Get the size of the WoT.
......@@ -177,7 +180,7 @@ pub trait WebOfTrust {
/// Returns `None` if this node doesn't exist.
fn is_enabled(&self, id: NodeId) -> Option<bool>;
/// Set if given node is enabled.
/// Set the enabled state of given node.
/// Returns `Null` if this node doesn't exist, `enabled` otherwise.
fn set_enabled(&mut self, id: NodeId, enabled: bool) -> Option<bool>;
......@@ -282,7 +285,6 @@ pub trait WebOfTrust {
let mut buffer_3b: Vec<u8> = Vec::with_capacity(3);
let mut count_bytes = 0;
let mut remaining_links: u8 = 0;
let mut source: u32 = 0;
let mut target: u32 = 0;
for byte in file_pointing_to_links {
if remaining_links == 0 {
......@@ -293,7 +295,7 @@ pub trait WebOfTrust {
buffer_3b.push(byte);
if count_bytes % 3 == 2 {
let mut buf = &buffer_3b.clone()[..];
source = buf.read_u24::<BigEndian>().expect("fail to parse source");
let source = buf.read_u24::<BigEndian>().expect("fail to parse source");
self.add_link(NodeId(source as usize), NodeId((target - 1) as usize));
remaining_links -= 1;
buffer_3b.clear();
......@@ -351,20 +353,17 @@ pub trait WebOfTrust {
}
// Write links
for n in 0..nodes_count {
match self.get_links_source(NodeId(n as usize)) {
Some(sources) => {
if let Some(sources) = self.get_links_source(NodeId(n as usize)) {
// Write sources_counts
let mut bytes = Vec::with_capacity(1);
bytes.write_u8(sources.len() as u8).unwrap();
buffer.append(&mut bytes);
for source in sources.iter() {
for source in sources {
// Write source
let mut bytes: Vec<u8> = Vec::with_capacity(3);
bytes.write_u24::<BigEndian>(source.0 as u32).unwrap();
buffer.append(&mut bytes);
}
}
None => {}
};
}
// Create or open file
......@@ -629,7 +628,12 @@ mod tests {
assert_eq!(wot.get_non_sentries(3).len(), 12); // 12 - 0
assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 1).len(), 0); // KO
assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2).len(), 1); // It exists 3 -> 2 -> 0
assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2)[0].len(), 3); // It exists 3 -> 2 -> 0
assert!(wot.get_paths(NodeId(3), NodeId(0), 2).contains(&vec![
NodeId(3),
NodeId(2),
NodeId(0),
]));
assert_eq!(
wot.is_outdistanced(WotDistanceParameters {
node: NodeId(0),
......@@ -684,7 +688,12 @@ mod tests {
assert_eq!(wot.get_non_sentries(3).len(), 12); // 12 - 0
assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 1).len(), 0); // KO
assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2).len(), 1); // It exists 3 -> 2 -> 0
assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2)[0].len(), 3); // It exists 3 -> 2 -> 0
assert!(wot.get_paths(NodeId(3), NodeId(0), 2).contains(&vec![
NodeId(3),
NodeId(2),
NodeId(0),
]));
assert_eq!(
wot.is_outdistanced(WotDistanceParameters {
node: NodeId(0),
......
// Copyright (C) 2017-2018 The Duniter Project Developers.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Experimental implementation of the Web of Trust in a more "rusty" style.
use std::collections::HashSet;
use rayon::prelude::*;
use WebOfTrust;
use WotDistance;
use WotDistanceParameters;
use HasLinkResult;
use RemLinkResult;
use NewLinkResult;
use NodeId;
/// A node in the *WoT* graph.
#[derive(Debug, Clone, PartialEq, Eq)]
struct Node {
/// Is this node enabled ?
enabled: bool,
/// Set of links this node is the target.
links_source: HashSet<NodeId>,
/// Number of links the node issued.
issued_count: usize,
}
impl Node {
/// Create a new node.
pub fn new() -> Node {
Node {
enabled: true,
links_source: HashSet::new(),
issued_count: 0,
}
}
}
/// A more idiomatic implementation of a Web of Trust.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RustyWebOfTrust {
/// List of nodes in the WoT.
nodes: Vec<Node>,
/// Maximum number of links a node can issue.
max_links: usize,
}
impl RustyWebOfTrust {
/// Create a new Web of Trust with the maximum of links a node can issue.
pub fn new(max_links: usize) -> RustyWebOfTrust {
RustyWebOfTrust {
nodes: vec![],
max_links,
}
}
/// Test if a node is a sentry.
pub fn is_sentry(&self, node: NodeId, sentry_requirement: usize) -> Option<bool> {
if node.0 >= self.size() {
return None;
}
let node = &self.nodes[node.0];
Some(
node.enabled && node.issued_count >= sentry_requirement
&& node.links_source.len() >= sentry_requirement,
)
}
}
impl WebOfTrust for RustyWebOfTrust {
fn get_max_link(&self) -> usize {
self.max_links
}
fn set_max_link(&mut self, max_links: usize) {
self.max_links = max_links;
}
fn add_node(&mut self) -> NodeId {
self.nodes.push(Node::new());
NodeId(self.nodes.len() - 1)
}
fn rem_node(&mut self) -> Option<NodeId> {
self.nodes.pop();
if !self.nodes.is_empty() {
Some(NodeId(self.nodes.len() - 1))
} else {
None
}
}
fn size(&self) -> usize {
self.nodes.len()
}
fn is_enabled(&self, id: NodeId) -> Option<bool> {
self.nodes.get(id.0).map(|n| n.enabled)
}
fn set_enabled(&mut self, id: NodeId, enabled: bool) -> Option<bool> {
self.nodes
.get_mut(id.0)
.map(|n| n.enabled = enabled)
.map(|_| enabled)
}
fn get_enabled(&self) -> Vec<NodeId> {
self.nodes
.par_iter()
.enumerate()
.filter(|&(_, n)| n.enabled)
.map(|(i, _)| NodeId(i))
.collect()
}
fn get_disabled(&self) -> Vec<NodeId> {
self.nodes
.par_iter()
.enumerate()
.filter(|&(_, n)| !n.enabled)
.map(|(i, _)| NodeId(i))
.collect()
}
fn add_link(&mut self, source: NodeId, target: NodeId) -> NewLinkResult {
if source == target {
NewLinkResult::SelfLinkingForbidden()
} else if source.0 >= self.size() {
NewLinkResult::UnknownSource()
} else if target.0 >= self.size() {
NewLinkResult::UnknownTarget()
} else if self.nodes[source.0].issued_count >= self.max_links {
NewLinkResult::AllCertificationsUsed(self.nodes[target.0].links_source.len())
} else if self.nodes[target.0].links_source.contains(&source) {
NewLinkResult::AlreadyCertified(self.nodes[target.0].links_source.len())
} else {
self.nodes[source.0].issued_count += 1;
self.nodes[target.0].links_source.insert(source);
NewLinkResult::Ok(self.nodes[target.0].links_source.len())
}
}
fn rem_link(&mut self, source: NodeId, target: NodeId) -> RemLinkResult {
if source.0 >= self.size() {
RemLinkResult::UnknownSource()
} else if target.0 >= self.size() {
RemLinkResult::UnknownTarget()
} else if !self.nodes[target.0].links_source.contains(&source) {
RemLinkResult::UnknownCert(self.nodes[target.0].links_source.len())
} else {
self.nodes[source.0].issued_count -= 1;
self.nodes[target.0].links_source.remove(&source);
RemLinkResult::Removed(self.nodes[target.0].links_source.len())
}
}
fn has_link(&self, source: NodeId, target: NodeId) -> HasLinkResult {
if source.0 >= self.size() {
HasLinkResult::UnknownSource()
} else if target.0 >= self.size() {
HasLinkResult::UnknownTarget()
} else {
HasLinkResult::Link(self.nodes[target.0].links_source.contains(&source))
}
}
fn get_links_source(&self, target: NodeId) -> Option<Vec<NodeId>> {
self.nodes
.get(target.0)
.map(|n| n.links_source.iter().cloned().collect())
}
fn issued_count(&self, id: NodeId) -> Option<usize> {
self.nodes.get(id.0).map(|n| n.issued_count)
}
fn get_sentries(&self, sentry_requirement: usize) -> Vec<NodeId> {
self.nodes
.par_iter()
.enumerate()
.filter(|&(_, n)| {
n.enabled && n.issued_count >= sentry_requirement
&& n.links_source.len() >= sentry_requirement
})
.map(|(i, _)| NodeId(i))
.collect()
}
fn get_non_sentries(&self, sentry_requirement: usize) -> Vec<NodeId> {
self.nodes
.par_iter()
.enumerate()
.filter(|&(_, n)| {
n.enabled
&& (n.issued_count < sentry_requirement
|| n.links_source.len() < sentry_requirement)
})
.map(|(i, _)| NodeId(i))
.collect()
}
fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
if from == to {
vec![vec![to]]
} else if k_max > 0 {
self.nodes[to.0]
.links_source
.par_iter()
.map(|&source| self.get_paths(from, source, k_max - 1))
.map(|paths| {
paths
.iter()
.map(|path| {
let mut path = path.clone();
path.push(to);
path
})
.collect::<Vec<Vec<NodeId>>>()
})
.reduce(
|| vec![],
|mut acc, mut paths| {
acc.append(&mut paths);
acc
},
)
} else {
vec![]
}
}
fn compute_distance(&self, params: WotDistanceParameters) -> Option<WotDistance> {
let WotDistanceParameters {
node,
sentry_requirement,
step_max,
x_percent,
} = params;
if node.0 >= self.size() {
return None;
}
let mut area = HashSet::new();
area.insert(node);
let mut border = HashSet::new();
border.insert(node);
for _ in 0..step_max {
border = border
.par_iter()
.map(|&id| {
self.nodes[id.0]
.links_source
.iter()
.filter(|source| !area.contains(source))
.cloned()
.collect::<HashSet<_>>()
})
.reduce(HashSet::new, |mut acc, sources| {
for source in sources {
acc.insert(source);
}
acc
});
area.extend(border.iter());
}
let sentries: Vec<_> = self.get_sentries(sentry_requirement as usize);
let success = area.iter().filter(|n| sentries.contains(n)).count() as u32;
let sentries = sentries.len() as u32
- if self.is_sentry(node, sentry_requirement as usize).unwrap() {
1
} else {
0
};
Some(WotDistance {
sentries,
reached: (area.len() - 1) as u32,
success,
outdistanced: f64::from(success) < x_percent * f64::from(sentries),
})
}
fn is_outdistanced(&self, params: WotDistanceParameters) -> Option<bool> {
self.compute_distance(params)
.map(|result| result.outdistanced)
}
}
#[cfg(test)]
mod tests {
use super::*;
use tests::generic_wot_test;
#[test]
fn wot_tests() {
let mut wot1 = RustyWebOfTrust::new(3);
let mut wot2 = RustyWebOfTrust::new(3);
generic_wot_test(&mut wot1, &mut wot2);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment