use vrf_pbft::{Config, ConsensusEngine, Error, Node};
#[test]
fn four_node_consensus() {
let config = Config::new(1);
let mut engine = ConsensusEngine::new(config);
for i in 1..=4 {
engine.add_node(Node::new(i, 1000).unwrap());
}
let blocks = engine.run(50).unwrap();
assert!(
!blocks.is_empty(),
"should commit at least one block in 50 rounds"
);
let first_len = engine.nodes()[0].ledger().len();
assert!(engine.nodes().iter().all(|n| n.ledger().len() == first_len));
}
#[test]
fn not_enough_nodes_errors() {
let config = Config::new(1); let mut engine = ConsensusEngine::new(config);
engine.add_node(Node::new(1, 100).unwrap());
match engine.run_round() {
Err(Error::NotEnoughNodes { needed: 4, have: 1 }) => {}
other => panic!("expected NotEnoughNodes, got {:?}", other),
}
}
#[test]
fn byzantine_nodes_cannot_prevent_consensus() {
let config = Config::new(2); let mut engine = ConsensusEngine::new(config);
for i in 1..=7 {
let mut node = Node::new(i, 1000).unwrap();
if i <= 2 {
node.set_byzantine(true);
}
engine.add_node(node);
}
let blocks = engine.run(200).unwrap();
assert!(
!blocks.is_empty(),
"should reach consensus despite 2 byzantine nodes in 200 rounds"
);
}
#[test]
fn committed_blocks_form_chain() {
let config = Config::new(1);
let mut engine = ConsensusEngine::new(config);
for i in 1..=4 {
engine.add_node(Node::new(i, 1000).unwrap());
}
let blocks = engine.run(100).unwrap();
if blocks.len() >= 2 {
for window in blocks.windows(2) {
assert_eq!(
window[1].prev_hash,
window[0].hash(),
"block chain is broken at round {}",
window[1].round
);
}
}
}
#[test]
fn run_returns_correct_count() {
let config = Config::new(1);
let mut engine = ConsensusEngine::new(config);
for i in 1..=4 {
engine.add_node(Node::new(i, 1000).unwrap());
}
let blocks = engine.run(30).unwrap();
assert_eq!(blocks.len(), engine.committed_blocks().len());
}