mod authority;
mod error;
mod network_tests;
mod prefix;
mod xorable;
use itertools::Itertools;
pub use self::authority::Authority;
pub use self::error::Error;
#[cfg(any(test, feature = "use-mock-crust"))]
pub use self::network_tests::verify_network_invariant;
pub use self::prefix::Prefix;
pub use self::xorable::Xorable;
use std::{iter, mem};
use std::cmp::Ordering;
use std::collections::{BTreeSet, HashMap, HashSet, hash_map, hash_set};
use std::fmt::{Binary, Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::hash::Hash;
pub type Sections<T> = HashMap<Prefix<T>, HashSet<T>>;
type MemberIter<'a, T> = hash_set::Iter<'a, T>;
type SectionIter<'a, T> = hash_map::Values<'a, Prefix<T>, HashSet<T>>;
type OtherSectionsIter<'a, T> = iter::FlatMap<SectionIter<'a, T>,
MemberIter<'a, T>,
FlatMapFn<'a, T>>;
type FlatMapFn<'a, T> = fn(&'a HashSet<T>) -> MemberIter<'a, T>;
const SPLIT_BUFFER: usize = 1;
pub struct Iter<'a, T: 'a + Binary + Clone + Copy + Default + Hash + Xorable> {
inner: iter::Chain<OtherSectionsIter<'a, T>, hash_set::Iter<'a, T>>,
our_name: T,
}
impl<'a, T: 'a + Binary + Clone + Copy + Default + Hash + Xorable> Iterator for Iter<'a, T> {
type Item = &'a T;
#[cfg_attr(feature="cargo-clippy", allow(while_let_on_iterator))]
fn next(&mut self) -> Option<&'a T> {
while let Some(name) = self.inner.next() {
if *name != self.our_name {
return Some(name);
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct OwnMergeDetails<T: Binary + Clone + Copy + Default + Hash + Xorable> {
pub sender_prefix: Prefix<T>,
pub merge_prefix: Prefix<T>,
pub sections: Sections<T>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct OtherMergeDetails<T: Binary + Clone + Copy + Default + Hash + Xorable> {
pub prefix: Prefix<T>,
pub section: HashSet<T>,
}
#[derive(Debug)]
pub struct RemovalDetails<T: Binary + Clone + Copy + Default + Hash + Xorable> {
pub name: T,
pub was_in_our_section: bool,
}
pub enum OwnMergeState<T: Binary + Clone + Copy + Default + Hash + Xorable> {
Ongoing,
Completed {
targets: BTreeSet<Prefix<T>>,
merge_details: OtherMergeDetails<T>,
},
AlreadyMerged,
}
#[derive(Clone, Eq, PartialEq)]
pub struct RoutingTable<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> {
min_section_size: usize,
our_name: T,
our_prefix: Prefix<T>,
our_section: HashSet<T>,
sections: Sections<T>,
we_want_to_merge: bool,
they_want_to_merge: bool,
}
impl<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> RoutingTable<T> {
pub fn new(our_name: T, min_section_size: usize) -> Self {
let mut our_section = HashSet::new();
our_section.insert(our_name);
RoutingTable {
our_name: our_name,
min_section_size: min_section_size,
our_section: our_section,
our_prefix: Default::default(),
sections: HashMap::new(),
we_want_to_merge: false,
they_want_to_merge: false,
}
}
pub fn add_prefixes(&mut self, prefixes: Vec<Prefix<T>>) -> Result<(), Error> {
for prefix in prefixes {
if prefix.matches(&self.our_name) {
self.our_prefix = prefix;
} else {
let _ = self.sections.entry(prefix).or_insert_with(HashSet::new);
}
}
let our_section = mem::replace(&mut self.our_section, HashSet::new());
for name in our_section {
if let Some(section) = self.get_section_mut(&name) {
let _ = section.insert(name);
} else {
return Err(Error::InvariantViolation);
}
}
self.check_invariant(true)
}
pub fn our_prefix(&self) -> &Prefix<T> {
&self.our_prefix
}
pub fn our_section(&self) -> &HashSet<T> {
&self.our_section
}
pub fn all_sections(&self) -> Sections<T> {
let mut result = self.sections.clone();
let _ = result.insert(self.our_prefix, self.our_section.clone());
result
}
pub fn section_with_prefix(&self, prefix: &Prefix<T>) -> Option<&HashSet<T>> {
if *prefix == self.our_prefix {
Some(&self.our_section)
} else {
self.sections.get(prefix)
}
}
pub fn len(&self) -> usize {
self.sections.values().fold(0, |acc, section| acc + section.len()) +
self.our_section.len() - 1
}
pub fn is_empty(&self) -> bool {
self.our_section.len() == 1 && self.sections.values().all(HashSet::is_empty)
}
pub fn min_section_size(&self) -> usize {
self.min_section_size
}
pub fn min_split_size(&self) -> usize {
self.min_section_size + SPLIT_BUFFER
}
pub fn has(&self, name: &T) -> bool {
self.get_section(name).map_or(false, |section| section.contains(name))
}
pub fn iter(&self) -> Iter<T> {
let iter: fn(_) -> _ = HashSet::iter;
Iter {
inner: self.sections.values().flat_map(iter).chain(self.our_section.iter()),
our_name: self.our_name,
}
}
pub fn other_prefixes(&self) -> BTreeSet<Prefix<T>> {
self.sections.keys().cloned().collect()
}
pub fn prefixes(&self) -> BTreeSet<Prefix<T>> {
self.sections.keys().cloned().chain(iter::once(self.our_prefix)).collect()
}
pub fn close_names(&self, name: &T) -> Option<HashSet<T>> {
if self.our_prefix.matches(name) {
Some(self.our_section().clone())
} else {
None
}
}
pub fn other_close_names(&self, name: &T) -> Option<HashSet<T>> {
if self.our_prefix.matches(name) {
let mut section = self.our_section.clone();
section.remove(&self.our_name);
Some(section)
} else {
None
}
}
pub fn is_closest(&self, name: &T, count: usize) -> bool {
self.closest_names(name, count).is_some()
}
fn closest_known_names(&self, name: &T, count: usize) -> Vec<&T> {
self.sections
.iter()
.chain(iter::once((&self.our_prefix, &self.our_section)))
.sorted_by(|&(pfx0, _), &(pfx1, _)| pfx0.cmp_distance(pfx1, name))
.into_iter()
.flat_map(|(_, section)| {
section.iter().sorted_by(|name0, name1| name.cmp_distance(name0, name1))
})
.take(count)
.collect_vec()
}
pub fn closest_names(&self, name: &T, count: usize) -> Option<Vec<&T>> {
let result = self.closest_known_names(name, count);
if result.contains(&&self.our_name) {
Some(result)
} else {
None
}
}
pub fn other_closest_names(&self, name: &T, count: usize) -> Option<Vec<&T>> {
self.closest_names(name, count).map(|mut result| {
result.retain(|name| *name != &self.our_name);
result
})
}
pub fn is_in_our_section(&self, name: &T) -> bool {
self.our_section.contains(name)
}
pub fn need_to_add(&self, name: &T) -> Result<(), Error> {
if *name == self.our_name {
return Err(Error::OwnNameDisallowed);
}
if let Some(section) = self.get_section(name) {
if section.contains(name) {
Err(Error::AlreadyExists)
} else {
Ok(())
}
} else {
Err(Error::PeerNameUnsuitable)
}
}
pub fn should_join_our_section(&self, name: &T) -> Result<(), Error> {
if !self.our_prefix.matches(name) {
return Err(Error::PeerNameUnsuitable);
}
if self.our_section.contains(name) {
return Err(Error::AlreadyExists);
}
Ok(())
}
pub fn validate_joining_node(&self, name: &T) -> Result<(), Error> {
if !self.our_prefix.matches(name) {
return Err(Error::PeerNameUnsuitable);
}
if self.our_section.contains(name) {
return Err(Error::AlreadyExists);
}
Ok(())
}
pub fn add(&mut self, name: T) -> Result<bool, Error> {
if name == self.our_name {
return Err(Error::OwnNameDisallowed);
}
if let Some(section) = self.get_section_mut(&name) {
if !section.insert(name) {
return Err(Error::AlreadyExists);
}
} else {
return Err(Error::PeerNameUnsuitable);
}
let split_size = self.min_split_size();
let close_to_merging_with_us = |(prefix, section): (&Prefix<T>, &HashSet<T>)| {
prefix.popped().is_compatible(&self.our_prefix) && section.len() < split_size
};
if self.we_want_to_merge || self.they_want_to_merge ||
self.sections.iter().any(close_to_merging_with_us) {
return Ok(false);
}
let new_size = self.our_section
.iter()
.filter(|name| self.our_name.common_prefix(name) > self.our_prefix.bit_count())
.count();
Ok(new_size >= split_size && self.our_section().len() >= split_size + new_size)
}
pub fn split(&mut self, prefix: Prefix<T>) -> (Vec<T>, Option<Prefix<T>>) {
let mut result = vec![];
if prefix == self.our_prefix {
result = self.split_our_section();
return (result, Some(self.our_prefix));
}
if let Some(to_split) = self.sections.remove(&prefix) {
let prefix0 = prefix.pushed(false);
let prefix1 = prefix.pushed(true);
let (section0, section1) = to_split.into_iter()
.partition::<HashSet<_>, _>(|name| prefix0.matches(name));
if self.our_prefix.is_neighbour(&prefix0) {
let _ = self.sections.insert(prefix0, section0);
} else {
result.extend(section0);
}
if self.our_prefix.is_neighbour(&prefix1) {
let _ = self.sections.insert(prefix1, section1);
} else {
result.extend(section1);
}
}
(result, None)
}
pub fn add_prefix(&mut self, prefix: Prefix<T>) -> Vec<T> {
let mut result = vec![];
if self.our_prefix == prefix || self.sections.contains_key(&prefix) {
return result; }
while let Some(&shorter_pfx) =
self.sections
.keys()
.chain(iter::once(&self.our_prefix))
.find(|p| p.is_compatible(&prefix) && p.bit_count() < prefix.bit_count()) {
let (dropped_nodes, _opt_our_pfx) = self.split(shorter_pfx);
result.extend(dropped_nodes);
}
let mut our_prefix = self.our_prefix;
while !our_prefix.is_neighbour(&prefix) && !our_prefix.is_compatible(&prefix) {
our_prefix = our_prefix.popped();
}
self.merge(&our_prefix);
self.merge(&prefix);
let mut missing_pfxs = (0..self.our_prefix.bit_count())
.map(|i| self.our_prefix.with_flipped_bit(i))
.collect_vec();
while let Some(pfx) = missing_pfxs.pop() {
if !pfx.is_covered_by(self.sections.keys()) {
if self.sections.keys().any(|p| pfx.is_compatible(p)) {
missing_pfxs.push(pfx.pushed(true));
missing_pfxs.push(pfx.pushed(false));
} else {
let _ = self.sections.insert(pfx, HashSet::new());
}
}
}
result
}
pub fn remove(&mut self, name: &T) -> Result<RemovalDetails<T>, Error> {
let removal_details = RemovalDetails {
name: *name,
was_in_our_section: self.our_prefix.matches(name),
};
if removal_details.was_in_our_section {
if self.our_name == *name {
return Err(Error::OwnNameDisallowed);
}
if !self.our_section.remove(name) {
return Err(Error::NoSuchPeer);
}
} else if let Some(prefix) = self.find_section_prefix(name) {
if let Some(section) = self.sections.get_mut(&prefix) {
if !section.remove(name) {
return Err(Error::NoSuchPeer);
}
}
} else {
return Err(Error::NoSuchPeer);
}
Ok(removal_details)
}
pub fn should_merge(&self) -> Option<OwnMergeDetails<T>> {
let bit_count = self.our_prefix.bit_count();
let doesnt_need_to_merge_with_us = |(prefix, section): (&Prefix<T>, &HashSet<T>)| {
!prefix.popped().is_compatible(&self.our_prefix) ||
section.len() >= self.min_section_size
};
if bit_count == 0 || self.we_want_to_merge ||
!self.sections.contains_key(&self.our_prefix.with_flipped_bit(bit_count - 1)) ||
(self.our_section.len() >= self.min_section_size &&
self.sections.iter().all(doesnt_need_to_merge_with_us)) {
return None;
}
let merge_prefix = self.our_prefix.popped();
let mut sections = self.sections.clone();
let _ = sections.insert(self.our_prefix, self.our_section().clone());
Some(OwnMergeDetails {
sender_prefix: self.our_prefix,
merge_prefix: merge_prefix,
sections: sections,
})
}
pub fn merge_own_section(&mut self, merge_details: OwnMergeDetails<T>) -> OwnMergeState<T> {
if !self.our_prefix.is_compatible(&merge_details.merge_prefix) ||
self.our_prefix.bit_count() != merge_details.merge_prefix.bit_count() + 1 {
debug!("{:?}: Attempt to call merge_own_section() for an already merged prefix {:?}",
self.our_name,
merge_details.merge_prefix);
return OwnMergeState::AlreadyMerged;
}
for prefix in merge_details.sections.keys() {
let compatible_with_ours = self.our_prefix.is_compatible(prefix);
if merge_details.merge_prefix.is_compatible(prefix) &&
!self.sections.contains_key(prefix) && !compatible_with_ours {
self.merge(prefix);
}
if !compatible_with_ours {
let _ = self.sections.entry(*prefix).or_insert_with(HashSet::new);
}
}
if merge_details.sender_prefix == self.our_prefix {
self.we_want_to_merge = true;
} else {
self.they_want_to_merge = true;
}
if self.we_want_to_merge && self.they_want_to_merge {
self.finish_merging_own_section(merge_details)
} else {
OwnMergeState::Ongoing
}
}
pub fn merge_other_section(&mut self, merge_details: OtherMergeDetails<T>) -> HashSet<T> {
if self.our_prefix.is_compatible(&merge_details.prefix) {
return HashSet::new();
}
self.merge(&merge_details.prefix);
merge_details.section
.difference(unwrap!(self.sections.get(&merge_details.prefix)))
.cloned()
.collect::<HashSet<_>>()
}
pub fn targets(&self,
dst: &Authority<T>,
exclude: T,
route: usize)
-> Result<HashSet<T>, Error> {
let candidates = |target_name: &T| {
self.closest_known_names(target_name, self.min_section_size)
.into_iter()
.filter(|name| **name != self.our_name)
.cloned()
.collect::<HashSet<T>>()
};
let closest_section = match *dst {
Authority::ManagedNode(ref target_name) |
Authority::Client { proxy_node_name: ref target_name, .. } => {
if *target_name == self.our_name {
return Ok(HashSet::new());
}
if self.has(target_name) {
return Ok(iter::once(*target_name).collect());
}
candidates(target_name)
}
Authority::ClientManager(ref target_name) |
Authority::NaeManager(ref target_name) |
Authority::NodeManager(ref target_name) => {
if let Some(group) = self.other_closest_names(target_name, self.min_section_size) {
return Ok(group.into_iter().cloned().collect());
}
candidates(target_name)
}
Authority::Section(ref target_name) => {
let (prefix, section) = self.closest_section(target_name);
if *prefix == self.our_prefix {
let mut section = section.clone();
section.remove(&self.our_name);
return Ok(section);
}
candidates(target_name)
}
Authority::PrefixSection(ref prefix) => {
if prefix.is_compatible(&self.our_prefix) {
if prefix.is_covered_by(self.prefixes().iter()) {
return Ok(self.iter()
.filter(|name| prefix.matches(name) && **name != self.our_name)
.cloned()
.collect());
} else {
return Err(Error::CannotRoute);
}
}
candidates(&prefix.lower_bound())
}
};
Ok(iter::once(self.get_routeth_node(&closest_section, dst.name(), Some(exclude), route)?)
.collect())
}
pub fn in_authority(&self, auth: &Authority<T>) -> bool {
match *auth {
Authority::Client { .. } => false,
Authority::ManagedNode(ref name) => self.our_name == *name,
Authority::ClientManager(ref name) |
Authority::NaeManager(ref name) |
Authority::NodeManager(ref name) => self.is_closest(name, self.min_section_size),
Authority::Section(ref name) => self.our_prefix.matches(name),
Authority::PrefixSection(ref prefix) => prefix.matches(&self.our_name),
}
}
pub fn get_section(&self, name: &T) -> Option<&HashSet<T>> {
if self.our_prefix.matches(name) {
return Some(&self.our_section);
}
if let Some(prefix) = self.find_section_prefix(name) {
return self.sections.get(&prefix);
}
None
}
pub fn our_name(&self) -> &T {
&self.our_name
}
fn split_our_section(&mut self) -> Vec<T> {
let next_bit = self.our_name.bit(self.our_prefix.bit_count());
let other_prefix = self.our_prefix.pushed(!next_bit);
self.our_prefix = self.our_prefix.pushed(next_bit);
let (our_new_section, other_section) = self.our_section
.iter()
.partition::<HashSet<_>, _>(|name| self.our_prefix.matches(name));
self.our_section = our_new_section;
let sections_to_remove = self.sections
.keys()
.filter(|prefix| !prefix.is_neighbour(&self.our_prefix))
.cloned()
.collect_vec();
let _ = self.sections.insert(other_prefix, other_section);
sections_to_remove.into_iter()
.filter_map(|prefix| self.sections.remove(&prefix))
.flat_map(HashSet::into_iter)
.collect()
}
fn finish_merging_own_section(&mut self,
merge_details: OwnMergeDetails<T>)
-> OwnMergeState<T> {
self.we_want_to_merge = false;
self.they_want_to_merge = false;
self.merge(&merge_details.merge_prefix);
let targets = self.sections.keys().cloned().collect();
let other_details = OtherMergeDetails {
prefix: merge_details.merge_prefix,
section: self.our_section().clone(),
};
OwnMergeState::Completed {
targets: targets,
merge_details: other_details,
}
}
fn merge(&mut self, new_prefix: &Prefix<T>) {
let original_sections = mem::replace(&mut self.sections, Sections::new());
let (sections_to_merge, mut sections) = original_sections.into_iter()
.partition::<HashMap<_, _>, _>(|&(prefix, _)| new_prefix.is_compatible(&prefix));
let merged_names = sections_to_merge.into_iter().flat_map(|(_, names)| names).collect();
if self.our_prefix.is_compatible(new_prefix) {
self.our_section.extend(merged_names);
self.our_prefix = *new_prefix;
} else {
let _ = sections.insert(*new_prefix, merged_names);
}
self.sections = sections;
}
fn get_section_mut(&mut self, name: &T) -> Option<&mut HashSet<T>> {
if self.our_prefix.matches(name) {
return Some(&mut self.our_section);
}
if let Some(prefix) = self.find_section_prefix(name) {
return self.sections.get_mut(&prefix);
}
None
}
pub fn find_section_prefix(&self, name: &T) -> Option<Prefix<T>> {
if self.our_prefix.matches(name) {
return Some(self.our_prefix);
}
self.sections.keys().find(|&prefix| prefix.matches(name)).cloned()
}
fn closest_section(&self, name: &T) -> (&Prefix<T>, &HashSet<T>) {
let mut result = (&self.our_prefix, &self.our_section);
for (prefix, section) in &self.sections {
if !section.is_empty() && result.0.cmp_distance(prefix, name) == Ordering::Greater {
result = (prefix, section)
}
}
result
}
fn get_routeth_name<'a, U: IntoIterator<Item = &'a T>>(names: U,
dst_name: &T,
route: usize)
-> &'a T {
let sorted_names = names.into_iter()
.sorted_by(|&lhs, &rhs| dst_name.cmp_distance(lhs, rhs));
sorted_names[route % sorted_names.len()]
}
fn get_routeth_node(&self,
section: &HashSet<T>,
target: T,
exclude: Option<T>,
route: usize)
-> Result<T, Error> {
let names = if let Some(exclude) = exclude {
section.iter().filter(|&x| *x != exclude).collect_vec()
} else {
section.iter().collect_vec()
};
if names.is_empty() {
return Err(Error::CannotRoute);
}
Ok(*RoutingTable::get_routeth_name(names, &target, route))
}
fn check_invariant(&self, allow_small_sections: bool) -> Result<(), Error> {
if !self.our_prefix.matches(&self.our_name) {
warn!("Our prefix does not match our name: {:?}", self);
return Err(Error::InvariantViolation);
}
if self.sections.contains_key(&self.our_prefix) {
warn!("Our own section is in the sections map: {:?}", self);
return Err(Error::InvariantViolation);
}
let has_enough_nodes = self.len() >= self.min_section_size;
if has_enough_nodes && self.our_section.len() < self.min_section_size {
warn!("Minimum section size not met for section {:?}: {:?}",
self.our_prefix,
self);
return Err(Error::InvariantViolation);
}
for name in &self.our_section {
if !self.our_prefix.matches(name) {
warn!("Name {} doesn't match section prefix {:?}: {:?}",
name.debug_binary(),
self.our_prefix,
self);
return Err(Error::InvariantViolation);
}
}
for (prefix, section) in &self.sections {
if has_enough_nodes && section.len() < self.min_section_size {
if section.len() <= 1 && allow_small_sections {
continue;
}
warn!("Minimum group size not met for group {:?}: {:?}",
prefix,
self);
return Err(Error::InvariantViolation);
}
for name in section {
if !prefix.matches(name) {
warn!("Name {} doesn't match section prefix {:?}: {:?}",
name.debug_binary(),
prefix,
self);
return Err(Error::InvariantViolation);
}
}
}
let all_are_neighbours = self.sections.keys().all(|&x| self.our_prefix.is_neighbour(&x));
let all_neighbours_covered = {
let prefixes = self.prefixes();
(0..self.our_prefix.bit_count())
.all(|i| self.our_prefix.with_flipped_bit(i).is_covered_by(&prefixes))
};
if !all_are_neighbours {
warn!("Some sections in the RT aren't neighbours of our section: {:?}",
self);
return Err(Error::InvariantViolation);
}
if !all_neighbours_covered {
warn!("Some neighbours aren't fully covered by the RT: {:?}", self);
return Err(Error::InvariantViolation);
}
Ok(())
}
#[cfg(any(test, feature = "use-mock-crust"))]
pub fn verify_invariant(&self) {
unwrap!(self.check_invariant(false),
"Invariant not satisfied for RT: {:?}",
self);
}
#[cfg(test)]
fn num_of_sections(&self) -> usize {
self.sections.len()
}
}
impl<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> Binary for RoutingTable<T> {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
writeln!(formatter, "RoutingTable {{")?;
writeln!(formatter, "\tmin_section_size: {},", self.min_section_size)?;
writeln!(formatter,
"\tour_name: {:?} ({}),",
self.our_name,
self.our_name.debug_binary())?;
writeln!(formatter, "\tour_prefix: {:?}", self.our_prefix)?;
let mut sections = self.sections
.iter()
.chain(iter::once((&self.our_prefix, &self.our_section)))
.collect_vec();
sections.sort_by(|&(lhs_prefix, _), &(rhs_prefix, _)| {
lhs_prefix.cmp_distance(rhs_prefix, &self.our_name)
});
let sections_len = sections.len();
for (section_index, (prefix, section)) in sections.into_iter().enumerate() {
write!(formatter,
"\tsection {} with {:?}: {{\n",
section_index,
prefix)?;
for (name_index, name) in section.iter().enumerate() {
let comma = if name_index == section.len() - 1 {
""
} else {
","
};
writeln!(formatter,
"\t\t{:?} ({}){}",
name,
name.debug_binary(),
comma)?;
}
let comma = if section_index == sections_len - 1 {
""
} else {
","
};
writeln!(formatter, "\t}}{}", comma)?;
}
writeln!(formatter,
"\tmerging: we {:?}, they {:?}",
self.we_want_to_merge,
self.they_want_to_merge)?;
write!(formatter, "}}")
}
}
impl<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> Debug for RoutingTable<T> {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
Binary::fmt(self, formatter)
}
}
#[cfg(test)]
mod tests {
use itertools::Itertools;
use std::collections::BTreeSet;
use super::*;
#[test]
fn small() {
let name = 123u32;
let table = RoutingTable::new(name, 6);
assert_eq!(*table.our_name(), name);
assert_eq!(table.len(), 0);
assert!(table.is_empty());
assert_eq!(table.iter().count(), 0);
}
#[test]
fn test_routing_sections() {
use rand::{Rng, SeedableRng, XorShiftRng};
let mut rng: XorShiftRng = SeedableRng::from_seed([1315, 30, 61894, 315]);
let our_name = rng.next_u32();
let mut table = RoutingTable::new(our_name, 8);
table.verify_invariant();
let mut unknown_distant_name = None;
for _ in 0..1000 {
let new_name = rng.next_u32();
match table.add(new_name) {
Err(Error::AlreadyExists) => {
table.verify_invariant();
assert!(table.iter().any(|u| *u == new_name));
}
Err(Error::PeerNameUnsuitable) => {
table.verify_invariant();
assert!(table.sections.keys().all(|p| !p.matches(&new_name)));
unknown_distant_name = Some(new_name);
}
Err(e) => {
panic!("unexpected error: {}", e);
}
Ok(true) => {
table.verify_invariant();
let our_prefix = *table.our_prefix();
assert!(our_prefix.matches(&new_name));
let _ = table.split(our_prefix);
table.verify_invariant();
}
Ok(false) => {
table.verify_invariant();
assert!(table.iter().any(|u| *u == new_name));
if table.is_in_our_section(&new_name) {
continue; }
let section_prefix = table.find_section_prefix(&new_name)
.expect("get section added to");
let (section_len, new_section_size) = {
let section =
table.sections.get(§ion_prefix).expect("get section from prefix");
(section.len(),
section.iter()
.filter(|name| {
new_name.common_prefix(name) > section_prefix.bit_count()
})
.count())
};
let min_section_size = table.min_split_size();
if new_section_size >= min_section_size &&
section_len - new_section_size >= min_section_size {
let _ = table.split(section_prefix); table.verify_invariant();
}
}
}
}
let unknown_neighbour;
loop {
let new_name = rng.next_u32();
if table.our_prefix.matches(&new_name) {
continue;
}
if let Some(prefix) = table.sections.keys().find(|p| p.matches(&new_name)) {
if !unwrap!(table.sections.get(&prefix)).contains(&new_name) {
unknown_neighbour = new_name;
break;
}
}
}
let unknown_distant_name = unwrap!(unknown_distant_name);
let num_known_nodes = 104;
let num_sections = 8;
let len_our_section = 13;
assert_eq!(table.len(), num_known_nodes);
assert_eq!(table.sections.len(), num_sections - 1);
assert_eq!(table.our_section.len(), len_our_section);
assert_eq!(our_name, table.our_name);
let close_name: u32 =
*unwrap!(table.our_section.iter().filter(|name| **name != our_name).nth(4));
let mut known_neighbour: Option<u32> = None;
for (prefix, section) in &table.sections {
if *prefix == table.our_prefix {
continue;
}
known_neighbour = Some(*unwrap!(section.iter().next()));
break;
}
let known_neighbour = unwrap!(known_neighbour);
assert!(!table.our_prefix.matches(&known_neighbour));
assert!(table.iter().any(|u| *u == close_name));
assert!(table.iter().any(|u| *u == known_neighbour));
assert!(table.iter().all(|u| *u != unknown_neighbour));
assert!(table.iter().all(|u| *u != unknown_distant_name));
assert!(table.is_in_our_section(&close_name));
assert!(!table.is_in_our_section(&known_neighbour));
assert_eq!(table.close_names(&close_name).unwrap().len(),
len_our_section);
assert!(table.close_names(&known_neighbour).is_none());
assert!(table.close_names(&unknown_neighbour).is_none());
assert!(table.close_names(&unknown_distant_name).is_none());
assert_eq!(table.other_close_names(&close_name).unwrap().len(),
len_our_section - 1);
assert!(table.other_close_names(&known_neighbour).is_none());
assert!(table.other_close_names(&unknown_neighbour).is_none());
assert!(table.other_close_names(&unknown_distant_name).is_none());
assert!(table.is_in_our_section(&our_name));
assert!(table.is_in_our_section(&close_name));
assert!(!table.is_in_our_section(&known_neighbour));
assert!(!table.is_in_our_section(&unknown_neighbour));
assert!(!table.is_in_our_section(&unknown_distant_name));
assert_eq!(table.need_to_add(&our_name), Err(Error::OwnNameDisallowed));
assert_eq!(table.need_to_add(&close_name), Err(Error::AlreadyExists));
assert_eq!(table.need_to_add(&known_neighbour),
Err(Error::AlreadyExists));
assert_eq!(table.need_to_add(&unknown_neighbour), Ok(()));
assert_eq!(table.need_to_add(&unknown_distant_name),
Err(Error::PeerNameUnsuitable));
}
#[test]
fn test_closest_names() {
let our_name = 0u16;
let mut table = RoutingTable::new(our_name, 8);
unwrap!(table.add(0x8000));
unwrap!(table.add(0x4000));
unwrap!(table.add(0x2000));
unwrap!(table.add(0x1000));
unwrap!(table.add(0x0800));
unwrap!(table.add(0x0400));
unwrap!(table.add(0x0200));
unwrap!(table.add(0x0100));
unwrap!(table.add(0x0080));
unwrap!(table.add(0x0040));
let mut name = 0xFFFF;
assert!(table.closest_names(&name, 10).is_none());
assert!(table.other_closest_names(&name, 10).is_none());
assert!(table.closest_names(&name, 11).is_some());
let result = unwrap!(table.other_closest_names(&name, 11));
assert_eq!(result.len(), 10);
name = 0x01FF;
assert!(table.closest_names(&name, 3).is_none());
let result = unwrap!(table.closest_names(&name, 4));
assert_eq!(result.len(), 4);
assert_eq!(*result[0], 0x0100);
assert_eq!(*result[1], 0x0080);
assert_eq!(*result[2], 0x0040);
assert_eq!(*result[3], 0x0000);
let result = unwrap!(table.other_closest_names(&name, 4));
assert_eq!(result.len(), 3);
assert_eq!(*result[0], 0x0100);
assert_eq!(*result[1], 0x0080);
assert_eq!(*result[2], 0x0040);
}
#[test]
fn test_add_prefix() {
let our_name = 0u8;
let mut table = RoutingTable::new(our_name, 1);
for i in 1..0x10 {
unwrap!(table.add(i * 0x10));
}
assert_eq!(prefixes_from_strs(vec![""]), table.prefixes());
assert_eq!(Vec::<u8>::new(), table.add_prefix(Prefix::from_str("01")));
assert_eq!(prefixes_from_strs(vec!["1", "00", "01"]), table.prefixes());
assert_eq!(vec![0xc0, 0xd0, 0xe0, 0xf0u8],
table.add_prefix(Prefix::from_str("111")).into_iter().sorted());
assert_eq!(prefixes_from_strs(vec!["110", "111", "10", "0"]),
table.prefixes());
assert_eq!(Vec::<u8>::new(), table.add_prefix(Prefix::from_str("0")));
assert_eq!(prefixes_from_strs(vec!["110", "111", "10", "0"]),
table.prefixes());
assert_eq!(Vec::<u8>::new(), table.add_prefix(Prefix::from_str("")));
assert_eq!(prefixes_from_strs(vec![""]), table.prefixes());
}
fn prefixes_from_strs(strs: Vec<&str>) -> BTreeSet<Prefix<u8>> {
strs.into_iter().map(Prefix::from_str).collect()
}
}