hbbft/tests/agreement.rs

113 lines
3.7 KiB
Rust
Raw Normal View History

#![deny(unused_must_use)]
2018-05-14 03:50:00 -07:00
//! Tests of the Binary Byzantine Agreement protocol. Only one proposer instance
//! is tested. Each of the nodes in the simulated network run only one instance
//! of Agreement. This way we only test correctness of the protocol and not
//! message dispatch between multiple proposers.
//!
//! There are three properties that are tested:
//!
//! - Agreement: If any correct node outputs the bit b, then every correct node outputs b.
//!
//! - Termination: If all correct nodes receive input, then every correct node outputs a bit.
//!
//! - Validity: If any correct node outputs b, then at least one correct node received b as input.
//!
//! TODO: Implement adversaries and send BVAL messages at different times.
extern crate env_logger;
extern crate hbbft;
#[macro_use]
extern crate log;
extern crate pairing;
extern crate rand;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate rand_derive;
extern crate threshold_crypto as crypto;
mod network;
use std::iter::once;
use std::sync::Arc;
use rand::Rng;
use hbbft::agreement::Agreement;
use hbbft::messaging::NetworkInfo;
2018-08-29 09:08:35 -07:00
use network::{Adversary, MessageScheduler, NodeId, SilentAdversary, TestNetwork, TestNode};
2018-08-29 09:08:35 -07:00
fn test_agreement<A: Adversary<Agreement<NodeId>>>(
mut network: TestNetwork<A, Agreement<NodeId>>,
input: Option<bool>,
) {
2018-08-29 09:08:35 -07:00
let ids: Vec<NodeId> = network.nodes.keys().cloned().collect();
for id in ids {
network.input(id, input.unwrap_or_else(rand::random));
}
// Handle messages in random order until all nodes have output the proposed value.
while !network.nodes.values().all(TestNode::terminated) {
network.step();
}
// Verify that all instances output the same value.
let mut expected = input;
for node in network.nodes.values() {
if let Some(b) = expected {
assert!(once(&b).eq(node.outputs()));
} else {
assert_eq!(1, node.outputs().len());
expected = Some(node.outputs()[0]);
}
}
assert!(expected.iter().eq(network.observer.outputs()));
}
fn test_agreement_different_sizes<A, F>(new_adversary: F)
where
2018-08-29 09:08:35 -07:00
A: Adversary<Agreement<NodeId>>,
F: Fn(usize, usize) -> A,
{
// This returns an error in all but the first test.
let _ = env_logger::try_init();
let mut rng = rand::thread_rng();
let sizes = (1..6)
.chain(once(rng.gen_range(6, 20)))
.chain(once(rng.gen_range(30, 50)));
for size in sizes {
let num_faulty_nodes = (size - 1) / 3;
let num_good_nodes = size - num_faulty_nodes;
for &input in &[None, Some(false), Some(true)] {
info!(
"Test start: {} good nodes and {} faulty nodes, input: {:?}",
num_good_nodes, num_faulty_nodes, input
);
let adversary = |_| new_adversary(num_good_nodes, num_faulty_nodes);
2018-08-29 09:08:35 -07:00
let new_agreement = |netinfo: Arc<NetworkInfo<NodeId>>| {
Agreement::new(netinfo, 0, NodeId(0)).expect("agreement instance")
};
let network =
TestNetwork::new(num_good_nodes, num_faulty_nodes, adversary, new_agreement);
test_agreement(network, input);
info!(
"Test success: {} good nodes and {} faulty nodes, input: {:?}",
num_good_nodes, num_faulty_nodes, input
);
}
}
}
2018-06-12 11:36:50 -07:00
#[test]
fn test_agreement_random_silent() {
let new_adversary = |_: usize, _: usize| SilentAdversary::new(MessageScheduler::Random);
test_agreement_different_sizes(new_adversary);
}
#[test]
fn test_agreement_first_silent() {
let new_adversary = |_: usize, _: usize| SilentAdversary::new(MessageScheduler::First);
test_agreement_different_sizes(new_adversary);
}