Replace `chain_error` with `failure`

Changes:

* Remove `error_chain` and convert errors to `failure` types.
* Add variants for each possible error generation point.
This commit is contained in:
c0gent 2018-07-25 14:38:33 -07:00
parent 649353b999
commit 847a79793e
No known key found for this signature in database
GPG Key ID: 9CC25E71A743E892
15 changed files with 448 additions and 157 deletions

View File

@ -20,7 +20,7 @@ travis-ci = { repository = "poanetwork/hbbft" }
bincode = "1.0.0"
byteorder = "1.2.3"
env_logger = "0.5.10"
error-chain = "0.11.0"
failure = "0.1"
init_with = "1.1.0"
itertools = "0.7"
log = "0.4.1"

View File

@ -7,7 +7,7 @@ use std::io;
use std::net::TcpStream;
use hbbft::messaging::SourcedMessage;
use hbbft::proto_io::{self, ProtoIo};
use hbbft::proto_io::{ErrorKind, ProtoIo};
use protobuf::Message;
#[derive(Debug)]
@ -85,13 +85,12 @@ impl<'a, P: Message + 'a, M: Into<P> + From<P> + Send + 'a> CommsTask<'a, P, M>
message: message.into(),
}).unwrap();
}
Err(proto_io::Error(proto_io::ErrorKind::Protobuf(e), _)) => {
warn!("Node {} - Protobuf error {}", node_index, e)
}
Err(e) => {
warn!("Node {} - Critical error {:?}", node_index, e);
break;
}
Err(err) => match err.kind() {
ErrorKind::Protobuf(pe) => {
warn!("Node {} - Protobuf error {}", node_index, pe)
}
_ => warn!("Node {} - Critical error {:?}", node_index, err),
},
}
}
});

View File

@ -77,21 +77,22 @@ use common_coin::{self, CommonCoin, CommonCoinMessage};
use fault_log::{Fault, FaultKind};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
error_chain!{
links {
CommonCoin(common_coin::Error, common_coin::ErrorKind);
}
errors {
UnknownProposer {
description("unknown proposer")
}
InputNotAccepted {
description("input not accepted")
}
}
/// An agreement error.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum Error {
#[fail(display = "HandleCoinCommonCoin error: {}", _0)]
HandleCoinCommonCoin(common_coin::Error),
#[fail(display = "TryFinishConfRoundCommonCoin error: {}", _0)]
TryFinishConfRoundCommonCoin(common_coin::Error),
#[fail(display = "Unknown proposer")]
UnknownProposer,
#[fail(display = "Input not accepted")]
InputNotAccepted,
}
/// An agreement result.
pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum AgreementContent {
/// `BVal` message.
@ -267,7 +268,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
proposer_id: NodeUid,
) -> Result<Self> {
if !netinfo.is_node_validator(&proposer_id) {
return Err(ErrorKind::UnknownProposer.into());
return Err(Error::UnknownProposer);
}
Ok(Agreement {
netinfo,
@ -291,7 +292,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
/// Sets the input value for agreement.
fn set_input(&mut self, input: bool) -> Result<Step<NodeUid>> {
if self.epoch != 0 || self.estimated.is_some() {
return Err(ErrorKind::InputNotAccepted.into());
return Err(Error::InputNotAccepted);
}
// Set the initial estimated value to the input value.
self.estimated = Some(input);
@ -411,9 +412,9 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
) -> Result<Step<NodeUid>> {
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.handle_message(sender_id, msg)?
}
CoinState::InProgress(ref mut common_coin) => common_coin
.handle_message(sender_id, msg)
.map_err(Error::HandleCoinCommonCoin)?,
};
self.on_coin_step(coin_step)
}
@ -571,7 +572,9 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
// Invoke the common coin.
let coin_step = match self.coin_state {
CoinState::Decided(_) => return Ok(Step::default()), // Coin has already decided.
CoinState::InProgress(ref mut common_coin) => common_coin.input(())?,
CoinState::InProgress(ref mut common_coin) => common_coin
.input(())
.map_err(Error::TryFinishConfRoundCommonCoin)?,
};
let mut step = self.on_coin_step(coin_step)?;
step.extend(self.try_update_epoch()?);

View File

@ -164,21 +164,37 @@ use fault_log::{Fault, FaultKind};
use fmt::{HexBytes, HexList, HexProof};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
error_chain!{
foreign_links {
ReedSolomon(rse::Error);
}
errors {
InstanceCannotPropose
NotImplemented
ProofConstructionFailed
RootHashMismatch
Threading
UnknownSender
}
/// A broadcast error.
#[derive(Clone, PartialEq, Debug, Fail)]
pub enum Error {
#[fail(display = "CodingNewReedSolomon error: {}", _0)]
CodingNewReedSolomon(#[cause] rse::Error),
#[fail(display = "CodingEncodeReedSolomon error: {}", _0)]
CodingEncodeReedSolomon(#[cause] rse::Error),
#[fail(display = "CodingReconstructShardsReedSolomon error: {}", _0)]
CodingReconstructShardsReedSolomon(#[cause] rse::Error),
#[fail(
display = "CodingReconstructShardsTrivialReedSolomon error: {}",
_0
)]
CodingReconstructShardsTrivialReedSolomon(#[cause] rse::Error),
#[fail(display = "Instance cannot propose")]
InstanceCannotPropose,
#[fail(display = "Not implemented")]
NotImplemented,
#[fail(display = "Proof construction failed")]
ProofConstructionFailed,
#[fail(display = "Root hash mismatch")]
RootHashMismatch,
#[fail(display = "Threading")]
Threading,
#[fail(display = "Unknown sender")]
UnknownSender,
}
/// A broadcast result.
pub type Result<T> = ::std::result::Result<T, Error>;
/// The three kinds of message sent during the reliable broadcast stage of the
/// consensus algorithm.
#[derive(Serialize, Deserialize, Clone, PartialEq)]
@ -255,7 +271,7 @@ impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
fn input(&mut self, input: Self::Input) -> Result<Step<NodeUid>> {
if *self.netinfo.our_uid() != self.proposer_id {
return Err(ErrorKind::InstanceCannotPropose.into());
return Err(Error::InstanceCannotPropose);
}
// Split the value into chunks/shards, encode them with erasure codes.
// Assemble a Merkle tree from data and parity shards. Take all proofs
@ -272,7 +288,7 @@ impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
message: Self::Message,
) -> Result<Step<NodeUid>> {
if !self.netinfo.is_node_validator(sender_id) {
return Err(ErrorKind::UnknownSender.into());
return Err(Error::UnknownSender);
}
match message {
BroadcastMessage::Value(p) => self.handle_value(sender_id, p),
@ -368,7 +384,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
let mtree = MerkleTree::from_vec(&digest::SHA256, shards_t);
// Default result in case of `gen_proof` error.
let mut result = Err(ErrorKind::ProofConstructionFailed.into());
let mut result = Err(Error::ProofConstructionFailed);
assert_eq!(self.netinfo.num_nodes(), mtree.iter().count());
let mut step = Step::default();
@ -376,7 +392,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
for (leaf_value, uid) in mtree.iter().zip(self.netinfo.all_uids()) {
let proof = mtree
.gen_proof(leaf_value.to_vec())
.ok_or(ErrorKind::ProofConstructionFailed)?;
.ok_or(Error::ProofConstructionFailed)?;
if *uid == *self.netinfo.our_uid() {
// The proof is addressed to this node.
result = Ok(proof);
@ -591,7 +607,8 @@ impl Coding {
/// Creates a new `Coding` instance with the given number of shards.
fn new(data_shard_num: usize, parity_shard_num: usize) -> Result<Self> {
Ok(if parity_shard_num > 0 {
let rs = ReedSolomon::new(data_shard_num, parity_shard_num)?;
let rs = ReedSolomon::new(data_shard_num, parity_shard_num)
.map_err(Error::CodingNewReedSolomon)?;
Coding::ReedSolomon(Box::new(rs))
} else {
Coding::Trivial(data_shard_num)
@ -617,7 +634,9 @@ impl Coding {
/// Constructs (and overwrites) the parity shards.
fn encode(&self, slices: &mut [&mut [u8]]) -> Result<()> {
match *self {
Coding::ReedSolomon(ref rs) => rs.encode(slices)?,
Coding::ReedSolomon(ref rs) => {
rs.encode(slices).map_err(Error::CodingEncodeReedSolomon)?
}
Coding::Trivial(_) => (),
}
Ok(())
@ -626,10 +645,14 @@ impl Coding {
/// If enough shards are present, reconstructs the missing ones.
fn reconstruct_shards(&self, shards: &mut [Option<Box<[u8]>>]) -> Result<()> {
match *self {
Coding::ReedSolomon(ref rs) => rs.reconstruct_shards(shards)?,
Coding::ReedSolomon(ref rs) => rs
.reconstruct_shards(shards)
.map_err(Error::CodingReconstructShardsReedSolomon)?,
Coding::Trivial(_) => {
if shards.iter().any(Option::is_none) {
return Err(rse::Error::TooFewShardsPresent.into());
return Err(Error::CodingReconstructShardsTrivialReedSolomon(
rse::Error::TooFewShardsPresent,
));
}
}
}
@ -645,7 +668,7 @@ fn decode_from_shards(
) -> Option<Vec<u8>> {
// Try to interpolate the Merkle tree using the Reed-Solomon erasure coding scheme.
if let Err(err) = coding.reconstruct_shards(leaf_values) {
debug!("Shard reconstruction failed: {:?}", err); // Faulty proposer
error!("Shard reconstruction failed: {:?}", err); // Faulty proposer
return None;
}

View File

@ -30,21 +30,20 @@ use crypto::{Signature, SignatureShare};
use fault_log::{Fault, FaultKind};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
error_chain! {
links {
Crypto(cerror::Error, cerror::ErrorKind);
}
errors {
UnknownSender {
description("unknown sender")
}
VerificationFailed {
description("signature verification failed")
}
}
/// A common coin error.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum Error {
#[fail(display = "CombineAndVerifySigCrypto error: {}", _0)]
CombineAndVerifySigCrypto(cerror::Error),
#[fail(display = "Unknown sender")]
UnknownSender,
#[fail(display = "Signature verification failed")]
VerificationFailed,
}
/// A common coin result.
pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Rand)]
pub struct CommonCoinMessage(SignatureShare);
@ -160,7 +159,7 @@ where
}
self.received_shares.insert(sender_id.clone(), share);
} else {
return Err(ErrorKind::UnknownSender.into());
return Err(Error::UnknownSender);
}
self.try_output()
}
@ -189,7 +188,11 @@ where
// Pass the indices of sender nodes to `combine_signatures`.
let to_idx = |(id, share)| (self.netinfo.node_index(id).unwrap(), share);
let shares = self.received_shares.iter().map(to_idx);
let sig = self.netinfo.public_key_set().combine_signatures(shares)?;
let sig = self
.netinfo
.public_key_set()
.combine_signatures(shares)
.map_err(Error::CombineAndVerifySigCrypto)?;
if !self
.netinfo
.public_key_set()
@ -201,7 +204,7 @@ where
"{:?} main public key verification failed",
self.netinfo.our_uid()
);
Err(ErrorKind::VerificationFailed.into())
Err(Error::VerificationFailed)
} else {
Ok(sig)
}

View File

@ -34,19 +34,30 @@ use fmt::HexBytes;
use messaging::{self, DistAlgorithm, NetworkInfo};
use rand::Rand;
error_chain!{
links {
Agreement(agreement::Error, agreement::ErrorKind);
Broadcast(broadcast::Error, broadcast::ErrorKind);
}
errors {
MultipleAgreementResults
NoSuchAgreementInstance
NoSuchBroadcastInstance
}
/// A common subset error.
#[derive(Clone, PartialEq, Debug, Fail)]
pub enum Error {
#[fail(display = "NewAgreement error: {}", _0)]
NewAgreement(agreement::Error),
#[fail(display = "ProcessAgreementAgreement0 error: {}", _0)]
ProcessAgreementAgreement0(agreement::Error),
#[fail(display = "ProcessAgreementAgreement1 error: {}", _0)]
ProcessAgreementAgreement1(agreement::Error),
#[fail(display = "NewBroadcast error: {}", _0)]
NewBroadcast(broadcast::Error),
#[fail(display = "ProcessBroadcastBroadcast error: {}", _0)]
ProcessBroadcastBroadcast(broadcast::Error),
#[fail(display = "Multiple agreement results")]
MultipleAgreementResults,
#[fail(display = "No such agreement instance")]
NoSuchAgreementInstance,
#[fail(display = "No such broadcast instance")]
NoSuchBroadcastInstance,
}
/// A common subset result.
pub type Result<T> = ::std::result::Result<T, Error>;
// TODO: Make this a generic argument of `CommonSubset`.
type ProposedValue = Vec<u8>;
@ -118,7 +129,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
for proposer_id in netinfo.all_uids() {
broadcast_instances.insert(
proposer_id.clone(),
Broadcast::new(netinfo.clone(), proposer_id.clone())?,
Broadcast::new(netinfo.clone(), proposer_id.clone()).map_err(Error::NewBroadcast)?,
);
}
@ -127,7 +138,8 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
for proposer_id in netinfo.all_uids() {
agreement_instances.insert(
proposer_id.clone(),
Agreement::new(netinfo.clone(), session_id, proposer_id.clone())?,
Agreement::new(netinfo.clone(), session_id, proposer_id.clone())
.map_err(Error::NewAgreement)?,
);
}
@ -189,9 +201,12 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
let broadcast = self
.broadcast_instances
.get_mut(proposer_id)
.ok_or(ErrorKind::NoSuchBroadcastInstance)?;
.ok_or(Error::NoSuchBroadcastInstance)?;
let to_msg = |b_msg| Message::Broadcast(proposer_id.clone(), b_msg);
let output = step.extend_with(f(broadcast)?, to_msg);
let output = step.extend_with(
f(broadcast).map_err(Error::ProcessBroadcastBroadcast)?,
to_msg,
);
if let Some(output) = output.into_iter().next() {
output
} else {
@ -222,12 +237,15 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
let agreement = self
.agreement_instances
.get_mut(proposer_id)
.ok_or(ErrorKind::NoSuchAgreementInstance)?;
.ok_or(Error::NoSuchAgreementInstance)?;
if agreement.terminated() {
return Ok(step);
}
let to_msg = |a_msg| Message::Agreement(proposer_id.clone(), a_msg);
let output = step.extend_with(f(agreement)?, to_msg);
let output = step.extend_with(
f(agreement).map_err(Error::ProcessAgreementAgreement0)?,
to_msg,
);
if let Some(output) = output.into_iter().next() {
output
} else {
@ -239,7 +257,7 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
.insert(proposer_id.clone(), value)
.is_some()
{
return Err(ErrorKind::MultipleAgreementResults.into());
return Err(Error::MultipleAgreementResults);
}
debug!(
"{:?} Updated Agreement results: {:?}",
@ -253,9 +271,14 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
for (uid, agreement) in &mut self.agreement_instances {
if agreement.accepts_input() {
let to_msg = |a_msg| Message::Agreement(uid.clone(), a_msg);
for output in step.extend_with(agreement.input(false)?, to_msg) {
for output in step.extend_with(
agreement
.input(false)
.map_err(Error::ProcessAgreementAgreement1)?,
to_msg,
) {
if self.agreement_results.insert(uid.clone(), output).is_some() {
return Err(ErrorKind::MultipleAgreementResults.into());
return Err(Error::MultipleAgreementResults);
}
}
}

View File

@ -1,10 +1,13 @@
error_chain! {
errors {
NotEnoughShares {
description("not enough signature shares")
}
DuplicateEntry {
description("signature shares contain a duplicated index")
}
}
//! Crypto errors.
/// A crypto error.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum Error {
#[fail(display = "Not enough signature shares")]
NotEnoughShares,
#[fail(display = "Signature shares contain a duplicated index")]
DuplicateEntry,
}
/// A crypto result.
pub type Result<T> = ::std::result::Result<T, Error>;

View File

@ -20,7 +20,7 @@ use pairing::{CurveAffine, CurveProjective, Engine, Field};
use rand::{ChaChaRng, OsRng, Rng, SeedableRng};
use ring::digest;
use self::error::{ErrorKind, Result};
use self::error::{Error, Result};
use self::into_fr::IntoFr;
use self::poly::{Commitment, Poly};
use fmt::HexBytes;
@ -459,13 +459,13 @@ where
.map(|(i, sample)| (into_fr_plus_1(i), sample))
.collect();
if samples.len() < t {
return Err(ErrorKind::NotEnoughShares.into());
return Err(Error::NotEnoughShares);
}
let mut result = C::zero();
let mut indexes = Vec::new();
for (x, sample) in samples.iter().take(t) {
if indexes.contains(x) {
return Err(ErrorKind::DuplicateEntry.into());
return Err(Error::DuplicateEntry);
}
indexes.push(x.clone());
// Compute the value at 0 of the Lagrange polynomial that is `0` at the other data

View File

@ -1,17 +1,70 @@
use bincode;
use failure::{Backtrace, Context, Fail};
use honey_badger;
use std::fmt::{self, Display};
error_chain!{
links {
HoneyBadger(honey_badger::Error, honey_badger::ErrorKind);
/// Dynamic honey badger error variants.
#[derive(Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "SendTransactionBincode error: {}", _0)]
SendTransactionBincode(bincode::ErrorKind),
#[fail(display = "VerifySignatureBincode error: {}", _0)]
VerifySignatureBincode(bincode::ErrorKind),
#[fail(display = "SignVoteForBincode error: {}", _0)]
SignVoteForBincode(bincode::ErrorKind),
#[fail(display = "ValidateBincode error: {}", _0)]
ValidateBincode(bincode::ErrorKind),
#[fail(display = "ProposeHoneyBadger error: {}", _0)]
ProposeHoneyBadger(honey_badger::Error),
#[fail(
display = "HandleHoneyBadgerMessageHoneyBadger error: {}",
_0
)]
HandleHoneyBadgerMessageHoneyBadger(honey_badger::Error),
#[fail(display = "Unknown sender")]
UnknownSender,
}
/// A dynamic honey badger error.
#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}
impl Fail for Error {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}
foreign_links {
Bincode(Box<bincode::ErrorKind>);
}
errors {
UnknownSender
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
self.inner.get_context()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
inner: Context::new(kind),
}
}
}
impl From<Context<ErrorKind>> for Error {
fn from(inner: Context<ErrorKind>) -> Error {
Error { inner }
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}
pub type Result<T> = ::std::result::Result<T, Error>;

View File

@ -192,11 +192,14 @@ where
/// Proposes a contribution in the current epoch.
pub fn propose(&mut self, contrib: C) -> Result<Step<C, NodeUid>> {
let step = self.honey_badger.input(InternalContrib {
contrib,
key_gen_messages: self.key_gen_msg_buffer.clone(),
votes: self.vote_counter.pending_votes().cloned().collect(),
})?;
let step = self
.honey_badger
.input(InternalContrib {
contrib,
key_gen_messages: self.key_gen_msg_buffer.clone(),
votes: self.vote_counter.pending_votes().cloned().collect(),
})
.map_err(ErrorKind::ProposeHoneyBadger)?;
self.process_output(step)
}
@ -226,7 +229,10 @@ where
return Err(ErrorKind::UnknownSender.into());
}
// Handle the message.
let step = self.honey_badger.handle_message(sender_id, message)?;
let step = self
.honey_badger
.handle_message(sender_id, message)
.map_err(ErrorKind::HandleHoneyBadgerMessageHoneyBadger)?;
self.process_output(step)
}
@ -375,7 +381,8 @@ where
/// Signs and sends a `KeyGenMessage` and also tries to commit it.
fn send_transaction(&mut self, kg_msg: KeyGenMessage) -> Result<Step<C, NodeUid>> {
let ser = bincode::serialize(&kg_msg)?;
let ser =
bincode::serialize(&kg_msg).map_err(|err| ErrorKind::SendTransactionBincode(*err))?;
let sig = Box::new(self.netinfo.secret_key().sign(ser));
if self.netinfo.is_validator() {
let our_uid = self.netinfo.our_uid().clone();
@ -412,7 +419,8 @@ where
sig: &Signature,
kg_msg: &KeyGenMessage,
) -> Result<bool> {
let ser = bincode::serialize(kg_msg)?;
let ser =
bincode::serialize(kg_msg).map_err(|err| ErrorKind::VerifySignatureBincode(*err))?;
let pk_opt = (self.netinfo.public_key(node_id)).or_else(|| {
self.key_gen
.iter()

View File

@ -6,7 +6,7 @@ use std::sync::Arc;
use bincode;
use serde::{Deserialize, Serialize};
use super::{Change, Result};
use super::{Change, ErrorKind, Result};
use crypto::Signature;
use fault_log::{FaultKind, FaultLog};
use messaging::NetworkInfo;
@ -50,7 +50,8 @@ where
era: self.era,
num: self.pending.get(&voter).map_or(0, |sv| sv.vote.num + 1),
};
let ser_vote = bincode::serialize(&vote)?;
let ser_vote =
bincode::serialize(&vote).map_err(|err| ErrorKind::SignVoteForBincode(*err))?;
let signed_vote = SignedVote {
vote,
voter: voter.clone(),
@ -149,7 +150,8 @@ where
/// Returns `true` if the signature is valid.
fn validate(&self, signed_vote: &SignedVote<NodeUid>) -> Result<bool> {
let ser_vote = bincode::serialize(&signed_vote.vote)?;
let ser_vote =
bincode::serialize(&signed_vote.vote).map_err(|err| ErrorKind::ValidateBincode(*err))?;
let pk_opt = self.netinfo.public_key(&signed_vote.voter);
Ok(pk_opt.map_or(false, |pk| pk.verify(&signed_vote.sig, ser_vote)))
}

View File

@ -25,13 +25,14 @@
use rand::Rand;
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::fmt::{self, Debug, Display};
use std::hash::Hash;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use bincode;
use failure::{Backtrace, Context, Fail};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
@ -40,20 +41,67 @@ use crypto::{Ciphertext, DecryptionShare};
use fault_log::{Fault, FaultKind, FaultLog};
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
error_chain!{
links {
CommonSubset(common_subset::Error, common_subset::ErrorKind);
/// Honey badger error variants.
#[derive(Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "ProposeBincode error: {}", _0)]
ProposeBincode(bincode::ErrorKind),
#[fail(display = "ProposeCommonSubset0 error: {}", _0)]
ProposeCommonSubset0(common_subset::Error),
#[fail(display = "ProposeCommonSubset1 error: {}", _0)]
ProposeCommonSubset1(common_subset::Error),
#[fail(display = "HandleCommonMessageCommonSubset0 error: {}", _0)]
HandleCommonMessageCommonSubset0(common_subset::Error),
#[fail(display = "HandleCommonMessageCommonSubset1 error: {}", _0)]
HandleCommonMessageCommonSubset1(common_subset::Error),
#[fail(display = "Unknown sender")]
UnknownSender,
}
/// A honey badger error.
#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}
impl Fail for Error {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}
foreign_links {
Bincode(Box<bincode::ErrorKind>);
}
errors {
UnknownSender
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
self.inner.get_context()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
inner: Context::new(kind),
}
}
}
impl From<Context<ErrorKind>> for Error {
fn from(inner: Context<ErrorKind>) -> Error {
Error { inner }
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}
pub type Result<T> = ::std::result::Result<T, Error>;
/// A Honey Badger builder, to configure the parameters and create new instances of `HoneyBadger`.
pub struct HoneyBadgerBuilder<C, NodeUid> {
/// Shared network data.
@ -195,14 +243,17 @@ where
let cs_step = {
let cs = match self.common_subsets.entry(epoch) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
entry.insert(CommonSubset::new(self.netinfo.clone(), epoch)?)
}
Entry::Vacant(entry) => entry.insert(
CommonSubset::new(self.netinfo.clone(), epoch)
.map_err(ErrorKind::ProposeCommonSubset0)?,
),
};
let ser_prop = bincode::serialize(&proposal)?;
let ser_prop =
bincode::serialize(&proposal).map_err(|err| ErrorKind::ProposeBincode(*err))?;
let ciphertext = self.netinfo.public_key_set().public_key().encrypt(ser_prop);
self.has_input = true;
cs.input(bincode::serialize(&ciphertext).unwrap())?
cs.input(bincode::serialize(&ciphertext).unwrap())
.map_err(ErrorKind::ProposeCommonSubset1)?
};
self.process_output(cs_step, epoch)
}
@ -245,11 +296,15 @@ where
// Epoch has already terminated. Message is obsolete.
return Ok(Step::default());
} else {
entry.insert(CommonSubset::new(self.netinfo.clone(), epoch)?)
entry.insert(
CommonSubset::new(self.netinfo.clone(), epoch)
.map_err(ErrorKind::HandleCommonMessageCommonSubset0)?,
)
}
}
};
cs.handle_message(sender_id, message)?
cs.handle_message(sender_id, message)
.map_err(ErrorKind::HandleCommonMessageCommonSubset1)?
};
let step = self.process_output(cs_step, epoch)?;
self.remove_terminated(epoch);

View File

@ -107,7 +107,7 @@
extern crate bincode;
extern crate byteorder;
#[macro_use]
extern crate error_chain;
extern crate failure;
extern crate init_with;
#[macro_use]
extern crate log;

View File

@ -1,10 +1,14 @@
//! Protobuf message IO task structure.
use failure::{Backtrace, Context, Fail};
use protobuf::{self, Message, ProtobufError};
use std::io::{Read, Write};
use std::io::{self, Read, Write};
use std::marker::PhantomData;
use std::net::TcpStream;
use std::{cmp, io};
use std::{
cmp,
fmt::{self, Display},
};
/// A magic key to put right before each message. An atavism of primitive serial
/// protocols.
@ -12,23 +16,77 @@ use std::{cmp, io};
/// TODO: Replace it with a proper handshake at connection initiation.
const FRAME_START: u32 = 0x2C0F_FEE5;
error_chain!{
types {
Error, ErrorKind, ResultExt, ProtoIoResult;
/// IO/Messaging error variants.
#[derive(Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "Io error: {}", _0)]
Io(#[cause] io::Error),
#[fail(display = "Protobuf error: {}", _0)]
Protobuf(#[cause] ProtobufError),
#[fail(display = "Decode error")]
Decode,
#[fail(display = "Encode error")]
Encode,
#[fail(display = "Frame start mismatch error")]
FrameStartMismatch,
}
/// An IO/Messaging error.
#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}
impl Fail for Error {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}
foreign_links {
Io(io::Error);
Protobuf(ProtobufError);
}
errors {
Decode
Encode
FrameStartMismatch
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
self.inner.get_context()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
inner: Context::new(kind),
}
}
}
impl From<Context<ErrorKind>> for Error {
fn from(inner: Context<ErrorKind>) -> Error {
Error { inner }
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
ErrorKind::Io(err).into()
}
}
impl From<ProtobufError> for Error {
fn from(err: ProtobufError) -> Error {
ErrorKind::Protobuf(err).into()
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}
pub type ProtoIoResult<T> = ::std::result::Result<T, Error>;
fn encode_u32_to_be(value: u32, buffer: &mut [u8]) -> ProtoIoResult<()> {
if buffer.len() < 4 {
return Err(ErrorKind::Encode.into());

View File

@ -22,9 +22,11 @@
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};
use rand::Rand;
use serde::{Deserialize, Serialize};
@ -34,12 +36,61 @@ use transaction_queue::TransactionQueue;
pub use dynamic_honey_badger::{Change, ChangeState, Input};
error_chain!{
links {
DynamicHoneyBadger(dynamic_honey_badger::Error, dynamic_honey_badger::ErrorKind);
/// Queueing honey badger error variants.
#[derive(Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "Input error: {}", _0)]
Input(dynamic_honey_badger::Error),
#[fail(display = "Handle message error: {}", _0)]
HandleMessage(dynamic_honey_badger::Error),
#[fail(display = "Propose error: {}", _0)]
Propose(dynamic_honey_badger::Error),
}
/// A queueing honey badger error.
#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}
impl Fail for Error {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
self.inner.get_context()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
inner: Context::new(kind),
}
}
}
impl From<Context<ErrorKind>> for Error {
fn from(inner: Context<ErrorKind>) -> Error {
Error { inner }
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}
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> {
@ -141,7 +192,11 @@ where
self.queue.0.push_back(tx);
Ok(Step::default())
}
Input::Change(change) => Ok(self.dyn_hb.input(Input::Change(change))?.convert()),
Input::Change(change) => Ok(self
.dyn_hb
.input(Input::Change(change))
.map_err(ErrorKind::Input)?
.convert()),
}
}
@ -152,7 +207,8 @@ where
) -> Result<Step<Tx, NodeUid>> {
let mut step = self
.dyn_hb
.handle_message(sender_id, message)?
.handle_message(sender_id, message)
.map_err(ErrorKind::HandleMessage)?
.convert::<Self>();
for batch in &step.output {
self.queue.remove_all(batch.iter());
@ -195,7 +251,12 @@ where
let mut step = Step::default();
while !self.dyn_hb.has_input() {
let proposal = self.queue.choose(amount, self.batch_size);
step.extend(self.dyn_hb.input(Input::User(proposal))?.convert());
step.extend(
self.dyn_hb
.input(Input::User(proposal))
.map_err(ErrorKind::Propose)?
.convert(),
);
}
Ok(step)
}