#![deny(unused_must_use)]
pub mod net;
use std::iter::once;
use std::sync::Arc;
use std::time;
use proptest::arbitrary::any;
use proptest::{prelude::ProptestConfig, prop_compose, proptest, proptest_helper};
use rand::{Rng, SeedableRng};
use hbbft::binary_agreement::BinaryAgreement;
use hbbft::ConsensusProtocol;
use crate::net::adversary::{Adversary, ReorderingAdversary};
use crate::net::proptest::{gen_seed, NetworkDimension, TestRng, TestRngSeed};
use crate::net::{NetBuilder, NewNodeInfo, VirtualNet};
#[derive(Debug)]
struct TestConfig {
dimension: NetworkDimension,
seed: TestRngSeed,
input: Option<bool>,
}
prop_compose! {
fn arb_config()
(
dimension in NetworkDimension::range(1, 50),
seed in gen_seed(),
input in any::<Option<bool>>(),
) -> TestConfig
{
TestConfig { dimension, seed, input }
}
}
proptest! {
#![proptest_config(ProptestConfig {
cases: 1, .. ProptestConfig::default()
})]
#[test]
#[allow(clippy::unnecessary_operation)]
fn run_binary_agreement(cfg in arb_config()) {
binary_agreement(cfg)
}
}
type NodeId = u16;
impl<A> VirtualNet<BinaryAgreement<NodeId, u8>, A>
where
A: Adversary<BinaryAgreement<NodeId, u8>>,
{
fn test_binary_agreement<R>(&mut self, input: Option<bool>, mut rng: R)
where
R: Rng + 'static,
{
let ids: Vec<NodeId> = self.nodes().map(|n| *n.id()).collect();
for id in ids {
let _ = self.send_input(id, input.unwrap_or_else(|| rng.gen::<bool>()), &mut rng);
}
while !self.nodes().all(|node| node.algorithm().terminated()) {
let _ = self.crank_expect(&mut rng);
}
let mut expected = input;
for node in self.nodes() {
if let Some(b) = expected {
assert!(once(&b).eq(node.outputs()));
} else {
assert_eq!(1, node.outputs().len());
expected = Some(node.outputs()[0]);
}
}
}
}
#[allow(clippy::needless_pass_by_value)]
fn binary_agreement(cfg: TestConfig) {
let mut rng: TestRng = TestRng::from_seed(cfg.seed);
let size = cfg.dimension.size();
let num_faulty_nodes = cfg.dimension.faulty();
let num_good_nodes = size - num_faulty_nodes;
println!(
"Test start: {} good nodes and {} faulty nodes, input: {:?}",
num_good_nodes, num_faulty_nodes, cfg.input
);
let (mut net, _) = NetBuilder::new(0..size as u16)
.num_faulty(num_faulty_nodes as usize)
.message_limit(10_000 * size as usize)
.time_limit(time::Duration::from_secs(30 * size as u64))
.adversary(ReorderingAdversary::new())
.using(move |node_info: NewNodeInfo<_>| {
BinaryAgreement::new(Arc::new(node_info.netinfo), 0)
.expect("Failed to create a BinaryAgreement instance.")
})
.build(&mut rng)
.expect("Could not construct test network.");
net.test_binary_agreement(cfg.input, TestRng::from_seed(rng.gen::<TestRngSeed>()));
println!(
"Test success: {} good nodes and {} faulty nodes, input: {:?}",
num_good_nodes, num_faulty_nodes, cfg.input
);
}