Split up messaging module.

This commit is contained in:
Andreas Fackler 2018-10-10 16:11:27 +02:00 committed by Andreas Fackler
parent 4cc35587c7
commit 8d1361e6ae
39 changed files with 438 additions and 453 deletions

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use std::io;
use std::net::TcpStream;
use hbbft::messaging::SourcedMessage;
use hbbft::SourcedMessage;
#[derive(Debug)]
pub enum Error {

View File

@ -2,7 +2,7 @@
use crossbeam::{Scope, ScopedJoinHandle};
use crossbeam_channel;
use crossbeam_channel::{bounded, unbounded, Receiver, Sender};
use hbbft::messaging::{SourcedMessage, Target, TargetedMessage};
use hbbft::{SourcedMessage, Target, TargetedMessage};
/// The queue functionality for messages sent between algorithm instances.
/// The messaging struct allows for targeted message exchange between comms

View File

@ -46,10 +46,9 @@ use crypto::poly::Poly;
use crypto::{SecretKey, SecretKeySet};
use hbbft::broadcast::{Broadcast, Message};
use hbbft::messaging::{DistAlgorithm, NetworkInfo, SourcedMessage};
use network::commst;
use network::connection;
use hbbft::{DistAlgorithm, NetworkInfo, SourcedMessage};
use network::messaging::Messaging;
use network::{commst, connection};
#[derive(Debug)]
pub enum Error {

View File

@ -25,8 +25,8 @@ use serde::Serialize;
use signifix::{metric, TryFrom};
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Step, Target};
use hbbft::queueing_honey_badger::{Batch, QueueingHoneyBadger};
use hbbft::{DistAlgorithm, NetworkInfo, Step, Target};
const VERSION: &str = env!("CARGO_PKG_VERSION");
const USAGE: &str = "

View File

@ -6,8 +6,7 @@ use super::bool_set::BoolSet;
use super::sbv_broadcast::{self, SbvBroadcast};
use super::{Error, Message, MessageContent, Nonce, Result, Step};
use coin::{self, Coin, CoinMessage};
use messaging::{DistAlgorithm, NetworkInfo, Target};
use traits::NodeIdT;
use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
/// The state of the current epoch's coin. In some epochs this is fixed, in others it starts
/// with in `InProgress`.

View File

@ -72,7 +72,6 @@ use rand;
use self::bool_set::BoolSet;
use coin::{self, CoinMessage};
use messaging;
pub use self::binary_agreement::BinaryAgreement;
@ -92,7 +91,7 @@ pub enum Error {
/// An Binary Agreement result.
pub type Result<T> = ::std::result::Result<T, Error>;
pub type Step<N> = messaging::Step<BinaryAgreement<N>>;
pub type Step<N> = ::Step<BinaryAgreement<N>>;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum MessageContent {

View File

@ -16,10 +16,9 @@ use super::bool_multimap::BoolMultimap;
use super::bool_set::{self, BoolSet};
use super::{Error, Result};
use fault_log::{Fault, FaultKind};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeIdT;
use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
pub type Step<N> = messaging::Step<SbvBroadcast<N>>;
pub type Step<N> = ::Step<SbvBroadcast<N>>;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Message {

View File

@ -11,8 +11,7 @@ use super::merkle::{Digest, MerkleTree, Proof};
use super::{Error, Result};
use fault_log::{Fault, FaultKind};
use fmt::{HexBytes, HexList, HexProof};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeIdT;
use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
/// The three kinds of message sent during the reliable broadcast stage of the
/// consensus algorithm.
@ -77,7 +76,7 @@ pub struct Broadcast<N> {
readys: BTreeMap<N, Vec<u8>>,
}
pub type Step<N> = messaging::Step<Broadcast<N>>;
pub type Step<N> = ::Step<Broadcast<N>>;
impl<N: NodeIdT> DistAlgorithm for Broadcast<N> {
type NodeId = N;

View File

@ -56,7 +56,7 @@
//! extern crate rand;
//!
//! use hbbft::broadcast::{Broadcast, Error, Step};
//! use hbbft::messaging::{DistAlgorithm, NetworkInfo, SourcedMessage, Target, TargetedMessage};
//! use hbbft::{DistAlgorithm, NetworkInfo, SourcedMessage, Target, TargetedMessage};
//! use rand::{thread_rng, Rng};
//! use std::collections::{BTreeMap, BTreeSet, VecDeque};
//! use std::iter::once;

View File

@ -24,17 +24,15 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use crypto::error as cerror;
use crypto::{Signature, SignatureShare};
use crypto::{self, Signature, SignatureShare};
use fault_log::{Fault, FaultKind};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeIdT;
use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
/// A coin error.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum Error {
#[fail(display = "CombineAndVerifySigCrypto error: {}", _0)]
CombineAndVerifySigCrypto(cerror::Error),
CombineAndVerifySigCrypto(crypto::error::Error),
#[fail(display = "Unknown sender")]
UnknownSender,
#[fail(display = "Signature verification failed")]
@ -73,7 +71,7 @@ pub struct Coin<N, T> {
terminated: bool,
}
pub type Step<N, T> = messaging::Step<Coin<N, T>>;
pub type Step<N, T> = ::Step<Coin<N, T>>;
impl<N, T> DistAlgorithm for Coin<N, T>
where

View File

@ -4,8 +4,7 @@ use std::sync::Arc;
use serde::{Deserialize, Serialize};
use super::{ChangeState, JoinPlan};
use messaging::NetworkInfo;
use traits::NodeIdT;
use {NetworkInfo, NodeIdT};
/// A batch of transactions the algorithm has output.
#[derive(Clone, Debug)]

View File

@ -9,9 +9,8 @@ use serde::{Deserialize, Serialize};
use super::{ChangeState, DynamicHoneyBadger, JoinPlan, Result, Step, VoteCounter};
use honey_badger::{HoneyBadger, SubsetHandlingStrategy};
use messaging::NetworkInfo;
use traits::{Contribution, NodeIdT};
use util::SubRng;
use {Contribution, NetworkInfo, NodeIdT};
/// A Dynamic Honey Badger builder, to configure the parameters and create new instances of
/// `DynamicHoneyBadger`.

View File

@ -14,10 +14,9 @@ use super::{
};
use fault_log::{Fault, FaultKind, FaultLog};
use honey_badger::{self, HoneyBadger, Message as HbMessage};
use messaging::{DistAlgorithm, NetworkInfo, Target};
use sync_key_gen::{Ack, Part, PartOutcome, SyncKeyGen};
use traits::{Contribution, NodeIdT};
use util::SubRng;
use {Contribution, DistAlgorithm, NetworkInfo, NodeIdT, Target};
/// A Honey Badger instance that can handle adding and removing nodes.
pub struct DynamicHoneyBadger<C, N: Rand> {

View File

@ -68,9 +68,8 @@ use std::collections::BTreeMap;
use self::votes::{SignedVote, VoteCounter};
use honey_badger::Message as HbMessage;
use messaging;
use sync_key_gen::{Ack, Part, SyncKeyGen};
use traits::NodeIdT;
use NodeIdT;
pub use self::batch::Batch;
pub use self::builder::DynamicHoneyBadgerBuilder;
@ -78,7 +77,7 @@ pub use self::change::{Change, ChangeState};
pub use self::dynamic_honey_badger::DynamicHoneyBadger;
pub use self::error::{Error, ErrorKind, Result};
pub type Step<C, N> = messaging::Step<DynamicHoneyBadger<C, N>>;
pub type Step<C, N> = ::Step<DynamicHoneyBadger<C, N>>;
/// The user input for `DynamicHoneyBadger`.
#[derive(Clone, Debug)]

View File

@ -7,8 +7,7 @@ use serde::{Deserialize, Serialize};
use super::{Change, ErrorKind, Result};
use fault_log::{FaultKind, FaultLog};
use messaging::NetworkInfo;
use traits::NodeIdT;
use {NetworkInfo, NodeIdT};
/// A buffer and counter collecting pending and committed votes for validator set changes.
///
@ -192,7 +191,7 @@ mod tests {
use super::{Change, SignedVote, VoteCounter};
use fault_log::{FaultKind, FaultLog};
use messaging::NetworkInfo;
use NetworkInfo;
/// Returns a vector of `node_num` `VoteCounter`s, and some signed example votes.
///

View File

@ -1,6 +1,6 @@
use std::collections::BTreeMap;
use traits::NodeIdT;
use NodeIdT;
/// A batch of contributions the algorithm has output.
#[derive(Clone, Debug)]

View File

@ -7,9 +7,8 @@ use serde::{Deserialize, Serialize};
use super::HoneyBadger;
use honey_badger::SubsetHandlingStrategy;
use messaging::NetworkInfo;
use traits::{Contribution, NodeIdT};
use util::SubRng;
use {Contribution, NetworkInfo, NodeIdT};
/// A Honey Badger builder, to configure the parameters and create new instances of `HoneyBadger`.
pub struct HoneyBadgerBuilder<C, N> {

View File

@ -11,10 +11,9 @@ use serde::{Deserialize, Serialize};
use super::{Batch, ErrorKind, MessageContent, Result, Step};
use fault_log::{Fault, FaultKind, FaultLog};
use messaging::{DistAlgorithm, NetworkInfo};
use subset::{self as cs, Subset, SubsetOutput};
use threshold_decryption::{self as td, ThresholdDecryption};
use traits::{Contribution, NodeIdT};
use {Contribution, DistAlgorithm, NetworkInfo, NodeIdT};
/// The status of an encrypted contribution.
#[derive(Debug)]

View File

@ -9,8 +9,7 @@ use serde::{Deserialize, Serialize};
use super::epoch_state::EpochState;
use super::{Batch, Error, ErrorKind, HoneyBadgerBuilder, Message, MessageContent, Result};
use messaging::{self, DistAlgorithm, NetworkInfo};
use traits::{Contribution, NodeIdT};
use {Contribution, DistAlgorithm, NetworkInfo, NodeIdT};
pub use super::epoch_state::SubsetHandlingStrategy;
@ -53,7 +52,7 @@ where
}
}
pub type Step<C, N> = messaging::Step<HoneyBadger<C, N>>;
pub type Step<C, N> = ::Step<HoneyBadger<C, N>>;
impl<C, N> DistAlgorithm for HoneyBadger<C, N>
where

View File

@ -143,28 +143,16 @@ pub mod dynamic_honey_badger;
pub mod fault_log;
mod fmt;
pub mod honey_badger;
pub mod messaging;
mod messaging;
mod network_info;
pub mod queueing_honey_badger;
pub mod subset;
pub mod sync_key_gen;
pub mod threshold_decryption;
mod traits;
pub mod transaction_queue;
pub mod util;
/// Common supertraits.
pub mod traits {
use std::fmt::Debug;
use std::hash::Hash;
/// A transaction, user message, etc.
pub trait Contribution: Eq + Debug + Hash + Send + Sync {}
impl<C> Contribution for C where C: Eq + Debug + Hash + Send + Sync {}
/// A peer node's unique identifier.
pub trait NodeIdT: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
impl<N> NodeIdT for N where N: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
/// Messages.
pub trait Message: Debug + Send + Sync {}
impl<M> Message for M where M: Debug + Send + Sync {}
}
pub use messaging::{SourcedMessage, Target, TargetedMessage};
pub use network_info::NetworkInfo;
pub use traits::{Contribution, DistAlgorithm, Message, NodeIdT, Step};

View File

@ -1,13 +1,3 @@
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::iter::once;
use failure::Fail;
use rand;
use crypto::{self, PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
use fault_log::{Fault, FaultLog};
use traits::{Message, NodeIdT};
/// Message sent by a given source.
#[derive(Clone, Debug)]
pub struct SourcedMessage<M, N> {
@ -52,352 +42,3 @@ impl<M, N> TargetedMessage<M, N> {
}
}
}
/// Result of one step of the local state machine of a distributed algorithm. Such a result should
/// be used and never discarded by the client of the algorithm.
#[must_use = "The algorithm step result must be used."]
#[derive(Debug)]
pub struct Step<D>
where
D: DistAlgorithm,
<D as DistAlgorithm>::NodeId: NodeIdT,
{
pub output: VecDeque<D::Output>,
pub fault_log: FaultLog<D::NodeId>,
pub messages: VecDeque<TargetedMessage<D::Message, D::NodeId>>,
}
impl<D> Default for Step<D>
where
D: DistAlgorithm,
<D as DistAlgorithm>::NodeId: NodeIdT,
{
fn default() -> Step<D> {
Step {
output: VecDeque::default(),
fault_log: FaultLog::default(),
messages: VecDeque::default(),
}
}
}
impl<D: DistAlgorithm> Step<D>
where
<D as DistAlgorithm>::NodeId: NodeIdT,
{
/// Creates a new `Step` from the given collections.
pub fn new(
output: VecDeque<D::Output>,
fault_log: FaultLog<D::NodeId>,
messages: VecDeque<TargetedMessage<D::Message, D::NodeId>>,
) -> Self {
Step {
output,
fault_log,
messages,
}
}
/// Returns the same step, with the given additional output.
pub fn with_output(mut self, output: D::Output) -> Self {
self.output.push_back(output);
self
}
/// Converts `self` into a step of another type, given conversion methods for output and
/// messages.
pub fn map<D2, FO, FM>(self, f_out: FO, f_msg: FM) -> Step<D2>
where
D2: DistAlgorithm<NodeId = D::NodeId>,
FO: Fn(D::Output) -> D2::Output,
FM: Fn(D::Message) -> D2::Message,
{
Step {
output: self.output.into_iter().map(f_out).collect(),
fault_log: self.fault_log,
messages: self.messages.into_iter().map(|tm| tm.map(&f_msg)).collect(),
}
}
/// Extends `self` with `other`s messages and fault logs, and returns `other.output`.
pub fn extend_with<D2, FM>(&mut self, other: Step<D2>, f_msg: FM) -> VecDeque<D2::Output>
where
D2: DistAlgorithm<NodeId = D::NodeId>,
FM: Fn(D2::Message) -> D::Message,
{
self.fault_log.extend(other.fault_log);
let msgs = other.messages.into_iter().map(|tm| tm.map(&f_msg));
self.messages.extend(msgs);
other.output
}
/// Adds the outputs, fault logs and messages of `other` to `self`.
pub fn extend(&mut self, other: Self) {
self.output.extend(other.output);
self.fault_log.extend(other.fault_log);
self.messages.extend(other.messages);
}
/// Converts this step into an equivalent step for a different `DistAlgorithm`.
// This cannot be a `From` impl, because it would conflict with `impl From<T> for T`.
pub fn convert<D2>(self) -> Step<D2>
where
D2: DistAlgorithm<NodeId = D::NodeId, Output = D::Output, Message = D::Message>,
{
Step {
output: self.output,
fault_log: self.fault_log,
messages: self.messages,
}
}
/// Returns `true` if there are now messages, faults or outputs.
pub fn is_empty(&self) -> bool {
self.output.is_empty() && self.fault_log.is_empty() && self.messages.is_empty()
}
}
impl<D: DistAlgorithm> From<FaultLog<D::NodeId>> for Step<D> {
fn from(fault_log: FaultLog<D::NodeId>) -> Self {
Step {
fault_log,
..Step::default()
}
}
}
impl<D: DistAlgorithm> From<Fault<D::NodeId>> for Step<D> {
fn from(fault: Fault<D::NodeId>) -> Self {
Step {
fault_log: fault.into(),
..Step::default()
}
}
}
impl<D: DistAlgorithm> From<TargetedMessage<D::Message, D::NodeId>> for Step<D> {
fn from(msg: TargetedMessage<D::Message, D::NodeId>) -> Self {
Step {
messages: once(msg).collect(),
..Step::default()
}
}
}
/// A distributed algorithm that defines a message flow.
pub trait DistAlgorithm: Send + Sync {
/// Unique node identifier.
type NodeId: NodeIdT;
/// The input provided by the user.
type Input;
/// The output type. Some algorithms return an output exactly once, others return multiple
/// times.
type Output;
/// The messages that need to be exchanged between the instances in the participating nodes.
type Message: Message;
/// The errors that can occur during execution.
type Error: Fail;
/// Handles an input provided by the user, and returns
fn handle_input(&mut self, input: Self::Input) -> Result<Step<Self>, Self::Error>
where
Self: Sized;
/// Handles a message received from node `sender_id`.
fn handle_message(
&mut self,
sender_id: &Self::NodeId,
message: Self::Message,
) -> Result<Step<Self>, Self::Error>
where
Self: Sized;
/// Returns `true` if execution has completed and this instance can be dropped.
fn terminated(&self) -> bool;
/// Returns this node's own ID.
fn our_id(&self) -> &Self::NodeId;
}
/// Common data shared between algorithms: the nodes' IDs and key shares.
#[derive(Debug, Clone)]
pub struct NetworkInfo<N> {
our_id: N,
num_nodes: usize,
num_faulty: usize,
is_validator: bool,
// TODO: Should this be an option? It only makes sense for validators.
secret_key_share: SecretKeyShare,
secret_key: SecretKey,
public_key_set: PublicKeySet,
public_key_shares: BTreeMap<N, PublicKeyShare>,
public_keys: BTreeMap<N, PublicKey>,
node_indices: BTreeMap<N, usize>,
}
impl<N: NodeIdT> NetworkInfo<N> {
pub fn new(
our_id: N,
secret_key_share: SecretKeyShare,
public_key_set: PublicKeySet,
secret_key: SecretKey,
public_keys: BTreeMap<N, PublicKey>,
) -> Self {
let num_nodes = public_keys.len();
let is_validator = public_keys.contains_key(&our_id);
let node_indices: BTreeMap<N, usize> = 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)))
.collect();
NetworkInfo {
our_id,
num_nodes,
num_faulty: (num_nodes - 1) / 3,
is_validator,
secret_key_share,
secret_key,
public_key_set,
public_key_shares,
node_indices,
public_keys,
}
}
/// The ID of the node the algorithm runs on.
pub fn our_id(&self) -> &N {
&self.our_id
}
/// ID of all nodes in the network.
pub fn all_ids(&self) -> impl Iterator<Item = &N> {
self.public_keys.keys()
}
/// The total number _N_ of nodes.
pub fn num_nodes(&self) -> usize {
self.num_nodes
}
/// The maximum number _f_ of faulty, Byzantine nodes up to which Honey Badger is guaranteed to
/// be correct.
pub fn num_faulty(&self) -> usize {
self.num_faulty
}
/// The minimum number _N - f_ of correct nodes with which Honey Badger is guaranteed to be
/// correct.
pub fn num_correct(&self) -> usize {
self.num_nodes - self.num_faulty
}
/// Returns our secret key share for threshold cryptography.
pub fn secret_key_share(&self) -> &SecretKeyShare {
&self.secret_key_share
}
/// Returns our secret key for encryption and signing.
pub fn secret_key(&self) -> &SecretKey {
&self.secret_key
}
/// Returns the public key set for threshold cryptography.
pub fn public_key_set(&self) -> &PublicKeySet {
&self.public_key_set
}
/// Returns the public key share if a node with that ID exists, otherwise `None`.
pub fn public_key_share(&self, id: &N) -> Option<&PublicKeyShare> {
self.public_key_shares.get(id)
}
/// Returns a map of all node IDs to their public key shares.
pub fn public_key_share_map(&self) -> &BTreeMap<N, PublicKeyShare> {
&self.public_key_shares
}
/// Returns a map of all node IDs to their public keys.
pub fn public_key(&self, id: &N) -> Option<&PublicKey> {
self.public_keys.get(id)
}
/// Returns a map of all node IDs to their public keys.
pub fn public_key_map(&self) -> &BTreeMap<N, PublicKey> {
&self.public_keys
}
/// The index of a node in a canonical numbering of all nodes.
pub fn node_index(&self, id: &N) -> Option<usize> {
self.node_indices.get(id).cloned()
}
/// Returns the unique ID of the Honey Badger invocation.
///
/// FIXME: Using the public key as the invocation ID either requires agreeing on the keys on
/// each invocation, or makes it unsafe to reuse keys for different invocations. A better
/// invocation ID would be one that is distributed to all nodes on each invocation and would be
/// independent from the public key, so that reusing keys would be safer.
pub fn invocation_id(&self) -> Vec<u8> {
self.public_key_set.public_key().to_bytes()
}
/// Returns `true` if this node takes part in the consensus itself. If not, it is only an
/// observer.
pub fn is_validator(&self) -> bool {
self.is_validator
}
/// Returns `true` if the given node takes part in the consensus itself. If not, it is only an
/// observer.
pub fn is_node_validator(&self, id: &N) -> bool {
self.public_keys.contains_key(id)
}
/// Generates a map of matching `NetworkInfo`s for testing.
pub fn generate_map<I, R>(
ids: I,
rng: &mut R,
) -> Result<BTreeMap<N, NetworkInfo<N>>, crypto::error::Error>
where
I: IntoIterator<Item = N>,
R: rand::Rng,
{
use crypto::SecretKeySet;
let all_ids: BTreeSet<N> = ids.into_iter().collect();
let num_faulty = (all_ids.len() - 1) / 3;
// Generate the keys for threshold cryptography.
let sk_set = SecretKeySet::random(num_faulty, rng)?;
let pk_set = sk_set.public_keys();
// Generate keys for individually signing and encrypting messages.
let sec_keys: BTreeMap<_, SecretKey> =
all_ids.iter().map(|id| (id.clone(), rng.gen())).collect();
let pub_keys: BTreeMap<_, PublicKey> = sec_keys
.iter()
.map(|(id, sk)| (id.clone(), sk.public_key()))
.collect();
// Create the corresponding `NetworkInfo` for each node.
let create_netinfo = |(i, id): (usize, N)| {
let netinfo = NetworkInfo::new(
id.clone(),
sk_set.secret_key_share(i)?,
pk_set.clone(),
sec_keys[&id].clone(),
pub_keys.clone(),
);
Ok((id, netinfo))
};
all_ids
.into_iter()
.enumerate()
.map(create_netinfo)
.collect()
}
}

189
src/network_info.rs Normal file
View File

@ -0,0 +1,189 @@
use std::collections::{BTreeMap, BTreeSet};
use crypto::{self, PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
use rand;
use NodeIdT;
/// Common data shared between algorithms: the nodes' IDs and key shares.
#[derive(Debug, Clone)]
pub struct NetworkInfo<N> {
our_id: N,
num_nodes: usize,
num_faulty: usize,
is_validator: bool,
// TODO: Should this be an option? It only makes sense for validators.
secret_key_share: SecretKeyShare,
secret_key: SecretKey,
public_key_set: PublicKeySet,
public_key_shares: BTreeMap<N, PublicKeyShare>,
public_keys: BTreeMap<N, PublicKey>,
node_indices: BTreeMap<N, usize>,
}
impl<N: NodeIdT> NetworkInfo<N> {
pub fn new(
our_id: N,
secret_key_share: SecretKeyShare,
public_key_set: PublicKeySet,
secret_key: SecretKey,
public_keys: BTreeMap<N, PublicKey>,
) -> Self {
let num_nodes = public_keys.len();
let is_validator = public_keys.contains_key(&our_id);
let node_indices: BTreeMap<N, usize> = 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)))
.collect();
NetworkInfo {
our_id,
num_nodes,
num_faulty: (num_nodes - 1) / 3,
is_validator,
secret_key_share,
secret_key,
public_key_set,
public_key_shares,
node_indices,
public_keys,
}
}
/// The ID of the node the algorithm runs on.
pub fn our_id(&self) -> &N {
&self.our_id
}
/// ID of all nodes in the network.
pub fn all_ids(&self) -> impl Iterator<Item = &N> {
self.public_keys.keys()
}
/// The total number _N_ of nodes.
pub fn num_nodes(&self) -> usize {
self.num_nodes
}
/// The maximum number _f_ of faulty, Byzantine nodes up to which Honey Badger is guaranteed to
/// be correct.
pub fn num_faulty(&self) -> usize {
self.num_faulty
}
/// The minimum number _N - f_ of correct nodes with which Honey Badger is guaranteed to be
/// correct.
pub fn num_correct(&self) -> usize {
self.num_nodes - self.num_faulty
}
/// Returns our secret key share for threshold cryptography.
pub fn secret_key_share(&self) -> &SecretKeyShare {
&self.secret_key_share
}
/// Returns our secret key for encryption and signing.
pub fn secret_key(&self) -> &SecretKey {
&self.secret_key
}
/// Returns the public key set for threshold cryptography.
pub fn public_key_set(&self) -> &PublicKeySet {
&self.public_key_set
}
/// Returns the public key share if a node with that ID exists, otherwise `None`.
pub fn public_key_share(&self, id: &N) -> Option<&PublicKeyShare> {
self.public_key_shares.get(id)
}
/// Returns a map of all node IDs to their public key shares.
pub fn public_key_share_map(&self) -> &BTreeMap<N, PublicKeyShare> {
&self.public_key_shares
}
/// Returns a map of all node IDs to their public keys.
pub fn public_key(&self, id: &N) -> Option<&PublicKey> {
self.public_keys.get(id)
}
/// Returns a map of all node IDs to their public keys.
pub fn public_key_map(&self) -> &BTreeMap<N, PublicKey> {
&self.public_keys
}
/// The index of a node in a canonical numbering of all nodes.
pub fn node_index(&self, id: &N) -> Option<usize> {
self.node_indices.get(id).cloned()
}
/// Returns the unique ID of the Honey Badger invocation.
///
/// FIXME: Using the public key as the invocation ID either requires agreeing on the keys on
/// each invocation, or makes it unsafe to reuse keys for different invocations. A better
/// invocation ID would be one that is distributed to all nodes on each invocation and would be
/// independent from the public key, so that reusing keys would be safer.
pub fn invocation_id(&self) -> Vec<u8> {
self.public_key_set.public_key().to_bytes()
}
/// Returns `true` if this node takes part in the consensus itself. If not, it is only an
/// observer.
pub fn is_validator(&self) -> bool {
self.is_validator
}
/// Returns `true` if the given node takes part in the consensus itself. If not, it is only an
/// observer.
pub fn is_node_validator(&self, id: &N) -> bool {
self.public_keys.contains_key(id)
}
/// Generates a map of matching `NetworkInfo`s for testing.
pub fn generate_map<I, R>(
ids: I,
rng: &mut R,
) -> Result<BTreeMap<N, NetworkInfo<N>>, crypto::error::Error>
where
I: IntoIterator<Item = N>,
R: rand::Rng,
{
use crypto::SecretKeySet;
let all_ids: BTreeSet<N> = ids.into_iter().collect();
let num_faulty = (all_ids.len() - 1) / 3;
// Generate the keys for threshold cryptography.
let sk_set = SecretKeySet::random(num_faulty, rng)?;
let pk_set = sk_set.public_keys();
// Generate keys for individually signing and encrypting messages.
let sec_keys: BTreeMap<_, SecretKey> =
all_ids.iter().map(|id| (id.clone(), rng.gen())).collect();
let pub_keys: BTreeMap<_, PublicKey> = sec_keys
.iter()
.map(|(id, sk)| (id.clone(), sk.public_key()))
.collect();
// Create the corresponding `NetworkInfo` for each node.
let create_netinfo = |(i, id): (usize, N)| {
let netinfo = NetworkInfo::new(
id.clone(),
sk_set.secret_key_share(i)?,
pk_set.clone(),
sec_keys[&id].clone(),
pub_keys.clone(),
);
Ok((id, netinfo))
};
all_ids
.into_iter()
.enumerate()
.map(create_netinfo)
.collect()
}
}

View File

@ -31,9 +31,8 @@ use rand::Rand;
use serde::{Deserialize, Serialize};
use dynamic_honey_badger::{self, Batch as DhbBatch, DynamicHoneyBadger, Message};
use messaging::{self, DistAlgorithm};
use traits::{Contribution, NodeIdT};
use transaction_queue::TransactionQueue;
use {Contribution, DistAlgorithm, NodeIdT};
pub use dynamic_honey_badger::{Change, ChangeState, Input};
@ -172,7 +171,7 @@ where
queue: TransactionQueue<T>,
}
pub type Step<T, N> = messaging::Step<QueueingHoneyBadger<T, N>>;
pub type Step<T, N> = ::Step<QueueingHoneyBadger<T, N>>;
impl<T, N> DistAlgorithm for QueueingHoneyBadger<T, N>
where

View File

@ -30,9 +30,8 @@ use std::sync::Arc;
use binary_agreement::{self, BinaryAgreement};
use broadcast::{self, Broadcast};
use fmt::HexBytes;
use messaging::{self, DistAlgorithm, NetworkInfo};
use rand::Rand;
use traits::NodeIdT;
use {DistAlgorithm, NetworkInfo, NodeIdT};
/// A subset error.
#[derive(Clone, PartialEq, Debug, Fail)]
@ -85,7 +84,7 @@ pub struct Subset<N: Rand> {
decided: bool,
}
pub type Step<N> = messaging::Step<Subset<N>>;
pub type Step<N> = ::Step<Subset<N>>;
impl<N: NodeIdT + Rand> DistAlgorithm for Subset<N> {
type NodeId = N;

View File

@ -175,8 +175,7 @@ use pairing::{CurveAffine, Field};
use rand;
use fault_log::{AckMessageFault as Fault, FaultKind, FaultLog};
use messaging::NetworkInfo;
use traits::NodeIdT;
use {NetworkInfo, NodeIdT};
// TODO: No need to send our own row and value to ourselves.

View File

@ -13,11 +13,9 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use crypto::error as cerror;
use crypto::{Ciphertext, DecryptionShare};
use crypto::{self, Ciphertext, DecryptionShare};
use fault_log::{Fault, FaultKind, FaultLog};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeIdT;
use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
/// A threshold decryption error.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
@ -29,7 +27,7 @@ pub enum Error {
#[fail(display = "Unknown sender")]
UnknownSender,
#[fail(display = "Decryption failed: {:?}", _0)]
Decryption(cerror::Error),
Decryption(crypto::error::Error),
}
/// A threshold decryption result.
@ -52,7 +50,7 @@ pub struct ThresholdDecryption<N> {
terminated: bool,
}
pub type Step<N> = messaging::Step<ThresholdDecryption<N>>;
pub type Step<N> = ::Step<ThresholdDecryption<N>>;
impl<N: NodeIdT> DistAlgorithm for ThresholdDecryption<N> {
type NodeId = N;

189
src/traits.rs Normal file
View File

@ -0,0 +1,189 @@
//! Common supertraits for distributed algorithms.
use std::collections::VecDeque;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::once;
use failure::Fail;
use fault_log::{Fault, FaultLog};
use TargetedMessage;
/// A transaction, user message, etc.
pub trait Contribution: Eq + Debug + Hash + Send + Sync {}
impl<C> Contribution for C where C: Eq + Debug + Hash + Send + Sync {}
/// A peer node's unique identifier.
pub trait NodeIdT: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
impl<N> NodeIdT for N where N: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
/// Messages.
pub trait Message: Debug + Send + Sync {}
impl<M> Message for M where M: Debug + Send + Sync {}
/// Result of one step of the local state machine of a distributed algorithm. Such a result should
/// be used and never discarded by the client of the algorithm.
#[must_use = "The algorithm step result must be used."]
#[derive(Debug)]
pub struct Step<D>
where
D: DistAlgorithm,
<D as DistAlgorithm>::NodeId: NodeIdT,
{
pub output: VecDeque<D::Output>,
pub fault_log: FaultLog<D::NodeId>,
pub messages: VecDeque<TargetedMessage<D::Message, D::NodeId>>,
}
impl<D> Default for Step<D>
where
D: DistAlgorithm,
<D as DistAlgorithm>::NodeId: NodeIdT,
{
fn default() -> Step<D> {
Step {
output: VecDeque::default(),
fault_log: FaultLog::default(),
messages: VecDeque::default(),
}
}
}
impl<D: DistAlgorithm> Step<D>
where
<D as DistAlgorithm>::NodeId: NodeIdT,
{
/// Creates a new `Step` from the given collections.
pub fn new(
output: VecDeque<D::Output>,
fault_log: FaultLog<D::NodeId>,
messages: VecDeque<TargetedMessage<D::Message, D::NodeId>>,
) -> Self {
Step {
output,
fault_log,
messages,
}
}
/// Returns the same step, with the given additional output.
pub fn with_output(mut self, output: D::Output) -> Self {
self.output.push_back(output);
self
}
/// Converts `self` into a step of another type, given conversion methods for output and
/// messages.
pub fn map<D2, FO, FM>(self, f_out: FO, f_msg: FM) -> Step<D2>
where
D2: DistAlgorithm<NodeId = D::NodeId>,
FO: Fn(D::Output) -> D2::Output,
FM: Fn(D::Message) -> D2::Message,
{
Step {
output: self.output.into_iter().map(f_out).collect(),
fault_log: self.fault_log,
messages: self.messages.into_iter().map(|tm| tm.map(&f_msg)).collect(),
}
}
/// Extends `self` with `other`s messages and fault logs, and returns `other.output`.
pub fn extend_with<D2, FM>(&mut self, other: Step<D2>, f_msg: FM) -> VecDeque<D2::Output>
where
D2: DistAlgorithm<NodeId = D::NodeId>,
FM: Fn(D2::Message) -> D::Message,
{
self.fault_log.extend(other.fault_log);
let msgs = other.messages.into_iter().map(|tm| tm.map(&f_msg));
self.messages.extend(msgs);
other.output
}
/// Adds the outputs, fault logs and messages of `other` to `self`.
pub fn extend(&mut self, other: Self) {
self.output.extend(other.output);
self.fault_log.extend(other.fault_log);
self.messages.extend(other.messages);
}
/// Converts this step into an equivalent step for a different `DistAlgorithm`.
// This cannot be a `From` impl, because it would conflict with `impl From<T> for T`.
pub fn convert<D2>(self) -> Step<D2>
where
D2: DistAlgorithm<NodeId = D::NodeId, Output = D::Output, Message = D::Message>,
{
Step {
output: self.output,
fault_log: self.fault_log,
messages: self.messages,
}
}
/// Returns `true` if there are now messages, faults or outputs.
pub fn is_empty(&self) -> bool {
self.output.is_empty() && self.fault_log.is_empty() && self.messages.is_empty()
}
}
impl<D: DistAlgorithm> From<FaultLog<D::NodeId>> for Step<D> {
fn from(fault_log: FaultLog<D::NodeId>) -> Self {
Step {
fault_log,
..Step::default()
}
}
}
impl<D: DistAlgorithm> From<Fault<D::NodeId>> for Step<D> {
fn from(fault: Fault<D::NodeId>) -> Self {
Step {
fault_log: fault.into(),
..Step::default()
}
}
}
impl<D: DistAlgorithm> From<TargetedMessage<D::Message, D::NodeId>> for Step<D> {
fn from(msg: TargetedMessage<D::Message, D::NodeId>) -> Self {
Step {
messages: once(msg).collect(),
..Step::default()
}
}
}
/// A distributed algorithm that defines a message flow.
pub trait DistAlgorithm: Send + Sync {
/// Unique node identifier.
type NodeId: NodeIdT;
/// The input provided by the user.
type Input;
/// The output type. Some algorithms return an output exactly once, others return multiple
/// times.
type Output;
/// The messages that need to be exchanged between the instances in the participating nodes.
type Message: Message;
/// The errors that can occur during execution.
type Error: Fail;
/// Handles an input provided by the user, and returns
fn handle_input(&mut self, input: Self::Input) -> Result<Step<Self>, Self::Error>
where
Self: Sized;
/// Handles a message received from node `sender_id`.
fn handle_message(
&mut self,
sender_id: &Self::NodeId,
message: Self::Message,
) -> Result<Step<Self>, Self::Error>
where
Self: Sized;
/// Returns `true` if execution has completed and this instance can be dropped.
fn terminated(&self) -> bool;
/// Returns this node's own ID.
fn our_id(&self) -> &Self::NodeId;
}

View File

@ -3,7 +3,7 @@ use std::collections::{HashSet, VecDeque};
use rand;
use traits::Contribution;
use Contribution;
/// A wrapper providing a few convenience methods for a queue of pending transactions.
#[derive(Debug)]

View File

@ -33,7 +33,7 @@ use std::sync::Arc;
use rand::Rng;
use hbbft::binary_agreement::BinaryAgreement;
use hbbft::messaging::NetworkInfo;
use hbbft::NetworkInfo;
use network::{Adversary, MessageScheduler, NodeId, SilentAdversary, TestNetwork, TestNode};

View File

@ -21,7 +21,7 @@ use std::sync::Arc;
use rand::Rng;
use hbbft::broadcast::{Broadcast, Message};
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
use hbbft::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
use network::{
Adversary, MessageScheduler, MessageWithSender, NodeId, RandomAdversary, SilentAdversary,
TestNetwork, TestNode,

View File

@ -22,8 +22,8 @@ use itertools::Itertools;
use rand::Rng;
use hbbft::dynamic_honey_badger::{Batch, Change, ChangeState, DynamicHoneyBadger, Input};
use hbbft::messaging::NetworkInfo;
use hbbft::transaction_queue::TransactionQueue;
use hbbft::NetworkInfo;
use network::{Adversary, MessageScheduler, NodeId, SilentAdversary, TestNetwork, TestNode};

View File

@ -23,9 +23,8 @@ use itertools::Itertools;
use rand::Rng;
use hbbft::honey_badger::{self, Batch, HoneyBadger, MessageContent};
use hbbft::messaging::{NetworkInfo, Target, TargetedMessage};
use hbbft::threshold_decryption;
use hbbft::transaction_queue::TransactionQueue;
use hbbft::{threshold_decryption, NetworkInfo, Target, TargetedMessage};
use network::{
Adversary, MessageScheduler, MessageWithSender, NodeId, RandomAdversary, SilentAdversary,

View File

@ -35,7 +35,8 @@
use std::cmp;
use hbbft::messaging::{DistAlgorithm, Step};
use hbbft::{DistAlgorithm, Step};
use net::{CrankError, NetMessage, Node, VirtualNet};
/// Immutable network handle.

View File

@ -3,7 +3,7 @@
use std::{fmt, time};
use failure;
use hbbft::messaging::DistAlgorithm;
use hbbft::DistAlgorithm;
use super::NetMessage;

View File

@ -26,9 +26,8 @@ use rand::{Rand, Rng};
use threshold_crypto as crypto;
use hbbft::dynamic_honey_badger::Batch;
use hbbft::messaging::{self, DistAlgorithm, NetworkInfo, Step};
use hbbft::traits::{Contribution, NodeIdT};
use hbbft::util::SubRng;
use hbbft::{self, Contribution, DistAlgorithm, NetworkInfo, NodeIdT, Step};
pub use self::adversary::Adversary;
pub use self::err::CrankError;
@ -135,7 +134,7 @@ impl<D: DistAlgorithm> Node<D> {
}
/// A network message on the virtual network.
// Note: We do not use `messaging::TargetedMessage` and `messaging::SourceMessage` here, the nesting
// Note: We do not use `hbbft::TargetedMessage` and `hbbft::SourceMessage` here, the nesting
// is inconvenient and we do not want to support broadcasts at this level.
#[derive(Clone, Debug)]
pub struct NetworkMessage<M, N> {
@ -198,7 +197,7 @@ where
for tmsg in &step.messages {
match &tmsg.target {
// Single target message.
messaging::Target::Node(to) => {
hbbft::Target::Node(to) => {
if !faulty {
message_count = message_count.saturating_add(1);
}
@ -210,7 +209,7 @@ where
));
}
// Broadcast messages get expanded into multiple direct messages.
messaging::Target::All => for to in nodes.keys().filter(|&to| to != &sender) {
hbbft::Target::All => for to in nodes.keys().filter(|&to| to != &sender) {
if !faulty {
message_count = message_count.saturating_add(1);
}
@ -706,7 +705,7 @@ where
R: rand::Rng,
{
// Generate a new set of cryptographic keys for threshold cryptography.
let net_infos = messaging::NetworkInfo::generate_map(node_ids, &mut rng)?;
let net_infos = NetworkInfo::generate_map(node_ids, &mut rng)?;
assert!(
faulty * 3 < net_infos.len(),

View File

@ -11,7 +11,7 @@ pub mod net;
use std::{collections, time};
use hbbft::dynamic_honey_badger::{Change, ChangeState, DynamicHoneyBadger, Input};
use hbbft::messaging::DistAlgorithm;
use hbbft::DistAlgorithm;
use net::proptest::{gen_seed, NetworkDimension, TestRng, TestRngSeed};
use net::NetBuilder;
use proptest::prelude::ProptestConfig;

View File

@ -7,8 +7,7 @@ use crypto::SecretKeyShare;
use rand::{self, Rng};
use hbbft::dynamic_honey_badger::Batch;
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Step, Target, TargetedMessage};
use hbbft::traits::Contribution;
use hbbft::{Contribution, DistAlgorithm, NetworkInfo, Step, Target, TargetedMessage};
/// A node identifier. In the tests, nodes are simply numbered.
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Serialize, Deserialize, Rand)]

View File

@ -19,8 +19,8 @@ use std::collections::BTreeMap;
use std::sync::Arc;
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
use hbbft::messaging::NetworkInfo;
use hbbft::queueing_honey_badger::{Batch, Change, ChangeState, Input, QueueingHoneyBadger, Step};
use hbbft::NetworkInfo;
use itertools::Itertools;
use rand::Rng;

View File

@ -18,8 +18,8 @@ use std::collections::{BTreeMap, BTreeSet};
use std::iter::once;
use std::sync::Arc;
use hbbft::messaging::NetworkInfo;
use hbbft::subset::{Subset, SubsetOutput};
use hbbft::NetworkInfo;
use network::{Adversary, MessageScheduler, NodeId, SilentAdversary, TestNetwork, TestNode};