Skip to main content

Config

Struct Config 

Source
pub struct Config { /* private fields */ }

Implementations§

Source§

impl Config

Source

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
Hide additional 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}
Source

pub fn with_expected_committee(self, n: u64) -> Self

Source

pub fn threshold(&self) -> u64

Minimum votes needed for quorum: 2f + 1

Source

pub fn min_nodes(&self) -> u64

Minimum nodes needed: 3f + 1

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V