2018-05-15 04:49:39 -07:00
|
|
|
//! Integration tests of the Asynchronous Common Subset protocol.
|
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
extern crate env_logger;
|
2018-05-15 04:49:39 -07:00
|
|
|
extern crate hbbft;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
2018-05-18 14:04:09 -07:00
|
|
|
extern crate rand;
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
mod network;
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
use std::collections::{BTreeMap, BTreeSet};
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
use hbbft::common_subset::CommonSubset;
|
|
|
|
use hbbft::messaging::DistAlgorithm;
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
use network::{Adversary, MessageScheduler, NodeUid, SilentAdversary, TestNetwork};
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
type ProposedValue = Vec<u8>;
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
fn test_common_subset<A: Adversary<CommonSubset<NodeUid>>>(
|
|
|
|
mut network: TestNetwork<A, CommonSubset<NodeUid>>,
|
|
|
|
inputs: &BTreeMap<NodeUid, ProposedValue>,
|
|
|
|
) {
|
|
|
|
let ids: Vec<NodeUid> = network.nodes.keys().cloned().collect();
|
|
|
|
let mut decided_nodes: BTreeSet<NodeUid> = BTreeSet::new();
|
2018-05-15 04:49:39 -07:00
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
for id in ids {
|
|
|
|
if let Some(value) = inputs.get(&id) {
|
|
|
|
network.input(id, value.to_owned());
|
2018-05-15 04:49:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
// Terminate when all good nodes do.
|
|
|
|
while network
|
|
|
|
.nodes
|
|
|
|
.values()
|
|
|
|
.any(|node| network.adv_nodes.contains(&node.algo.our_id()) || node.algo.terminated())
|
|
|
|
{
|
|
|
|
let id = network.step();
|
|
|
|
if let Some(output) = network.nodes[&id].outputs().iter().next() {
|
|
|
|
assert_eq!(inputs, output);
|
|
|
|
debug!("Node {:?} decided: {:?}", id, output);
|
|
|
|
|
|
|
|
// Test uniqueness of output of the good nodes.
|
|
|
|
if !network.adv_nodes.contains(&id) {
|
|
|
|
assert!(!decided_nodes.insert(id));
|
2018-05-15 04:49:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
fn new_network<A: Adversary<CommonSubset<NodeUid>>>(
|
|
|
|
good_num: usize,
|
|
|
|
bad_num: usize,
|
|
|
|
adversary: A,
|
|
|
|
) -> TestNetwork<A, CommonSubset<NodeUid>> {
|
|
|
|
// This returns an error in all but the first test.
|
2018-05-15 04:49:39 -07:00
|
|
|
let _ = env_logger::try_init();
|
|
|
|
|
2018-05-18 14:04:09 -07:00
|
|
|
let new_common_subset = |id, all_ids: BTreeSet<_>| {
|
|
|
|
CommonSubset::new(id, &all_ids).expect("new Common Subset instance")
|
|
|
|
};
|
|
|
|
TestNetwork::new(good_num, bad_num, adversary, new_common_subset)
|
2018-05-15 04:49:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2018-05-17 02:43:56 -07:00
|
|
|
fn test_common_subset_3_out_of_4_nodes_propose() {
|
2018-05-15 04:49:39 -07:00
|
|
|
let proposed_value = Vec::from("Fake news");
|
2018-05-18 14:04:09 -07:00
|
|
|
let proposing_ids: BTreeSet<NodeUid> = (0..3).map(NodeUid).collect();
|
|
|
|
let proposals: BTreeMap<NodeUid, ProposedValue> = proposing_ids
|
2018-05-15 10:18:05 -07:00
|
|
|
.iter()
|
2018-05-15 14:25:41 -07:00
|
|
|
.map(|id| (*id, proposed_value.clone()))
|
2018-05-15 10:18:05 -07:00
|
|
|
.collect();
|
2018-05-18 14:04:09 -07:00
|
|
|
let adversary = SilentAdversary::new(MessageScheduler::First);
|
|
|
|
let network = new_network(3, 1, adversary);
|
|
|
|
test_common_subset(network, &proposals);
|
2018-05-15 04:49:39 -07:00
|
|
|
}
|
2018-05-16 03:21:53 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_common_subset_5_nodes_different_proposed_values() {
|
|
|
|
let proposed_values = vec![
|
|
|
|
Vec::from("Alpha"),
|
|
|
|
Vec::from("Bravo"),
|
|
|
|
Vec::from("Charlie"),
|
|
|
|
Vec::from("Delta"),
|
|
|
|
Vec::from("Echo"),
|
|
|
|
];
|
2018-05-18 14:04:09 -07:00
|
|
|
let proposals: BTreeMap<NodeUid, ProposedValue> = (0..5)
|
|
|
|
.into_iter()
|
|
|
|
.map(NodeUid)
|
|
|
|
.zip(proposed_values)
|
2018-05-16 03:21:53 -07:00
|
|
|
.collect();
|
2018-05-18 14:04:09 -07:00
|
|
|
let adversary = SilentAdversary::new(MessageScheduler::Random);
|
|
|
|
let network = new_network(5, 0, adversary);
|
|
|
|
test_common_subset(network, &proposals);
|
2018-05-16 03:21:53 -07:00
|
|
|
}
|