pub struct Config { /* private fields */ }Implementations§
Source§impl Config
impl Config
Sourcepub fn new(fault_tolerance: u64) -> Self
pub fn new(fault_tolerance: u64) -> Self
Create a config with the given fault tolerance f.
The system tolerates up to f byzantine nodes.
Requires at least 3f + 1 total nodes.
Examples found in repository?
examples/single_round.rs (line 4)
3fn main() {
4 let config = Config::new(1); // f=1, needs 4 nodes
5 let mut engine = ConsensusEngine::new(config);
6
7 for i in 1..=4 {
8 let node = Node::new(i, 1000).expect("failed to create node");
9 engine.add_node(node);
10 }
11
12 println!("Running VRF-PBFT with 4 nodes (f=1)...\n");
13
14 // VRF selection is probabilistic, so retry until a round succeeds
15 loop {
16 match engine.run_round() {
17 Ok(block) => {
18 println!("Consensus reached on round {}!", engine.round());
19 println!(" Proposer: node {}", block.proposer);
20 println!(" Seed: {}", block.seed);
21 println!(" Prev hash: {}...", &hex(&block.prev_hash)[..16]);
22 println!(" Hash: {}...", &hex(&block.hash())[..16]);
23 println!("\nMessages exchanged: {}", engine.messages().len());
24 break;
25 }
26 Err(vrf_pbft::Error::NoProposer(r)) => {
27 println!("Round {}: no proposer elected, retrying...", r);
28 }
29 Err(vrf_pbft::Error::InsufficientVotes { needed, got }) => {
30 println!(
31 "Round {}: not enough votes ({}/{}), retrying...",
32 engine.round(),
33 got,
34 needed
35 );
36 }
37 Err(e) => {
38 eprintln!("Fatal error: {}", e);
39 std::process::exit(1);
40 }
41 }
42 }
43}More examples
examples/byzantine.rs (line 5)
3fn main() {
4 // f=2: can tolerate 2 byzantine nodes, needs 7 total
5 let config = Config::new(2);
6 let mut engine = ConsensusEngine::new(config);
7
8 for i in 1..=7 {
9 let mut node = Node::new(i, 1000).expect("failed to create node");
10 // Mark first 2 nodes as byzantine (they vote against valid blocks)
11 if i <= 2 {
12 node.set_byzantine(true);
13 }
14 engine.add_node(node);
15 }
16
17 println!("Byzantine fault tolerance demo");
18 println!(" Nodes: 7 (5 honest, 2 byzantine)");
19 println!(" f=2: system tolerates up to 2 faults");
20 println!(" Threshold: 2f+1 = {}\n", 2 * 2 + 1);
21
22 let total_rounds = 100;
23 let blocks = engine.run(total_rounds).expect("simulation failed");
24
25 println!("After {} round attempts:", engine.round());
26 println!(" Blocks committed: {}", blocks.len());
27
28 if !blocks.is_empty() {
29 println!("\n Byzantine nodes voted AGAINST every block,");
30 println!(" but consensus still passed because 5 honest");
31 println!(" nodes exceed the threshold of 5 (2f+1).\n");
32
33 // Verify ledger consistency
34 let first_len = engine.nodes()[0].ledger().len();
35 let consistent = engine.nodes().iter().all(|n| n.ledger().len() == first_len);
36 println!(
37 " Ledger consistency: {} ({} blocks per node)",
38 if consistent { "PASS" } else { "FAIL" },
39 first_len
40 );
41 } else {
42 println!("\n No blocks committed (VRF didn't elect enough validators).");
43 println!(" Try running again -- VRF selection is probabilistic.");
44 }
45}examples/simulation.rs (line 5)
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}pub fn with_expected_committee(self, n: u64) -> Self
Auto Trait Implementations§
impl Freeze for Config
impl RefUnwindSafe for Config
impl Send for Config
impl Sync for Config
impl Unpin for Config
impl UnsafeUnpin for Config
impl UnwindSafe for Config
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more