mirror of https://github.com/poanetwork/hbbft.git
Split FaultKind. (#371)
This commit is contained in:
parent
108ac574bb
commit
5bfcd6c692
|
@ -439,7 +439,8 @@ fn main() {
|
|||
.build_with_transactions(txs.clone(), rng)
|
||||
.expect("instantiate QueueingHoneyBadger");
|
||||
let (sq, mut step) = SenderQueue::builder(qhb, peer_ids.into_iter()).build(our_id);
|
||||
assert!(step.extend_with(qhb_step, Message::from).is_empty());
|
||||
let output = step.extend_with(qhb_step, |fault| fault, Message::from);
|
||||
assert!(output.is_empty());
|
||||
(sq, step)
|
||||
};
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ use rand::Rng;
|
|||
use super::bool_multimap::BoolMultimap;
|
||||
use super::bool_set::{self, BoolSet};
|
||||
use super::sbv_broadcast::{self, Message as SbvMessage, SbvBroadcast};
|
||||
use super::{Error, Message, MessageContent, Result, Step};
|
||||
use crate::fault_log::{Fault, FaultKind};
|
||||
use super::{Error, FaultKind, Message, MessageContent, Result, Step};
|
||||
use crate::fault_log::Fault;
|
||||
use crate::threshold_sign::{self, Message as TsMessage, ThresholdSign};
|
||||
use crate::{DistAlgorithm, NetworkInfo, NodeIdT, SessionIdT, Target};
|
||||
|
||||
|
@ -177,6 +177,7 @@ impl<N: NodeIdT, S: SessionIdT> DistAlgorithm for BinaryAgreement<N, S> {
|
|||
type Output = bool;
|
||||
type Message = Message;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, input: Self::Input, _rng: &mut R) -> Result<Step<N>> {
|
||||
self.propose(input)
|
||||
|
@ -299,9 +300,11 @@ impl<N: NodeIdT, S: SessionIdT> BinaryAgreement<N, S> {
|
|||
/// decides.
|
||||
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| {
|
||||
MessageContent::SbvBroadcast(msg).with_epoch(self.epoch)
|
||||
});
|
||||
let output = step.extend_with(
|
||||
sbvb_step,
|
||||
|fault| fault,
|
||||
|msg| MessageContent::SbvBroadcast(msg).with_epoch(self.epoch),
|
||||
);
|
||||
if self.conf_values.is_some() {
|
||||
return Ok(step); // The `Conf` round has already started.
|
||||
}
|
||||
|
@ -393,7 +396,7 @@ impl<N: NodeIdT, S: SessionIdT> BinaryAgreement<N, S> {
|
|||
let mut step = Step::default();
|
||||
let epoch = self.epoch;
|
||||
let to_msg = |c_msg| MessageContent::Coin(Box::new(c_msg)).with_epoch(epoch);
|
||||
let ts_output = step.extend_with(ts_step, to_msg);
|
||||
let ts_output = step.extend_with(ts_step, FaultKind::CoinFault, to_msg);
|
||||
if let Some(sig) = ts_output.into_iter().next() {
|
||||
// Take the parity of the signature as the coin value.
|
||||
self.coin_state = sig.parity().into();
|
||||
|
|
|
@ -105,8 +105,30 @@ impl From<bincode::Error> for Error {
|
|||
/// A `BinaryAgreement` result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// A faulty Binary Agreement message received from a peer.
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `BinaryAgreement` received a duplicate `BVal` message.
|
||||
#[fail(display = "`BinaryAgreement` received a duplicate `BVal` message.")]
|
||||
DuplicateBVal,
|
||||
/// `BinaryAgreement` received a duplicate `Aux` message.
|
||||
#[fail(display = "`BinaryAgreement` received a duplicate `Aux` message.")]
|
||||
DuplicateAux,
|
||||
/// `BinaryAgreement` received multiple `Conf` messages.
|
||||
#[fail(display = "`BinaryAgreement` received multiple `Conf` messages.")]
|
||||
MultipleConf,
|
||||
/// `BinaryAgreement` received multiple `Term` messages.
|
||||
#[fail(display = "`BinaryAgreement` received multiple `Term` messages.")]
|
||||
MultipleTerm,
|
||||
/// `BinaryAgreement` received a message with an epoch too far ahead.
|
||||
#[fail(display = "`BinaryAgreement` received a message with an epoch too far ahead.")]
|
||||
AgreementEpoch,
|
||||
/// `BinaryAgreement` received a Coin Fault.
|
||||
#[fail(display = "`BinaryAgreement` received a Coin Fault.")]
|
||||
CoinFault(threshold_sign::FaultKind),
|
||||
}
|
||||
/// A `BinaryAgreement` step, containing at most one output.
|
||||
pub type Step<N> = crate::Step<Message, bool, N>;
|
||||
pub type Step<N> = crate::Step<Message, bool, N, FaultKind>;
|
||||
|
||||
/// The content of a message belonging to a particular `BinaryAgreement` epoch.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
|
|
|
@ -17,11 +17,11 @@ use serde_derive::{Deserialize, Serialize};
|
|||
|
||||
use super::bool_multimap::BoolMultimap;
|
||||
use super::bool_set::{self, BoolSet};
|
||||
use super::Result;
|
||||
use crate::fault_log::{Fault, FaultKind};
|
||||
use super::{FaultKind, Result};
|
||||
use crate::fault_log::Fault;
|
||||
use crate::{NetworkInfo, NodeIdT, Target};
|
||||
|
||||
pub type Step<N> = crate::Step<Message, BoolSet, N>;
|
||||
pub type Step<N> = crate::Step<Message, BoolSet, N, FaultKind>;
|
||||
|
||||
/// A message belonging to the Synchronized Binary Value Broadcast phase of a `BinaryAgreement`
|
||||
/// epoch.
|
||||
|
|
|
@ -11,8 +11,8 @@ use reed_solomon_erasure::ReedSolomon;
|
|||
|
||||
use super::merkle::{Digest, MerkleTree, Proof};
|
||||
use super::message::HexProof;
|
||||
use super::{Error, Message, Result};
|
||||
use crate::fault_log::{Fault, FaultKind};
|
||||
use super::{Error, FaultKind, Message, Result};
|
||||
use crate::fault_log::Fault;
|
||||
use crate::{DistAlgorithm, NetworkInfo, NodeIdT, Target};
|
||||
|
||||
type RseResult<T> = result::Result<T, rse::Error>;
|
||||
|
@ -49,6 +49,7 @@ impl<N: NodeIdT> DistAlgorithm for Broadcast<N> {
|
|||
type Output = Self::Input;
|
||||
type Message = Message;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, input: Self::Input, _rng: &mut R) -> Result<Step<N>> {
|
||||
self.broadcast(input)
|
||||
|
|
|
@ -22,3 +22,26 @@ pub enum Error {
|
|||
|
||||
/// A broadcast result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// Represents each reason why a broadcast message could be faulty.
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `Broadcast` received a `Value` from a node other than the proposer.
|
||||
#[fail(display = "`Broadcast` received a `Value` from a node other than the proposer.")]
|
||||
ReceivedValueFromNonProposer,
|
||||
/// `Broadcast` received multiple different `Value`s from the proposer.
|
||||
#[fail(display = "`Broadcast` received multiple different `Value`s from the proposer.")]
|
||||
MultipleValues,
|
||||
/// `Broadcast` received multiple different `Echo`s from the same sender.
|
||||
#[fail(display = "`Broadcast` received multiple different `Echo`s from the same sender.")]
|
||||
MultipleEchos,
|
||||
/// `Broadcast` received multiple different `Ready`s from the same sender.
|
||||
#[fail(display = "`Broadcast` received multiple different `Ready`s from the same sender.")]
|
||||
MultipleReadys,
|
||||
/// `Broadcast` recevied an Echo message containing an invalid proof.
|
||||
#[fail(display = "`Broadcast` recevied an Echo message containing an invalid proof.")]
|
||||
InvalidProof,
|
||||
///`Broadcast` received shards with valid proofs, that couldn't be decoded.
|
||||
#[fail(display = "`Broadcast` received shards with valid proofs, that couldn't be decoded.")]
|
||||
BroadcastDecoding,
|
||||
}
|
||||
|
|
|
@ -190,5 +190,5 @@ pub(crate) mod merkle;
|
|||
mod message;
|
||||
|
||||
pub use self::broadcast::{Broadcast, Step};
|
||||
pub use self::error::{Error, Result};
|
||||
pub use self::error::{Error, FaultKind, Result};
|
||||
pub use self::message::Message;
|
||||
|
|
|
@ -11,11 +11,11 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
|
||||
use super::votes::{SignedVote, VoteCounter};
|
||||
use super::{
|
||||
Batch, Change, ChangeState, DynamicHoneyBadgerBuilder, EncryptionSchedule, Error, Input,
|
||||
InternalContrib, JoinPlan, KeyGenMessage, KeyGenState, Message, Params, Result,
|
||||
Batch, Change, ChangeState, DynamicHoneyBadgerBuilder, EncryptionSchedule, Error, FaultKind,
|
||||
Input, InternalContrib, JoinPlan, KeyGenMessage, KeyGenState, Message, Params, Result,
|
||||
SignedKeyGenMsg, Step,
|
||||
};
|
||||
use crate::fault_log::{Fault, FaultKind, FaultLog};
|
||||
use crate::fault_log::{Fault, FaultLog};
|
||||
use crate::honey_badger::{self, HoneyBadger, Message as HbMessage};
|
||||
|
||||
use crate::sync_key_gen::{Ack, AckOutcome, Part, PartOutcome, SyncKeyGen};
|
||||
|
@ -52,6 +52,7 @@ where
|
|||
type Output = Batch<C, N>;
|
||||
type Message = Message<N>;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, input: Self::Input, rng: &mut R) -> Result<Step<C, N>> {
|
||||
// User contributions are forwarded to `HoneyBadger` right away. Votes are signed and
|
||||
|
@ -280,7 +281,7 @@ where
|
|||
sender_id: &N,
|
||||
kg_msg: KeyGenMessage,
|
||||
sig: Signature,
|
||||
) -> Result<FaultLog<N>> {
|
||||
) -> Result<FaultLog<N, FaultKind>> {
|
||||
if !self.verify_signature(sender_id, &sig, &kg_msg)? {
|
||||
let fault_kind = FaultKind::InvalidKeyGenMessageSignature;
|
||||
return Ok(Fault::new(sender_id.clone(), fault_kind).into());
|
||||
|
@ -311,7 +312,9 @@ where
|
|||
rng: &mut R,
|
||||
) -> Result<Step<C, N>> {
|
||||
let mut step: Step<C, N> = Step::default();
|
||||
let output = step.extend_with(hb_step, |hb_msg| Message::HoneyBadger(self.era, hb_msg));
|
||||
let output = step.extend_with(hb_step, FaultKind::HbFault, |hb_msg| {
|
||||
Message::HoneyBadger(self.era, hb_msg)
|
||||
});
|
||||
for hb_batch in output {
|
||||
let batch_era = self.era;
|
||||
let batch_epoch = hb_batch.epoch + batch_era;
|
||||
|
|
|
@ -29,3 +29,65 @@ pub enum Error {
|
|||
|
||||
/// The result of `DynamicHoneyBadger` handling an input or message.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
/// Represents each way an an incoming message can be considered faulty.
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `DynamicHoneyBadger` received a key generation message with an invalid signature.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received a key generation message with an invalid signature."
|
||||
)]
|
||||
InvalidKeyGenMessageSignature,
|
||||
/// `DynamicHoneyBadger` received a key generation message with an invalid era.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received a key generation message with an invalid era."
|
||||
)]
|
||||
InvalidKeyGenMessageEra,
|
||||
/// `DynamicHoneyBadger` received a key generation message when there was no key generation in
|
||||
/// progress.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received a key generation message when there was no key
|
||||
generation in progress."
|
||||
)]
|
||||
UnexpectedKeyGenMessage,
|
||||
/// `DynamicHoneyBadger` received a signed `Ack` when no key generation in progress.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received a signed `Ack` when no key generation in progress."
|
||||
)]
|
||||
UnexpectedKeyGenAck,
|
||||
/// `DynamicHoneyBadger` received a signed `Part` when no key generation in progress.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received a signed `Part` when no key generation in progress."
|
||||
)]
|
||||
UnexpectedKeyGenPart,
|
||||
/// `DynamicHoneyBadger` received more key generation messages from the peer than expected.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received more key generation messages from the peer than
|
||||
expected."
|
||||
)]
|
||||
TooManyKeyGenMessages,
|
||||
/// `DynamicHoneyBadger` received a message (Accept, Propose, or Change with an invalid
|
||||
/// signature.
|
||||
#[fail(
|
||||
display = "`DynamicHoneyBadger` received a message (Accept, Propose, or Change
|
||||
with an invalid signature."
|
||||
)]
|
||||
IncorrectPayloadSignature,
|
||||
/// `DynamicHoneyBadger`/`SyncKeyGen` received an invalid `Ack` message.
|
||||
#[fail(display = "`DynamicHoneyBadger`/`SyncKeyGen` received an invalid `Ack` message.")]
|
||||
SyncKeyGenAck(sync_key_gen::AckFault),
|
||||
/// `DynamicHoneyBadger`/`SyncKeyGen` received an invalid `Part` message.
|
||||
#[fail(display = "`DynamicHoneyBadger`/`SyncKeyGen` received an invalid `Part` message.")]
|
||||
SyncKeyGenPart(sync_key_gen::PartFault),
|
||||
/// `DynamicHoneyBadger` received a change vote with an invalid signature.
|
||||
#[fail(display = "`DynamicHoneyBadger` received a change vote with an invalid signature.")]
|
||||
InvalidVoteSignature,
|
||||
/// A validator committed an invalid vote in `DynamicHoneyBadger`.
|
||||
#[fail(display = "A validator committed an invalid vote in `DynamicHoneyBadger`.")]
|
||||
InvalidCommittedVote,
|
||||
/// `DynamicHoneyBadger` received a message with an invalid era.
|
||||
#[fail(display = "`DynamicHoneyBadger` received a message with an invalid era.")]
|
||||
UnexpectedDhbMessageEra,
|
||||
/// `DynamicHoneyBadger` received a fault from `HoneyBadger`.
|
||||
#[fail(display = "`DynamicHoneyBadger` received a fault from `HoneyBadger`.")]
|
||||
HbFault(honey_badger::FaultKind),
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ pub use self::batch::Batch;
|
|||
pub use self::builder::DynamicHoneyBadgerBuilder;
|
||||
pub use self::change::{Change, ChangeState};
|
||||
pub use self::dynamic_honey_badger::DynamicHoneyBadger;
|
||||
pub use self::error::{Error, Result};
|
||||
pub use self::error::{Error, FaultKind, Result};
|
||||
|
||||
/// A `DynamicHoneyBadger` step, possibly containing multiple outputs.
|
||||
pub type Step<C, N> = crate::DaStep<DynamicHoneyBadger<C, N>>;
|
||||
|
|
|
@ -6,10 +6,12 @@ use bincode;
|
|||
use serde::Serialize;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::{Change, Error, Result};
|
||||
use crate::fault_log::{FaultKind, FaultLog};
|
||||
use super::{Change, Error, FaultKind, Result};
|
||||
use crate::fault_log;
|
||||
use crate::{NetworkInfo, NodeIdT};
|
||||
|
||||
pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
|
||||
|
||||
/// 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
|
||||
|
@ -190,8 +192,8 @@ mod tests {
|
|||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{Change, SignedVote, VoteCounter};
|
||||
use crate::fault_log::{FaultKind, FaultLog};
|
||||
use super::{Change, FaultKind, SignedVote, VoteCounter};
|
||||
use crate::fault_log::FaultLog;
|
||||
use crate::NetworkInfo;
|
||||
use rand;
|
||||
|
||||
|
|
166
src/fault_log.rs
166
src/fault_log.rs
|
@ -1,135 +1,90 @@
|
|||
//! Functionality for logging faulty node behavior encountered by each
|
||||
//! algorithm.
|
||||
//!
|
||||
//! Each algorithm can propogate their faulty node logs upwards to a
|
||||
//! calling algorithm via `DistAlgorihm`'s `.handle_input()` and
|
||||
//! `.handle_message()` trait methods.
|
||||
//! Each algorithm can propogate their faulty node logs upwards to a calling algorithm via
|
||||
//! `DistAlgorihm`'s `.handle_input()` and `.handle_message()` trait methods.
|
||||
|
||||
pub use crate::sync_key_gen::{AckFault, PartFault};
|
||||
|
||||
/// Represents each reason why a node could be considered faulty.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `Coin` received a signature share from an unverified sender.
|
||||
UnverifiedSignatureShareSender,
|
||||
/// `HoneyBadger` received a decryption share from an unverified sender.
|
||||
UnverifiedDecryptionShareSender,
|
||||
/// `HoneyBadger` received a decryption share for an unaccepted proposer.
|
||||
UnexpectedDecryptionShare,
|
||||
/// `HoneyBadger` was unable to deserialize a proposer's ciphertext.
|
||||
DeserializeCiphertext,
|
||||
/// `HoneyBadger` received an invalid ciphertext from the proposer.
|
||||
InvalidCiphertext,
|
||||
/// `HoneyBadger` received a message with an invalid epoch.
|
||||
UnexpectedHbMessageEpoch,
|
||||
/// `ThresholdDecrypt` received multiple shares from the same sender.
|
||||
MultipleDecryptionShares,
|
||||
/// `Broadcast` received a `Value` from a node other than the proposer.
|
||||
ReceivedValueFromNonProposer,
|
||||
/// `Broadcast` received multiple different `Value`s from the proposer.
|
||||
MultipleValues,
|
||||
/// `Broadcast` received multiple different `Echo`s from the same sender.
|
||||
MultipleEchos,
|
||||
/// `Broadcast` received multiple different `Ready`s from the same sender.
|
||||
MultipleReadys,
|
||||
/// `Broadcast` recevied an Echo message containing an invalid proof.
|
||||
InvalidProof,
|
||||
/// `Broadcast` received shards with valid proofs, that couldn't be decoded.
|
||||
BroadcastDecoding,
|
||||
/// `HoneyBadger` could not deserialize bytes (i.e. a serialized Batch)
|
||||
/// from a given proposer into a vector of transactions.
|
||||
BatchDeserializationFailed,
|
||||
/// `DynamicHoneyBadger` received a key generation message with an invalid signature.
|
||||
InvalidKeyGenMessageSignature,
|
||||
/// `DynamicHoneyBadger` received a key generation message with an invalid era.
|
||||
InvalidKeyGenMessageEra,
|
||||
/// `DynamicHoneyBadger` received a key generation message when there was no key generation in
|
||||
/// progress.
|
||||
UnexpectedKeyGenMessage,
|
||||
/// `DynamicHoneyBadger` received a signed `Ack` when no key generation in progress.
|
||||
UnexpectedKeyGenAck,
|
||||
/// `DynamicHoneyBadger` received a signed `Part` when no key generation in progress.
|
||||
UnexpectedKeyGenPart,
|
||||
/// `DynamicHoneyBadger` received more key generation messages from the peer than expected.
|
||||
TooManyKeyGenMessages,
|
||||
/// `DynamicHoneyBadger` received a message (Accept, Propose, or Change)
|
||||
/// with an invalid signature.
|
||||
IncorrectPayloadSignature,
|
||||
/// `DynamicHoneyBadger`/`SyncKeyGen` received an invalid `Ack` message.
|
||||
SyncKeyGenAck(AckFault),
|
||||
/// `DynamicHoneyBadger`/`SyncKeyGen` received an invalid `Part` message.
|
||||
SyncKeyGenPart(PartFault),
|
||||
/// `DynamicHoneyBadger` received a change vote with an invalid signature.
|
||||
InvalidVoteSignature,
|
||||
/// A validator committed an invalid vote in `DynamicHoneyBadger`.
|
||||
InvalidCommittedVote,
|
||||
/// `DynamicHoneyBadger` received a message with an invalid era.
|
||||
UnexpectedDhbMessageEra,
|
||||
/// `BinaryAgreement` received a duplicate `BVal` message.
|
||||
DuplicateBVal,
|
||||
/// `BinaryAgreement` received a duplicate `Aux` message.
|
||||
DuplicateAux,
|
||||
/// `BinaryAgreement` received multiple `Conf` messages.
|
||||
MultipleConf,
|
||||
/// `BinaryAgreement` received multiple `Term` messages.
|
||||
MultipleTerm,
|
||||
/// `BinaryAgreement` received a message with an epoch too far ahead.
|
||||
AgreementEpoch,
|
||||
}
|
||||
pub use failure::Fail;
|
||||
|
||||
/// A structure representing the context of a faulty node. This structure
|
||||
/// describes which node is faulty (`node_id`) and which faulty behavior
|
||||
/// that the node exhibited ('kind').
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Fault<N> {
|
||||
pub struct Fault<N, F: Fail> {
|
||||
/// The faulty node's ID.
|
||||
pub node_id: N,
|
||||
/// The kind of fault the node is blamed for.
|
||||
pub kind: FaultKind,
|
||||
pub kind: F,
|
||||
}
|
||||
|
||||
impl<N> Fault<N> {
|
||||
impl<N, F> Fault<N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
/// Creates a new fault, blaming `node_id` for the `kind`.
|
||||
pub fn new(node_id: N, kind: FaultKind) -> Self {
|
||||
pub fn new(node_id: N, kind: F) -> Self {
|
||||
Fault { node_id, kind }
|
||||
}
|
||||
|
||||
/// Applies `f_fault` to `kind`, leaves `node_id` unchanged
|
||||
pub fn map<F2, FF>(self, f_fault: FF) -> Fault<N, F2>
|
||||
where
|
||||
F2: Fail,
|
||||
FF: Fn(F) -> F2,
|
||||
{
|
||||
Fault {
|
||||
node_id: self.node_id,
|
||||
kind: f_fault(self.kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `FaultLog` where `self` is the first element in the log
|
||||
/// vector.
|
||||
impl<N> Into<FaultLog<N>> for Fault<N> {
|
||||
fn into(self) -> FaultLog<N> {
|
||||
impl<N, F> Into<FaultLog<N, F>> for Fault<N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn into(self) -> FaultLog<N, F> {
|
||||
FaultLog(vec![self])
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure used to contain reports of faulty node behavior.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct FaultLog<N>(pub Vec<Fault<N>>);
|
||||
pub struct FaultLog<N, F: Fail>(pub Vec<Fault<N, F>>);
|
||||
|
||||
impl<N> FaultLog<N> {
|
||||
impl<N, F> FaultLog<N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
/// Creates an empty `FaultLog`.
|
||||
pub fn new() -> Self {
|
||||
FaultLog::default()
|
||||
}
|
||||
|
||||
/// Creates a new `FaultLog` initialized with a single log.
|
||||
pub fn init(node_id: N, kind: FaultKind) -> Self {
|
||||
pub fn init(node_id: N, kind: F) -> 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: N, kind: FaultKind) {
|
||||
pub fn append(&mut self, node_id: N, kind: F) {
|
||||
self.0.push(Fault::new(node_id, kind));
|
||||
}
|
||||
|
||||
/// Consumes a `Fault` and pushes it onto the fault log.
|
||||
pub fn append_fault(&mut self, fault: Fault<N, F>) {
|
||||
self.0.push(fault);
|
||||
}
|
||||
|
||||
/// Consumes `new_logs`, appending its logs onto the end of `self`.
|
||||
pub fn extend(&mut self, new_logs: FaultLog<N>) {
|
||||
pub fn extend(&mut self, new_logs: FaultLog<N, F>) {
|
||||
self.0.extend(new_logs.0);
|
||||
}
|
||||
|
||||
/// Consumes `self`, appending its logs onto the end of `logs`.
|
||||
pub fn merge_into(self, logs: &mut FaultLog<N>) {
|
||||
pub fn merge_into(self, logs: &mut FaultLog<N, F>) {
|
||||
logs.extend(self);
|
||||
}
|
||||
|
||||
|
@ -137,10 +92,47 @@ impl<N> FaultLog<N> {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// Applies `f_fault` to each element in log, modifying its `kind` only
|
||||
pub fn map<F2, FF>(self, f_fault: FF) -> FaultLog<N, F2>
|
||||
where
|
||||
F2: Fail,
|
||||
FF: Fn(F) -> F2,
|
||||
{
|
||||
FaultLog(self.into_iter().map(|f| f.map(&f_fault)).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> Default for FaultLog<N> {
|
||||
impl<N, F> Default for FaultLog<N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn default() -> Self {
|
||||
FaultLog(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, F> IntoIterator for FaultLog<N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
type Item = Fault<N, F>;
|
||||
type IntoIter = std::vec::IntoIter<Fault<N, F>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, F> std::iter::FromIterator<Fault<N, F>> for FaultLog<N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn from_iter<I: IntoIterator<Item = Fault<N, F>>>(iter: I) -> Self {
|
||||
let mut log = FaultLog::new();
|
||||
for i in iter {
|
||||
log.append_fault(i);
|
||||
}
|
||||
log
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ use rand::Rng;
|
|||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::{Batch, Error, MessageContent, Result, Step};
|
||||
use crate::fault_log::{Fault, FaultKind, FaultLog};
|
||||
use super::{Batch, Error, FaultKind, FaultLog, MessageContent, Result, Step};
|
||||
use crate::fault_log::Fault;
|
||||
use crate::subset::{self as cs, Subset, SubsetOutput};
|
||||
use crate::threshold_decrypt::{self as td, ThresholdDecrypt};
|
||||
use crate::{Contribution, NetworkInfo, NodeIdT};
|
||||
|
@ -306,7 +306,7 @@ where
|
|||
/// Checks whether the subset has output, and if it does, sends out our decryption shares.
|
||||
fn process_subset(&mut self, cs_step: CsStep<N>) -> Result<Step<C, N>> {
|
||||
let mut step = Step::default();
|
||||
let cs_outputs = step.extend_with(cs_step, |cs_msg| {
|
||||
let cs_outputs = step.extend_with(cs_step, FaultKind::SubsetFault, |cs_msg| {
|
||||
MessageContent::Subset(cs_msg).with_epoch(self.epoch)
|
||||
});
|
||||
let mut has_seen_done = false;
|
||||
|
@ -357,7 +357,7 @@ where
|
|||
/// Processes a Threshold Decrypt step.
|
||||
fn process_decryption(&mut self, proposer_id: N, td_step: td::Step<N>) -> Result<Step<C, N>> {
|
||||
let mut step = Step::default();
|
||||
let opt_output = step.extend_with(td_step, |share| {
|
||||
let opt_output = step.extend_with(td_step, FaultKind::DecryptionFault, |share| {
|
||||
MessageContent::DecryptionShare {
|
||||
proposer_id: proposer_id.clone(),
|
||||
share,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use bincode;
|
||||
use failure::Fail;
|
||||
|
||||
use crate::fault_log;
|
||||
use crate::subset;
|
||||
use crate::threshold_decrypt;
|
||||
|
||||
|
@ -29,3 +30,36 @@ pub enum Error {
|
|||
|
||||
/// The result of `HoneyBadger` handling an input or a message.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// Faults detectable from receiving honey badger messages
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `HoneyBadger` received a decryption share for an unaccepted proposer.
|
||||
#[fail(display = "`HoneyBadger` received a decryption share for an unaccepted proposer.")]
|
||||
UnexpectedDecryptionShare,
|
||||
/// `HoneyBadger` was unable to deserialize a proposer's ciphertext.
|
||||
#[fail(display = "`HoneyBadger` was unable to deserialize a proposer's ciphertext.")]
|
||||
DeserializeCiphertext,
|
||||
/// `HoneyBadger` received an invalid ciphertext from the proposer.
|
||||
#[fail(display = "`HoneyBadger` received an invalid ciphertext from the proposer.")]
|
||||
InvalidCiphertext,
|
||||
/// `HoneyBadger` received a message with an invalid epoch.
|
||||
#[fail(display = "`HoneyBadger` received a message with an invalid epoch.")]
|
||||
UnexpectedHbMessageEpoch,
|
||||
/// `HoneyBadger` could not deserialize bytes (i.e. a serialized Batch) from a given proposer
|
||||
/// into a vector of transactions.
|
||||
#[fail(
|
||||
display = "`HoneyBadger` could not deserialize bytes (i.e. a serialized Batch) from a
|
||||
given proposer into a vector of transactions."
|
||||
)]
|
||||
BatchDeserializationFailed,
|
||||
/// `HoneyBadger` received a fault from `Subset`.
|
||||
#[fail(display = "`HoneyBadger` received a fault from `Subset`.")]
|
||||
SubsetFault(subset::FaultKind),
|
||||
/// `HoneyBadger` received a fault from `ThresholdDecrypt`.
|
||||
#[fail(display = "`HoneyBadger` received a fault from `ThresholdDecrypt`.")]
|
||||
DecryptionFault(threshold_decrypt::FaultKind),
|
||||
}
|
||||
|
||||
/// The type of fault log whose entries are `HoneyBadger` faults.
|
||||
pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
|
||||
|
|
|
@ -8,8 +8,8 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::epoch_state::EpochState;
|
||||
use super::{Batch, Error, HoneyBadgerBuilder, Message, Result};
|
||||
use crate::{Contribution, DistAlgorithm, Fault, FaultKind, NetworkInfo, NodeIdT};
|
||||
use super::{Batch, Error, FaultKind, HoneyBadgerBuilder, Message, Result};
|
||||
use crate::{Contribution, DistAlgorithm, Fault, NetworkInfo, NodeIdT};
|
||||
|
||||
use super::Params;
|
||||
|
||||
|
@ -45,6 +45,7 @@ where
|
|||
type Output = Batch<C, N>;
|
||||
type Message = Message<N>;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, input: Self::Input, rng: &mut R) -> Result<Step<C, N>> {
|
||||
self.propose(&input, rng)
|
||||
|
|
|
@ -33,7 +33,7 @@ mod params;
|
|||
pub use self::batch::Batch;
|
||||
pub use self::builder::HoneyBadgerBuilder;
|
||||
pub use self::epoch_state::SubsetHandlingStrategy;
|
||||
pub use self::error::{Error, Result};
|
||||
pub use self::error::{Error, FaultKind, FaultLog, Result};
|
||||
pub use self::honey_badger::{EncryptionSchedule, HoneyBadger, Step};
|
||||
pub use self::message::{Message, MessageContent};
|
||||
pub use self::params::Params;
|
||||
|
|
|
@ -140,7 +140,7 @@ pub mod transaction_queue;
|
|||
pub mod util;
|
||||
|
||||
pub use crate::crypto::pairing;
|
||||
pub use crate::fault_log::{Fault, FaultKind, FaultLog};
|
||||
pub use crate::fault_log::{Fault, FaultLog};
|
||||
pub use crate::messaging::{SourcedMessage, Target, TargetedMessage};
|
||||
pub use crate::network_info::NetworkInfo;
|
||||
pub use crate::traits::{
|
||||
|
|
|
@ -33,7 +33,7 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
|
||||
use crate::crypto::{PublicKey, SecretKey};
|
||||
use crate::dynamic_honey_badger::{
|
||||
self, Batch as DhbBatch, DynamicHoneyBadger, JoinPlan, Message, Step as DhbStep,
|
||||
self, Batch as DhbBatch, DynamicHoneyBadger, FaultKind, JoinPlan, Message, Step as DhbStep,
|
||||
};
|
||||
use crate::transaction_queue::TransactionQueue;
|
||||
use crate::{Contribution, DistAlgorithm, NetworkInfo, NodeIdT};
|
||||
|
@ -162,7 +162,7 @@ pub struct QueueingHoneyBadger<T, N: Ord, Q> {
|
|||
}
|
||||
|
||||
/// A `QueueingHoneyBadger` step, possibly containing multiple outputs.
|
||||
pub type Step<T, N> = crate::Step<Message<N>, Batch<T, N>, N>;
|
||||
pub type Step<T, N> = crate::Step<Message<N>, Batch<T, N>, N, FaultKind>;
|
||||
|
||||
impl<T, N, Q> DistAlgorithm for QueueingHoneyBadger<T, N, Q>
|
||||
where
|
||||
|
@ -176,6 +176,7 @@ where
|
|||
type Output = Batch<T, N>;
|
||||
type Message = Message<N>;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, input: Self::Input, rng: &mut R) -> Result<Step<T, N>> {
|
||||
// User transactions are forwarded to `HoneyBadger` right away. Internal messages are
|
||||
|
|
|
@ -120,6 +120,7 @@ where
|
|||
type Output = D::Output;
|
||||
type Message = Message<D::Message>;
|
||||
type Error = D::Error;
|
||||
type FaultKind = D::FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(
|
||||
&mut self,
|
||||
|
@ -201,7 +202,7 @@ where
|
|||
let mut step = f(&mut self.algo)?;
|
||||
let mut sender_queue_step = self.update_epoch(&step);
|
||||
self.defer_messages(&mut step);
|
||||
sender_queue_step.extend(step.map(|output| output, Message::from));
|
||||
sender_queue_step.extend(step.map(|output| output, |fault| fault, Message::from));
|
||||
Ok(sender_queue_step)
|
||||
}
|
||||
|
||||
|
|
|
@ -27,3 +27,14 @@ pub enum Error {
|
|||
|
||||
/// A subset result.
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
/// Faults that can be detected in Subset.
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `Subset` received a faulty Broadcast message.
|
||||
#[fail(display = "`Subset` received a faulty Broadcast message.")]
|
||||
BroadcastFault(broadcast::FaultKind),
|
||||
/// `Subset` received a faulty Binary Agreement message.
|
||||
#[fail(display = "`Subset` received a faulty Binary Agreement message.")]
|
||||
BaFault(binary_agreement::FaultKind),
|
||||
}
|
||||
|
|
|
@ -28,6 +28,6 @@ mod message;
|
|||
mod proposal_state;
|
||||
mod subset;
|
||||
|
||||
pub use self::error::{Error, Result};
|
||||
pub use self::error::{Error, FaultKind, Result};
|
||||
pub use self::message::{Message, MessageContent};
|
||||
pub use self::subset::{Step, Subset, SubsetOutput};
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::mem;
|
|||
use std::sync::Arc;
|
||||
|
||||
use super::subset::BaSessionId;
|
||||
use super::{Error, MessageContent, Result};
|
||||
use super::{Error, FaultKind, MessageContent, Result};
|
||||
use crate::binary_agreement;
|
||||
use crate::broadcast::{self, Broadcast};
|
||||
use crate::{NetworkInfo, NodeIdT, SessionIdT};
|
||||
|
@ -11,7 +11,7 @@ type BaInstance<N, S> = binary_agreement::BinaryAgreement<N, BaSessionId<S>>;
|
|||
type ValueAndStep<N> = (Option<Vec<u8>>, Step<N>);
|
||||
type BaResult<N> = binary_agreement::Result<binary_agreement::Step<N>>;
|
||||
|
||||
pub type Step<N> = crate::Step<MessageContent, Vec<u8>, N>;
|
||||
pub type Step<N> = crate::Step<MessageContent, Vec<u8>, N, FaultKind>;
|
||||
|
||||
/// The state of a proposal's broadcast and agreement process.
|
||||
#[derive(Debug)]
|
||||
|
@ -138,7 +138,13 @@ impl<N: NodeIdT, S: SessionIdT> ProposalState<N, S> {
|
|||
fn convert_bc(result: broadcast::Result<broadcast::Step<N>>) -> Result<ValueAndStep<N>> {
|
||||
let bc_step = result.map_err(Error::HandleBroadcast)?;
|
||||
let mut step = Step::default();
|
||||
let opt_value = step.extend_with(bc_step, MessageContent::Broadcast).pop();
|
||||
let opt_value = step
|
||||
.extend_with(
|
||||
bc_step,
|
||||
FaultKind::BroadcastFault,
|
||||
MessageContent::Broadcast,
|
||||
)
|
||||
.pop();
|
||||
Ok((opt_value, step))
|
||||
}
|
||||
|
||||
|
@ -146,7 +152,9 @@ impl<N: NodeIdT, S: SessionIdT> ProposalState<N, S> {
|
|||
fn convert_ba(result: BaResult<N>) -> Result<(Option<bool>, Step<N>)> {
|
||||
let ba_step = result.map_err(Error::HandleAgreement)?;
|
||||
let mut step = Step::default();
|
||||
let opt_decision = step.extend_with(ba_step, MessageContent::Agreement).pop();
|
||||
let opt_decision = step
|
||||
.extend_with(ba_step, FaultKind::BaFault, MessageContent::Agreement)
|
||||
.pop();
|
||||
Ok((opt_decision, step))
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@ use log::debug;
|
|||
use serde_derive::Serialize;
|
||||
|
||||
use super::proposal_state::{ProposalState, Step as ProposalStep};
|
||||
use super::{Error, Message, MessageContent, Result};
|
||||
use super::{Error, FaultKind, Message, MessageContent, Result};
|
||||
use crate::{util, DistAlgorithm, NetworkInfo, NodeIdT, SessionIdT};
|
||||
use rand::Rng;
|
||||
|
||||
/// A `Subset` step, possibly containing several outputs.
|
||||
pub type Step<N> = crate::Step<Message<N>, SubsetOutput<N>, N>;
|
||||
pub type Step<N> = crate::Step<Message<N>, SubsetOutput<N>, N, FaultKind>;
|
||||
|
||||
/// An output with an accepted contribution or the end of the set.
|
||||
#[derive(Derivative, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
@ -47,6 +47,7 @@ impl<N: NodeIdT, S: SessionIdT> DistAlgorithm for Subset<N, S> {
|
|||
type Output = SubsetOutput<N>;
|
||||
type Message = Message<N>;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, input: Self::Input, _rng: &mut R) -> Result<Step<N>> {
|
||||
self.propose(input)
|
||||
|
@ -135,7 +136,7 @@ impl<N: NodeIdT, S: SessionIdT> Subset<N, S> {
|
|||
fn convert_step(proposer_id: &N, prop_step: ProposalStep<N>) -> Step<N> {
|
||||
let from_p_msg = |p_msg: MessageContent| p_msg.with(proposer_id.clone());
|
||||
let mut step = Step::default();
|
||||
if let Some(value) = step.extend_with(prop_step, from_p_msg).pop() {
|
||||
if let Some(value) = step.extend_with(prop_step, |fault| fault, from_p_msg).pop() {
|
||||
let contribution = SubsetOutput::Contribution(proposer_id.clone(), value);
|
||||
step.output.push(contribution);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use rand::Rng;
|
|||
use rand_derive::Rand;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::fault_log::{Fault, FaultKind, FaultLog};
|
||||
use crate::fault_log::{self, Fault};
|
||||
use crate::{DistAlgorithm, NetworkInfo, NodeIdT, Target};
|
||||
|
||||
/// A threshold decryption error.
|
||||
|
@ -46,6 +46,20 @@ pub enum Error {
|
|||
/// A threshold decryption result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// A threshold decryption message fault
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `ThresholdDecrypt` received multiple shares from the same sender.
|
||||
#[fail(display = "`ThresholdDecrypt` received multiple shares from the same sender.")]
|
||||
MultipleDecryptionShares,
|
||||
/// `HoneyBadger` received a decryption share from an unverified sender.
|
||||
#[fail(display = "`HoneyBadger` received a decryption share from an unverified sender.")]
|
||||
UnverifiedDecryptionShareSender,
|
||||
}
|
||||
|
||||
/// The type of fault log whose entries are `ThresholdDecrypt` faults.
|
||||
pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
|
||||
|
||||
/// A Threshold Decryption message.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Rand)]
|
||||
pub struct Message(pub DecryptionShare);
|
||||
|
@ -74,6 +88,7 @@ impl<N: NodeIdT> DistAlgorithm for ThresholdDecrypt<N> {
|
|||
type Output = Vec<u8>;
|
||||
type Message = Message;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
fn handle_input<R: Rng>(&mut self, _input: (), _rng: &mut R) -> Result<Step<N>> {
|
||||
self.start_decryption()
|
||||
|
|
|
@ -26,7 +26,7 @@ use rand::Rng;
|
|||
use rand_derive::Rand;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::fault_log::{Fault, FaultKind, FaultLog};
|
||||
use crate::fault_log::{Fault, FaultLog};
|
||||
use crate::{DistAlgorithm, NetworkInfo, NodeIdT, Target};
|
||||
|
||||
/// A threshold signing error.
|
||||
|
@ -52,6 +52,22 @@ pub enum Error {
|
|||
/// A threshold signing result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// A threshold sign message fault
|
||||
#[derive(Clone, Debug, Fail, PartialEq)]
|
||||
pub enum FaultKind {
|
||||
/// `ThresholdSign` (`Coin`) received a signature share from an unverified sender.
|
||||
#[fail(
|
||||
display = "`ThresholdSign` (`Coin`) received a signature share from an unverified sender."
|
||||
)]
|
||||
UnverifiedSignatureShareSender,
|
||||
/// `HoneyBadger` received a signatures share for the random value even though it is disabled.
|
||||
#[fail(
|
||||
display = "`HoneyBadger` received a signatures share for the random value even though it
|
||||
is disabled."
|
||||
)]
|
||||
UnexpectedSignatureShare,
|
||||
}
|
||||
|
||||
/// A threshold signing message, containing a signature share.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Rand)]
|
||||
pub struct Message(pub SignatureShare);
|
||||
|
@ -81,6 +97,7 @@ impl<N: NodeIdT> DistAlgorithm for ThresholdSign<N> {
|
|||
type Output = Signature;
|
||||
type Message = Message;
|
||||
type Error = Error;
|
||||
type FaultKind = FaultKind;
|
||||
|
||||
/// Sends our threshold signature share if not yet sent.
|
||||
fn handle_input<R: Rng>(&mut self, _input: (), _rng: &mut R) -> Result<Step<N>> {
|
||||
|
@ -180,7 +197,7 @@ impl<N: NodeIdT> ThresholdSign<N> {
|
|||
}
|
||||
|
||||
/// Removes all shares that are invalid, and returns faults for their senders.
|
||||
fn remove_invalid_shares(&mut self) -> FaultLog<N> {
|
||||
fn remove_invalid_shares(&mut self) -> FaultLog<N, FaultKind> {
|
||||
let faulty_senders: Vec<N> = self
|
||||
.received_shares
|
||||
.iter()
|
||||
|
|
|
@ -21,6 +21,10 @@ impl<C> Contribution for C where C: Eq + Debug + Hash + Send + Sync {}
|
|||
pub trait NodeIdT: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
|
||||
impl<N> NodeIdT for N where N: Eq + Ord + Clone + Debug + Hash + Send + Sync {}
|
||||
|
||||
/// A distributed algorithm fault.
|
||||
pub trait FaultT: Clone + Debug + Fail + PartialEq {}
|
||||
impl<N> FaultT for N where N: Clone + Debug + Fail + PartialEq {}
|
||||
|
||||
/// Messages.
|
||||
pub trait Message: Debug + Send + Sync {}
|
||||
impl<M> Message for M where M: Debug + Send + Sync {}
|
||||
|
@ -57,19 +61,22 @@ impl<E> EpochT for E where E: Copy + Message + Default + Eq + Ord + Serialize +
|
|||
/// catch it, instead of potentially stalling the algorithm.
|
||||
#[must_use = "The algorithm step result must be used."]
|
||||
#[derive(Debug)]
|
||||
pub struct Step<M, O, N> {
|
||||
pub struct Step<M, O, N, F: Fail> {
|
||||
/// The algorithm's output, after consensus has been reached. This is guaranteed to be the same
|
||||
/// in all nodes.
|
||||
pub output: Vec<O>,
|
||||
/// A list of nodes that are not following consensus, together with information about the
|
||||
/// detected misbehavior.
|
||||
pub fault_log: FaultLog<N>,
|
||||
pub fault_log: FaultLog<N, F>,
|
||||
/// A list of messages that must be sent to other nodes. Each entry contains a message and a
|
||||
/// `Target`.
|
||||
pub messages: Vec<TargetedMessage<M, N>>,
|
||||
}
|
||||
|
||||
impl<M, O, N> Default for Step<M, O, N> {
|
||||
impl<M, O, N, F> Default for Step<M, O, N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Step {
|
||||
output: Vec::default(),
|
||||
|
@ -79,11 +86,14 @@ impl<M, O, N> Default for Step<M, O, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<M, O, N> Step<M, O, N> {
|
||||
impl<M, O, N, F> Step<M, O, N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
/// Creates a new `Step` from the given collections.
|
||||
pub fn new(
|
||||
output: Vec<O>,
|
||||
fault_log: FaultLog<N>,
|
||||
fault_log: FaultLog<N, F>,
|
||||
messages: Vec<TargetedMessage<M, N>>,
|
||||
) -> Self {
|
||||
Step {
|
||||
|
@ -99,27 +109,42 @@ impl<M, O, N> Step<M, O, N> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Converts `self` into a step of another type, given conversion methods for output and
|
||||
/// messages.
|
||||
pub fn map<M2, O2, FO, FM>(self, f_out: FO, f_msg: FM) -> Step<M2, O2, N>
|
||||
/// Converts `self` into a step of another type, given conversion methods for output, faults,
|
||||
/// and messages.
|
||||
pub fn map<M2, O2, F2, FO, FF, FM>(
|
||||
self,
|
||||
f_out: FO,
|
||||
f_fail: FF,
|
||||
f_msg: FM,
|
||||
) -> Step<M2, O2, N, F2>
|
||||
where
|
||||
F2: Fail,
|
||||
FO: Fn(O) -> O2,
|
||||
FF: Fn(F) -> F2,
|
||||
FM: Fn(M) -> M2,
|
||||
{
|
||||
Step {
|
||||
output: self.output.into_iter().map(f_out).collect(),
|
||||
fault_log: self.fault_log,
|
||||
fault_log: self.fault_log.map(f_fail),
|
||||
messages: self.messages.into_iter().map(|tm| tm.map(&f_msg)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends `self` with `other`s messages and fault logs, and returns `other.output`.
|
||||
#[must_use]
|
||||
pub fn extend_with<M2, O2, FM>(&mut self, other: Step<M2, O2, N>, f_msg: FM) -> Vec<O2>
|
||||
pub fn extend_with<M2, O2, F2, FF, FM>(
|
||||
&mut self,
|
||||
other: Step<M2, O2, N, F2>,
|
||||
f_fail: FF,
|
||||
f_msg: FM,
|
||||
) -> Vec<O2>
|
||||
where
|
||||
F2: Fail,
|
||||
FF: Fn(F2) -> F,
|
||||
FM: Fn(M2) -> M,
|
||||
{
|
||||
self.fault_log.extend(other.fault_log);
|
||||
let fails = other.fault_log.map(f_fail);
|
||||
self.fault_log.extend(fails);
|
||||
let msgs = other.messages.into_iter().map(|tm| tm.map(&f_msg));
|
||||
self.messages.extend(msgs);
|
||||
other.output
|
||||
|
@ -144,8 +169,11 @@ impl<M, O, N> Step<M, O, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<M, O, N> From<FaultLog<N>> for Step<M, O, N> {
|
||||
fn from(fault_log: FaultLog<N>) -> Self {
|
||||
impl<M, O, N, F> From<FaultLog<N, F>> for Step<M, O, N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn from(fault_log: FaultLog<N, F>) -> Self {
|
||||
Step {
|
||||
fault_log,
|
||||
..Step::default()
|
||||
|
@ -153,8 +181,11 @@ impl<M, O, N> From<FaultLog<N>> for Step<M, O, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<M, O, N> From<Fault<N>> for Step<M, O, N> {
|
||||
fn from(fault: Fault<N>) -> Self {
|
||||
impl<M, O, N, F> From<Fault<N, F>> for Step<M, O, N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn from(fault: Fault<N, F>) -> Self {
|
||||
Step {
|
||||
fault_log: fault.into(),
|
||||
..Step::default()
|
||||
|
@ -162,7 +193,10 @@ impl<M, O, N> From<Fault<N>> for Step<M, O, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<M, O, N> From<TargetedMessage<M, N>> for Step<M, O, N> {
|
||||
impl<M, O, N, F> From<TargetedMessage<M, N>> for Step<M, O, N, F>
|
||||
where
|
||||
F: Fail,
|
||||
{
|
||||
fn from(msg: TargetedMessage<M, N>) -> Self {
|
||||
Step {
|
||||
messages: once(msg).collect(),
|
||||
|
@ -171,9 +205,10 @@ impl<M, O, N> From<TargetedMessage<M, N>> for Step<M, O, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I, M, O, N> From<I> for Step<M, O, N>
|
||||
impl<I, M, O, N, F> From<I> for Step<M, O, N, F>
|
||||
where
|
||||
I: IntoIterator<Item = TargetedMessage<M, N>>,
|
||||
F: Fail,
|
||||
{
|
||||
fn from(msgs: I) -> Self {
|
||||
Step {
|
||||
|
@ -195,13 +230,18 @@ pub trait Epoched {
|
|||
}
|
||||
|
||||
/// An alias for the type of `Step` returned by `D`'s methods.
|
||||
pub type DaStep<D> =
|
||||
Step<<D as DistAlgorithm>::Message, <D as DistAlgorithm>::Output, <D as DistAlgorithm>::NodeId>;
|
||||
pub type DaStep<D> = Step<
|
||||
<D as DistAlgorithm>::Message,
|
||||
<D as DistAlgorithm>::Output,
|
||||
<D as DistAlgorithm>::NodeId,
|
||||
<D as DistAlgorithm>::FaultKind,
|
||||
>;
|
||||
|
||||
impl<'i, M, O, N> Step<M, O, N>
|
||||
impl<'i, M, O, N, F> Step<M, O, N, F>
|
||||
where
|
||||
N: NodeIdT,
|
||||
M: 'i + Clone + SenderQueueableMessage,
|
||||
F: Fail,
|
||||
{
|
||||
/// Removes and returns any messages that are not yet accepted by remote nodes according to the
|
||||
/// mapping `remote_epochs`. This way the returned messages are postponed until later, and the
|
||||
|
@ -266,6 +306,8 @@ pub trait DistAlgorithm: Send + Sync {
|
|||
type Message: Message;
|
||||
/// The errors that can occur during execution.
|
||||
type Error: Fail;
|
||||
/// The kinds of message faults that can be detected during execution.
|
||||
type FaultKind: FaultT;
|
||||
|
||||
/// Handles an input provided by the user, and returns
|
||||
fn handle_input<R: Rng>(
|
||||
|
|
|
@ -41,7 +41,7 @@ where
|
|||
/// The execution time limit has been reached or exceeded.
|
||||
TimeLimitHit(time::Duration),
|
||||
/// A `Fault` is encountered in a step of a `DistAlgorithm`.
|
||||
Fault(Fault<D::NodeId>),
|
||||
Fault(Fault<D::NodeId, D::FaultKind>),
|
||||
/// An error occurred while generating initial keys for threshold cryptography.
|
||||
InitialKeyGeneration(crypto::error::Error),
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ pub struct Node<D: DistAlgorithm> {
|
|||
/// Captured algorithm outputs, in order.
|
||||
outputs: Vec<D::Output>,
|
||||
/// Collected fault log, in order.
|
||||
faults: Vec<Fault<D::NodeId>>,
|
||||
faults: Vec<Fault<D::NodeId, D::FaultKind>>,
|
||||
}
|
||||
|
||||
impl<D> fmt::Debug for Node<D>
|
||||
|
@ -141,7 +141,7 @@ impl<D: DistAlgorithm> Node<D> {
|
|||
///
|
||||
/// All faults are collected for reference purposes.
|
||||
#[inline]
|
||||
pub fn faults(&self) -> &[Fault<D::NodeId>] {
|
||||
pub fn faults(&self) -> &[Fault<D::NodeId, D::FaultKind>] {
|
||||
self.faults.as_slice()
|
||||
}
|
||||
|
||||
|
@ -934,7 +934,7 @@ where
|
|||
.ok_or_else(|| CrankError::NodeDisappearedInCrank(msg.to.clone())))
|
||||
.is_faulty();
|
||||
|
||||
let step: Step<_, _, _> = if is_faulty {
|
||||
let step: Step<_, _, _, _> = if is_faulty {
|
||||
// The swap-dance is painful here, as we are creating an `opt_step` just to avoid
|
||||
// borrow issues.
|
||||
let mut adv = self.adversary.take();
|
||||
|
|
|
@ -379,7 +379,7 @@ where
|
|||
.expect("failed to reconstruct the pivot node");
|
||||
let (sq, mut sq_step) = SenderQueue::builder(dhb, peer_ids.into_iter()).build(id);
|
||||
*node.algorithm_mut() = sq;
|
||||
sq_step.extend(dhb_step.map(|output| output, Message::from));
|
||||
sq_step.extend(dhb_step.map(|output| output, |fault| fault, Message::from));
|
||||
net.insert_node(node);
|
||||
sq_step
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ pub struct TestNode<D: DistAlgorithm> {
|
|||
/// Outgoing messages to be sent to other nodes.
|
||||
messages: Vec<TargetedMessage<D::Message, D::NodeId>>,
|
||||
/// Collected fault logs.
|
||||
faults: Vec<Fault<D::NodeId>>,
|
||||
faults: Vec<Fault<D::NodeId, D::FaultKind>>,
|
||||
}
|
||||
|
||||
impl<D: DistAlgorithm> TestNode<D> {
|
||||
|
@ -594,7 +594,7 @@ where
|
|||
}
|
||||
|
||||
/// Verifies that no correct node is reported as faulty.
|
||||
fn check_faults<I: IntoIterator<Item = Fault<D::NodeId>>>(&self, faults: I) {
|
||||
fn check_faults<I: IntoIterator<Item = Fault<D::NodeId, D::FaultKind>>>(&self, faults: I) {
|
||||
for fault in faults {
|
||||
if self.nodes.contains_key(&fault.node_id) {
|
||||
panic!("Unexpected fault: {:?}", fault);
|
||||
|
|
|
@ -169,7 +169,7 @@ where
|
|||
.expect("failed to rebuild the node with a join plan");
|
||||
let (sq, mut sq_step) = SenderQueue::builder(qhb, peer_ids.into_iter()).build(our_id);
|
||||
*node.instance_mut() = sq;
|
||||
sq_step.extend(qhb_step.map(|output| output, Message::from));
|
||||
sq_step.extend(qhb_step.map(|output| output, |fault| fault, Message::from));
|
||||
network.nodes.insert(our_id, node);
|
||||
sq_step
|
||||
}
|
||||
|
@ -193,7 +193,8 @@ fn new_queueing_hb(
|
|||
.build(&mut rng)
|
||||
.expect("failed to build QueueingHoneyBadger");
|
||||
let (sq, mut step) = SenderQueue::builder(qhb, peer_ids).build(our_id);
|
||||
assert!(step.extend_with(qhb_step, Message::from).is_empty());
|
||||
let output = step.extend_with(qhb_step, |fault| fault, Message::from);
|
||||
assert!(output.is_empty());
|
||||
(sq, step)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue