2018-07-16 06:31:21 -07:00
|
|
|
#![deny(unused_must_use)]
|
2018-07-09 05:29:01 -07:00
|
|
|
//! Network tests for Queueing Honey Badger.
|
|
|
|
|
2018-07-10 08:29:31 -07:00
|
|
|
extern crate env_logger;
|
2018-07-09 05:29:01 -07:00
|
|
|
extern crate hbbft;
|
2018-07-15 03:12:27 -07:00
|
|
|
extern crate itertools;
|
2018-07-09 05:29:01 -07:00
|
|
|
extern crate log;
|
|
|
|
extern crate rand;
|
2018-07-05 09:20:53 -07:00
|
|
|
extern crate rand_derive;
|
2018-10-29 07:36:56 -07:00
|
|
|
extern crate serde_derive;
|
2018-07-30 05:39:27 -07:00
|
|
|
extern crate threshold_crypto as crypto;
|
2018-07-09 05:29:01 -07:00
|
|
|
|
|
|
|
mod network;
|
|
|
|
|
|
|
|
use std::collections::BTreeMap;
|
2018-10-25 08:07:52 -07:00
|
|
|
use std::iter;
|
2018-07-11 12:15:08 -07:00
|
|
|
use std::sync::Arc;
|
2018-07-09 05:29:01 -07:00
|
|
|
|
2018-10-11 06:33:03 -07:00
|
|
|
use itertools::Itertools;
|
2018-10-29 07:36:56 -07:00
|
|
|
use log::info;
|
2018-10-11 06:33:03 -07:00
|
|
|
use rand::{Isaac64Rng, Rng};
|
|
|
|
|
2018-07-17 06:54:12 -07:00
|
|
|
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
|
2018-10-23 22:18:18 -07:00
|
|
|
use hbbft::queueing_honey_badger::{
|
2018-10-25 08:07:52 -07:00
|
|
|
Batch, Change, ChangeState, Input, NodeChange, QueueingHoneyBadger,
|
2018-10-23 22:18:18 -07:00
|
|
|
};
|
2018-10-25 08:07:52 -07:00
|
|
|
use hbbft::sender_queue::{Message, SenderQueue, Step};
|
2018-10-10 07:11:27 -07:00
|
|
|
use hbbft::NetworkInfo;
|
2018-07-09 05:29:01 -07:00
|
|
|
|
2018-08-29 09:08:35 -07:00
|
|
|
use network::{Adversary, MessageScheduler, NodeId, SilentAdversary, TestNetwork, TestNode};
|
2018-07-09 05:29:01 -07:00
|
|
|
|
2018-10-25 08:07:52 -07:00
|
|
|
type QHB = SenderQueue<QueueingHoneyBadger<usize, NodeId, Vec<usize>>>;
|
2018-10-11 06:33:03 -07:00
|
|
|
|
2018-07-09 05:29:01 -07:00
|
|
|
/// Proposes `num_txs` values and expects nodes to output and order them.
|
2018-10-11 06:33:03 -07:00
|
|
|
fn test_queueing_honey_badger<A>(mut network: TestNetwork<A, QHB>, num_txs: usize)
|
|
|
|
where
|
|
|
|
A: Adversary<QHB>,
|
2018-07-09 05:29:01 -07:00
|
|
|
{
|
|
|
|
// The second half of the transactions will be input only after a node has been removed.
|
2018-10-23 22:18:18 -07:00
|
|
|
network.input_all(Input::Change(Change::NodeChange(NodeChange::Remove(
|
|
|
|
NodeId(0),
|
|
|
|
))));
|
2018-07-09 05:29:01 -07:00
|
|
|
for tx in 0..(num_txs / 2) {
|
|
|
|
network.input_all(Input::User(tx));
|
|
|
|
}
|
|
|
|
|
2018-10-11 06:33:03 -07:00
|
|
|
fn has_remove(node: &TestNode<QHB>) -> bool {
|
2018-10-23 22:18:18 -07:00
|
|
|
node.outputs().iter().any(|batch| {
|
|
|
|
*batch.change()
|
|
|
|
== ChangeState::Complete(Change::NodeChange(NodeChange::Remove(NodeId(0))))
|
|
|
|
})
|
2018-07-09 05:29:01 -07:00
|
|
|
}
|
|
|
|
|
2018-10-11 06:33:03 -07:00
|
|
|
fn has_add(node: &TestNode<QHB>) -> bool {
|
2018-07-15 03:56:29 -07:00
|
|
|
node.outputs().iter().any(|batch| match *batch.change() {
|
2018-10-23 22:18:18 -07:00
|
|
|
ChangeState::Complete(Change::NodeChange(NodeChange::Add(ref id, _))) => {
|
|
|
|
*id == NodeId(0)
|
|
|
|
}
|
2018-07-09 05:29:01 -07:00
|
|
|
_ => false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns `true` if the node has not output all transactions yet.
|
|
|
|
// If it has, and has advanced another epoch, it clears all messages for later epochs.
|
2018-10-11 06:33:03 -07:00
|
|
|
let node_busy = |node: &mut TestNode<QHB>| {
|
2018-07-09 05:29:01 -07:00
|
|
|
if !has_remove(node) || !has_add(node) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-07-15 03:12:27 -07:00
|
|
|
if node.outputs().iter().flat_map(Batch::iter).unique().count() < num_txs {
|
2018-07-09 05:29:01 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut input_add = false;
|
|
|
|
// Handle messages in random order until all nodes have output all transactions.
|
|
|
|
while network.nodes.values_mut().any(node_busy) {
|
|
|
|
network.step();
|
|
|
|
if !input_add && network.nodes.values().all(has_remove) {
|
|
|
|
for tx in (num_txs / 2)..num_txs {
|
|
|
|
network.input_all(Input::User(tx));
|
|
|
|
}
|
2018-08-29 09:08:35 -07:00
|
|
|
let pk = network.nodes[&NodeId(0)]
|
2018-07-17 06:54:12 -07:00
|
|
|
.instance()
|
2018-10-25 08:07:52 -07:00
|
|
|
.algo()
|
2018-07-17 06:54:12 -07:00
|
|
|
.dyn_hb()
|
|
|
|
.netinfo()
|
|
|
|
.secret_key()
|
|
|
|
.public_key();
|
2018-10-23 22:18:18 -07:00
|
|
|
network.input_all(Input::Change(Change::NodeChange(NodeChange::Add(
|
|
|
|
NodeId(0),
|
|
|
|
pk,
|
|
|
|
))));
|
2018-07-09 05:29:01 -07:00
|
|
|
input_add = true;
|
|
|
|
}
|
|
|
|
}
|
2018-10-10 06:05:04 -07:00
|
|
|
network.verify_batches();
|
2018-07-09 05:29:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allow passing `netinfo` by value. `TestNetwork` expects this function signature.
|
|
|
|
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
|
2018-10-25 08:07:52 -07:00
|
|
|
fn new_queueing_hb(
|
|
|
|
netinfo: Arc<NetworkInfo<NodeId>>,
|
|
|
|
) -> (QHB, Step<QueueingHoneyBadger<usize, NodeId, Vec<usize>>>) {
|
|
|
|
let observer = NodeId(netinfo.num_nodes());
|
|
|
|
let our_id = *netinfo.our_id();
|
|
|
|
let peer_ids = netinfo
|
|
|
|
.all_ids()
|
|
|
|
.filter(|&&them| them != our_id)
|
|
|
|
.cloned()
|
|
|
|
.chain(iter::once(observer));
|
|
|
|
let dhb = DynamicHoneyBadger::builder().build((*netinfo).clone());
|
2018-10-11 06:33:03 -07:00
|
|
|
let rng = rand::thread_rng().gen::<Isaac64Rng>();
|
2018-10-25 08:07:52 -07:00
|
|
|
let (qhb, qhb_step) = QueueingHoneyBadger::builder(dhb).batch_size(3).build(rng);
|
|
|
|
let (sq, mut step) = SenderQueue::builder(qhb, peer_ids).build(our_id);
|
|
|
|
step.extend_with(qhb_step, Message::from);
|
|
|
|
(sq, step)
|
2018-07-09 05:29:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn test_queueing_honey_badger_different_sizes<A, F>(new_adversary: F, num_txs: usize)
|
|
|
|
where
|
2018-10-11 06:33:03 -07:00
|
|
|
A: Adversary<QHB>,
|
2018-08-29 09:08:35 -07:00
|
|
|
F: Fn(usize, usize, BTreeMap<NodeId, Arc<NetworkInfo<NodeId>>>) -> A,
|
2018-07-09 05:29:01 -07:00
|
|
|
{
|
|
|
|
// This returns an error in all but the first test.
|
|
|
|
let _ = env_logger::try_init();
|
|
|
|
|
|
|
|
let mut rng = rand::thread_rng();
|
2018-07-12 08:53:12 -07:00
|
|
|
let sizes = vec![3, 5, rng.gen_range(6, 10)];
|
2018-07-09 05:29:01 -07:00
|
|
|
for size in sizes {
|
|
|
|
// The test is removing one correct node, so we allow fewer faulty ones.
|
|
|
|
let num_adv_nodes = (size - 2) / 3;
|
|
|
|
let num_good_nodes = size - num_adv_nodes;
|
|
|
|
info!(
|
|
|
|
"Network size: {} good nodes, {} faulty nodes",
|
|
|
|
num_good_nodes, num_adv_nodes
|
|
|
|
);
|
|
|
|
let adversary = |adv_nodes| new_adversary(num_good_nodes, num_adv_nodes, adv_nodes);
|
2018-07-21 01:18:08 -07:00
|
|
|
let network =
|
|
|
|
TestNetwork::new_with_step(num_good_nodes, num_adv_nodes, adversary, new_queueing_hb);
|
2018-07-09 05:29:01 -07:00
|
|
|
test_queueing_honey_badger(network, num_txs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_queueing_honey_badger_random_delivery_silent() {
|
|
|
|
let new_adversary = |_: usize, _: usize, _| SilentAdversary::new(MessageScheduler::Random);
|
2018-07-12 08:53:12 -07:00
|
|
|
test_queueing_honey_badger_different_sizes(new_adversary, 30);
|
2018-07-09 05:29:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_queueing_honey_badger_first_delivery_silent() {
|
|
|
|
let new_adversary = |_: usize, _: usize, _| SilentAdversary::new(MessageScheduler::First);
|
2018-07-12 08:53:12 -07:00
|
|
|
test_queueing_honey_badger_different_sizes(new_adversary, 30);
|
2018-07-09 05:29:01 -07:00
|
|
|
}
|