use num_bigint::BigUint;
use super::dht_convergence::spec;
use super::dht_convergence::Layout;
use super::dht_convergence::K;
use crate::dht::Chord;
use crate::dht::Did;
use crate::dht::PeerRing;
use crate::dht::PeerRingAction;
use crate::storage::MemStorage;
const MAX_HOPS: usize = 64;
fn midpoints(all: &[Did]) -> Vec<Did> {
let m = BigUint::from(1u8) << 160;
let mut pos: Vec<BigUint> = all.iter().map(|&d| BigUint::from(d)).collect();
pos.sort();
let n = pos.len();
(0..n)
.map(|i| {
let a = pos[i].clone();
let b = if i + 1 < n {
pos[i + 1].clone()
} else {
&pos[0] + &m
};
Did::from((a + b) / BigUint::from(2u8))
})
.collect()
}
fn converged_rings(all: &[Did]) -> Vec<PeerRing> {
all.iter()
.map(|&me| {
let dht = PeerRing::new_with_storage(me, K as u8, Box::new(MemStorage::new()));
for &other in all {
if other != me {
let _ = dht.join(other);
}
}
dht
})
.collect()
}
fn route(rings: &[PeerRing], all: &[Did], origin: usize, target: Did) -> Did {
let idx = |did: Did| all.iter().position(|&d| d == did).expect("did in set");
let mut at = origin;
for _ in 0..MAX_HOPS {
match rings[at].find_successor(target).unwrap() {
PeerRingAction::Some(did) => return did,
PeerRingAction::RemoteAction(next, _) => {
let ni = idx(next);
assert_ne!(ni, at, "production find_successor self-routed at {at}");
at = ni;
}
other => panic!("unexpected find_successor action: {other:?}"),
}
}
panic!("find_successor routing did not resolve within {MAX_HOPS} hops");
}
fn true_successor(all: &[Did], target: Did) -> Did {
*all.iter()
.min_by_key(|&&d| spec::dist(target, d))
.expect("non-empty")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn real_find_successor_routing_is_correct() {
let layouts = [
Layout::Even(5),
Layout::Pow2(8),
Layout::Clustered,
Layout::DyadicBoundary,
];
for layout in layouts {
let all = layout.dids();
let rings = converged_rings(&all);
let targets = midpoints(&all);
for origin in 0..all.len() {
for &target in &targets {
assert_eq!(
route(&rings, &all, origin, target),
true_successor(&all, target),
"wrong successor (origin={origin}, target={target}, all={all:?})"
);
}
}
}
}
}