Merge pull request #187 from c0gent/c0gent-supertraits

Add common supertraits and rename related type parameters.
This commit is contained in:
Andreas Fackler 2018-08-03 11:13:40 +02:00 committed by GitHub
commit 22ccb740f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 448 additions and 481 deletions

View File

@ -1,5 +1,4 @@
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::sync::Arc;
use itertools::Itertools;
@ -10,18 +9,19 @@ use super::{AgreementContent, AgreementMessage, Error, Nonce, Result, Step};
use agreement::bool_set::BoolSet;
use common_coin::{self, CommonCoin, CommonCoinMessage};
use messaging::{DistAlgorithm, NetworkInfo, Target};
use traits::NodeUidT;
/// The state of the current epoch's common coin. In some epochs this is fixed, in others it starts
/// with in `InProgress`.
#[derive(Debug)]
enum CoinState<NodeUid> {
enum CoinState<N> {
/// The value was fixed in the current epoch, or the coin has already terminated.
Decided(bool),
/// The coin value is not known yet.
InProgress(CommonCoin<NodeUid, Nonce>),
InProgress(CommonCoin<N, Nonce>),
}
impl<NodeUid> CoinState<NodeUid> {
impl<N> CoinState<N> {
/// Returns the value, if this coin has already decided.
fn value(&self) -> Option<bool> {
match self {
@ -31,7 +31,7 @@ impl<NodeUid> CoinState<NodeUid> {
}
}
impl<NodeUid> From<bool> for CoinState<NodeUid> {
impl<N> From<bool> for CoinState<N> {
fn from(value: bool) -> Self {
CoinState::Decided(value)
}
@ -39,22 +39,22 @@ impl<NodeUid> From<bool> for CoinState<NodeUid> {
/// Binary Agreement instance
#[derive(Debug)]
pub struct Agreement<NodeUid> {
pub struct Agreement<N> {
/// Shared network information.
netinfo: Arc<NetworkInfo<NodeUid>>,
netinfo: Arc<NetworkInfo<N>>,
/// Session ID, e.g, the Honey Badger algorithm epoch.
session_id: u64,
/// The ID of the proposer of the value for this agreement instance.
proposer_id: NodeUid,
proposer_id: N,
/// Agreement algorithm epoch.
epoch: u32,
/// This epoch's Synchronized Binary Value Broadcast instance.
sbv_broadcast: SbvBroadcast<NodeUid>,
sbv_broadcast: SbvBroadcast<N>,
/// Received `Conf` messages. Reset on every epoch update.
received_conf: BTreeMap<NodeUid, BoolSet>,
received_conf: BTreeMap<N, BoolSet>,
/// Received `Term` messages. Kept throughout epoch updates. These count as `BVal`, `Aux` and
/// `Conf` messages for all future epochs.
received_term: BoolMultimap<NodeUid>,
received_term: BoolMultimap<N>,
/// The estimate of the decision value in the current epoch.
estimated: Option<bool>,
/// A permanent, latching copy of the output value. This copy is required because `output` can
@ -65,21 +65,21 @@ pub struct Agreement<NodeUid> {
decision: Option<bool>,
/// A cache for messages for future epochs that cannot be handled yet.
// TODO: Find a better solution for this; defend against spam.
incoming_queue: BTreeMap<u32, Vec<(NodeUid, AgreementContent)>>,
incoming_queue: BTreeMap<u32, Vec<(N, AgreementContent)>>,
/// The values we found in the first _N - f_ `Aux` messages that were in `bin_values`.
conf_values: Option<BoolSet>,
/// The state of this epoch's common coin.
coin_state: CoinState<NodeUid>,
coin_state: CoinState<N>,
}
impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for Agreement<NodeUid> {
type NodeUid = NodeUid;
impl<N: NodeUidT> DistAlgorithm for Agreement<N> {
type NodeUid = N;
type Input = bool;
type Output = bool;
type Message = AgreementMessage;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<N>> {
self.set_input(input)
}
@ -88,7 +88,7 @@ impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for Agreement<NodeUid> {
&mut self,
sender_id: &Self::NodeUid,
AgreementMessage { epoch, content }: Self::Message,
) -> Result<Step<NodeUid>> {
) -> Result<Step<N>> {
if self.decision.is_some() || (epoch < self.epoch && content.can_expire()) {
// Message is obsolete: We are already in a later epoch or terminated.
Ok(Step::default())
@ -112,12 +112,8 @@ impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for Agreement<NodeUid> {
}
}
impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
pub fn new(
netinfo: Arc<NetworkInfo<NodeUid>>,
session_id: u64,
proposer_id: NodeUid,
) -> Result<Self> {
impl<N: NodeUidT> Agreement<N> {
pub fn new(netinfo: Arc<NetworkInfo<N>>, session_id: u64, proposer_id: N) -> Result<Self> {
if !netinfo.is_node_validator(&proposer_id) {
return Err(Error::UnknownProposer);
}
@ -138,7 +134,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Sets the input value for agreement.
fn set_input(&mut self, input: bool) -> Result<Step<NodeUid>> {
fn set_input(&mut self, input: bool) -> Result<Step<N>> {
if self.epoch != 0 || self.estimated.is_some() {
return Err(Error::InputNotAccepted);
}
@ -157,9 +153,9 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Dispatches the message content to the corresponding handling method.
fn handle_message_content(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
content: AgreementContent,
) -> Result<Step<NodeUid>> {
) -> Result<Step<N>> {
match content {
AgreementContent::SbvBroadcast(msg) => self.handle_sbv_broadcast(sender_id, msg),
AgreementContent::Conf(v) => self.handle_conf(sender_id, v),
@ -171,19 +167,16 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Handles a Synchroniced Binary Value Broadcast message.
fn handle_sbv_broadcast(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
msg: sbv_broadcast::Message,
) -> Result<Step<NodeUid>> {
) -> Result<Step<N>> {
let sbvb_step = self.sbv_broadcast.handle_message(sender_id, msg)?;
self.handle_sbvb_step(sbvb_step)
}
/// Handles a Synchronized Binary Value Broadcast step. On output, starts the `Conf` round or
/// decides.
fn handle_sbvb_step(
&mut self,
sbvb_step: sbv_broadcast::Step<NodeUid>,
) -> Result<Step<NodeUid>> {
fn handle_sbvb_step(&mut self, sbvb_step: sbv_broadcast::Step<N>) -> Result<Step<N>> {
let mut step = Step::default();
let output = step.extend_with(sbvb_step, |msg| {
AgreementContent::SbvBroadcast(msg).with_epoch(self.epoch)
@ -209,7 +202,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Handles a `Conf` message. When _N - f_ `Conf` messages with values in `bin_values` have
/// been received, updates the epoch or decides.
fn handle_conf(&mut self, sender_id: &NodeUid, v: BoolSet) -> Result<Step<NodeUid>> {
fn handle_conf(&mut self, sender_id: &N, v: BoolSet) -> Result<Step<N>> {
self.received_conf.insert(sender_id.clone(), v);
self.try_finish_conf_round()
}
@ -217,7 +210,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Handles a `Term(v)` message. If we haven't yet decided on a value and there are more than
/// _f_ such messages with the same value from different nodes, performs expedite termination:
/// decides on `v`, broadcasts `Term(v)` and terminates the instance.
fn handle_term(&mut self, sender_id: &NodeUid, b: bool) -> Result<Step<NodeUid>> {
fn handle_term(&mut self, sender_id: &N, b: bool) -> Result<Step<N>> {
self.received_term[b].insert(sender_id.clone());
// Check for the expedite termination condition.
if self.decision.is_some() {
@ -236,11 +229,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Handles a Common Coin message. If there is output from Common Coin, starts the next
/// epoch. The function may output a decision value.
fn handle_coin(
&mut self,
sender_id: &NodeUid,
msg: CommonCoinMessage,
) -> Result<Step<NodeUid>> {
fn handle_coin(&mut self, sender_id: &N, msg: CommonCoinMessage) -> Result<Step<N>> {
let coin_step = match self.coin_state {
CoinState::Decided(_) => return Ok(Step::default()), // Coin value is already decided.
CoinState::InProgress(ref mut common_coin) => common_coin
@ -251,7 +240,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Multicasts a `Conf(values)` message, and handles it.
fn send_conf(&mut self, values: BoolSet) -> Result<Step<NodeUid>> {
fn send_conf(&mut self, values: BoolSet) -> Result<Step<N>> {
if self.conf_values.is_some() {
// Only one `Conf` message is allowed in an epoch.
return Ok(Step::default());
@ -268,7 +257,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Multicasts and handles a message. Does nothing if we are only an observer.
fn send(&mut self, content: AgreementContent) -> Result<Step<NodeUid>> {
fn send(&mut self, content: AgreementContent) -> Result<Step<N>> {
if !self.netinfo.is_validator() {
return Ok(Step::default());
}
@ -281,10 +270,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Handles a step returned from the `CommonCoin`.
fn on_coin_step(
&mut self,
coin_step: common_coin::Step<NodeUid, Nonce>,
) -> Result<Step<NodeUid>> {
fn on_coin_step(&mut self, coin_step: common_coin::Step<N, Nonce>) -> Result<Step<N>> {
let mut step = Step::default();
let epoch = self.epoch;
let to_msg = |c_msg| AgreementContent::Coin(Box::new(c_msg)).with_epoch(epoch);
@ -302,7 +288,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// With two conf values, the next epoch's estimate is the coin value. If there is only one conf
/// value and that disagrees with the coin, the conf value is the next epoch's estimate. If
/// the unique conf value agrees with the coin, terminates and decides on that value.
fn try_update_epoch(&mut self) -> Result<Step<NodeUid>> {
fn try_update_epoch(&mut self) -> Result<Step<N>> {
if self.decision.is_some() {
// Avoid an infinite regression without making an Agreement step.
return Ok(Step::default());
@ -325,7 +311,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Creates the initial coin state for the current epoch, i.e. sets it to the predetermined
/// value, or initializes a `CommonCoin` instance.
fn coin_state(&self) -> CoinState<NodeUid> {
fn coin_state(&self) -> CoinState<N> {
match self.epoch % 3 {
0 => CoinState::Decided(true),
1 => CoinState::Decided(false),
@ -342,7 +328,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Decides on a value and broadcasts a `Term` message with that value.
fn decide(&mut self, b: bool) -> Step<NodeUid> {
fn decide(&mut self, b: bool) -> Step<N> {
if self.decision.is_some() {
return Step::default();
}
@ -366,7 +352,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Checks whether the _N - f_ `Conf` messages have arrived, and if so, activates the coin.
fn try_finish_conf_round(&mut self) -> Result<Step<NodeUid>> {
fn try_finish_conf_round(&mut self) -> Result<Step<N>> {
if self.conf_values.is_none() || self.count_conf() < self.netinfo.num_correct() {
return Ok(Step::default());
}
@ -390,7 +376,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
}
/// Increments the epoch, sets the new estimate and handles queued messages.
fn update_epoch(&mut self, b: bool) -> Result<Step<NodeUid>> {
fn update_epoch(&mut self, b: bool) -> Result<Step<N>> {
self.sbv_broadcast.clear(&self.received_term);
self.received_conf.clear();
for (v, id) in &self.received_term {

View File

@ -92,7 +92,7 @@ pub enum Error {
/// An agreement result.
pub type Result<T> = ::std::result::Result<T, Error>;
pub type Step<NodeUid> = messaging::Step<Agreement<NodeUid>>;
pub type Step<N> = messaging::Step<Agreement<N>>;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum AgreementContent {

View File

@ -10,7 +10,6 @@
//! `bin_values` of values for which _2 f + 1_ `BVal`s were received.
use rand;
use std::fmt::Debug;
use std::sync::Arc;
use super::bool_multimap::BoolMultimap;
@ -18,8 +17,9 @@ use super::bool_set::{self, BoolSet};
use super::{Error, Result};
use fault_log::{Fault, FaultKind};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeUidT;
pub type Step<NodeUid> = messaging::Step<SbvBroadcast<NodeUid>>;
pub type Step<N> = messaging::Step<SbvBroadcast<N>>;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Message {
@ -43,37 +43,33 @@ impl rand::Rand for Message {
}
#[derive(Debug)]
pub struct SbvBroadcast<NodeUid> {
pub struct SbvBroadcast<N> {
/// Shared network information.
netinfo: Arc<NetworkInfo<NodeUid>>,
netinfo: Arc<NetworkInfo<N>>,
/// The set of values for which _2 f + 1_ `BVal`s have been received.
bin_values: BoolSet,
/// The nodes that sent us a `BVal(b)`, by `b`.
received_bval: BoolMultimap<NodeUid>,
received_bval: BoolMultimap<N>,
/// The values `b` for which we already sent `BVal(b)`.
sent_bval: BoolSet,
/// The nodes that sent us an `Aux(b)`, by `b`.
received_aux: BoolMultimap<NodeUid>,
received_aux: BoolMultimap<N>,
/// Whether we have already output.
terminated: bool,
}
impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for SbvBroadcast<NodeUid> {
type NodeUid = NodeUid;
impl<N: NodeUidT> DistAlgorithm for SbvBroadcast<N> {
type NodeUid = N;
type Input = bool;
type Output = BoolSet;
type Message = Message;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<N>> {
self.send_bval(input)
}
fn handle_message(
&mut self,
sender_id: &Self::NodeUid,
msg: Self::Message,
) -> Result<Step<NodeUid>> {
fn handle_message(&mut self, sender_id: &Self::NodeUid, msg: Self::Message) -> Result<Step<N>> {
match msg {
Message::BVal(b) => self.handle_bval(sender_id, b),
Message::Aux(b) => self.handle_aux(sender_id, b),
@ -89,8 +85,8 @@ impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for SbvBroadcast<NodeUid> {
}
}
impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>) -> Self {
impl<N: NodeUidT> SbvBroadcast<N> {
pub fn new(netinfo: Arc<NetworkInfo<N>>) -> Self {
SbvBroadcast {
netinfo,
bin_values: bool_set::NONE,
@ -103,7 +99,7 @@ impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
/// Resets the algorithm, but assumes the given `init` values have already been received as
/// both `BVal` and `Aux` messages.
pub fn clear(&mut self, init: &BoolMultimap<NodeUid>) {
pub fn clear(&mut self, init: &BoolMultimap<N>) {
self.bin_values = bool_set::NONE;
self.received_bval = init.clone();
self.sent_bval = bool_set::NONE;
@ -115,7 +111,7 @@ impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
///
/// Upon receiving _f + 1_ `BVal(b)`, multicasts `BVal(b)`. Upon receiving _2 f + 1_ `BVal(b)`,
/// updates `bin_values`. When `bin_values` gets its first entry, multicasts `Aux(b)`.
pub fn handle_bval(&mut self, sender_id: &NodeUid, b: bool) -> Result<Step<NodeUid>> {
pub fn handle_bval(&mut self, sender_id: &N, b: bool) -> Result<Step<N>> {
let count_bval = {
if !self.received_bval[b].insert(sender_id.clone()) {
return Ok(Fault::new(sender_id.clone(), FaultKind::DuplicateBVal).into());
@ -148,7 +144,7 @@ impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
}
/// Multicasts and handles a message. Does nothing if we are only an observer.
fn send(&mut self, msg: Message) -> Result<Step<NodeUid>> {
fn send(&mut self, msg: Message) -> Result<Step<N>> {
if !self.netinfo.is_validator() {
return Ok(Step::default());
}
@ -159,7 +155,7 @@ impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
}
/// Multicasts a `BVal(b)` message, and handles it.
fn send_bval(&mut self, b: bool) -> Result<Step<NodeUid>> {
fn send_bval(&mut self, b: bool) -> Result<Step<N>> {
// Record the value `b` as sent. If it was already there, don't send it again.
if !self.sent_bval.insert(b) {
return Ok(Step::default());
@ -168,7 +164,7 @@ impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
}
/// Handles an `Aux` message.
pub fn handle_aux(&mut self, sender_id: &NodeUid, b: bool) -> Result<Step<NodeUid>> {
pub fn handle_aux(&mut self, sender_id: &N, b: bool) -> Result<Step<N>> {
if !self.received_aux[b].insert(sender_id.clone()) {
return Ok(Fault::new(sender_id.clone(), FaultKind::DuplicateAux).into());
}
@ -176,7 +172,7 @@ impl<NodeUid: Clone + Debug + Ord> SbvBroadcast<NodeUid> {
}
/// Checks whether there are _N - f_ `Aux` messages with values in `bin_values`, and outputs.
fn try_output(&mut self) -> Result<Step<NodeUid>> {
fn try_output(&mut self) -> Result<Step<N>> {
if self.terminated || self.bin_values == bool_set::NONE {
return Ok(Step::default());
}

View File

@ -163,6 +163,7 @@ use ring::digest;
use fault_log::{Fault, FaultKind};
use fmt::{HexBytes, HexList, HexProof};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeUidT;
/// A broadcast error.
#[derive(Clone, PartialEq, Debug, Fail)]
@ -239,11 +240,11 @@ impl Debug for BroadcastMessage {
/// Reliable Broadcast algorithm instance.
#[derive(Debug)]
pub struct Broadcast<NodeUid> {
pub struct Broadcast<N> {
/// Shared network data.
netinfo: Arc<NetworkInfo<NodeUid>>,
netinfo: Arc<NetworkInfo<N>>,
/// The UID of the sending node.
proposer_id: NodeUid,
proposer_id: N,
data_shard_num: usize,
coding: Coding,
/// Whether we have already multicast `Echo`.
@ -253,15 +254,15 @@ pub struct Broadcast<NodeUid> {
/// Whether we have already output a value.
decided: bool,
/// The proofs we have received via `Echo` messages, by sender ID.
echos: BTreeMap<NodeUid, Proof<Vec<u8>>>,
echos: BTreeMap<N, Proof<Vec<u8>>>,
/// The root hashes we received via `Ready` messages, by sender ID.
readys: BTreeMap<NodeUid, Vec<u8>>,
readys: BTreeMap<N, Vec<u8>>,
}
pub type Step<NodeUid> = messaging::Step<Broadcast<NodeUid>>;
pub type Step<N> = messaging::Step<Broadcast<N>>;
impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
type NodeUid = NodeUid;
impl<N: NodeUidT> DistAlgorithm for Broadcast<N> {
type NodeUid = N;
// TODO: Allow anything serializable and deserializable, i.e. make this a type parameter
// T: Serialize + DeserializeOwned
type Input = Vec<u8>;
@ -269,7 +270,7 @@ impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
type Message = BroadcastMessage;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<N>> {
if *self.netinfo.our_uid() != self.proposer_id {
return Err(Error::InstanceCannotPropose);
}
@ -282,11 +283,7 @@ impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
Ok(step)
}
fn handle_message(
&mut self,
sender_id: &NodeUid,
message: Self::Message,
) -> Result<Step<NodeUid>> {
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> Result<Step<N>> {
if !self.netinfo.is_node_validator(sender_id) {
return Err(Error::UnknownSender);
}
@ -301,15 +298,15 @@ impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
self.decided
}
fn our_id(&self) -> &NodeUid {
fn our_id(&self) -> &N {
self.netinfo.our_uid()
}
}
impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
impl<N: NodeUidT> 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<NodeUid>>, proposer_id: NodeUid) -> Result<Self> {
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;
let coding = Coding::new(data_shard_num, parity_shard_num)?;
@ -332,7 +329,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
/// scheme. The returned value contains the shard assigned to this
/// node. That shard doesn't need to be sent anywhere. It gets recorded in
/// the broadcast instance.
fn send_shards(&mut self, mut value: Vec<u8>) -> Result<(Proof<Vec<u8>>, Step<NodeUid>)> {
fn send_shards(&mut self, mut value: Vec<u8>) -> Result<(Proof<Vec<u8>>, Step<N>)> {
let data_shard_num = self.coding.data_shard_count();
let parity_shard_num = self.coding.parity_shard_count();
@ -407,7 +404,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
}
/// Handles a received echo and verifies the proof it contains.
fn handle_value(&mut self, sender_id: &NodeUid, p: Proof<Vec<u8>>) -> Result<Step<NodeUid>> {
fn handle_value(&mut self, sender_id: &N, p: Proof<Vec<u8>>) -> Result<Step<N>> {
// If the sender is not the proposer or if this is not the first `Value`, ignore.
if *sender_id != self.proposer_id {
info!(
@ -439,7 +436,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
}
/// Handles a received `Echo` message.
fn handle_echo(&mut self, sender_id: &NodeUid, p: Proof<Vec<u8>>) -> Result<Step<NodeUid>> {
fn handle_echo(&mut self, sender_id: &N, p: Proof<Vec<u8>>) -> Result<Step<N>> {
// If the sender has already sent `Echo`, ignore.
if self.echos.contains_key(sender_id) {
info!(
@ -469,7 +466,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
}
/// Handles a received `Ready` message.
fn handle_ready(&mut self, sender_id: &NodeUid, hash: &[u8]) -> Result<Step<NodeUid>> {
fn handle_ready(&mut self, sender_id: &N, hash: &[u8]) -> Result<Step<N>> {
// If the sender has already sent a `Ready` before, ignore.
if self.readys.contains_key(sender_id) {
info!(
@ -494,7 +491,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
}
/// Sends an `Echo` message and handles it. Does nothing if we are only an observer.
fn send_echo(&mut self, p: Proof<Vec<u8>>) -> Result<Step<NodeUid>> {
fn send_echo(&mut self, p: Proof<Vec<u8>>) -> Result<Step<N>> {
self.echo_sent = true;
if !self.netinfo.is_validator() {
return Ok(Step::default());
@ -507,7 +504,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
}
/// Sends a `Ready` message and handles it. Does nothing if we are only an observer.
fn send_ready(&mut self, hash: &[u8]) -> Result<Step<NodeUid>> {
fn send_ready(&mut self, hash: &[u8]) -> Result<Step<N>> {
self.ready_sent = true;
if !self.netinfo.is_validator() {
return Ok(Step::default());
@ -521,7 +518,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
/// Checks whether the conditions for output are met for this hash, and if so, sets the output
/// value.
fn compute_output(&mut self, hash: &[u8]) -> Result<Step<NodeUid>> {
fn compute_output(&mut self, hash: &[u8]) -> Result<Step<N>> {
if self.decided
|| self.count_readys(hash) <= 2 * self.netinfo.num_faulty()
|| self.count_echos(hash) < self.coding.data_shard_count()
@ -555,7 +552,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
/// Returns `true` if the proof is valid and has the same index as the node ID. Otherwise
/// logs an info message.
fn validate_proof(&self, p: &Proof<Vec<u8>>, id: &NodeUid) -> bool {
fn validate_proof(&self, p: &Proof<Vec<u8>>, id: &N) -> bool {
if !p.validate(&p.root_hash) {
info!(
"Node {:?} received invalid proof: {:?}",

View File

@ -22,13 +22,13 @@
//! of its bits.
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::sync::Arc;
use crypto::error as cerror;
use crypto::{Signature, SignatureShare};
use fault_log::{Fault, FaultKind};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::NodeUidT;
/// A common coin error.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
@ -61,33 +61,33 @@ impl CommonCoinMessage {
/// receiving at least `num_faulty + 1` shares, attempts to combine them into a signature. If that
/// signature is valid, the instance outputs it and terminates; otherwise the instance aborts.
#[derive(Debug)]
pub struct CommonCoin<NodeUid, T> {
netinfo: Arc<NetworkInfo<NodeUid>>,
pub struct CommonCoin<N, T> {
netinfo: Arc<NetworkInfo<N>>,
/// The name of this common coin. It is required to be unique for each common coin round.
nonce: T,
/// All received threshold signature shares.
received_shares: BTreeMap<NodeUid, SignatureShare>,
received_shares: BTreeMap<N, SignatureShare>,
/// Whether we provided input to the common coin.
had_input: bool,
/// Termination flag.
terminated: bool,
}
pub type Step<NodeUid, T> = messaging::Step<CommonCoin<NodeUid, T>>;
pub type Step<N, T> = messaging::Step<CommonCoin<N, T>>;
impl<NodeUid, T> DistAlgorithm for CommonCoin<NodeUid, T>
impl<N, T> DistAlgorithm for CommonCoin<N, T>
where
NodeUid: Clone + Debug + Ord,
N: NodeUidT,
T: Clone + AsRef<[u8]>,
{
type NodeUid = NodeUid;
type NodeUid = N;
type Input = ();
type Output = bool;
type Message = CommonCoinMessage;
type Error = Error;
/// Sends our threshold signature share if not yet sent.
fn input(&mut self, _input: Self::Input) -> Result<Step<NodeUid, T>> {
fn input(&mut self, _input: Self::Input) -> Result<Step<N, T>> {
if !self.had_input {
self.had_input = true;
self.get_coin()
@ -101,7 +101,7 @@ where
&mut self,
sender_id: &Self::NodeUid,
message: Self::Message,
) -> Result<Step<NodeUid, T>> {
) -> Result<Step<N, T>> {
if !self.terminated {
let CommonCoinMessage(share) = message;
self.handle_share(sender_id, share)
@ -120,12 +120,12 @@ where
}
}
impl<NodeUid, T> CommonCoin<NodeUid, T>
impl<N, T> CommonCoin<N, T>
where
NodeUid: Clone + Debug + Ord,
N: NodeUidT,
T: Clone + AsRef<[u8]>,
{
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>, nonce: T) -> Self {
pub fn new(netinfo: Arc<NetworkInfo<N>>, nonce: T) -> Self {
CommonCoin {
netinfo,
nonce,
@ -135,7 +135,7 @@ where
}
}
fn get_coin(&mut self) -> Result<Step<NodeUid, T>> {
fn get_coin(&mut self) -> Result<Step<N, T>> {
if !self.netinfo.is_validator() {
return self.try_output();
}
@ -146,11 +146,7 @@ where
Ok(step)
}
fn handle_share(
&mut self,
sender_id: &NodeUid,
share: SignatureShare,
) -> Result<Step<NodeUid, T>> {
fn handle_share(&mut self, sender_id: &N, share: SignatureShare) -> Result<Step<N, T>> {
if let Some(pk_i) = self.netinfo.public_key_share(sender_id) {
if !pk_i.verify(&share, &self.nonce) {
// Log the faulty node and ignore the invalid share.
@ -164,7 +160,7 @@ where
self.try_output()
}
fn try_output(&mut self) -> Result<Step<NodeUid, T>> {
fn try_output(&mut self) -> Result<Step<N, T>> {
debug!(
"{:?} received {} shares, had_input = {}",
self.netinfo.our_uid(),

View File

@ -24,7 +24,6 @@
//! values for which the decision was "yes".
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::result;
use std::sync::Arc;
@ -33,6 +32,7 @@ use broadcast::{self, Broadcast, BroadcastMessage};
use fmt::HexBytes;
use messaging::{self, DistAlgorithm, NetworkInfo};
use rand::Rand;
use traits::NodeUidT;
/// A common subset error.
#[derive(Clone, PartialEq, Debug, Fail)]
@ -63,37 +63,37 @@ type ProposedValue = Vec<u8>;
/// Message from Common Subset to remote nodes.
#[derive(Serialize, Deserialize, Clone, Debug, Rand)]
pub enum Message<NodeUid: Rand> {
pub enum Message<N: Rand> {
/// A message for the broadcast algorithm concerning the set element proposed by the given node.
Broadcast(NodeUid, BroadcastMessage),
Broadcast(N, BroadcastMessage),
/// A message for the agreement algorithm concerning the set element proposed by the given
/// node.
Agreement(NodeUid, AgreementMessage),
Agreement(N, AgreementMessage),
}
/// Asynchronous Common Subset algorithm instance
#[derive(Debug)]
pub struct CommonSubset<NodeUid: Rand> {
pub struct CommonSubset<N: Rand> {
/// Shared network information.
netinfo: Arc<NetworkInfo<NodeUid>>,
broadcast_instances: BTreeMap<NodeUid, Broadcast<NodeUid>>,
agreement_instances: BTreeMap<NodeUid, Agreement<NodeUid>>,
broadcast_results: BTreeMap<NodeUid, ProposedValue>,
agreement_results: BTreeMap<NodeUid, bool>,
netinfo: Arc<NetworkInfo<N>>,
broadcast_instances: BTreeMap<N, Broadcast<N>>,
agreement_instances: BTreeMap<N, Agreement<N>>,
broadcast_results: BTreeMap<N, ProposedValue>,
agreement_results: BTreeMap<N, bool>,
/// Whether the instance has decided on a value.
decided: bool,
}
pub type Step<NodeUid> = messaging::Step<CommonSubset<NodeUid>>;
pub type Step<N> = messaging::Step<CommonSubset<N>>;
impl<NodeUid: Clone + Debug + Ord + Rand> DistAlgorithm for CommonSubset<NodeUid> {
type NodeUid = NodeUid;
impl<N: NodeUidT + Rand> DistAlgorithm for CommonSubset<N> {
type NodeUid = N;
type Input = ProposedValue;
type Output = BTreeMap<NodeUid, ProposedValue>;
type Message = Message<NodeUid>;
type Output = BTreeMap<N, ProposedValue>;
type Message = Message<N>;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<N>> {
debug!(
"{:?} Proposing {:?}",
self.netinfo.our_uid(),
@ -106,7 +106,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> DistAlgorithm for CommonSubset<NodeUid
&mut self,
sender_id: &Self::NodeUid,
message: Self::Message,
) -> Result<Step<NodeUid>> {
) -> Result<Step<N>> {
match message {
Message::Broadcast(p_id, b_msg) => self.handle_broadcast(sender_id, &p_id, b_msg),
Message::Agreement(p_id, a_msg) => self.handle_agreement(sender_id, &p_id, a_msg),
@ -122,10 +122,10 @@ impl<NodeUid: Clone + Debug + Ord + Rand> DistAlgorithm for CommonSubset<NodeUid
}
}
impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>, session_id: u64) -> Result<Self> {
impl<N: NodeUidT + Rand> CommonSubset<N> {
pub fn new(netinfo: Arc<NetworkInfo<N>>, session_id: u64) -> Result<Self> {
// Create all broadcast instances.
let mut broadcast_instances: BTreeMap<NodeUid, Broadcast<NodeUid>> = BTreeMap::new();
let mut broadcast_instances: BTreeMap<N, Broadcast<N>> = BTreeMap::new();
for proposer_id in netinfo.all_uids() {
broadcast_instances.insert(
proposer_id.clone(),
@ -134,7 +134,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
}
// Create all agreement instances.
let mut agreement_instances: BTreeMap<NodeUid, Agreement<NodeUid>> = BTreeMap::new();
let mut agreement_instances: BTreeMap<N, Agreement<N>> = BTreeMap::new();
for proposer_id in netinfo.all_uids() {
agreement_instances.insert(
proposer_id.clone(),
@ -155,7 +155,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
/// Common Subset input message handler. It receives a value for broadcast
/// and redirects it to the corresponding broadcast instance.
pub fn send_proposed_value(&mut self, value: ProposedValue) -> Result<Step<NodeUid>> {
pub fn send_proposed_value(&mut self, value: ProposedValue) -> Result<Step<N>> {
if !self.netinfo.is_validator() {
return Ok(Step::default());
}
@ -173,10 +173,10 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
/// value proposed by the node `proposer_id`.
fn handle_broadcast(
&mut self,
sender_id: &NodeUid,
proposer_id: &NodeUid,
sender_id: &N,
proposer_id: &N,
bmessage: BroadcastMessage,
) -> Result<Step<NodeUid>> {
) -> Result<Step<N>> {
self.process_broadcast(proposer_id, |bc| bc.handle_message(sender_id, bmessage))
}
@ -184,10 +184,10 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
/// a value proposed by the node `proposer_id`.
fn handle_agreement(
&mut self,
sender_id: &NodeUid,
proposer_id: &NodeUid,
sender_id: &N,
proposer_id: &N,
amessage: AgreementMessage,
) -> Result<Step<NodeUid>> {
) -> Result<Step<N>> {
// Send the message to the local instance of Agreement
self.process_agreement(proposer_id, |agreement| {
agreement.handle_message(sender_id, amessage)
@ -196,10 +196,9 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
/// Upon delivery of v_j from RBC_j, if input has not yet been provided to
/// BA_j, then provide input 1 to BA_j. See Figure 11.
fn process_broadcast<F>(&mut self, proposer_id: &NodeUid, f: F) -> Result<Step<NodeUid>>
fn process_broadcast<F>(&mut self, proposer_id: &N, f: F) -> Result<Step<N>>
where
F: FnOnce(&mut Broadcast<NodeUid>)
-> result::Result<broadcast::Step<NodeUid>, broadcast::Error>,
F: FnOnce(&mut Broadcast<N>) -> result::Result<broadcast::Step<N>, broadcast::Error>,
{
let mut step = Step::default();
let value = {
@ -219,7 +218,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
}
};
self.broadcast_results.insert(proposer_id.clone(), value);
let set_agreement_input = |agreement: &mut Agreement<NodeUid>| {
let set_agreement_input = |agreement: &mut Agreement<N>| {
if agreement.accepts_input() {
agreement.input(true)
} else {
@ -232,10 +231,9 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
/// Callback to be invoked on receipt of the decision value of the Agreement
/// instance `uid`.
fn process_agreement<F>(&mut self, proposer_id: &NodeUid, f: F) -> Result<Step<NodeUid>>
fn process_agreement<F>(&mut self, proposer_id: &N, f: F) -> Result<Step<N>>
where
F: FnOnce(&mut Agreement<NodeUid>)
-> result::Result<agreement::Step<NodeUid>, agreement::Error>,
F: FnOnce(&mut Agreement<N>) -> result::Result<agreement::Step<N>, agreement::Error>,
{
let mut step = Step::default();
let value = {
@ -298,7 +296,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
self.agreement_results.values().filter(|v| **v).count()
}
fn try_agreement_completion(&mut self) -> Option<BTreeMap<NodeUid, ProposedValue>> {
fn try_agreement_completion(&mut self) -> Option<BTreeMap<N, ProposedValue>> {
if self.decided || self.count_true() < self.netinfo.num_correct() {
return None;
}
@ -313,7 +311,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
self.netinfo.our_uid()
);
// All instances of Agreement that delivered `true` (or "1" in the paper).
let delivered_1: BTreeSet<&NodeUid> = self
let delivered_1: BTreeSet<&N> = self
.agreement_results
.iter()
.filter(|(_, v)| **v)
@ -322,7 +320,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
debug!("Agreement instances that delivered 1: {:?}", delivered_1);
// Results of Broadcast instances in `delivered_1`
let broadcast_results: BTreeMap<NodeUid, ProposedValue> = self
let broadcast_results: BTreeMap<N, ProposedValue> = self
.broadcast_results
.iter()
.filter(|(k, _)| delivered_1.contains(k))

View File

@ -1,5 +1,4 @@
use std::collections::BTreeMap;
use std::fmt::Debug;
use rand::Rand;
use serde::{Deserialize, Serialize};
@ -7,22 +6,23 @@ use serde::{Deserialize, Serialize};
use super::{ChangeState, JoinPlan};
use crypto::{PublicKey, PublicKeySet};
use messaging::NetworkInfo;
use traits::NodeUidT;
/// A batch of transactions the algorithm has output.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Batch<C, NodeUid> {
pub struct Batch<C, N> {
/// The sequence number: there is exactly one batch in each epoch.
pub(super) epoch: u64,
/// The user contributions committed in this epoch.
pub(super) contributions: BTreeMap<NodeUid, C>,
pub(super) contributions: BTreeMap<N, C>,
/// The current state of adding or removing a node: whether any is in progress, or completed
/// this epoch.
change: ChangeState<NodeUid>,
change: ChangeState<N>,
/// The public network info, if `change` is not `None`.
pub_netinfo: Option<(PublicKeySet, BTreeMap<NodeUid, PublicKey>)>,
pub_netinfo: Option<(PublicKeySet, BTreeMap<N, PublicKey>)>,
}
impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
impl<C, N: NodeUidT + Rand> Batch<C, N> {
/// Returns a new, empty batch with the given epoch.
pub fn new(epoch: u64) -> Self {
Batch {
@ -39,7 +39,7 @@ impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
/// Returns whether any change to the set of participating nodes is in progress or was
/// completed in this epoch.
pub fn change(&self) -> &ChangeState<NodeUid> {
pub fn change(&self) -> &ChangeState<N> {
&self.change
}
@ -60,33 +60,33 @@ impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
}
/// Returns the number of transactions in the batch (without detecting duplicates).
pub fn len<Tx>(&self) -> usize
pub fn len<T>(&self) -> usize
where
C: AsRef<[Tx]>,
C: AsRef<[T]>,
{
self.contributions
.values()
.map(C::as_ref)
.map(<[Tx]>::len)
.map(<[T]>::len)
.sum()
}
/// Returns `true` if the batch contains no transactions.
pub fn is_empty<Tx>(&self) -> bool
pub fn is_empty<T>(&self) -> bool
where
C: AsRef<[Tx]>,
C: AsRef<[T]>,
{
self.contributions
.values()
.map(C::as_ref)
.all(<[Tx]>::is_empty)
.all(<[T]>::is_empty)
}
/// Returns the `JoinPlan` to be sent to new observer nodes, if it is possible to join in the
/// next epoch.
pub fn join_plan(&self) -> Option<JoinPlan<NodeUid>>
pub fn join_plan(&self) -> Option<JoinPlan<N>>
where
NodeUid: Serialize + for<'r> Deserialize<'r>,
N: Serialize + for<'r> Deserialize<'r>,
{
self.pub_netinfo
.as_ref()
@ -100,11 +100,7 @@ impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
/// Sets the current change state, and if it is not `None`, inserts the network information so
/// that a `JoinPlan` can be generated for the next epoch.
pub(super) fn set_change(
&mut self,
change: ChangeState<NodeUid>,
netinfo: &NetworkInfo<NodeUid>,
) {
pub(super) fn set_change(&mut self, change: ChangeState<N>, netinfo: &NetworkInfo<N>) {
self.change = change;
if self.change != ChangeState::None {
self.pub_netinfo = Some((

View File

@ -1,6 +1,4 @@
use std::default::Default;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::once;
use std::marker::PhantomData;
use std::sync::Arc;
@ -12,16 +10,17 @@ use serde::{Deserialize, Serialize};
use super::{ChangeState, DynamicHoneyBadger, JoinPlan, Result, Step, VoteCounter};
use honey_badger::HoneyBadger;
use messaging::NetworkInfo;
use traits::{Contribution, NodeUidT};
/// A Dynamic Honey Badger builder, to configure the parameters and create new instances of
/// `DynamicHoneyBadger`.
pub struct DynamicHoneyBadgerBuilder<C, NodeUid> {
pub struct DynamicHoneyBadgerBuilder<C, N> {
/// The maximum number of future epochs for which we handle messages simultaneously.
max_future_epochs: usize,
_phantom: PhantomData<(C, NodeUid)>,
_phantom: PhantomData<(C, N)>,
}
impl<C, NodeUid> Default for DynamicHoneyBadgerBuilder<C, NodeUid> {
impl<C, N> Default for DynamicHoneyBadgerBuilder<C, N> {
fn default() -> Self {
// TODO: Use the defaults from `HoneyBadgerBuilder`.
DynamicHoneyBadgerBuilder {
@ -31,10 +30,10 @@ impl<C, NodeUid> Default for DynamicHoneyBadgerBuilder<C, NodeUid> {
}
}
impl<C, NodeUid> DynamicHoneyBadgerBuilder<C, NodeUid>
impl<C, N> DynamicHoneyBadgerBuilder<C, N>
where
C: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash,
NodeUid: Eq + Ord + Clone + Debug + Serialize + for<'r> Deserialize<'r> + Hash + Rand,
C: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
/// Returns a new `DynamicHoneyBadgerBuilder` configured to use the node IDs and cryptographic
/// keys specified by `netinfo`.
@ -49,7 +48,7 @@ where
}
/// Creates a new Dynamic Honey Badger instance with an empty buffer.
pub fn build(&self, netinfo: NetworkInfo<NodeUid>) -> DynamicHoneyBadger<C, NodeUid> {
pub fn build(&self, netinfo: NetworkInfo<N>) -> DynamicHoneyBadger<C, N> {
let arc_netinfo = Arc::new(netinfo.clone());
let honey_badger = HoneyBadger::builder(arc_netinfo.clone())
.max_future_epochs(self.max_future_epochs)
@ -67,7 +66,7 @@ where
}
/// Creates a new `DynamicHoneyBadger` configured to start a new network as a single validator.
pub fn build_first_node(&self, our_uid: NodeUid) -> DynamicHoneyBadger<C, NodeUid> {
pub fn build_first_node(&self, our_uid: N) -> DynamicHoneyBadger<C, N> {
let mut rng = rand::thread_rng();
let sk_set = SecretKeySet::random(0, &mut rng);
let pk_set = sk_set.public_keys();
@ -82,10 +81,10 @@ where
/// the `JoinPlan`.
pub fn build_joining(
&self,
our_uid: NodeUid,
our_uid: N,
secret_key: SecretKey,
join_plan: JoinPlan<NodeUid>,
) -> Result<(DynamicHoneyBadger<C, NodeUid>, Step<C, NodeUid>)> {
join_plan: JoinPlan<N>,
) -> Result<(DynamicHoneyBadger<C, N>, Step<C, N>)> {
let netinfo = NetworkInfo::new(
our_uid,
SecretKeyShare::default(), // TODO: Should be an option?

View File

@ -2,16 +2,16 @@ use crypto::PublicKey;
/// A node change action: adding or removing a node.
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
pub enum Change<NodeUid> {
pub enum Change<N> {
/// Add a node. The public key is used only temporarily, for key generation.
Add(NodeUid, PublicKey),
Add(N, PublicKey),
/// Remove a node.
Remove(NodeUid),
Remove(N),
}
impl<NodeUid> Change<NodeUid> {
impl<N> Change<N> {
/// Returns the ID of the current candidate for being added, if any.
pub fn candidate(&self) -> Option<&NodeUid> {
pub fn candidate(&self) -> Option<&N> {
match *self {
Change::Add(ref id, _) => Some(id),
Change::Remove(_) => None,
@ -21,13 +21,13 @@ impl<NodeUid> Change<NodeUid> {
/// A change status: whether a node addition or removal is currently in progress or completed.
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
pub enum ChangeState<NodeUid> {
pub enum ChangeState<N> {
/// No node is currently being considered for addition or removal.
None,
/// A change is currently in progress. If it is an addition, all broadcast messages must be
/// sent to the new node, too.
InProgress(Change<NodeUid>),
InProgress(Change<N>),
/// A change has been completed in this epoch. From the next epoch on, the new composition of
/// the network will perform the consensus process.
Complete(Change<NodeUid>),
Complete(Change<N>),
}

View File

@ -1,6 +1,4 @@
use rand::Rand;
use std::fmt::Debug;
use std::hash::Hash;
use std::mem;
use std::sync::Arc;
@ -17,40 +15,41 @@ 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, NodeUidT};
/// A Honey Badger instance that can handle adding and removing nodes.
#[derive(Debug)]
pub struct DynamicHoneyBadger<C, NodeUid: Rand> {
pub struct DynamicHoneyBadger<C, N: Rand> {
/// Shared network data.
pub(super) netinfo: NetworkInfo<NodeUid>,
pub(super) netinfo: NetworkInfo<N>,
/// The maximum number of future epochs for which we handle messages simultaneously.
pub(super) max_future_epochs: usize,
/// The first epoch after the latest node change.
pub(super) start_epoch: u64,
/// The buffer and counter for the pending and committed change votes.
pub(super) vote_counter: VoteCounter<NodeUid>,
pub(super) vote_counter: VoteCounter<N>,
/// Pending node transactions that we will propose in the next epoch.
pub(super) key_gen_msg_buffer: Vec<SignedKeyGenMsg<NodeUid>>,
pub(super) key_gen_msg_buffer: Vec<SignedKeyGenMsg<N>>,
/// The `HoneyBadger` instance with the current set of nodes.
pub(super) honey_badger: HoneyBadger<InternalContrib<C, NodeUid>, NodeUid>,
pub(super) honey_badger: HoneyBadger<InternalContrib<C, N>, N>,
/// The current key generation process, and the change it applies to.
pub(super) key_gen_state: Option<KeyGenState<NodeUid>>,
pub(super) key_gen_state: Option<KeyGenState<N>>,
/// A queue for messages from future epochs that cannot be handled yet.
pub(super) incoming_queue: Vec<(NodeUid, Message<NodeUid>)>,
pub(super) incoming_queue: Vec<(N, Message<N>)>,
}
impl<C, NodeUid> DistAlgorithm for DynamicHoneyBadger<C, NodeUid>
impl<C, N> DistAlgorithm for DynamicHoneyBadger<C, N>
where
C: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash,
NodeUid: Eq + Ord + Clone + Serialize + for<'r> Deserialize<'r> + Debug + Hash + Rand,
C: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
type NodeUid = NodeUid;
type Input = Input<C, NodeUid>;
type Output = Batch<C, NodeUid>;
type Message = Message<NodeUid>;
type NodeUid = N;
type Input = Input<C, N>;
type Output = Batch<C, N>;
type Message = Message<N>;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<C, NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<C, N>> {
// User contributions are forwarded to `HoneyBadger` right away. Votes are signed and
// broadcast.
match input {
@ -59,11 +58,7 @@ where
}
}
fn handle_message(
&mut self,
sender_id: &NodeUid,
message: Self::Message,
) -> Result<Step<C, NodeUid>> {
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> Result<Step<C, N>> {
let epoch = message.start_epoch();
if epoch < self.start_epoch {
// Obsolete message.
@ -93,18 +88,18 @@ where
false
}
fn our_id(&self) -> &NodeUid {
fn our_id(&self) -> &N {
self.netinfo.our_uid()
}
}
impl<C, NodeUid> DynamicHoneyBadger<C, NodeUid>
impl<C, N> DynamicHoneyBadger<C, N>
where
C: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash,
NodeUid: Eq + Ord + Clone + Debug + Serialize + for<'r> Deserialize<'r> + Hash + Rand,
C: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
/// Returns a new `DynamicHoneyBadgerBuilder`.
pub fn builder() -> DynamicHoneyBadgerBuilder<C, NodeUid> {
pub fn builder() -> DynamicHoneyBadgerBuilder<C, N> {
DynamicHoneyBadgerBuilder::new()
}
@ -114,7 +109,7 @@ where
}
/// Proposes a contribution in the current epoch.
pub fn propose(&mut self, contrib: C) -> Result<Step<C, NodeUid>> {
pub fn propose(&mut self, contrib: C) -> Result<Step<C, N>> {
let step = self
.honey_badger
.input(InternalContrib {
@ -127,7 +122,7 @@ where
}
/// Cast a vote to change the set of validators.
pub fn vote_for(&mut self, change: Change<NodeUid>) -> Result<Step<C, NodeUid>> {
pub fn vote_for(&mut self, change: Change<N>) -> Result<Step<C, N>> {
if !self.netinfo.is_validator() {
return Ok(Step::default()); // TODO: Return an error?
}
@ -137,7 +132,7 @@ where
}
/// Returns the information about the node IDs in the network, and the cryptographic keys.
pub fn netinfo(&self) -> &NetworkInfo<NodeUid> {
pub fn netinfo(&self) -> &NetworkInfo<N> {
&self.netinfo
}
@ -172,9 +167,9 @@ where
/// Handles a message for the `HoneyBadger` instance.
fn handle_honey_badger_message(
&mut self,
sender_id: &NodeUid,
message: HbMessage<NodeUid>,
) -> Result<Step<C, NodeUid>> {
sender_id: &N,
message: HbMessage<N>,
) -> Result<Step<C, N>> {
if !self.netinfo.is_node_validator(sender_id) {
info!("Unknown sender {:?} of message {:?}", sender_id, message);
return Err(ErrorKind::UnknownSender.into());
@ -191,10 +186,10 @@ where
/// messages are only handled once they appear in a batch output from Honey Badger.
fn handle_key_gen_message(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
kg_msg: KeyGenMessage,
sig: Signature,
) -> Result<FaultLog<NodeUid>> {
) -> Result<FaultLog<N>> {
if !self.verify_signature(sender_id, &sig, &kg_msg)? {
info!("Invalid signature from {:?} for: {:?}.", sender_id, kg_msg);
let fault_kind = FaultKind::InvalidKeyGenMessageSignature;
@ -234,9 +229,9 @@ where
/// Processes all pending batches output by Honey Badger.
fn process_output(
&mut self,
hb_step: honey_badger::Step<InternalContrib<C, NodeUid>, NodeUid>,
) -> Result<Step<C, NodeUid>> {
let mut step: Step<C, NodeUid> = Step::default();
hb_step: honey_badger::Step<InternalContrib<C, N>, N>,
) -> Result<Step<C, N>> {
let mut step: Step<C, N> = Step::default();
let start_epoch = self.start_epoch;
let output = step.extend_with(hb_step, |hb_msg| Message::HoneyBadger(start_epoch, hb_msg));
for hb_batch in output {
@ -302,11 +297,7 @@ where
/// If the winner of the vote has changed, restarts Key Generation for the set of nodes implied
/// by the current change.
pub(super) fn update_key_gen(
&mut self,
epoch: u64,
change: &Change<NodeUid>,
) -> Result<Step<C, NodeUid>> {
pub(super) fn update_key_gen(&mut self, epoch: u64, change: &Change<N>) -> Result<Step<C, N>> {
if self.key_gen_state.as_ref().map(|kgs| &kgs.change) == Some(change) {
return Ok(Step::default()); // The change is the same as before. Continue DKG as is.
}
@ -347,8 +338,8 @@ where
}
/// Handles a `Part` message that was output by Honey Badger.
fn handle_part(&mut self, sender_id: &NodeUid, part: Part) -> Result<Step<C, NodeUid>> {
let handle = |kgs: &mut KeyGenState<NodeUid>| kgs.key_gen.handle_part(&sender_id, part);
fn handle_part(&mut self, sender_id: &N, part: Part) -> Result<Step<C, N>> {
let handle = |kgs: &mut KeyGenState<N>| kgs.key_gen.handle_part(&sender_id, part);
match self.key_gen_state.as_mut().and_then(handle) {
Some(PartOutcome::Valid(ack)) => self.send_transaction(KeyGenMessage::Ack(ack)),
Some(PartOutcome::Invalid(fault_log)) => Ok(fault_log.into()),
@ -357,7 +348,7 @@ where
}
/// Handles an `Ack` message that was output by Honey Badger.
fn handle_ack(&mut self, sender_id: &NodeUid, ack: Ack) -> Result<FaultLog<NodeUid>> {
fn handle_ack(&mut self, sender_id: &N, ack: Ack) -> Result<FaultLog<N>> {
if let Some(kgs) = self.key_gen_state.as_mut() {
Ok(kgs.key_gen.handle_ack(sender_id, ack))
} else {
@ -366,7 +357,7 @@ where
}
/// Signs and sends a `KeyGenMessage` and also tries to commit it.
fn send_transaction(&mut self, kg_msg: KeyGenMessage) -> Result<Step<C, NodeUid>> {
fn send_transaction(&mut self, kg_msg: KeyGenMessage) -> Result<Step<C, N>> {
let ser =
bincode::serialize(&kg_msg).map_err(|err| ErrorKind::SendTransactionBincode(*err))?;
let sig = Box::new(self.netinfo.secret_key().sign(ser));
@ -385,7 +376,7 @@ where
/// We require the minimum number of completed proposals (`SyncKeyGen::is_ready`) and if a new
/// node is joining, we require in addition that the new node's proposal is complete. That way
/// the new node knows that it's key is secret, without having to trust any number of nodes.
fn take_ready_key_gen(&mut self) -> Option<KeyGenState<NodeUid>> {
fn take_ready_key_gen(&mut self) -> Option<KeyGenState<N>> {
if self
.key_gen_state
.as_ref()
@ -403,7 +394,7 @@ where
/// This accepts signatures from both validators and the currently joining candidate, if any.
fn verify_signature(
&self,
node_id: &NodeUid,
node_id: &N,
sig: &Signature,
kg_msg: &KeyGenMessage,
) -> Result<bool> {

View File

@ -65,12 +65,12 @@ mod votes;
use crypto::{PublicKey, PublicKeySet, Signature};
use rand::Rand;
use std::collections::BTreeMap;
use std::fmt::Debug;
use self::votes::{SignedVote, VoteCounter};
use honey_badger::Message as HbMessage;
use messaging;
use sync_key_gen::{Ack, Part, SyncKeyGen};
use traits::NodeUidT;
pub use self::batch::Batch;
pub use self::builder::DynamicHoneyBadgerBuilder;
@ -78,15 +78,15 @@ pub use self::change::{Change, ChangeState};
pub use self::dynamic_honey_badger::DynamicHoneyBadger;
pub use self::error::{Error, ErrorKind, Result};
pub type Step<C, NodeUid> = messaging::Step<DynamicHoneyBadger<C, NodeUid>>;
pub type Step<C, N> = messaging::Step<DynamicHoneyBadger<C, N>>;
/// The user input for `DynamicHoneyBadger`.
#[derive(Clone, Debug)]
pub enum Input<C, NodeUid> {
pub enum Input<C, N> {
/// A user-defined contribution for the next epoch.
User(C),
/// A vote to change the set of validators.
Change(Change<NodeUid>),
Change(Change<N>),
}
/// An internal message containing a vote for adding or removing a validator, or a message for key
@ -102,16 +102,16 @@ pub enum KeyGenMessage {
/// A message sent to or received from another node's Honey Badger instance.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Message<NodeUid: Rand> {
pub enum Message<N: Rand> {
/// A message belonging to the `HoneyBadger` algorithm started in the given epoch.
HoneyBadger(u64, HbMessage<NodeUid>),
HoneyBadger(u64, HbMessage<N>),
/// A transaction to be committed, signed by a node.
KeyGen(u64, KeyGenMessage, Box<Signature>),
/// A vote to be committed, signed by a validator.
SignedVote(SignedVote<NodeUid>),
SignedVote(SignedVote<N>),
}
impl<NodeUid: Rand> Message<NodeUid> {
impl<N: Rand> Message<N> {
fn start_epoch(&self) -> u64 {
match *self {
Message::HoneyBadger(epoch, _) => epoch,
@ -133,31 +133,31 @@ impl<NodeUid: Rand> Message<NodeUid> {
/// of voting and key generation after a specific epoch, so that the new node will be in sync if it
/// joins in the next one.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JoinPlan<NodeUid: Ord> {
pub struct JoinPlan<N: Ord> {
/// The first epoch the new node will observe.
epoch: u64,
/// The current change. If `InProgress`, key generation for it is beginning at `epoch`.
change: ChangeState<NodeUid>,
change: ChangeState<N>,
/// The current public key set for threshold cryptography.
pub_key_set: PublicKeySet,
/// The public keys of the nodes taking part in key generation.
pub_keys: BTreeMap<NodeUid, PublicKey>,
pub_keys: BTreeMap<N, PublicKey>,
}
/// The ongoing key generation, together with information about the validator change.
#[derive(Debug)]
struct KeyGenState<NodeUid> {
struct KeyGenState<N> {
/// The key generation instance.
key_gen: SyncKeyGen<NodeUid>,
key_gen: SyncKeyGen<N>,
/// The change for which key generation is performed.
change: Change<NodeUid>,
change: Change<N>,
/// The number of key generation messages received from the candidate. At most _N² + 1_ are
/// accepted.
candidate_msg_count: usize,
}
impl<NodeUid: Ord + Clone + Debug> KeyGenState<NodeUid> {
fn new(key_gen: SyncKeyGen<NodeUid>, change: Change<NodeUid>) -> Self {
impl<N: NodeUidT> KeyGenState<N> {
fn new(key_gen: SyncKeyGen<N>, change: Change<N>) -> Self {
KeyGenState {
key_gen,
change,
@ -168,12 +168,12 @@ impl<NodeUid: Ord + Clone + Debug> KeyGenState<NodeUid> {
/// Returns `true` if the candidate's, if any, as well as enough validators' key generation
/// parts have been completed.
fn is_ready(&self) -> bool {
let candidate_ready = |id: &NodeUid| self.key_gen.is_node_ready(id);
let candidate_ready = |id: &N| self.key_gen.is_node_ready(id);
self.key_gen.is_ready() && self.change.candidate().map_or(true, candidate_ready)
}
/// If the node `node_id` is the currently joining candidate, returns its public key.
fn candidate_key(&self, node_id: &NodeUid) -> Option<&PublicKey> {
fn candidate_key(&self, node_id: &N) -> Option<&PublicKey> {
match self.change {
Change::Add(ref id, ref pk) if id == node_id => Some(pk),
Change::Add(_, _) | Change::Remove(_) => None,
@ -184,15 +184,15 @@ impl<NodeUid: Ord + Clone + Debug> KeyGenState<NodeUid> {
/// The contribution for the internal `HoneyBadger` instance: this includes a user-defined
/// application-level contribution as well as internal signed messages.
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize, Hash)]
struct InternalContrib<C, NodeUid> {
struct InternalContrib<C, N> {
/// A user-defined contribution.
contrib: C,
/// Key generation messages that get committed via Honey Badger to communicate synchronously.
key_gen_messages: Vec<SignedKeyGenMsg<NodeUid>>,
key_gen_messages: Vec<SignedKeyGenMsg<N>>,
/// Signed votes for validator set changes.
votes: Vec<SignedVote<NodeUid>>,
votes: Vec<SignedVote<N>>,
}
/// A signed internal message.
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Hash, Clone)]
struct SignedKeyGenMsg<NodeUid>(u64, NodeUid, KeyGenMessage, Signature);
struct SignedKeyGenMsg<N>(u64, N, KeyGenMessage, Signature);

View File

@ -1,6 +1,4 @@
use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::Arc;
use bincode;
@ -10,30 +8,31 @@ use serde::{Deserialize, Serialize};
use super::{Change, ErrorKind, Result};
use fault_log::{FaultKind, FaultLog};
use messaging::NetworkInfo;
use traits::NodeUidT;
/// A buffer and counter collecting pending and committed votes for validator set changes.
///
/// This is reset whenever the set of validators changes or a change reaches _f + 1_ votes. We call
/// the epochs since the last reset the current _era_.
#[derive(Debug)]
pub struct VoteCounter<NodeUid> {
pub struct VoteCounter<N> {
/// Shared network data.
netinfo: Arc<NetworkInfo<NodeUid>>,
netinfo: Arc<NetworkInfo<N>>,
/// The epoch when voting was reset.
era: u64,
/// Pending node transactions that we will propose in the next epoch.
pending: BTreeMap<NodeUid, SignedVote<NodeUid>>,
pending: BTreeMap<N, SignedVote<N>>,
/// Collected votes for adding or removing nodes. Each node has one vote, and casting another
/// vote revokes the previous one.
committed: BTreeMap<NodeUid, Vote<NodeUid>>,
committed: BTreeMap<N, Vote<N>>,
}
impl<NodeUid> VoteCounter<NodeUid>
impl<N> VoteCounter<N>
where
NodeUid: Eq + Hash + Ord + Clone + Debug + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Serialize + for<'r> Deserialize<'r>,
{
/// Creates a new `VoteCounter` object with empty buffer and counter.
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>, era: u64) -> Self {
pub fn new(netinfo: Arc<NetworkInfo<N>>, era: u64) -> Self {
VoteCounter {
era,
netinfo,
@ -43,7 +42,7 @@ where
}
/// Creates a signed vote for the given change, and inserts it into the pending votes buffer.
pub fn sign_vote_for(&mut self, change: Change<NodeUid>) -> Result<&SignedVote<NodeUid>> {
pub fn sign_vote_for(&mut self, change: Change<N>) -> Result<&SignedVote<N>> {
let voter = self.netinfo.our_uid().clone();
let vote = Vote {
change,
@ -64,9 +63,9 @@ where
/// Inserts a pending vote into the buffer, if it has a higher number than the existing one.
pub fn add_pending_vote(
&mut self,
sender_id: &NodeUid,
signed_vote: SignedVote<NodeUid>,
) -> Result<FaultLog<NodeUid>> {
sender_id: &N,
signed_vote: SignedVote<N>,
) -> Result<FaultLog<N>> {
if signed_vote.vote.era != self.era
|| self
.pending
@ -87,7 +86,7 @@ where
/// Returns an iterator over all pending votes that are newer than their voter's committed
/// vote.
pub fn pending_votes(&self) -> impl Iterator<Item = &SignedVote<NodeUid>> {
pub fn pending_votes(&self) -> impl Iterator<Item = &SignedVote<N>> {
self.pending.values().filter(move |signed_vote| {
self.committed
.get(&signed_vote.voter)
@ -98,11 +97,11 @@ where
// TODO: Document and return fault logs?
pub fn add_committed_votes<I>(
&mut self,
proposer_id: &NodeUid,
proposer_id: &N,
signed_votes: I,
) -> Result<FaultLog<NodeUid>>
) -> Result<FaultLog<N>>
where
I: IntoIterator<Item = SignedVote<NodeUid>>,
I: IntoIterator<Item = SignedVote<N>>,
{
let mut fault_log = FaultLog::new();
for signed_vote in signed_votes {
@ -114,9 +113,9 @@ where
/// Inserts a committed vote into the counter, if it has a higher number than the existing one.
pub fn add_committed_vote(
&mut self,
proposer_id: &NodeUid,
signed_vote: SignedVote<NodeUid>,
) -> Result<FaultLog<NodeUid>> {
proposer_id: &N,
signed_vote: SignedVote<N>,
) -> Result<FaultLog<N>> {
if self
.committed
.get(&signed_vote.voter)
@ -135,8 +134,8 @@ where
}
/// Returns the change that has at least _f + 1_ votes, if any.
pub fn compute_winner(&self) -> Option<&Change<NodeUid>> {
let mut vote_counts: HashMap<&Change<NodeUid>, usize> = HashMap::new();
pub fn compute_winner(&self) -> Option<&Change<N>> {
let mut vote_counts: HashMap<&Change<N>, usize> = HashMap::new();
for vote in self.committed.values() {
let change = &vote.change;
let entry = vote_counts.entry(change).or_insert(0);
@ -149,7 +148,7 @@ where
}
/// Returns `true` if the signature is valid.
fn validate(&self, signed_vote: &SignedVote<NodeUid>) -> Result<bool> {
fn validate(&self, signed_vote: &SignedVote<N>) -> Result<bool> {
let ser_vote =
bincode::serialize(&signed_vote.vote).map_err(|err| ErrorKind::ValidateBincode(*err))?;
let pk_opt = self.netinfo.public_key(&signed_vote.voter);
@ -159,9 +158,9 @@ where
/// A vote fore removing or adding a validator.
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Hash, Clone)]
struct Vote<NodeUid> {
struct Vote<N> {
/// The change this vote is for.
change: Change<NodeUid>,
change: Change<N>,
/// The epoch in which the current era began.
era: u64,
/// The vote number: VoteCounter can be changed by casting another vote with a higher number.
@ -170,18 +169,18 @@ struct Vote<NodeUid> {
/// A signed vote for removing or adding a validator.
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Hash, Clone)]
pub struct SignedVote<NodeUid> {
vote: Vote<NodeUid>,
voter: NodeUid,
pub struct SignedVote<N> {
vote: Vote<N>,
voter: N,
sig: Signature,
}
impl<NodeUid> SignedVote<NodeUid> {
impl<N> SignedVote<N> {
pub fn era(&self) -> u64 {
self.vote.era
}
pub fn voter(&self) -> &NodeUid {
pub fn voter(&self) -> &N {
&self.voter
}
}

View File

@ -52,52 +52,52 @@ pub enum FaultKind {
/// describes which node is faulty (`node_id`) and which faulty behavior
/// that the node exhibited ('kind').
#[derive(Debug, PartialEq)]
pub struct Fault<NodeUid> {
pub node_id: NodeUid,
pub struct Fault<N> {
pub node_id: N,
pub kind: FaultKind,
}
impl<NodeUid> Fault<NodeUid> {
pub fn new(node_id: NodeUid, kind: FaultKind) -> Self {
impl<N> Fault<N> {
pub fn new(node_id: N, kind: FaultKind) -> Self {
Fault { node_id, kind }
}
}
/// Creates a new `FaultLog` where `self` is the first element in the log
/// vector.
impl<NodeUid> Into<FaultLog<NodeUid>> for Fault<NodeUid> {
fn into(self) -> FaultLog<NodeUid> {
impl<N> Into<FaultLog<N>> for Fault<N> {
fn into(self) -> FaultLog<N> {
FaultLog(vec![self])
}
}
/// A structure used to contain reports of faulty node behavior.
#[derive(Debug, PartialEq)]
pub struct FaultLog<NodeUid>(pub Vec<Fault<NodeUid>>);
pub struct FaultLog<N>(pub Vec<Fault<N>>);
impl<NodeUid> FaultLog<NodeUid> {
impl<N> FaultLog<N> {
/// Creates an empty `FaultLog`.
pub fn new() -> Self {
FaultLog::default()
}
/// Creates a new `FaultLog` initialized with a single log.
pub fn init(node_id: NodeUid, kind: FaultKind) -> Self {
pub fn init(node_id: N, kind: FaultKind) -> Self {
Fault::new(node_id, kind).into()
}
/// Creates a new `Fault` and pushes it onto the fault log.
pub fn append(&mut self, node_id: NodeUid, kind: FaultKind) {
pub fn append(&mut self, node_id: N, kind: FaultKind) {
self.0.push(Fault::new(node_id, kind));
}
/// Consumes `new_logs`, appending its logs onto the end of `self`.
pub fn extend(&mut self, new_logs: FaultLog<NodeUid>) {
pub fn extend(&mut self, new_logs: FaultLog<N>) {
self.0.extend(new_logs.0);
}
/// Consumes `self`, appending its logs onto the end of `logs`.
pub fn merge_into(self, logs: &mut FaultLog<NodeUid>) {
pub fn merge_into(self, logs: &mut FaultLog<N>) {
logs.extend(self);
}
@ -107,7 +107,7 @@ impl<NodeUid> FaultLog<NodeUid> {
}
}
impl<NodeUid> Default for FaultLog<NodeUid> {
impl<N> Default for FaultLog<N> {
fn default() -> Self {
FaultLog(vec![])
}

View File

@ -1,13 +1,15 @@
use std::collections::BTreeMap;
use traits::NodeUidT;
/// A batch of contributions the algorithm has output.
#[derive(Clone, Debug)]
pub struct Batch<C, NodeUid> {
pub struct Batch<C, N> {
pub epoch: u64,
pub contributions: BTreeMap<NodeUid, C>,
pub contributions: BTreeMap<N, C>,
}
impl<C, NodeUid: Ord> Batch<C, NodeUid> {
impl<C, N: NodeUidT> Batch<C, N> {
/// Returns an iterator over references to all transactions included in the batch.
pub fn iter<'a>(&'a self) -> impl Iterator<Item = <&'a C as IntoIterator>::Item>
where
@ -25,25 +27,25 @@ impl<C, NodeUid: Ord> Batch<C, NodeUid> {
}
/// Returns the number of transactions in the batch (without detecting duplicates).
pub fn len<Tx>(&self) -> usize
pub fn len<T>(&self) -> usize
where
C: AsRef<[Tx]>,
C: AsRef<[T]>,
{
self.contributions
.values()
.map(C::as_ref)
.map(<[Tx]>::len)
.map(<[T]>::len)
.sum()
}
/// Returns `true` if the batch contains no transactions.
pub fn is_empty<Tx>(&self) -> bool
pub fn is_empty<T>(&self) -> bool
where
C: AsRef<[Tx]>,
C: AsRef<[T]>,
{
self.contributions
.values()
.map(C::as_ref)
.all(<[Tx]>::is_empty)
.all(<[T]>::is_empty)
}
}

View File

@ -1,6 +1,4 @@
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::Arc;
@ -9,24 +7,25 @@ use serde::{Deserialize, Serialize};
use super::HoneyBadger;
use messaging::NetworkInfo;
use traits::{Contribution, NodeUidT};
/// A Honey Badger builder, to configure the parameters and create new instances of `HoneyBadger`.
pub struct HoneyBadgerBuilder<C, NodeUid> {
pub struct HoneyBadgerBuilder<C, N> {
/// Shared network data.
netinfo: Arc<NetworkInfo<NodeUid>>,
netinfo: Arc<NetworkInfo<N>>,
/// The maximum number of future epochs for which we handle messages simultaneously.
max_future_epochs: usize,
_phantom: PhantomData<C>,
}
impl<C, NodeUid> HoneyBadgerBuilder<C, NodeUid>
impl<C, N> HoneyBadgerBuilder<C, N>
where
C: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
NodeUid: Ord + Clone + Debug + Rand,
C: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Rand,
{
/// Returns a new `HoneyBadgerBuilder` configured to use the node IDs and cryptographic keys
/// specified by `netinfo`.
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>) -> Self {
pub fn new(netinfo: Arc<NetworkInfo<N>>) -> Self {
HoneyBadgerBuilder {
netinfo,
max_future_epochs: 3,
@ -41,7 +40,7 @@ where
}
/// Creates a new Honey Badger instance.
pub fn build(&self) -> HoneyBadger<C, NodeUid> {
pub fn build(&self) -> HoneyBadger<C, N> {
HoneyBadger {
netinfo: self.netinfo.clone(),
epoch: 0,

View File

@ -1,7 +1,5 @@
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
@ -16,57 +14,53 @@ use super::{Batch, Error, ErrorKind, HoneyBadgerBuilder, Message, MessageContent
use common_subset::{self, CommonSubset};
use fault_log::{Fault, FaultKind, FaultLog};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
use traits::{Contribution, NodeUidT};
/// An instance of the Honey Badger Byzantine fault tolerant consensus algorithm.
#[derive(Debug)]
pub struct HoneyBadger<C, NodeUid: Rand> {
pub struct HoneyBadger<C, N: Rand> {
/// Shared network data.
pub(super) netinfo: Arc<NetworkInfo<NodeUid>>,
pub(super) netinfo: Arc<NetworkInfo<N>>,
/// The earliest epoch from which we have not yet received output.
pub(super) epoch: u64,
/// Whether we have already submitted a proposal for the current epoch.
pub(super) has_input: bool,
/// The Asynchronous Common Subset instance that decides which nodes' transactions to include,
/// indexed by epoch.
pub(super) common_subsets: BTreeMap<u64, CommonSubset<NodeUid>>,
pub(super) common_subsets: BTreeMap<u64, CommonSubset<N>>,
/// The maximum number of `CommonSubset` instances that we run simultaneously.
pub(super) max_future_epochs: u64,
/// Messages for future epochs that couldn't be handled yet.
pub(super) incoming_queue: BTreeMap<u64, Vec<(NodeUid, MessageContent<NodeUid>)>>,
pub(super) incoming_queue: BTreeMap<u64, Vec<(N, MessageContent<N>)>>,
/// Received decryption shares for an epoch. Each decryption share has a sender and a
/// proposer. The outer `BTreeMap` has epochs as its key. The next `BTreeMap` has proposers as
/// its key. The inner `BTreeMap` has the sender as its key.
pub(super) received_shares:
BTreeMap<u64, BTreeMap<NodeUid, BTreeMap<NodeUid, DecryptionShare>>>,
pub(super) received_shares: BTreeMap<u64, BTreeMap<N, BTreeMap<N, DecryptionShare>>>,
/// Decoded accepted proposals.
pub(super) decrypted_contributions: BTreeMap<NodeUid, Vec<u8>>,
pub(super) decrypted_contributions: BTreeMap<N, Vec<u8>>,
/// Ciphertexts output by Common Subset in an epoch.
pub(super) ciphertexts: BTreeMap<u64, BTreeMap<NodeUid, Ciphertext>>,
pub(super) ciphertexts: BTreeMap<u64, BTreeMap<N, Ciphertext>>,
pub(super) _phantom: PhantomData<C>,
}
pub type Step<C, NodeUid> = messaging::Step<HoneyBadger<C, NodeUid>>;
pub type Step<C, N> = messaging::Step<HoneyBadger<C, N>>;
impl<C, NodeUid> DistAlgorithm for HoneyBadger<C, NodeUid>
impl<C, N> DistAlgorithm for HoneyBadger<C, N>
where
C: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
NodeUid: Ord + Clone + Debug + Rand,
C: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Rand,
{
type NodeUid = NodeUid;
type NodeUid = N;
type Input = C;
type Output = Batch<C, NodeUid>;
type Message = Message<NodeUid>;
type Output = Batch<C, N>;
type Message = Message<N>;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<C, NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<C, N>> {
self.propose(&input)
}
fn handle_message(
&mut self,
sender_id: &NodeUid,
message: Self::Message,
) -> Result<Step<C, NodeUid>> {
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> Result<Step<C, N>> {
if !self.netinfo.is_node_validator(sender_id) {
return Err(ErrorKind::UnknownSender.into());
}
@ -87,24 +81,24 @@ where
false
}
fn our_id(&self) -> &NodeUid {
fn our_id(&self) -> &N {
self.netinfo.our_uid()
}
}
impl<C, NodeUid> HoneyBadger<C, NodeUid>
impl<C, N> HoneyBadger<C, N>
where
C: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
NodeUid: Ord + Clone + Debug + Rand,
C: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Rand,
{
/// Returns a new `HoneyBadgerBuilder` configured to use the node IDs and cryptographic keys
/// specified by `netinfo`.
pub fn builder(netinfo: Arc<NetworkInfo<NodeUid>>) -> HoneyBadgerBuilder<C, NodeUid> {
pub fn builder(netinfo: Arc<NetworkInfo<N>>) -> HoneyBadgerBuilder<C, N> {
HoneyBadgerBuilder::new(netinfo)
}
/// Proposes a new item in the current epoch.
pub fn propose(&mut self, proposal: &C) -> Result<Step<C, NodeUid>> {
pub fn propose(&mut self, proposal: &C) -> Result<Step<C, N>> {
if !self.netinfo.is_validator() {
return Ok(Step::default());
}
@ -143,10 +137,10 @@ where
/// Handles a message for the given epoch.
fn handle_message_content(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
epoch: u64,
content: MessageContent<NodeUid>,
) -> Result<Step<C, NodeUid>> {
content: MessageContent<N>,
) -> Result<Step<C, N>> {
match content {
MessageContent::CommonSubset(cs_msg) => {
self.handle_common_subset_message(sender_id, epoch, cs_msg)
@ -160,10 +154,10 @@ where
/// Handles a message for the common subset sub-algorithm.
fn handle_common_subset_message(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
epoch: u64,
message: common_subset::Message<NodeUid>,
) -> Result<Step<C, NodeUid>> {
message: common_subset::Message<N>,
) -> Result<Step<C, N>> {
let cs_step = {
// Borrow the instance for `epoch`, or create it.
let cs = match self.common_subsets.entry(epoch) {
@ -191,11 +185,11 @@ where
/// Handles decryption shares sent by `HoneyBadger` instances.
fn handle_decryption_share_message(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
epoch: u64,
proposer_id: NodeUid,
proposer_id: N,
share: DecryptionShare,
) -> Result<Step<C, NodeUid>> {
) -> Result<Step<C, N>> {
if let Some(ciphertext) = self
.ciphertexts
.get(&epoch)
@ -227,7 +221,7 @@ where
/// has failed.
fn verify_decryption_share(
&self,
sender_id: &NodeUid,
sender_id: &N,
share: &DecryptionShare,
ciphertext: &Ciphertext,
) -> bool {
@ -240,7 +234,7 @@ where
/// When contributions of transactions have been decrypted for all valid proposers in this
/// epoch, moves those contributions into a batch, outputs the batch and updates the epoch.
fn try_output_batch(&mut self) -> Result<Option<Step<C, NodeUid>>> {
fn try_output_batch(&mut self) -> Result<Option<Step<C, N>>> {
// Return if we don't have ciphertexts yet.
let proposer_ids = match self.ciphertexts.get(&self.epoch) {
Some(cts) => cts.keys().cloned().collect_vec(),
@ -258,7 +252,7 @@ where
let mut step = Step::default();
// Deserialize the output.
let contributions: BTreeMap<NodeUid, C> =
let contributions: BTreeMap<N, C> =
mem::replace(&mut self.decrypted_contributions, BTreeMap::new())
.into_iter()
.flat_map(|(proposer_id, ser_contrib)| {
@ -289,7 +283,7 @@ where
}
/// Increments the epoch number and clears any state that is local to the finished epoch.
fn update_epoch(&mut self) -> Result<Step<C, NodeUid>> {
fn update_epoch(&mut self) -> Result<Step<C, N>> {
// Clear the state of the old epoch.
self.ciphertexts.remove(&self.epoch);
self.received_shares.remove(&self.epoch);
@ -309,7 +303,7 @@ where
}
/// Tries to decrypt contributions from all proposers and output those in a batch.
fn try_output_batches(&mut self) -> Result<Step<C, NodeUid>> {
fn try_output_batches(&mut self) -> Result<Step<C, N>> {
let mut step = Step::default();
while let Some(new_step) = self.try_output_batch()? {
step.extend(new_step);
@ -318,7 +312,7 @@ where
}
/// Tries to decrypt the contribution from a given proposer.
fn try_decrypt_proposer_contribution(&mut self, proposer_id: NodeUid) -> bool {
fn try_decrypt_proposer_contribution(&mut self, proposer_id: N) -> bool {
if self.decrypted_contributions.contains_key(&proposer_id) {
return true; // Already decrypted.
}
@ -356,9 +350,9 @@ where
fn send_decryption_shares(
&mut self,
cs_output: BTreeMap<NodeUid, Vec<u8>>,
cs_output: BTreeMap<N, Vec<u8>>,
epoch: u64,
) -> Result<Step<C, NodeUid>> {
) -> Result<Step<C, N>> {
let mut step = Step::default();
let mut ciphertexts = BTreeMap::new();
for (proposer_id, v) in cs_output {
@ -399,10 +393,10 @@ where
/// Sends decryption shares without verifying the ciphertext.
fn send_decryption_share(
&mut self,
proposer_id: &NodeUid,
proposer_id: &N,
ciphertext: &Ciphertext,
epoch: u64,
) -> Result<Step<C, NodeUid>> {
) -> Result<Step<C, N>> {
let share = self
.netinfo
.secret_key_share()
@ -427,10 +421,10 @@ where
/// senders with incorrect pending shares.
fn verify_pending_decryption_shares(
&self,
proposer_id: &NodeUid,
proposer_id: &N,
ciphertext: &Ciphertext,
epoch: u64,
) -> (BTreeSet<NodeUid>, FaultLog<NodeUid>) {
) -> (BTreeSet<N>, FaultLog<N>) {
let mut incorrect_senders = BTreeSet::new();
let mut fault_log = FaultLog::new();
if let Some(sender_shares) = self
@ -451,8 +445,8 @@ where
fn remove_incorrect_decryption_shares(
&mut self,
proposer_id: &NodeUid,
incorrect_senders: BTreeSet<NodeUid>,
proposer_id: &N,
incorrect_senders: BTreeSet<N>,
epoch: u64,
) {
if let Some(sender_shares) = self
@ -472,9 +466,9 @@ where
/// `epoch == Some(given_epoch)`.
fn process_output(
&mut self,
cs_step: common_subset::Step<NodeUid>,
cs_step: common_subset::Step<N>,
epoch: u64,
) -> Result<Step<C, NodeUid>> {
) -> Result<Step<C, N>> {
let mut step = Step::default();
let mut cs_outputs = step.extend_with(cs_step, |cs_msg| {
MessageContent::CommonSubset(cs_msg).with_epoch(epoch)

View File

@ -5,18 +5,18 @@ use common_subset;
/// The content of a `HoneyBadger` message. It should be further annotated with an epoch.
#[derive(Clone, Debug, Deserialize, Rand, Serialize)]
pub enum MessageContent<NodeUid: Rand> {
pub enum MessageContent<N: Rand> {
/// A message belonging to the common subset algorithm in the given epoch.
CommonSubset(common_subset::Message<NodeUid>),
CommonSubset(common_subset::Message<N>),
/// A decrypted share of the output of `proposer_id`.
DecryptionShare {
proposer_id: NodeUid,
proposer_id: N,
share: DecryptionShare,
},
}
impl<NodeUid: Rand> MessageContent<NodeUid> {
pub fn with_epoch(self, epoch: u64) -> Message<NodeUid> {
impl<N: Rand> MessageContent<N> {
pub fn with_epoch(self, epoch: u64) -> Message<N> {
Message {
epoch,
content: self,
@ -26,12 +26,12 @@ impl<NodeUid: Rand> MessageContent<NodeUid> {
/// A message sent to or received from another node's Honey Badger instance.
#[derive(Clone, Debug, Deserialize, Rand, Serialize)]
pub struct Message<NodeUid: Rand> {
pub struct Message<N: Rand> {
pub(super) epoch: u64,
pub(super) content: MessageContent<NodeUid>,
pub(super) content: MessageContent<N>,
}
impl<NodeUid: Rand> Message<NodeUid> {
impl<N: Rand> Message<N> {
pub fn epoch(&self) -> u64 {
self.epoch
}

View File

@ -135,3 +135,21 @@ pub mod messaging;
pub mod queueing_honey_badger;
pub mod sync_key_gen;
pub mod transaction_queue;
/// 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 NodeUidT: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
impl<N> NodeUidT 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 {}
}

View File

@ -4,6 +4,7 @@ use std::iter::once;
use crypto::{PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
use fault_log::{Fault, FaultLog};
use traits::{Message, NodeUidT};
/// Message sent by a given source.
#[derive(Clone, Debug)]
@ -57,7 +58,7 @@ impl<M, N> TargetedMessage<M, N> {
pub struct Step<D>
where
D: DistAlgorithm,
<D as DistAlgorithm>::NodeUid: Clone,
<D as DistAlgorithm>::NodeUid: NodeUidT,
{
pub output: VecDeque<D::Output>,
pub fault_log: FaultLog<D::NodeUid>,
@ -67,7 +68,7 @@ where
impl<D> Default for Step<D>
where
D: DistAlgorithm,
<D as DistAlgorithm>::NodeUid: Clone,
<D as DistAlgorithm>::NodeUid: NodeUidT,
{
fn default() -> Step<D> {
Step {
@ -80,7 +81,7 @@ where
impl<D: DistAlgorithm> Step<D>
where
<D as DistAlgorithm>::NodeUid: Clone,
<D as DistAlgorithm>::NodeUid: NodeUidT,
{
/// Creates a new `Step` from the given collections.
pub fn new(
@ -184,14 +185,14 @@ impl<D: DistAlgorithm> From<TargetedMessage<D::Message, D::NodeUid>> for Step<D>
/// A distributed algorithm that defines a message flow.
pub trait DistAlgorithm {
/// Unique node identifier.
type NodeUid: Debug + Clone + Ord + Eq;
type NodeUid: NodeUidT;
/// 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: Debug;
type Message: Message;
/// The errors that can occur during execution.
type Error: Debug;
@ -218,8 +219,8 @@ pub trait DistAlgorithm {
/// Common data shared between algorithms: the nodes' IDs and key shares.
#[derive(Debug, Clone)]
pub struct NetworkInfo<NodeUid> {
our_uid: NodeUid,
pub struct NetworkInfo<N> {
our_uid: N,
num_nodes: usize,
num_faulty: usize,
is_validator: bool,
@ -227,22 +228,22 @@ pub struct NetworkInfo<NodeUid> {
secret_key_share: SecretKeyShare,
secret_key: SecretKey,
public_key_set: PublicKeySet,
public_key_shares: BTreeMap<NodeUid, PublicKeyShare>,
public_keys: BTreeMap<NodeUid, PublicKey>,
node_indices: BTreeMap<NodeUid, usize>,
public_key_shares: BTreeMap<N, PublicKeyShare>,
public_keys: BTreeMap<N, PublicKey>,
node_indices: BTreeMap<N, usize>,
}
impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
impl<N: NodeUidT> NetworkInfo<N> {
pub fn new(
our_uid: NodeUid,
our_uid: N,
secret_key_share: SecretKeyShare,
public_key_set: PublicKeySet,
secret_key: SecretKey,
public_keys: BTreeMap<NodeUid, PublicKey>,
public_keys: BTreeMap<N, PublicKey>,
) -> Self {
let num_nodes = public_keys.len();
let is_validator = public_keys.contains_key(&our_uid);
let node_indices: BTreeMap<NodeUid, usize> = public_keys
let node_indices: BTreeMap<N, usize> = public_keys
.keys()
.enumerate()
.map(|(n, id)| (id.clone(), n))
@ -266,12 +267,12 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
}
/// The ID of the node the algorithm runs on.
pub fn our_uid(&self) -> &NodeUid {
pub fn our_uid(&self) -> &N {
&self.our_uid
}
/// ID of all nodes in the network.
pub fn all_uids(&self) -> impl Iterator<Item = &NodeUid> {
pub fn all_uids(&self) -> impl Iterator<Item = &N> {
self.public_keys.keys()
}
@ -308,27 +309,27 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
}
/// Returns the public key share if a node with that ID exists, otherwise `None`.
pub fn public_key_share(&self, id: &NodeUid) -> Option<&PublicKeyShare> {
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<NodeUid, PublicKeyShare> {
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: &NodeUid) -> Option<&PublicKey> {
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<NodeUid, PublicKey> {
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: &NodeUid) -> Option<usize> {
pub fn node_index(&self, id: &N) -> Option<usize> {
self.node_indices.get(id).cloned()
}
@ -350,14 +351,14 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
/// 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, uid: &NodeUid) -> bool {
pub fn is_node_validator(&self, uid: &N) -> bool {
self.public_keys.contains_key(uid)
}
/// Generates a map of matching `NetworkInfo`s for testing.
pub fn generate_map<I>(uids: I) -> BTreeMap<NodeUid, NetworkInfo<NodeUid>>
pub fn generate_map<I>(uids: I) -> BTreeMap<N, NetworkInfo<N>>
where
I: IntoIterator<Item = NodeUid>,
I: IntoIterator<Item = N>,
{
use rand::{self, Rng};
@ -365,7 +366,7 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
let mut rng = rand::thread_rng();
let all_uids: BTreeSet<NodeUid> = uids.into_iter().collect();
let all_uids: BTreeSet<N> = uids.into_iter().collect();
let num_faulty = (all_uids.len() - 1) / 3;
// Generate the keys for threshold cryptography.
@ -381,7 +382,7 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
.collect();
// Create the corresponding `NetworkInfo` for each node.
let create_netinfo = |(i, uid): (usize, NodeUid)| {
let create_netinfo = |(i, uid): (usize, N)| {
let netinfo = NetworkInfo::new(
uid.clone(),
sk_set.secret_key_share(i),

View File

@ -23,9 +23,7 @@
//! the same transaction multiple times.
use std::cmp;
use std::fmt::Debug;
use std::fmt::{self, Display};
use std::hash::Hash;
use std::marker::PhantomData;
use failure::{Backtrace, Context, Fail};
@ -34,6 +32,7 @@ use serde::{Deserialize, Serialize};
use dynamic_honey_badger::{self, Batch as DhbBatch, DynamicHoneyBadger, Message};
use messaging::{self, DistAlgorithm};
use traits::{Contribution, NodeUidT};
use transaction_queue::TransactionQueue;
pub use dynamic_honey_badger::{Change, ChangeState, Input};
@ -95,24 +94,24 @@ pub type Result<T> = ::std::result::Result<T, Error>;
/// A Queueing Honey Badger builder, to configure the parameters and create new instances of
/// `QueueingHoneyBadger`.
pub struct QueueingHoneyBadgerBuilder<Tx, NodeUid: Rand> {
pub struct QueueingHoneyBadgerBuilder<T, N: Rand> {
/// Shared network data.
dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>,
dyn_hb: DynamicHoneyBadger<Vec<T>, N>,
/// The target number of transactions to be included in each batch.
batch_size: usize,
_phantom: PhantomData<Tx>,
_phantom: PhantomData<T>,
}
impl<Tx, NodeUid> QueueingHoneyBadgerBuilder<Tx, NodeUid>
impl<T, N> QueueingHoneyBadgerBuilder<T, N>
where
Tx: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash + Clone,
NodeUid: Eq + Ord + Clone + Debug + Serialize + for<'r> Deserialize<'r> + Hash + Rand,
T: Contribution + Serialize + for<'r> Deserialize<'r> + Clone,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
/// Returns a new `QueueingHoneyBadgerBuilder` configured to use the node IDs and cryptographic
/// keys specified by `netinfo`.
// TODO: Make it easier to build a `QueueingHoneyBadger` with a `JoinPlan`. Handle `Step`
// conversion internally.
pub fn new(dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>) -> Self {
pub fn new(dyn_hb: DynamicHoneyBadger<Vec<T>, N>) -> Self {
// TODO: Use the defaults from `HoneyBadgerBuilder`.
QueueingHoneyBadgerBuilder {
dyn_hb,
@ -128,9 +127,9 @@ where
}
/// Creates a new Queueing Honey Badger instance with an empty buffer.
pub fn build(self) -> (QueueingHoneyBadger<Tx, NodeUid>, Step<Tx, NodeUid>)
pub fn build(self) -> (QueueingHoneyBadger<T, N>, Step<T, N>)
where
Tx: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
T: Contribution + Serialize + for<'r> Deserialize<'r>,
{
self.build_with_transactions(None)
.expect("building without transactions cannot fail")
@ -141,10 +140,10 @@ where
pub fn build_with_transactions<TI>(
self,
txs: TI,
) -> Result<(QueueingHoneyBadger<Tx, NodeUid>, Step<Tx, NodeUid>)>
) -> Result<(QueueingHoneyBadger<T, N>, Step<T, N>)>
where
TI: IntoIterator<Item = Tx>,
Tx: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
TI: IntoIterator<Item = T>,
T: Contribution + Serialize + for<'r> Deserialize<'r>,
{
let queue = TransactionQueue(txs.into_iter().collect());
let mut qhb = QueueingHoneyBadger {
@ -160,33 +159,33 @@ where
/// A Honey Badger instance that can handle adding and removing nodes and manages a transaction
/// queue.
#[derive(Debug)]
pub struct QueueingHoneyBadger<Tx, NodeUid>
pub struct QueueingHoneyBadger<T, N>
where
Tx: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash,
NodeUid: Ord + Clone + Serialize + for<'r> Deserialize<'r> + Debug + Rand,
T: Contribution + Serialize + for<'r> Deserialize<'r>,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
/// The target number of transactions to be included in each batch.
batch_size: usize,
/// The internal `DynamicHoneyBadger` instance.
dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>,
dyn_hb: DynamicHoneyBadger<Vec<T>, N>,
/// The queue of pending transactions that haven't been output in a batch yet.
queue: TransactionQueue<Tx>,
queue: TransactionQueue<T>,
}
pub type Step<Tx, NodeUid> = messaging::Step<QueueingHoneyBadger<Tx, NodeUid>>;
pub type Step<T, N> = messaging::Step<QueueingHoneyBadger<T, N>>;
impl<Tx, NodeUid> DistAlgorithm for QueueingHoneyBadger<Tx, NodeUid>
impl<T, N> DistAlgorithm for QueueingHoneyBadger<T, N>
where
Tx: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash + Clone,
NodeUid: Eq + Ord + Clone + Serialize + for<'r> Deserialize<'r> + Debug + Hash + Rand,
T: Contribution + Serialize + for<'r> Deserialize<'r> + Clone,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
type NodeUid = NodeUid;
type Input = Input<Tx, NodeUid>;
type Output = Batch<Tx, NodeUid>;
type Message = Message<NodeUid>;
type NodeUid = N;
type Input = Input<T, N>;
type Output = Batch<T, N>;
type Message = Message<N>;
type Error = Error;
fn input(&mut self, input: Self::Input) -> Result<Step<Tx, NodeUid>> {
fn input(&mut self, input: Self::Input) -> Result<Step<T, N>> {
// User transactions are forwarded to `HoneyBadger` right away. Internal messages are
// in addition signed and broadcast.
let mut step = match input {
@ -204,11 +203,7 @@ where
Ok(step)
}
fn handle_message(
&mut self,
sender_id: &NodeUid,
message: Self::Message,
) -> Result<Step<Tx, NodeUid>> {
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> Result<Step<T, N>> {
let mut step = self
.dyn_hb
.handle_message(sender_id, message)
@ -225,26 +220,24 @@ where
false
}
fn our_id(&self) -> &NodeUid {
fn our_id(&self) -> &N {
self.dyn_hb.our_id()
}
}
impl<Tx, NodeUid> QueueingHoneyBadger<Tx, NodeUid>
impl<T, N> QueueingHoneyBadger<T, N>
where
Tx: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash + Clone,
NodeUid: Eq + Ord + Clone + Debug + Serialize + for<'r> Deserialize<'r> + Hash + Rand,
T: Contribution + Serialize + for<'r> Deserialize<'r> + Clone,
N: NodeUidT + Serialize + for<'r> Deserialize<'r> + Rand,
{
/// Returns a new `QueueingHoneyBadgerBuilder` configured to use the node IDs and cryptographic
/// keys specified by `netinfo`.
pub fn builder(
dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>,
) -> QueueingHoneyBadgerBuilder<Tx, NodeUid> {
pub fn builder(dyn_hb: DynamicHoneyBadger<Vec<T>, N>) -> QueueingHoneyBadgerBuilder<T, N> {
QueueingHoneyBadgerBuilder::new(dyn_hb)
}
/// Returns a reference to the internal `DynamicHoneyBadger` instance.
pub fn dyn_hb(&self) -> &DynamicHoneyBadger<Vec<Tx>, NodeUid> {
pub fn dyn_hb(&self) -> &DynamicHoneyBadger<Vec<T>, N> {
&self.dyn_hb
}
@ -259,7 +252,7 @@ where
}
/// Initiates the next epoch by proposing a batch from the queue.
fn propose(&mut self) -> Result<Step<Tx, NodeUid>> {
fn propose(&mut self) -> Result<Step<T, N>> {
let mut step = Step::default();
while self.can_propose() {
let amount = cmp::max(1, self.batch_size / self.dyn_hb.netinfo().num_nodes());
@ -275,4 +268,4 @@ where
}
}
pub type Batch<Tx, NodeUid> = DhbBatch<Vec<Tx>, NodeUid>;
pub type Batch<T, N> = DhbBatch<Vec<T>, N>;

View File

@ -166,6 +166,7 @@ use crypto::serde_impl::field_vec::FieldWrap;
use crypto::{Ciphertext, PublicKey, PublicKeySet, SecretKey, SecretKeyShare};
use fault_log::{FaultKind, FaultLog};
use messaging::NetworkInfo;
use traits::NodeUidT;
// TODO: No need to send our own row and value to ourselves.
@ -228,7 +229,7 @@ impl ProposalState {
}
/// The outcome of handling and verifying a `Part` message.
pub enum PartOutcome<NodeUid: Clone> {
pub enum PartOutcome<N: Clone> {
/// The message was valid: the part of it that was encrypted to us matched the public
/// commitment, so we can multicast an `Ack` message for it.
Valid(Ack),
@ -236,40 +237,40 @@ pub enum PartOutcome<NodeUid: Clone> {
// fault is logged and passed onto the caller.
/// The message was invalid: the part encrypted to us was malformed or didn't match the
/// commitment. We now know that the proposer is faulty, and dont' send an `Ack`.
Invalid(FaultLog<NodeUid>),
Invalid(FaultLog<N>),
}
/// A synchronous algorithm for dealerless distributed key generation.
///
/// It requires that all nodes handle all messages in the exact same order.
#[derive(Debug)]
pub struct SyncKeyGen<NodeUid> {
pub struct SyncKeyGen<N> {
/// Our node ID.
our_uid: NodeUid,
our_uid: N,
/// Our node index.
our_idx: Option<u64>,
/// Our secret key.
sec_key: SecretKey,
/// The public keys of all nodes, by node index.
pub_keys: BTreeMap<NodeUid, PublicKey>,
pub_keys: BTreeMap<N, PublicKey>,
/// Proposed bivariate polynomials.
parts: BTreeMap<u64, ProposalState>,
/// The degree of the generated polynomial.
threshold: usize,
}
impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
impl<N: NodeUidT> SyncKeyGen<N> {
/// Creates a new `SyncKeyGen` instance, together with the `Part` message that should be
/// multicast to all nodes.
///
/// If we are not a validator but only an observer, no `Part` message is produced and no
/// messages need to be sent.
pub fn new(
our_uid: NodeUid,
our_uid: N,
sec_key: SecretKey,
pub_keys: BTreeMap<NodeUid, PublicKey>,
pub_keys: BTreeMap<N, PublicKey>,
threshold: usize,
) -> (SyncKeyGen<NodeUid>, Option<Part>) {
) -> (SyncKeyGen<N>, Option<Part>) {
let our_idx = pub_keys
.keys()
.position(|uid| *uid == our_uid)
@ -305,9 +306,9 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
/// Note that `handle_part` also needs to explicitly be called with this instance's own `Part`.
pub fn handle_part(
&mut self,
sender_id: &NodeUid,
sender_id: &N,
Part(commit, rows): Part,
) -> Option<PartOutcome<NodeUid>> {
) -> Option<PartOutcome<N>> {
let sender_idx = self.node_index(sender_id)?;
let opt_commit_row = self.our_idx.map(|idx| commit.row(idx + 1));
match self.parts.entry(sender_idx) {
@ -351,7 +352,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
///
/// All participating nodes must handle the exact same sequence of messages.
/// Note that `handle_ack` also needs to explicitly be called with this instance's own `Ack`s.
pub fn handle_ack(&mut self, sender_id: &NodeUid, ack: Ack) -> FaultLog<NodeUid> {
pub fn handle_ack(&mut self, sender_id: &N, ack: Ack) -> FaultLog<N> {
let mut fault_log = FaultLog::new();
if let Some(sender_idx) = self.node_index(sender_id) {
if let Err(err) = self.handle_ack_or_err(sender_idx, ack) {
@ -372,7 +373,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
}
/// Returns `true` if the part of the given node is complete.
pub fn is_node_ready(&self, proposer_id: &NodeUid) -> bool {
pub fn is_node_ready(&self, proposer_id: &N) -> bool {
self.node_index(proposer_id)
.and_then(|proposer_idx| self.parts.get(&proposer_idx))
.map_or(false, |part| part.is_complete(self.threshold))
@ -412,7 +413,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
///
/// All participating nodes must have handled the exact same sequence of `Part` and `Ack`
/// messages before calling this method. Otherwise their key shares will not match.
pub fn into_network_info(self) -> NetworkInfo<NodeUid> {
pub fn into_network_info(self) -> NetworkInfo<N> {
let (pk_set, opt_sk_share) = self.generate();
let sk_share = opt_sk_share.unwrap_or_default(); // TODO: Make this an option.
NetworkInfo::new(self.our_uid, sk_share, pk_set, self.sec_key, self.pub_keys)
@ -453,7 +454,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
}
/// Returns the index of the node, or `None` if it is unknown.
fn node_index(&self, node_id: &NodeUid) -> Option<u64> {
fn node_index(&self, node_id: &N) -> Option<u64> {
if let Some(node_idx) = self.pub_keys.keys().position(|uid| uid == node_id) {
Some(node_idx as u64)
} else {

View File

@ -1,19 +1,20 @@
use std::cmp;
use std::collections::{HashSet, VecDeque};
use std::hash::Hash;
use rand;
use traits::Contribution;
/// A wrapper providing a few convenience methods for a queue of pending transactions.
#[derive(Debug)]
pub struct TransactionQueue<Tx>(pub VecDeque<Tx>);
pub struct TransactionQueue<T>(pub VecDeque<T>);
impl<Tx: Clone> TransactionQueue<Tx> {
impl<T: Clone> TransactionQueue<T> {
/// Removes the given transactions from the queue.
pub fn remove_all<'a, I>(&mut self, txs: I)
where
I: IntoIterator<Item = &'a Tx>,
Tx: Eq + Hash + 'a,
I: IntoIterator<Item = &'a T>,
T: 'a + Contribution,
{
let tx_set: HashSet<_> = txs.into_iter().collect();
self.0.retain(|tx| !tx_set.contains(tx));
@ -22,7 +23,7 @@ impl<Tx: Clone> TransactionQueue<Tx> {
/// Returns a new set of `amount` transactions, randomly chosen from the first `batch_size`.
/// No transactions are removed from the queue.
// TODO: Return references, once the `HoneyBadger` API accepts them. Remove `Clone` bound.
pub fn choose(&self, amount: usize, batch_size: usize) -> Vec<Tx> {
pub fn choose(&self, amount: usize, batch_size: usize) -> Vec<T> {
let mut rng = rand::thread_rng();
let limit = cmp::min(batch_size, self.0.len());
let sample = match rand::seq::sample_iter(&mut rng, self.0.iter().take(limit), amount) {