mirror of https://github.com/poanetwork/hbbft.git
Remove NetworkInfo from Broadcast.
This commit is contained in:
parent
8ee999b73f
commit
d15467eb09
|
@ -32,7 +32,7 @@
|
|||
//! the consensus `result` is not an error then every successfully terminated
|
||||
//! consensus node will be the same `result`.
|
||||
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::{Send, Sync};
|
||||
use std::net::SocketAddr;
|
||||
|
@ -45,8 +45,7 @@ use log::{debug, error};
|
|||
use crate::network::messaging::Messaging;
|
||||
use crate::network::{commst, connection};
|
||||
use hbbft::broadcast::{Broadcast, Message};
|
||||
use hbbft::crypto::{poly::Poly, SecretKey, SecretKeySet};
|
||||
use hbbft::{ConsensusProtocol, NetworkInfo, SourcedMessage};
|
||||
use hbbft::{ConsensusProtocol, SourcedMessage};
|
||||
|
||||
/// This is a structure to start a consensus node.
|
||||
pub struct Node<T> {
|
||||
|
@ -79,29 +78,14 @@ impl<T: Clone + Debug + AsRef<[u8]> + PartialEq + Send + Sync + From<Vec<u8>> +
|
|||
.collect();
|
||||
node_strs.sort();
|
||||
let our_id = node_strs.binary_search(&our_str).unwrap();
|
||||
let all_ids: BTreeSet<_> = (0..node_strs.len()).collect();
|
||||
|
||||
// FIXME: This example doesn't call algorithms that use cryptography. However the keys are
|
||||
// required by the interface to all algorithms in Honey Badger. Therefore we set placeholder
|
||||
// keys here. A fully-featured application would need to take appropriately initialized keys
|
||||
// from elsewhere.
|
||||
let secret_key_set = SecretKeySet::from(Poly::zero());
|
||||
let sk_share = secret_key_set.secret_key_share(our_id);
|
||||
let pub_key_set = secret_key_set.public_keys();
|
||||
let sk = SecretKey::default();
|
||||
let pub_keys = all_ids
|
||||
.iter()
|
||||
.map(|id| (*id, SecretKey::default().public_key()))
|
||||
.collect();
|
||||
|
||||
let netinfo = NetworkInfo::new(our_id, sk_share, pub_key_set, sk, pub_keys);
|
||||
let num_nodes = node_strs.len();
|
||||
|
||||
if value.is_some() != (our_id == 0) {
|
||||
panic!("Exactly the first node must propose a value.");
|
||||
}
|
||||
|
||||
// Initialise the message delivery system and obtain TX and RX handles.
|
||||
let messaging: Messaging<Message> = Messaging::new(all_ids.len());
|
||||
let messaging: Messaging<Message> = Messaging::new(num_nodes);
|
||||
let rxs_to_comms = messaging.rxs_to_comms();
|
||||
let tx_from_comms = messaging.tx_from_comms();
|
||||
let rx_to_algo = messaging.rx_to_algo();
|
||||
|
@ -120,8 +104,9 @@ impl<T: Clone + Debug + AsRef<[u8]> + PartialEq + Send + Sync + From<Vec<u8>> +
|
|||
// corresponding to this instance, and no dedicated comms task. The
|
||||
// node index is 0.
|
||||
let broadcast_handle = scope.spawn(move |_| {
|
||||
let mut broadcast =
|
||||
Broadcast::new(Arc::new(netinfo), 0).expect("failed to instantiate broadcast");
|
||||
let validators = (0..num_nodes).into();
|
||||
let mut broadcast = Broadcast::new(our_id, Arc::new(validators), 0)
|
||||
.expect("failed to instantiate broadcast");
|
||||
|
||||
if let Some(v) = value {
|
||||
// FIXME: Use the output.
|
||||
|
|
|
@ -14,15 +14,18 @@ use super::merkle::{Digest, MerkleTree, Proof};
|
|||
use super::message::HexProof;
|
||||
use super::{Error, FaultKind, Message, Result};
|
||||
use crate::fault_log::Fault;
|
||||
use crate::{ConsensusProtocol, NetworkInfo, NodeIdT, Target};
|
||||
use crate::{ConsensusProtocol, NodeIdT, Target, ValidatorSet};
|
||||
|
||||
type RseResult<T> = result::Result<T, rse::Error>;
|
||||
|
||||
/// Broadcast algorithm instance.
|
||||
#[derive(Debug)]
|
||||
pub struct Broadcast<N> {
|
||||
/// Shared network data.
|
||||
netinfo: Arc<NetworkInfo<N>>,
|
||||
/// Our ID.
|
||||
// TODO: Make optional for observers?
|
||||
our_id: N,
|
||||
/// The set of validator IDs.
|
||||
val_set: Arc<ValidatorSet<N>>,
|
||||
/// The ID of the sending node.
|
||||
proposer_id: N,
|
||||
/// The Reed-Solomon erasure coding configuration.
|
||||
|
@ -40,6 +43,7 @@ pub struct Broadcast<N> {
|
|||
/// Whether we have already output a value.
|
||||
decided: bool,
|
||||
/// Number of faulty nodes to optimize performance for.
|
||||
// TODO: Make this configurable: Allow numbers between 0 and N/3?
|
||||
fault_estimate: usize,
|
||||
/// The hashes and proofs we have received via `Echo` and `EchoHash` messages, by sender ID.
|
||||
echos: BTreeMap<N, EchoContent>,
|
||||
|
@ -79,22 +83,27 @@ impl<N: NodeIdT> ConsensusProtocol for Broadcast<N> {
|
|||
}
|
||||
|
||||
fn our_id(&self) -> &N {
|
||||
self.netinfo.our_id()
|
||||
&self.our_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: NodeIdT> Broadcast<N> {
|
||||
/// Creates a new broadcast instance to be used by node `our_id` which expects a value proposal
|
||||
/// from node `proposer_id`.
|
||||
pub fn new(netinfo: Arc<NetworkInfo<N>>, proposer_id: N) -> Result<Self> {
|
||||
let parity_shard_num = 2 * netinfo.num_faulty();
|
||||
let data_shard_num = netinfo.num_nodes() - parity_shard_num;
|
||||
pub fn new<V>(our_id: N, val_set: V, proposer_id: N) -> Result<Self>
|
||||
where
|
||||
V: Into<Arc<ValidatorSet<N>>>,
|
||||
{
|
||||
let val_set: Arc<ValidatorSet<N>> = val_set.into();
|
||||
let parity_shard_num = 2 * val_set.num_faulty();
|
||||
let data_shard_num = val_set.num() - parity_shard_num;
|
||||
let coding =
|
||||
Coding::new(data_shard_num, parity_shard_num).map_err(|_| Error::InvalidNodeCount)?;
|
||||
let fault_estimate = netinfo.num_faulty();
|
||||
let fault_estimate = val_set.num_faulty();
|
||||
|
||||
Ok(Broadcast {
|
||||
netinfo,
|
||||
our_id,
|
||||
val_set,
|
||||
proposer_id,
|
||||
coding,
|
||||
value_sent: false,
|
||||
|
@ -131,7 +140,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
///
|
||||
/// This must be called with every message we receive from another node.
|
||||
pub fn handle_message(&mut self, sender_id: &N, message: Message) -> Result<Step<N>> {
|
||||
if !self.netinfo.is_node_validator(sender_id) {
|
||||
if !self.val_set.contains(sender_id) {
|
||||
return Err(Error::UnknownSender);
|
||||
}
|
||||
match message {
|
||||
|
@ -148,6 +157,11 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
&self.proposer_id
|
||||
}
|
||||
|
||||
/// Returns the set of all validator IDs.
|
||||
pub fn validator_set(&self) -> &Arc<ValidatorSet<N>> {
|
||||
&self.val_set
|
||||
}
|
||||
|
||||
/// Breaks the input value into shards of equal length and encodes them --
|
||||
/// and some extra parity shards -- with a Reed-Solomon erasure coding
|
||||
/// scheme. The returned value contains the shard assigned to this
|
||||
|
@ -191,12 +205,12 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
|
||||
// Default result in case of `proof` error.
|
||||
let mut result = Err(Error::ProofConstructionFailed);
|
||||
assert_eq!(self.netinfo.num_nodes(), mtree.values().len());
|
||||
assert_eq!(self.val_set.num(), mtree.values().len());
|
||||
|
||||
let mut step = Step::default();
|
||||
// Send each proof to a node.
|
||||
for (index, id) in self.netinfo.all_ids().enumerate() {
|
||||
let proof = mtree.proof(index).ok_or(Error::ProofConstructionFailed)?;
|
||||
for (id, index) in self.val_set.all_indices() {
|
||||
let proof = mtree.proof(*index).ok_or(Error::ProofConstructionFailed)?;
|
||||
if *id == *self.our_id() {
|
||||
// The proof is addressed to this node.
|
||||
result = Ok(proof);
|
||||
|
@ -293,7 +307,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
}
|
||||
|
||||
// Upon receiving `N - f` `Echo`s with this root hash, multicast `Ready`.
|
||||
if !self.ready_sent && self.count_echos(&hash) >= self.netinfo.num_correct() {
|
||||
if !self.ready_sent && self.count_echos(&hash) >= self.val_set.num_correct() {
|
||||
step.extend(self.send_ready(&hash)?);
|
||||
}
|
||||
|
||||
|
@ -333,7 +347,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
self.echos
|
||||
.insert(sender_id.clone(), EchoContent::Hash(*hash));
|
||||
|
||||
if self.ready_sent || self.count_echos(&hash) < self.netinfo.num_correct() {
|
||||
if self.ready_sent || self.count_echos(&hash) < self.val_set.num_correct() {
|
||||
return self.compute_output(&hash);
|
||||
}
|
||||
// Upon receiving `N - f` `Echo`s with this root hash, multicast `Ready`.
|
||||
|
@ -382,13 +396,13 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
let mut step = Step::default();
|
||||
// Upon receiving f + 1 matching Ready(h) messages, if Ready
|
||||
// has not yet been sent, multicast Ready(h).
|
||||
if self.count_readys(hash) == self.netinfo.num_faulty() + 1 && !self.ready_sent {
|
||||
if self.count_readys(hash) == self.val_set.num_faulty() + 1 && !self.ready_sent {
|
||||
// Enqueue a broadcast of a Ready message.
|
||||
step.extend(self.send_ready(hash)?);
|
||||
}
|
||||
// Upon receiving 2f + 1 matching Ready(h) messages, send full
|
||||
// `Echo` message to every node who hasn't sent us a `CanDecode`
|
||||
if self.count_readys(hash) == 2 * self.netinfo.num_faulty() + 1 {
|
||||
if self.count_readys(hash) == 2 * self.val_set.num_faulty() + 1 {
|
||||
step.extend(self.send_echo_remaining(hash)?);
|
||||
}
|
||||
|
||||
|
@ -397,7 +411,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
|
||||
/// Sends `Echo` message to all left nodes and handles it.
|
||||
fn send_echo_left(&mut self, p: Proof<Vec<u8>>) -> Result<Step<N>> {
|
||||
if !self.netinfo.is_validator() {
|
||||
if !self.val_set.contains(&self.our_id) {
|
||||
return Ok(Step::default());
|
||||
}
|
||||
let echo_msg = Message::Echo(p.clone());
|
||||
|
@ -413,7 +427,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
/// Sends `Echo` message to remaining nodes who haven't sent `CanDecode`
|
||||
fn send_echo_remaining(&mut self, hash: &Digest) -> Result<Step<N>> {
|
||||
self.echo_sent = true;
|
||||
if !self.netinfo.is_validator() {
|
||||
if !self.val_set.contains(&self.our_id) {
|
||||
return Ok(Step::default());
|
||||
}
|
||||
|
||||
|
@ -441,7 +455,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
/// Sends an `EchoHash` message and handles it. Does nothing if we are only an observer.
|
||||
fn send_echo_hash(&mut self, hash: &Digest) -> Result<Step<N>> {
|
||||
self.echo_hash_sent = true;
|
||||
if !self.netinfo.is_validator() {
|
||||
if !self.val_set.contains(&self.our_id) {
|
||||
return Ok(Step::default());
|
||||
}
|
||||
let echo_hash_msg = Message::EchoHash(*hash);
|
||||
|
@ -462,18 +476,18 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
fn right_nodes(&self) -> impl Iterator<Item = &N> {
|
||||
let our_id = self.our_id().clone();
|
||||
let not_us = move |x: &&N| **x != our_id;
|
||||
self.netinfo
|
||||
self.val_set
|
||||
.all_ids()
|
||||
.cycle()
|
||||
.skip_while(not_us.clone())
|
||||
.skip(self.netinfo.num_correct() - self.netinfo.num_faulty() + self.fault_estimate)
|
||||
.skip(self.val_set.num_correct() - self.val_set.num_faulty() + self.fault_estimate)
|
||||
.take_while(not_us)
|
||||
}
|
||||
|
||||
/// Sends a `CanDecode` message and handles it. Does nothing if we are only an observer.
|
||||
fn send_can_decode(&mut self, hash: &Digest) -> Result<Step<N>> {
|
||||
self.can_decode_sent.insert(hash.clone());
|
||||
if !self.netinfo.is_validator() {
|
||||
if !self.val_set.contains(&self.our_id) {
|
||||
return Ok(Step::default());
|
||||
}
|
||||
|
||||
|
@ -481,7 +495,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
let mut step = Step::default();
|
||||
|
||||
let recipients = self
|
||||
.netinfo
|
||||
.val_set
|
||||
.all_ids()
|
||||
.filter(|id| match self.echos.get(id) {
|
||||
Some(EchoContent::Hash(_)) | None => true,
|
||||
|
@ -498,7 +512,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
/// Sends a `Ready` message and handles it. Does nothing if we are only an observer.
|
||||
fn send_ready(&mut self, hash: &Digest) -> Result<Step<N>> {
|
||||
self.ready_sent = true;
|
||||
if !self.netinfo.is_validator() {
|
||||
if !self.val_set.contains(&self.our_id) {
|
||||
return Ok(Step::default());
|
||||
}
|
||||
let ready_msg = Message::Ready(*hash);
|
||||
|
@ -511,7 +525,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
/// value.
|
||||
fn compute_output(&mut self, hash: &Digest) -> Result<Step<N>> {
|
||||
if self.decided
|
||||
|| self.count_readys(hash) <= 2 * self.netinfo.num_faulty()
|
||||
|| self.count_readys(hash) <= 2 * self.val_set.num_faulty()
|
||||
|| self.count_echos_full(hash) < self.coding.data_shard_count()
|
||||
{
|
||||
return Ok(Step::default());
|
||||
|
@ -519,7 +533,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
|
||||
// Upon receiving 2f + 1 matching Ready(h) messages, wait for N − 2f Echo messages.
|
||||
let mut leaf_values: Vec<Option<Box<[u8]>>> = self
|
||||
.netinfo
|
||||
.val_set
|
||||
.all_ids()
|
||||
.map(|id| {
|
||||
self.echos
|
||||
|
@ -588,7 +602,7 @@ impl<N: NodeIdT> Broadcast<N> {
|
|||
|
||||
/// Returns `true` if the proof is valid and has the same index as the node ID.
|
||||
fn validate_proof(&self, p: &Proof<Vec<u8>>, id: &N) -> bool {
|
||||
self.netinfo.node_index(id) == Some(p.index()) && p.validate(self.netinfo.num_nodes())
|
||||
self.val_set.index(id) == Some(p.index()) && p.validate(self.val_set.num())
|
||||
}
|
||||
|
||||
/// Returns the number of nodes that have sent us a full `Echo` message with this hash.
|
||||
|
|
|
@ -139,8 +139,8 @@
|
|||
//!
|
||||
//! ```
|
||||
//! use hbbft::broadcast::{Broadcast, Error, Step};
|
||||
//! use hbbft::{NetworkInfo, SourcedMessage, Target, TargetedMessage};
|
||||
//! use rand::{OsRng, Rng, RngCore};
|
||||
//! use hbbft::{ValidatorSet, SourcedMessage, Target, TargetedMessage};
|
||||
//! use rand::{rngs::OsRng, Rng, RngCore};
|
||||
//! use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||
//! use std::iter::once;
|
||||
//! use std::sync::Arc;
|
||||
|
@ -152,14 +152,12 @@
|
|||
//!
|
||||
//! let mut rng = OsRng::new().expect("Could not initialize OS random number generator.");
|
||||
//!
|
||||
//! // Create a random set of keys for testing.
|
||||
//! let netinfos = NetworkInfo::generate_map(0..NUM_NODES, &mut rng)
|
||||
//! .expect("Failed to create `NetworkInfo` map");
|
||||
//! let validators = Arc::new(ValidatorSet::from(0..NUM_NODES));
|
||||
//!
|
||||
//! // Create initial nodes by instantiating a `Broadcast` for each.
|
||||
//! let mut nodes = BTreeMap::new();
|
||||
//! for (i, netinfo) in netinfos {
|
||||
//! let bc = Broadcast::new(Arc::new(netinfo), PROPOSER_ID)?;
|
||||
//! for i in 0..NUM_NODES {
|
||||
//! let bc = Broadcast::new(i, validators.clone(), PROPOSER_ID)?;
|
||||
//! nodes.insert(i, bc);
|
||||
//! }
|
||||
//!
|
||||
|
|
|
@ -142,7 +142,7 @@ pub mod util;
|
|||
pub use crate::crypto::pairing;
|
||||
pub use crate::fault_log::{Fault, FaultLog};
|
||||
pub use crate::messaging::{SourcedMessage, Target, TargetedMessage};
|
||||
pub use crate::network_info::NetworkInfo;
|
||||
pub use crate::network_info::{NetworkInfo, ValidatorSet};
|
||||
pub use crate::traits::{
|
||||
ConsensusProtocol, Contribution, CpStep, Epoched, Message, NodeIdT, SessionIdT, Step,
|
||||
};
|
||||
|
|
|
@ -1,19 +1,92 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::crypto::{self, PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
|
||||
use rand;
|
||||
|
||||
use crate::{util, NodeIdT};
|
||||
|
||||
/// The set of all node IDs of the network's validators.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValidatorSet<N> {
|
||||
num_faulty: usize,
|
||||
indices: BTreeMap<N, usize>,
|
||||
}
|
||||
|
||||
impl<I, N> From<I> for ValidatorSet<N>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<N>,
|
||||
N: NodeIdT,
|
||||
{
|
||||
fn from(i: I) -> Self {
|
||||
let indices: BTreeMap<N, usize> = i
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(n, id)| (id.borrow().clone(), n))
|
||||
.collect();
|
||||
let num_faulty = util::max_faulty(indices.len());
|
||||
assert!(3 * num_faulty < indices.len(), "3 f >= N. This is a bug!");
|
||||
ValidatorSet {
|
||||
num_faulty,
|
||||
indices,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: NodeIdT> ValidatorSet<N> {
|
||||
/// Returns `true` if the given ID belongs to a known validator.
|
||||
#[inline]
|
||||
pub fn contains(&self, id: &N) -> bool {
|
||||
self.indices.contains_key(id)
|
||||
}
|
||||
|
||||
/// Returns the validators index in the ordered list of all IDs.
|
||||
#[inline]
|
||||
pub fn index(&self, id: &N) -> Option<usize> {
|
||||
self.indices.get(id).cloned()
|
||||
}
|
||||
|
||||
/// The total number _N_ of validators.
|
||||
#[inline]
|
||||
pub fn num(&self) -> usize {
|
||||
self.indices.len()
|
||||
}
|
||||
|
||||
/// The maximum number _f_ of faulty, Byzantine validators up to which Honey Badger is
|
||||
/// guaranteed to be correct.
|
||||
#[inline]
|
||||
pub fn num_faulty(&self) -> usize {
|
||||
self.num_faulty
|
||||
}
|
||||
|
||||
/// The minimum number _N - f_ of correct validators with which Honey Badger is guaranteed to
|
||||
/// be correct.
|
||||
#[inline]
|
||||
pub fn num_correct(&self) -> usize {
|
||||
// As asserted in `new`, `num_faulty` is never greater than `num`.
|
||||
self.num() - self.num_faulty
|
||||
}
|
||||
|
||||
/// IDs of all validators in the network.
|
||||
#[inline]
|
||||
pub fn all_ids(&self) -> impl Iterator<Item = &N> + Clone {
|
||||
self.indices.keys()
|
||||
}
|
||||
|
||||
/// IDs and indices of all validators in the network.
|
||||
#[inline]
|
||||
pub fn all_indices(&self) -> impl Iterator<Item = (&N, &usize)> + Clone {
|
||||
self.indices.iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Common data shared between algorithms: the nodes' IDs and key shares.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NetworkInfo<N> {
|
||||
/// This node's ID.
|
||||
our_id: N,
|
||||
/// The number _N_ of nodes in the network. Equal to the size of `public_keys`.
|
||||
num_nodes: usize,
|
||||
/// The number _f_ of faulty nodes that can be tolerated. Less than a third of _N_.
|
||||
num_faulty: usize,
|
||||
/// Whether this node is a validator. This is true if `public_keys` contains our own ID.
|
||||
is_validator: bool,
|
||||
/// This node's secret key share. Only validators have one.
|
||||
|
@ -27,7 +100,7 @@ pub struct NetworkInfo<N> {
|
|||
/// The validators' public keys.
|
||||
public_keys: BTreeMap<N, PublicKey>,
|
||||
/// The indices in the list of sorted validator IDs.
|
||||
node_indices: BTreeMap<N, usize>,
|
||||
val_set: Arc<ValidatorSet<N>>,
|
||||
}
|
||||
|
||||
impl<N: NodeIdT> NetworkInfo<N> {
|
||||
|
@ -47,29 +120,21 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
|||
secret_key: SecretKey,
|
||||
public_keys: BTreeMap<N, PublicKey>,
|
||||
) -> Self {
|
||||
let num_nodes = public_keys.len();
|
||||
let num_faulty = util::max_faulty(num_nodes);
|
||||
assert!(3 * num_faulty < num_nodes, " 3 f >= N. This is a bug!");
|
||||
let is_validator = public_keys.contains_key(&our_id);
|
||||
let node_indices: BTreeMap<N, usize> = public_keys
|
||||
let val_set = Arc::new(ValidatorSet::from(public_keys.keys()));
|
||||
let is_validator = val_set.contains(&our_id);
|
||||
let public_key_shares = public_keys
|
||||
.keys()
|
||||
.enumerate()
|
||||
.map(|(n, id)| (id.clone(), n))
|
||||
.collect();
|
||||
let public_key_shares = node_indices
|
||||
.iter()
|
||||
.map(|(id, idx)| (id.clone(), public_key_set.public_key_share(*idx)))
|
||||
.map(|(idx, id)| (id.clone(), public_key_set.public_key_share(idx)))
|
||||
.collect();
|
||||
NetworkInfo {
|
||||
our_id,
|
||||
num_nodes,
|
||||
num_faulty,
|
||||
is_validator,
|
||||
secret_key_share: secret_key_share.into(),
|
||||
secret_key,
|
||||
public_key_set,
|
||||
public_key_shares,
|
||||
node_indices,
|
||||
val_set,
|
||||
public_keys,
|
||||
}
|
||||
}
|
||||
|
@ -83,35 +148,34 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
|||
/// ID of all nodes in the network.
|
||||
#[inline]
|
||||
pub fn all_ids(&self) -> impl Iterator<Item = &N> + Clone {
|
||||
self.public_keys.keys()
|
||||
self.val_set.all_ids()
|
||||
}
|
||||
|
||||
/// ID of all nodes in the network except this one.
|
||||
#[inline]
|
||||
pub fn other_ids(&self) -> impl Iterator<Item = &N> + Clone {
|
||||
let our_id = self.our_id.clone();
|
||||
self.public_keys.keys().filter(move |id| **id != our_id)
|
||||
self.all_ids().filter(move |id| **id != our_id)
|
||||
}
|
||||
|
||||
/// The total number _N_ of nodes.
|
||||
#[inline]
|
||||
pub fn num_nodes(&self) -> usize {
|
||||
self.num_nodes
|
||||
self.val_set.num()
|
||||
}
|
||||
|
||||
/// The maximum number _f_ of faulty, Byzantine nodes up to which Honey Badger is guaranteed to
|
||||
/// be correct.
|
||||
#[inline]
|
||||
pub fn num_faulty(&self) -> usize {
|
||||
self.num_faulty
|
||||
self.val_set.num_faulty()
|
||||
}
|
||||
|
||||
/// The minimum number _N - f_ of correct nodes with which Honey Badger is guaranteed to be
|
||||
/// correct.
|
||||
#[inline]
|
||||
pub fn num_correct(&self) -> usize {
|
||||
// As asserted in `new`, `num_faulty` is never greater than `num_nodes`.
|
||||
self.num_nodes - self.num_faulty
|
||||
self.val_set.num_correct()
|
||||
}
|
||||
|
||||
/// Returns our secret key share for threshold cryptography, or `None` if not a validator.
|
||||
|
@ -160,7 +224,7 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
|||
/// node appears in `all_ids`.
|
||||
#[inline]
|
||||
pub fn node_index(&self, id: &N) -> Option<usize> {
|
||||
self.node_indices.get(id).cloned()
|
||||
self.val_set.index(id)
|
||||
}
|
||||
|
||||
/// Returns `true` if this node takes part in the consensus itself. If not, it is only an
|
||||
|
@ -177,6 +241,11 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
|||
self.public_keys.contains_key(id)
|
||||
}
|
||||
|
||||
/// Returns the set of validator IDs.
|
||||
pub fn validator_set(&self) -> &Arc<ValidatorSet<N>> {
|
||||
&self.val_set
|
||||
}
|
||||
|
||||
/// Generates a map of matching `NetworkInfo`s for testing.
|
||||
pub fn generate_map<I, R>(
|
||||
ids: I,
|
||||
|
|
|
@ -30,8 +30,10 @@ pub enum ProposalState<N, S> {
|
|||
impl<N: NodeIdT, S: SessionIdT> ProposalState<N, S> {
|
||||
/// Creates a new `ProposalState::Ongoing`, with a fresh broadcast and agreement instance.
|
||||
pub fn new(netinfo: Arc<NetworkInfo<N>>, ba_id: BaSessionId<S>, prop_id: N) -> Result<Self> {
|
||||
let agreement = BaInstance::new(netinfo.clone(), ba_id).map_err(Error::NewAgreement)?;
|
||||
let broadcast = Broadcast::new(netinfo, prop_id).map_err(Error::NewBroadcast)?;
|
||||
let our_id = netinfo.our_id().clone();
|
||||
let validators = netinfo.validator_set().clone();
|
||||
let agreement = BaInstance::new(netinfo, ba_id).map_err(Error::NewAgreement)?;
|
||||
let broadcast = Broadcast::new(our_id, validators, prop_id).map_err(Error::NewBroadcast)?;
|
||||
Ok(ProposalState::Ongoing(broadcast, agreement))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::iter::once;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use hbbft::{broadcast::Broadcast, util, ConsensusProtocol, CpStep, NetworkInfo};
|
||||
use hbbft::{broadcast::Broadcast, util, ConsensusProtocol, CpStep};
|
||||
use hbbft_testing::adversary::{
|
||||
sort_ascending, swap_random, Adversary, NetMutHandle, NodeOrderAdversary, RandomAdversary,
|
||||
ReorderingAdversary,
|
||||
|
@ -14,7 +12,6 @@ use proptest::{prelude::ProptestConfig, proptest};
|
|||
use rand::{Rng, SeedableRng};
|
||||
|
||||
type NodeId = u16;
|
||||
type NetworkInfoMap = BTreeMap<NodeId, Arc<NetworkInfo<NodeId>>>;
|
||||
|
||||
/// A strategy for picking the next node to handle a message.
|
||||
/// The sorting algorithm used is stable - preserves message
|
||||
|
@ -37,26 +34,16 @@ pub struct ProposeAdversary {
|
|||
message_strategy: MessageSorting,
|
||||
has_sent: bool,
|
||||
drop_messages: bool,
|
||||
// TODO this is really hacky but there's no better way to get this value
|
||||
// Solution taken from binary_agreement_mitm test - ideally the new network simulator
|
||||
// should be altered to store the netinfo structure alongside nodes similar to
|
||||
// the way the old network simulator did it.
|
||||
netinfo_mutex: Arc<Mutex<NetworkInfoMap>>,
|
||||
}
|
||||
|
||||
impl ProposeAdversary {
|
||||
/// Creates a new `ProposeAdversary`.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
message_strategy: MessageSorting,
|
||||
netinfo_mutex: Arc<Mutex<NetworkInfoMap>>,
|
||||
drop_messages: bool,
|
||||
) -> Self {
|
||||
pub fn new(message_strategy: MessageSorting, drop_messages: bool) -> Self {
|
||||
ProposeAdversary {
|
||||
message_strategy,
|
||||
has_sent: false,
|
||||
drop_messages,
|
||||
netinfo_mutex,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,15 +84,8 @@ impl Adversary<Broadcast<NodeId>> for ProposeAdversary {
|
|||
// Instantiate a temporary broadcast consensus protocol for each faulty node
|
||||
// and add the generated messages to the current step.
|
||||
for faulty_node in faulty_nodes {
|
||||
let netinfo = self
|
||||
.netinfo_mutex
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(faulty_node.id())
|
||||
.cloned()
|
||||
.expect("Adversary netinfo mutex not populated");
|
||||
|
||||
let fake_step = Broadcast::new(netinfo, *faulty_node.id())
|
||||
let validators = faulty_node.algorithm().validator_set().clone();
|
||||
let fake_step = Broadcast::new(*faulty_node.id(), validators, *faulty_node.id())
|
||||
.expect("broadcast instance")
|
||||
.handle_input(b"Fake news".to_vec(), &mut rng)
|
||||
.expect("propose");
|
||||
|
@ -166,12 +146,8 @@ fn test_broadcast<A: Adversary<Broadcast<NodeId>>>(
|
|||
}
|
||||
}
|
||||
|
||||
fn test_broadcast_different_sizes<A, F>(
|
||||
new_adversary: F,
|
||||
proposed_value: &[u8],
|
||||
seed: TestRngSeed,
|
||||
adversary_netinfo: &Arc<Mutex<NetworkInfoMap>>,
|
||||
) where
|
||||
fn test_broadcast_different_sizes<A, F>(new_adversary: F, proposed_value: &[u8], seed: TestRngSeed)
|
||||
where
|
||||
A: Adversary<Broadcast<NodeId>>,
|
||||
F: Fn() -> A,
|
||||
{
|
||||
|
@ -181,7 +157,6 @@ fn test_broadcast_different_sizes<A, F>(
|
|||
.chain(once(rng.gen_range(30, 50)));
|
||||
for size in sizes {
|
||||
// cloning since it gets moved into a closure
|
||||
let cloned_netinfo_map = adversary_netinfo.clone();
|
||||
let num_faulty_nodes = util::max_faulty(size);
|
||||
info!(
|
||||
"Network size: {} good nodes, {} faulty nodes",
|
||||
|
@ -197,12 +172,9 @@ fn test_broadcast_different_sizes<A, F>(
|
|||
.no_time_limit()
|
||||
.adversary(new_adversary())
|
||||
.using(move |info| {
|
||||
let netinfo = Arc::new(info.netinfo);
|
||||
cloned_netinfo_map
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(info.id, netinfo.clone());
|
||||
Broadcast::new(netinfo, proposer_id)
|
||||
let validators = info.netinfo.validator_set().clone();
|
||||
let id = *info.netinfo.our_id();
|
||||
Broadcast::new(id, validators, proposer_id)
|
||||
.expect("Failed to create a Broadcast instance.")
|
||||
})
|
||||
.build(&mut rng)
|
||||
|
@ -272,7 +244,9 @@ fn do_test_8_broadcast_equal_leaves_silent(seed: TestRngSeed) {
|
|||
.no_time_limit()
|
||||
.adversary(ReorderingAdversary::new())
|
||||
.using(move |node_info: NewNodeInfo<_>| {
|
||||
Broadcast::new(Arc::new(node_info.netinfo), proposer_id)
|
||||
let id = *node_info.netinfo.our_id();
|
||||
let validators = node_info.netinfo.validator_set().clone();
|
||||
Broadcast::new(id, validators, proposer_id)
|
||||
.expect("Failed to create a Broadcast instance.")
|
||||
})
|
||||
.build(&mut rng)
|
||||
|
@ -284,40 +258,29 @@ fn do_test_8_broadcast_equal_leaves_silent(seed: TestRngSeed) {
|
|||
}
|
||||
|
||||
fn do_test_broadcast_random_delivery_silent(seed: TestRngSeed) {
|
||||
test_broadcast_different_sizes(ReorderingAdversary::new, b"Foo", seed, &Default::default());
|
||||
test_broadcast_different_sizes(ReorderingAdversary::new, b"Foo", seed);
|
||||
}
|
||||
|
||||
fn do_test_broadcast_first_delivery_silent(seed: TestRngSeed) {
|
||||
test_broadcast_different_sizes(NodeOrderAdversary::new, b"Foo", seed, &Default::default());
|
||||
test_broadcast_different_sizes(NodeOrderAdversary::new, b"Foo", seed);
|
||||
}
|
||||
|
||||
fn do_test_broadcast_first_delivery_adv_propose(seed: TestRngSeed) {
|
||||
let adversary_netinfo: Arc<Mutex<NetworkInfoMap>> = Default::default();
|
||||
let new_adversary = || {
|
||||
ProposeAdversary::new(
|
||||
MessageSorting::SortAscending,
|
||||
adversary_netinfo.clone(),
|
||||
false,
|
||||
)
|
||||
};
|
||||
test_broadcast_different_sizes(new_adversary, b"Foo", seed, &adversary_netinfo);
|
||||
let new_adversary = || ProposeAdversary::new(MessageSorting::SortAscending, false);
|
||||
test_broadcast_different_sizes(new_adversary, b"Foo", seed);
|
||||
}
|
||||
|
||||
fn do_test_broadcast_random_delivery_adv_propose(seed: TestRngSeed) {
|
||||
let adversary_netinfo: Arc<Mutex<NetworkInfoMap>> = Default::default();
|
||||
let new_adversary =
|
||||
|| ProposeAdversary::new(MessageSorting::RandomPick, adversary_netinfo.clone(), false);
|
||||
test_broadcast_different_sizes(new_adversary, b"Foo", seed, &adversary_netinfo);
|
||||
let new_adversary = || ProposeAdversary::new(MessageSorting::RandomPick, false);
|
||||
test_broadcast_different_sizes(new_adversary, b"Foo", seed);
|
||||
}
|
||||
|
||||
fn do_test_broadcast_random_delivery_adv_propose_and_drop(seed: TestRngSeed) {
|
||||
let adversary_netinfo: Arc<Mutex<NetworkInfoMap>> = Default::default();
|
||||
let new_adversary =
|
||||
|| ProposeAdversary::new(MessageSorting::RandomPick, adversary_netinfo.clone(), true);
|
||||
test_broadcast_different_sizes(new_adversary, b"Foo", seed, &adversary_netinfo);
|
||||
let new_adversary = || ProposeAdversary::new(MessageSorting::RandomPick, true);
|
||||
test_broadcast_different_sizes(new_adversary, b"Foo", seed);
|
||||
}
|
||||
|
||||
fn do_test_broadcast_random_adversary(seed: TestRngSeed) {
|
||||
let new_adversary = || RandomAdversary::new(0.2, 0.2);
|
||||
test_broadcast_different_sizes(new_adversary, b"RandomFoo", seed, &Default::default());
|
||||
test_broadcast_different_sizes(new_adversary, b"RandomFoo", seed);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue