Iroh gives us a lot as a transport layer. Lets make use of it. Co-authored-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com> Co-committed-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
94 lines
3 KiB
Rust
94 lines
3 KiB
Rust
/// Network topology shapes for simulation.
|
|
#[derive(Debug, Clone)]
|
|
pub enum Topology {
|
|
/// Each node gossips to the next; last gossips to first.
|
|
Ring,
|
|
/// Node 0 is the hub; all others gossip to/from it.
|
|
Star,
|
|
/// Every node gossips to every other node.
|
|
FullMesh,
|
|
/// Unidirectional chain: 0→1→2→…→(n-1).
|
|
Chain,
|
|
/// Two halves with no cross-links (healed later via `heal_after_round`).
|
|
Partitioned,
|
|
}
|
|
|
|
impl Topology {
|
|
/// Compute abstract index-pair edges for `num_nodes` nodes.
|
|
pub fn edges(&self, num_nodes: usize) -> Vec<(usize, usize)> {
|
|
let n = num_nodes;
|
|
let mut edges = Vec::new();
|
|
|
|
match self {
|
|
Topology::Ring => {
|
|
for i in 0..n {
|
|
edges.push((i, (i + 1) % n));
|
|
}
|
|
}
|
|
Topology::Star => {
|
|
for i in 1..n {
|
|
edges.push((0, i));
|
|
edges.push((i, 0));
|
|
}
|
|
}
|
|
Topology::FullMesh => {
|
|
for i in 0..n {
|
|
for j in 0..n {
|
|
if i != j {
|
|
edges.push((i, j));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Topology::Chain => {
|
|
for i in 0..n.saturating_sub(1) {
|
|
edges.push((i, i + 1));
|
|
}
|
|
}
|
|
Topology::Partitioned => {
|
|
let half = n / 2;
|
|
for i in 0..half {
|
|
for j in 0..half {
|
|
if i != j {
|
|
edges.push((i, j));
|
|
}
|
|
}
|
|
}
|
|
for i in half..n {
|
|
for j in half..n {
|
|
if i != j {
|
|
edges.push((i, j));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
edges
|
|
}
|
|
|
|
/// Partition healing edges: bidirectional links between the two halves.
|
|
///
|
|
/// Connects up to 3 evenly-spaced node pairs across the partition boundary.
|
|
/// A single bridge link is unreliable under random peer selection: with half=50,
|
|
/// there is only a 1/50 chance per round that the bridge node gossips across,
|
|
/// giving a ~1.7% probability of zero crossings in 200 rounds.
|
|
pub fn heal_edges(&self, num_nodes: usize) -> Vec<(usize, usize)> {
|
|
if !matches!(self, Topology::Partitioned) {
|
|
return Vec::new();
|
|
}
|
|
let half = num_nodes / 2;
|
|
if half == 0 || half >= num_nodes {
|
|
return Vec::new();
|
|
}
|
|
let right = num_nodes - half;
|
|
let num_bridges = half.min(3);
|
|
let mut edges = Vec::with_capacity(num_bridges * 2);
|
|
for b in 0..num_bridges {
|
|
let a_node = b * half / num_bridges;
|
|
let b_node = half + b * right / num_bridges;
|
|
edges.push((a_node, b_node));
|
|
edges.push((b_node, a_node));
|
|
}
|
|
edges
|
|
}
|
|
}
|