pub struct Node { /* private fields */ }Implementations§
Source§impl Node
impl Node
Sourcepub fn new(id: NodeId, weight: u64) -> Result<Self>
pub fn new(id: NodeId, weight: u64) -> Result<Self>
Examples found in repository?
examples/single_round.rs (line 8)
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 9)
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 11)
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 id(&self) -> NodeId
pub fn weight(&self) -> u64
pub fn role(&self) -> Role
pub fn seed(&self) -> u64
Sourcepub fn ledger(&self) -> &[Block]
pub fn ledger(&self) -> &[Block]
Examples found in repository?
examples/byzantine.rs (line 34)
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}More examples
examples/simulation.rs (line 52)
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 public_key(&self) -> &[u8] ⓘ
pub fn is_byzantine(&self) -> bool
Sourcepub fn set_byzantine(&mut self, byzantine: bool)
pub fn set_byzantine(&mut self, byzantine: bool)
Examples found in repository?
examples/byzantine.rs (line 12)
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}Sourcepub fn assign_role(
&mut self,
round_num: u64,
total_weight: u64,
role_expected: &[(Role, u64)],
) -> Result<Role>
pub fn assign_role( &mut self, round_num: u64, total_weight: u64, role_expected: &[(Role, u64)], ) -> Result<Role>
Use VRF sortition to determine this node’s role for a round. Checks roles in order: Proposer, Validator, Packer. First role selected wins; otherwise Normal.
Sourcepub fn propose_block(&self, round_num: u64) -> Result<Block>
pub fn propose_block(&self, round_num: u64) -> Result<Block>
Propose a new block for this round. Only valid for Proposers.
Sourcepub fn validate_block(&self, block: &Block) -> bool
pub fn validate_block(&self, block: &Block) -> bool
Validate a proposed block. Byzantine nodes always reject.
Sourcepub fn commit_block(&mut self, block: Block)
pub fn commit_block(&mut self, block: Block)
Commit a finalized block to the local ledger.
pub fn start_round(&mut self, round_num: u64, threshold: u64)
Auto Trait Implementations§
impl Freeze for Node
impl RefUnwindSafe for Node
impl Send for Node
impl Sync for Node
impl Unpin for Node
impl UnsafeUnpin for Node
impl UnwindSafe for Node
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