mod authority;
mod error;
mod network_tests;
mod prefix;
mod xorable;
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, VersionedPrefix};
pub use self::xorable::Xorable;
use itertools::Itertools;
use log::Level;
use std::cmp::Ordering;
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Result as FmtResult;
use std::fmt::{Binary, Debug, Formatter};
use std::hash::Hash;
use std::{iter, mem};
pub type Sections<T> = BTreeMap<Prefix<T>, (u64, BTreeSet<T>)>;
type SectionItem<'a, T> = (Prefix<T>, (u64, &'a BTreeSet<T>));
const SPLIT_BUFFER: usize = 3;
pub struct Iter<'a, T: 'a + Binary + Clone + Copy + Default + Hash + Xorable> {
inner: Box<Iterator<Item = &'a T> + 'a>,
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(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> {
Completed {
targets: BTreeSet<Prefix<T>>,
versioned_prefix: VersionedPrefix<T>,
section: BTreeSet<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: BTreeSet<T>,
our_version: u64,
sections: Sections<T>,
}
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 = BTreeSet::new();
let _ = our_section.insert(our_name);
RoutingTable {
our_name,
min_section_size,
our_section,
our_prefix: Default::default(),
our_version: 0,
sections: BTreeMap::new(),
}
}
pub fn add_prefixes(&mut self, ver_pfxs: Vec<VersionedPrefix<T>>) -> Result<(), Error> {
if self.our_version != 0 || !self.sections.is_empty() {
return Err(Error::InvariantViolation);
}
for ver_pfx in ver_pfxs {
let (prefix, version) = ver_pfx.into();
if prefix.matches(&self.our_name) {
self.our_prefix = prefix;
self.our_version = version;
} else if self
.sections
.insert(prefix, (version, BTreeSet::new()))
.is_some()
{
return Err(Error::InvariantViolation);
};
}
let our_section = mem::replace(&mut self.our_section, BTreeSet::new());
for name in our_section {
let sec_insert = |section: &mut BTreeSet<T>| !section.insert(name);
if self.get_section_mut(&name).map_or(true, sec_insert) {
return Err(Error::InvariantViolation);
}
}
self.check_invariant(true, true)
}
pub fn check_node_approval_msg(
&self,
sections: BTreeMap<Prefix<T>, BTreeSet<T>>,
) -> Result<(), Error> {
let mut temp_rt = RoutingTable::new(self.our_name, self.min_section_size);
temp_rt.add_prefixes(sections.keys().map(|pfx| pfx.with_version(0)).collect())?;
for peer in sections.values().flat_map(BTreeSet::iter) {
let _ = temp_rt.add(*peer);
}
temp_rt.check_invariant(false, true)
}
pub fn our_prefix(&self) -> &Prefix<T> {
&self.our_prefix
}
pub fn our_version(&self) -> u64 {
self.our_version
}
pub fn our_versioned_prefix(&self) -> VersionedPrefix<T> {
self.our_prefix.with_version(self.our_version)
}
pub fn our_section(&self) -> &BTreeSet<T> {
&self.our_section
}
pub fn all_sections(&self) -> Sections<T> {
self.all_sections_iter()
.map(|(p, (v, section))| (p, (v, section.clone())))
.collect()
}
pub fn all_sections_iter<'a>(&'a self) -> Box<Iterator<Item = SectionItem<T>> + 'a> {
let iter = self
.sections
.iter()
.map(|(&p, &(v, ref sec))| (p, (v, sec)))
.chain(iter::once((
self.our_prefix,
(self.our_version, &self.our_section),
)));
Box::new(iter)
}
pub fn section_with_prefix(&self, prefix: &Prefix<T>) -> Option<&BTreeSet<T>> {
self.lookup_section(prefix).map(|(_, section)| section)
}
pub fn section_version(&self, prefix: &Prefix<T>) -> Option<u64> {
self.lookup_section(prefix).map(|(v, _)| v)
}
pub fn len(&self) -> usize {
self.all_sections_iter()
.map(|(_, (_, section))| section.len())
.sum::<usize>()
- 1
}
pub fn is_empty(&self) -> bool {
self.our_section.len() == 1 && self
.sections
.values()
.all(|&(_, ref section)| section.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 = self
.all_sections_iter()
.flat_map(|(_, (_, section))| section.iter());
Iter {
inner: Box::new(iter),
our_name: self.our_name,
}
}
pub fn network_size_estimate(&self) -> (u64, bool) {
let known_prefixes = self.prefixes();
let is_exact = Prefix::default().is_covered_by(known_prefixes.iter());
let network_fraction: f64 = known_prefixes
.iter()
.map(|p| 1.0 / (p.bit_count() as f64).exp2())
.sum();
let network_size = (self.len() + 1) as f64 / network_fraction;
(network_size.ceil() as u64, is_exact)
}
pub fn other_prefixes(&self) -> BTreeSet<Prefix<T>> {
self.sections.keys().cloned().collect()
}
pub fn prefixes(&self) -> BTreeSet<Prefix<T>> {
self.all_sections_iter().map(|(prefix, _)| prefix).collect()
}
pub fn close_names(&self, name: &T) -> Option<BTreeSet<T>> {
if self.our_prefix.matches(name) {
Some(self.our_section().clone())
} else {
None
}
}
pub fn other_close_names(&self, name: &T) -> Option<BTreeSet<T>> {
if self.our_prefix.matches(name) {
let mut section = self.our_section.clone();
let _ = 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()
}
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 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<(), 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);
}
Ok(())
}
fn lookup_section(&self, prefix: &Prefix<T>) -> Option<(u64, &BTreeSet<T>)> {
if *prefix == self.our_prefix {
Some((self.our_version, &self.our_section))
} else {
self.sections
.get(prefix)
.map(|&(ver, ref section)| (ver, section))
}
}
fn closest_known_names(&self, name: &T, count: usize) -> Vec<&T> {
self.all_sections_iter()
.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()
}
fn neighbour_needs_merge(&self) -> bool {
self.neighbour_size_is_below(self.min_section_size)
}
fn neighbour_might_need_merge(&self) -> bool {
self.neighbour_size_is_below(self.min_split_size())
}
fn neighbour_size_is_below(&self, threshold: usize) -> bool {
self.sections.iter().any(|(prefix, &(_, ref section))| {
prefix.popped().is_compatible(&self.our_prefix) && section.len() < threshold
})
}
pub fn should_split(&self) -> bool {
if self.neighbour_might_need_merge() {
return false;
}
let split_size = self.min_split_size();
let new_size = self
.our_section
.iter()
.filter(|name| self.our_name.common_prefix(name) > self.our_prefix.bit_count())
.count();
new_size >= split_size && self.our_section().len() >= split_size + new_size
}
pub fn split(&mut self, ver_pfx: VersionedPrefix<T>) -> (Vec<T>, Option<Prefix<T>>) {
let mut result = vec![];
let (prefix, version) = ver_pfx.into();
if prefix == self.our_prefix {
result = self.split_our_section(version);
return (result, Some(self.our_prefix));
}
let (_version, to_split) = match self.sections.entry(prefix) {
Entry::Vacant(_) => return (result, None),
Entry::Occupied(ref entry) if entry.get().0 != version => {
debug!(
"{:?} Not splitting section with {:?} ver. {}, \
update is for a different version: {}",
self.our_name,
prefix,
entry.get().0,
version
);
return (result, None);
}
Entry::Occupied(entry) => entry.remove(),
};
let prefix0 = prefix.pushed(false);
let prefix1 = prefix.pushed(true);
let (section0, section1) = to_split
.into_iter()
.partition::<BTreeSet<_>, _>(|name| prefix0.matches(name));
for (pfx, section) in vec![(prefix0, section0), (prefix1, section1)] {
if self.our_prefix.is_neighbour(&pfx) {
self.insert_new_section(pfx, version + 1, section);
} else {
result.extend(section);
}
}
(result, None)
}
pub fn add_prefix(&mut self, ver_pfx: VersionedPrefix<T>) -> Vec<T> {
let (prefix, version) = ver_pfx.into();
if !prefix.is_compatible(&self.our_prefix) && !prefix.is_neighbour(&self.our_prefix) {
return vec![];
}
for (pfx, (v, _)) in self.all_sections_iter() {
if prefix.is_compatible(&pfx) && version <= v {
trace!(
"{:?} Not adding {:?} v{} to the RT as the existing {:?} v{} \
does not predate it.",
self.our_name,
prefix,
version,
pfx,
v
);
return vec![];
}
}
let original_sections = mem::replace(&mut self.sections, Sections::new());
let (sections_to_replace, sections) = original_sections
.into_iter()
.partition::<BTreeMap<_, _>, _>(|&(ref pfx, _)| prefix.is_compatible(pfx));
self.sections = sections;
if prefix.matches(&self.our_name) {
self.our_prefix = prefix;
self.our_version = version;
} else if prefix.is_compatible(&self.our_prefix) {
self.our_prefix = Prefix::new(prefix.common_prefix(&self.our_name) + 1, self.our_name);
self.insert_new_section(prefix, version, BTreeSet::new());
} else {
self.insert_new_section(prefix, version, BTreeSet::new());
}
self.add_missing_prefixes();
sections_to_replace
.into_iter()
.flat_map(|(_, (_, names))| names)
.chain(mem::replace(
&mut self.our_section,
iter::once(self.our_name).collect(),
)).filter(|name| {
*name != self.our_name && self.add(*name) == Err(Error::PeerNameUnsuitable)
}).collect()
}
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(&mut (_, ref mut 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) -> bool {
let bit_count = self.our_prefix.bit_count();
if bit_count == 0 || !self.sections.contains_key(&self.our_prefix.sibling()) {
return false; }
self.our_section.len() < self.min_section_size || self.neighbour_needs_merge()
}
pub fn merge_own_section<I>(
&mut self,
merge_ver_pfx: VersionedPrefix<T>,
ver_pfxs: I,
) -> OwnMergeState<T>
where
I: IntoIterator<Item = VersionedPrefix<T>>,
{
if !self.our_prefix.is_compatible(merge_ver_pfx.prefix())
|| self.our_prefix.bit_count() != merge_ver_pfx.prefix().bit_count() + 1
{
debug!(
"{:?} Attempt to call merge_own_section() for an already merged prefix {:?}",
self.our_name, merge_ver_pfx
);
return OwnMergeState::AlreadyMerged;
}
self.merge(&merge_ver_pfx);
let dropped_names = ver_pfxs
.into_iter()
.flat_map(|ver_pfx| self.add_prefix(ver_pfx))
.collect_vec();
if !dropped_names.is_empty() {
log_or_panic!(
Level::Warn,
"{:?} Removed peers from RT as part of OwnSectionMerge {:?}",
self.our_name,
dropped_names
);
}
self.add_missing_prefixes();
let (merge_pfx, _) = merge_ver_pfx.into();
let targets = self
.sections
.keys()
.cloned()
.chain((0..merge_pfx.bit_count()).map(|i| merge_pfx.with_flipped_bit(i)))
.collect();
OwnMergeState::Completed {
targets,
versioned_prefix: self.our_versioned_prefix(),
section: self.our_section().clone(),
}
}
pub fn merge_other_section<I>(&mut self, ver_pfx: VersionedPrefix<T>, members: I) -> BTreeSet<T>
where
I: IntoIterator<Item = T>,
{
if self.our_prefix.is_compatible(ver_pfx.prefix()) {
error!(
"{:?} Attempt to merge other section {:?} when our prefix is {:?}",
self.our_name,
ver_pfx.prefix(),
self.our_prefix
);
return BTreeSet::new();
}
self.merge(&ver_pfx);
self.sections
.get(ver_pfx.prefix())
.map_or_else(BTreeSet::new, |&(_, ref section)| {
members
.into_iter()
.filter(|name| !section.contains(name))
.collect()
})
}
pub fn targets(
&self,
dst: &Authority<T>,
exclude: T,
route: usize,
) -> Result<BTreeSet<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::<BTreeSet<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(BTreeSet::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();
let _ = 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()) {
let is_compatible = |(pfx, &(_, ref section))| {
if prefix.is_compatible(pfx) {
Some(section)
} else {
None
}
};
return Ok(self
.sections
.iter()
.filter_map(is_compatible)
.flat_map(BTreeSet::iter)
.chain(
self.our_section
.iter()
.filter(|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) => self.our_prefix.is_compatible(prefix),
}
}
pub fn get_section(&self, name: &T) -> Option<&BTreeSet<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).map(|&(_, ref section)| section);
}
None
}
pub fn our_name(&self) -> &T {
&self.our_name
}
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()
}
pub fn min_len_prefix(&self) -> Prefix<T> {
*iter::once(&self.our_prefix)
.chain(self.sections.keys())
.min_by_key(|prefix| prefix.bit_count())
.unwrap_or(&self.our_prefix)
}
fn split_our_section(&mut self, version: u64) -> Vec<T> {
if self.our_version != version {
debug!(
"{:?} Not splitting our section with {:?} ver. {}, \
update is for a different version: {}",
self.our_name, self.our_prefix, self.our_version, version
);
return Vec::new(); }
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::<BTreeSet<_>, _>(|name| self.our_prefix.matches(name));
self.our_section = our_new_section;
self.our_version = version + 1;
let sections_to_remove = self
.sections
.keys()
.filter(|prefix| !prefix.is_neighbour(&self.our_prefix))
.cloned()
.collect_vec();
self.insert_new_section(other_prefix, version + 1, other_section);
sections_to_remove
.into_iter()
.filter_map(|prefix| self.sections.remove(&prefix).map(|(_, section)| section))
.flat_map(BTreeSet::into_iter)
.collect()
}
fn insert_new_section(&mut self, prefix: Prefix<T>, version: u64, section: BTreeSet<T>) {
match self.sections.entry(prefix) {
Entry::Vacant(entry) => {
let _section_ref = entry.insert((version, section));
}
Entry::Occupied(entry) => {
error!(
"{:?} Inserting section {:?}, but already has members {:?}. This is a bug!",
self.our_name,
prefix,
entry.get()
);
let &mut (ref mut v, ref mut s) = entry.into_mut();
if *v > version {
return; }
*v = version;
s.extend(section);
}
}
}
fn merge(&mut self, new_ver_pfx: &VersionedPrefix<T>) {
let checker = |pfx: &Prefix<T>| new_ver_pfx.prefix().is_extension_of(pfx);
if new_ver_pfx.prefix().is_extension_of(&self.our_prefix)
|| self.sections.keys().any(checker)
{
return; }
let dropped_names = self.add_prefix(*new_ver_pfx);
if !dropped_names.is_empty() {
error!(
"{:?} Dropped names when merging {:?}: {:?}",
self.our_name, new_ver_pfx, dropped_names
);
}
}
fn add_missing_prefixes(&mut self) {
let mut prefix = self.our_prefix;
let mut missing_pfxs = vec![];
while prefix.bit_count() > 0 {
missing_pfxs.push(prefix.sibling());
prefix = prefix.popped();
}
while let Some(pfx) = missing_pfxs.pop() {
if !pfx.is_covered_by(self.sections.keys()) && pfx.is_neighbour(&self.our_prefix) {
if self.sections.keys().any(|p| pfx.is_compatible(p)) {
missing_pfxs.push(pfx.pushed(true));
missing_pfxs.push(pfx.pushed(false));
} else {
self.insert_new_section(pfx, 0, BTreeSet::new());
}
}
}
}
fn get_section_mut(&mut self, name: &T) -> Option<&mut BTreeSet<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)
.map(|&mut (_, ref mut section)| section);
}
None
}
fn closest_section(&self, name: &T) -> (&Prefix<T>, &BTreeSet<T>) {
let mut result = (&self.our_prefix, &self.our_section);
for (prefix, &(_, ref 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: &BTreeSet<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))
}
pub fn check_invariant(
&self,
allow_small_sections: bool,
show_warnings: bool,
) -> Result<(), Error> {
let warn = |log_msg: String| -> Result<(), Error> {
if show_warnings {
warn!("{}", log_msg);
}
Err(Error::InvariantViolation)
};
if !self.our_prefix.matches(&self.our_name) {
return warn(format!("Our prefix does not match our name: {:?}", self));
}
if self.sections.contains_key(&self.our_prefix) {
return warn(format!(
"Our own section is in the sections map: {:?}",
self
));
}
let has_enough_nodes = self.len() >= self.min_section_size;
if has_enough_nodes && self.our_section.len() < self.min_section_size {
return warn(format!(
"Minimum section size not met for section {:?}: {:?}",
self.our_prefix, self
));
}
for name in &self.our_section {
if !self.our_prefix.matches(name) {
return warn(format!(
"Name {} doesn't match section prefix {:?}: {:?}",
name.debug_binary(),
self.our_prefix,
self
));
}
}
for (prefix, &(_, ref section)) in &self.sections {
if has_enough_nodes && section.len() < self.min_section_size {
if section.len() <= 1 && allow_small_sections {
continue;
}
return warn(format!(
"Minimum group size not met for group {:?}: {:?}",
prefix, self
));
}
for name in section {
if !prefix.matches(name) {
return warn(format!(
"Name {} doesn't match section prefix {:?}: {:?}",
name.debug_binary(),
prefix,
self
));
}
}
}
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 {
return warn(format!(
"Some sections in the RT aren't neighbours of our section: {:?}",
self
));
}
if !all_neighbours_covered {
return warn(format!(
"Some neighbours aren't fully covered by the RT: {:?}",
self
));
}
Ok(())
}
#[cfg(any(test, feature = "use-mock-crust"))]
pub fn verify_invariant(&self) {
unwrap!(
self.check_invariant(false, true),
"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)?;
writeln!(formatter, "\tour_version: {}", self.our_version)?;
let sections = self.all_sections_iter().collect::<BTreeSet<_>>();
for (section_index, &(prefix, (version, section))) in sections.iter().enumerate() {
writeln!(
formatter,
"\tsection {} with {:?} v{}: {{",
section_index, prefix, version
)?;
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)?;
}
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 super::SPLIT_BUFFER;
use super::*;
use itertools::Itertools;
use std::collections::BTreeSet;
use std::str::FromStr;
#[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);
assert_eq!(table.all_sections_iter().count(), 1);
}
fn add_sequential_entries(table: &mut RoutingTable<u16>, name: &mut u16) {
for _ in 1..table.min_split_size() {
assert_eq!(table.add(*name), Ok(()));
assert!(!table.should_split());
table.verify_invariant();
*name += 1;
}
}
#[test]
fn test_routing_sections() {
assert!(
SPLIT_BUFFER < 3818,
"Given the chosen values for 'our_name' and RT type (u16), this requires the \
SPLIT_BUFFER to be less than 3818."
);
let our_name = 0b_0001_0001_0001_0001u16;
let mut table = RoutingTable::new(our_name, 5);
table.verify_invariant();
let mut expected_rt_len = 0; let mut section_00_name = our_name + 1;
let mut section_10_name = our_name.with_flipped_bit(0);
add_sequential_entries(&mut table, &mut section_00_name);
add_sequential_entries(&mut table, &mut section_10_name);
expected_rt_len += 2 * (table.min_split_size() - 1);
assert_eq!(table.add(section_10_name), Ok(()));
assert!(table.should_split());
expected_rt_len += 1;
let mut expected_own_prefix = Prefix::new(0, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(expected_own_prefix.with_version(0));
expected_own_prefix = Prefix::new(1, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert_eq!(unwrap!(our_new_prefix), expected_own_prefix);
assert!(nodes_to_drop.is_empty());
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 2);
assert_eq!(table.our_section().len(), table.min_split_size());
let mut section_01_name = our_name.with_flipped_bit(1);
let mut section_11_name = section_10_name.with_flipped_bit(1);
add_sequential_entries(&mut table, &mut section_01_name);
add_sequential_entries(&mut table, &mut section_11_name);
expected_rt_len += 2 * (table.min_split_size() - 1);
assert_eq!(table.add(section_01_name), Ok(()));
assert!(table.should_split());
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(expected_own_prefix.with_version(1));
expected_own_prefix = Prefix::new(2, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert_eq!(unwrap!(our_new_prefix), expected_own_prefix);
assert!(nodes_to_drop.is_empty());
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 3);
assert_eq!(table.our_section().len(), table.min_split_size());
assert_eq!(table.add(section_11_name), Ok(()));
assert!(!table.should_split());
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) =
table.split(Prefix::new(1, section_11_name).with_version(1));
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert!(our_new_prefix.is_none());
assert_eq!(nodes_to_drop.len(), table.min_split_size());
let mut drop_prefix = Prefix::new(2, section_11_name);
assert!(nodes_to_drop.iter().all(|name| drop_prefix.matches(name)));
expected_rt_len -= nodes_to_drop.len();
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 3);
assert_eq!(table.our_section().len(), table.min_split_size());
let mut section_001_name = our_name.with_flipped_bit(2);
let mut section_011_name = section_001_name.with_flipped_bit(1);
add_sequential_entries(&mut table, &mut section_001_name);
add_sequential_entries(&mut table, &mut section_011_name);
expected_rt_len += 2 * (table.min_split_size() - 1);
assert_eq!(table.add(section_011_name), Ok(()));
assert!(!table.should_split());
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) =
table.split(Prefix::new(2, section_011_name).with_version(2));
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert!(our_new_prefix.is_none());
assert!(nodes_to_drop.is_empty());
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 4);
assert_eq!(table.our_section().len(), 2 * table.min_split_size() - 1);
assert_eq!(table.add(section_001_name), Ok(()));
assert!(table.should_split());
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) =
table.split(expected_own_prefix.with_version(expected_own_prefix.bit_count() as u64));
expected_own_prefix = Prefix::new(3, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert_eq!(unwrap!(our_new_prefix), expected_own_prefix);
assert_eq!(nodes_to_drop.len(), table.min_split_size());
drop_prefix = Prefix::new(3, section_011_name);
assert!(nodes_to_drop.iter().all(|name| drop_prefix.matches(name)));
expected_rt_len -= nodes_to_drop.len();
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 4);
assert_eq!(table.our_section().len(), table.min_split_size());
assert_eq!(table.add(section_001_name), Err(Error::AlreadyExists));
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.add(our_name), Err(Error::OwnNameDisallowed));
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.add(nodes_to_drop[0]), Err(Error::PeerNameUnsuitable));
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert!(table.is_in_our_section(&our_name));
assert!(table.is_in_our_section(&(section_00_name - 1)));
assert!(!table.is_in_our_section(§ion_001_name));
assert!(!table.is_in_our_section(§ion_10_name));
let our_section = table.our_section().clone();
assert!(our_section.contains(&our_name));
assert_eq!(unwrap!(table.close_names(&our_name)), our_section);
assert_eq!(unwrap!(table.close_names(§ion_00_name)), our_section);
assert!(table.close_names(§ion_001_name).is_none());
assert!(table.close_names(§ion_10_name).is_none());
let our_section_without_us = our_section
.into_iter()
.filter(|name| *name != our_name)
.collect::<BTreeSet<_>>();
assert_eq!(
unwrap!(table.other_close_names(&our_name)),
our_section_without_us
);
assert_eq!(
unwrap!(table.other_close_names(§ion_00_name)),
our_section_without_us
);
assert!(table.other_close_names(§ion_001_name).is_none());
assert!(table.other_close_names(§ion_10_name).is_none());
assert_eq!(
table.need_to_add(§ion_001_name),
Err(Error::AlreadyExists)
);
assert_eq!(table.need_to_add(&our_name), Err(Error::OwnNameDisallowed));
assert_eq!(
table.need_to_add(&nodes_to_drop[0]),
Err(Error::PeerNameUnsuitable)
);
assert_eq!(table.need_to_add(&(section_001_name + 1)), Ok(()));
}
#[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(unwrap!(Prefix::from_str("01")).with_version(2))
);
assert_eq!(prefixes_from_strs(vec!["1", "00", "01"]), table.prefixes());
assert_eq!(
Vec::<u8>::new(),
table
.add_prefix(unwrap!(Prefix::from_str("111")).with_version(4))
.into_iter()
.sorted()
);
assert_eq!(prefixes_from_strs(vec!["1", "00", "01"]), table.prefixes());
assert_eq!(
vec![0xc0, 0xd0, 0xe0, 0xf0u8],
table
.add_prefix(unwrap!(Prefix::from_str("101")).with_version(4))
.into_iter()
.sorted()
);
assert_eq!(
prefixes_from_strs(vec!["101", "100", "01", "00"]),
table.prefixes()
);
assert_eq!(
Vec::<u8>::new(),
table.add_prefix(unwrap!(Prefix::from_str("0")).with_version(7))
);
assert_eq!(
prefixes_from_strs(vec!["101", "11", "100", "0"]),
table.prefixes()
);
assert_eq!(
Vec::<u8>::new(),
table.add_prefix(unwrap!(Prefix::from_str("")).with_version(15))
);
assert_eq!(prefixes_from_strs(vec![""]), table.prefixes());
}
#[test]
fn test_add_prefix_outdated_version() {
let our_name = 0u8;
let mut table = RoutingTable::<u8>::new(our_name, 1);
for i in 1..0x10 {
unwrap!(table.add(i * 0x10));
}
let empty = Vec::<u8>::new();
assert_eq!(empty, table.add_prefix(prefix_str("0").with_version(1)));
assert_eq!(Some(1), table.section_version(&prefix_str("0")));
assert_eq!(Some(0), table.section_version(&prefix_str("1")));
assert_eq!(empty, table.add_prefix(prefix_str("00").with_version(2)));
assert_eq!(Some(2), table.section_version(&prefix_str("00")));
assert_eq!(Some(0), table.section_version(&prefix_str("01")));
assert_eq!(Some(0), table.section_version(&prefix_str("1")));
assert_eq!(
vec![0xc0, 0xd0, 0xe0, 0xf0u8],
table
.add_prefix(prefix_str("10").with_version(2))
.into_iter()
.sorted()
);
assert_eq!(prefixes_from_strs(vec!["10", "01", "00"]), table.prefixes());
assert_eq!(empty, table.add_prefix(prefix_str("10").with_version(4)));
assert_eq!(Some(4), table.section_version(&prefix_str("10")));
assert_eq!(empty, table.add_prefix(prefix_str("100").with_version(3)));
assert_eq!(Some(4), table.section_version(&prefix_str("10")));
assert_eq!(prefixes_from_strs(vec!["10", "01", "00"]), table.prefixes());
assert_eq!(empty, table.add_prefix(prefix_str("").with_version(0)));
assert_eq!(empty, table.add_prefix(prefix_str("0").with_version(1)));
assert_eq!(empty, table.add_prefix(prefix_str("101").with_version(3)));
assert_eq!(prefixes_from_strs(vec!["10", "01", "00"]), table.prefixes());
assert_eq!(empty, table.add_prefix(prefix_str("01").with_version(2)));
assert_eq!(Some(2), table.section_version(&prefix_str("01")));
}
fn prefix_str(s: &str) -> Prefix<u8> {
unwrap!(Prefix::from_str(s))
}
fn prefixes_from_strs(strs: Vec<&str>) -> BTreeSet<Prefix<u8>> {
strs.into_iter()
.map(|s| unwrap!(Prefix::from_str(s)))
.collect()
}
}