Skip to main content

simulation/
simulation.rs

1use std::collections::HashMap;
2use vrf_pbft::{Config, ConsensusEngine, Node};
3
4fn main() {
5    let config = Config::new(3); // f=3, needs 10 nodes
6    let mut engine = ConsensusEngine::new(config);
7
8    // 10 nodes with varying weights (simulating different stakes)
9    let weights = [500, 300, 200, 150, 100, 100, 80, 60, 40, 20];
10    for (i, &w) in weights.iter().enumerate() {
11        let node = Node::new((i + 1) as u64, w).expect("failed to create node");
12        engine.add_node(node);
13    }
14
15    let total_rounds = 100;
16    println!(
17        "Simulating {} rounds with {} nodes (f=3)\n",
18        total_rounds,
19        weights.len()
20    );
21    println!(
22        "Node weights: {:?}",
23        weights
24    );
25    println!("Total weight: {}\n", weights.iter().sum::<u64>());
26
27    let blocks = engine.run(total_rounds).expect("simulation failed");
28
29    // Proposer distribution
30    let mut proposer_count: HashMap<u64, u32> = HashMap::new();
31    for block in &blocks {
32        *proposer_count.entry(block.proposer).or_default() += 1;
33    }
34
35    println!("Results:");
36    println!("  Rounds attempted: {}", engine.round());
37    println!("  Blocks committed:  {}", blocks.len());
38    println!(
39        "  Success rate:      {:.1}%",
40        blocks.len() as f64 / engine.round() as f64 * 100.0
41    );
42
43    println!("\nProposer distribution:");
44    let mut sorted: Vec<_> = proposer_count.iter().collect();
45    sorted.sort_by_key(|(id, _)| *id);
46    for (id, count) in sorted {
47        let w = weights[(*id - 1) as usize];
48        println!("  Node {} (weight {:>3}): {} blocks", id, w, count);
49    }
50
51    // Verify all nodes have the same ledger length
52    let ledger_lens: Vec<usize> = engine.nodes().iter().map(|n| n.ledger().len()).collect();
53    let all_same = ledger_lens.windows(2).all(|w| w[0] == w[1]);
54    println!(
55        "\nLedger consistency: {} (all nodes have {} blocks)",
56        if all_same { "PASS" } else { "FAIL" },
57        ledger_lens[0]
58    );
59}