use std::time::Duration;
use peaveil::sim::{Simulation, sim_config};
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("╔═════════════════════════════════════════════════════════════╗");
println!("║ peaveil — local simulation metrics ║");
println!("╚═════════════════════════════════════════════════════════════╝");
println!();
println!("Building a 20-node ring with one bootstrap and running");
println!("discovery. Metrics are sampled every second and printed");
println!("at the end. All randomness is seeded from a single");
println!("value, so the run is fully reproducible.\n");
let mut sim = Simulation::new(20, 0xC0FFEE_C0FFEE, sim_config()).await;
let bs = sim.addr(0);
for i in 1..20 {
sim.node(i).add_bootstrap(bs);
}
sim.connect_ring().await;
for i in 0..20 {
sim.node(i).add_recent(bs);
let prev = sim.addr((i + 19) % 20);
let next = sim.addr((i + 1) % 20);
sim.node(i).add_recent(prev);
sim.node(i).add_recent(next);
}
println!(
"{:<8} {:<5} {:<10} {:<10} {:<10} {:<10} {:<10}",
"t (s)", "alive", "avg_view", "trusted", "recent", "random", "coverage"
);
println!("{}", "-".repeat(72));
let start = std::time::Instant::now();
for tick in 1..=10 {
sim.step(Duration::from_secs(1)).await;
let m = sim.metrics();
println!(
"{:<8} {:<5} {:<10.2} {:<10.2} {:<10.2} {:<10.2} {:<10.2}",
tick, m.alive, m.avg_view_size, m.avg_trusted, m.avg_recent, m.avg_random, m.coverage,
);
}
println!();
println!("Total wall-clock: {:?}", start.elapsed());
println!();
println!("Now: partition into two halves, wait, then heal.");
let avg_conn = |sim: &Simulation| -> f64 {
let n = sim.len() as f64;
(0..sim.len())
.map(|i| sim.node(i).connected_peers().len() as f64)
.sum::<f64>()
/ n
};
let conn_pre = avg_conn(&sim);
let m_pre = sim.metrics();
println!(
"pre: coverage = {:.2}, avg_view = {:.2}, avg_conn = {:.2}",
m_pre.coverage, m_pre.avg_view_size, conn_pre,
);
sim.partition((0..10).collect(), (10..20).collect()).await;
sim.step(Duration::from_secs(2)).await;
let m_partitioned = sim.metrics();
let conn_partitioned = avg_conn(&sim);
println!(
"post-partition: coverage = {:.2}, avg_view = {:.2}, avg_conn = {:.2}",
m_partitioned.coverage, m_partitioned.avg_view_size, conn_partitioned,
);
sim.heal_partition().await;
sim.step(Duration::from_secs(3)).await;
let m_healed = sim.metrics();
let conn_healed = avg_conn(&sim);
println!(
"post-heal: coverage = {:.2}, avg_view = {:.2}, avg_conn = {:.2}",
m_healed.coverage, m_healed.avg_view_size, conn_healed,
);
sim.shutdown().await;
Ok(())
}