mirror of https://github.com/poanetwork/hbbft.git
Extend the documentation, simplify errors.
This changes and adds several doc comments, adds the `missing_docs` lint and simplifies some of the error types.
This commit is contained in:
parent
ae37879239
commit
b2071fe2be
|
@ -98,7 +98,7 @@ impl ReceivedMessages {
|
|||
}
|
||||
MessageContent::Coin(msg) => {
|
||||
if self.coin.is_none() {
|
||||
self.coin = Some(msg.to_sig().clone());
|
||||
self.coin = Some(msg.0);
|
||||
} else {
|
||||
return Some(FaultKind::AgreementEpoch);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ impl ReceivedMessages {
|
|||
messages.push(MessageContent::Term(b));
|
||||
}
|
||||
if let Some(ss) = coin {
|
||||
messages.push(MessageContent::Coin(Box::new(TsMessage::new(ss))));
|
||||
messages.push(MessageContent::Coin(Box::new(TsMessage(ss))));
|
||||
}
|
||||
messages
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! A single-byte representation of a set of boolean values.
|
||||
|
||||
use rand_derive::Rand;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -83,28 +83,31 @@ pub use self::sbv_broadcast::Message as SbvMessage;
|
|||
/// An Binary Agreement error.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
#[fail(display = "Error handling threshold sign message: {}", _0)]
|
||||
/// Error handling a `ThresholdSign` message.
|
||||
#[fail(display = "Error handling ThresholdSign message: {}", _0)]
|
||||
HandleThresholdSign(threshold_sign::Error),
|
||||
/// Error invoking the common coin.
|
||||
#[fail(display = "Error invoking the common coin: {}", _0)]
|
||||
InvokeCoin(threshold_sign::Error),
|
||||
// Strings because `io` and `bincode` errors lack `Eq` and `Clone`.
|
||||
#[fail(display = "Error writing epoch for nonce: {}", _0)]
|
||||
Io(String),
|
||||
#[fail(display = "Error serializing session ID for nonce: {}", _0)]
|
||||
// String because `io` and `bincode` errors lack `Eq` and `Clone`.
|
||||
/// Error serializing the session ID for the common coin.
|
||||
#[fail(display = "Error serializing session ID for coin: {}", _0)]
|
||||
Serialize(String),
|
||||
}
|
||||
|
||||
impl From<bincode::Error> for Error {
|
||||
fn from(err: bincode::Error) -> Error {
|
||||
Error::Io(format!("{:?}", err))
|
||||
Error::Serialize(format!("{:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
/// An Binary Agreement result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// A `BinaryAgreement` step, containing at most one output.
|
||||
pub type Step<N> = ::Step<Message, bool, N>;
|
||||
|
||||
/// The content of a message belonging to a particular `BinaryAgreement` epoch.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
pub enum MessageContent {
|
||||
/// Synchronized Binary Value Broadcast message.
|
||||
|
@ -138,7 +141,9 @@ impl MessageContent {
|
|||
/// Messages sent during the Binary Agreement stage.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Rand)]
|
||||
pub struct Message {
|
||||
/// The `BinaryAgreement` epoch this message belongs to.
|
||||
pub epoch: u64,
|
||||
/// The message content for the `epoch`.
|
||||
pub content: MessageContent,
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,13 @@ use {NetworkInfo, NodeIdT, Target};
|
|||
|
||||
pub type Step<N> = ::Step<Message, BoolSet, N>;
|
||||
|
||||
/// A message belonging to the Synchronized Binary Value Broadcast phase of a `BinaryAgreement`
|
||||
/// epoch.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||
pub enum Message {
|
||||
/// Contains the sender's estimate for the current epoch.
|
||||
BVal(bool),
|
||||
/// A confirmation that the sender has received _2 f + 1_ `BVal`s with the same value.
|
||||
Aux(bool),
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ pub struct Broadcast<N> {
|
|||
readys: BTreeMap<N, Vec<u8>>,
|
||||
}
|
||||
|
||||
/// A `Broadcast` step, containing at most one output.
|
||||
pub type Step<N> = ::DaStep<Broadcast<N>>;
|
||||
|
||||
impl<N: NodeIdT> DistAlgorithm for Broadcast<N> {
|
||||
|
|
|
@ -4,29 +4,32 @@ use reed_solomon_erasure as rse;
|
|||
/// A broadcast error.
|
||||
#[derive(Clone, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
/// Failed to create a `ReedSolomon` instance.
|
||||
#[fail(display = "CodingNewReedSolomon error: {}", _0)]
|
||||
CodingNewReedSolomon(#[cause] rse::Error),
|
||||
/// Failed to encode the value.
|
||||
#[fail(display = "CodingEncodeReedSolomon error: {}", _0)]
|
||||
CodingEncodeReedSolomon(#[cause] rse::Error),
|
||||
/// Failed to reconstruct the value.
|
||||
#[fail(display = "CodingReconstructShardsReedSolomon error: {}", _0)]
|
||||
CodingReconstructShardsReedSolomon(#[cause] rse::Error),
|
||||
/// Failed to reconstruct the value.
|
||||
// TODO: This should be unreachable.
|
||||
#[fail(
|
||||
display = "CodingReconstructShardsTrivialReedSolomon error: {}",
|
||||
_0
|
||||
)]
|
||||
CodingReconstructShardsTrivialReedSolomon(#[cause] rse::Error),
|
||||
/// Observers cannot propose a value.
|
||||
#[fail(display = "Instance cannot propose")]
|
||||
InstanceCannotPropose,
|
||||
/// Multiple inputs received. Only a single value can be proposed.
|
||||
#[fail(display = "Multiple inputs received")]
|
||||
MultipleInputs,
|
||||
#[fail(display = "Not implemented")]
|
||||
NotImplemented,
|
||||
/// Failed to construct a Merkle tree proof.
|
||||
#[fail(display = "Proof construction failed")]
|
||||
ProofConstructionFailed,
|
||||
#[fail(display = "Root hash mismatch")]
|
||||
RootHashMismatch,
|
||||
#[fail(display = "Threading")]
|
||||
Threading,
|
||||
/// Unknown sender
|
||||
#[fail(display = "Unknown sender")]
|
||||
UnknownSender,
|
||||
}
|
||||
|
|
|
@ -10,8 +10,11 @@ use super::merkle::{Digest, MerkleTree, Proof};
|
|||
/// consensus algorithm.
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub enum Message {
|
||||
/// A share of the value, sent from the sender to another validator.
|
||||
Value(Proof<Vec<u8>>),
|
||||
/// A copy of the value received from the sender, multicast by a validator.
|
||||
Echo(Proof<Vec<u8>>),
|
||||
/// Indicates that the sender knows that every node will eventually be able to decode.
|
||||
Ready(Digest),
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
|
||||
use super::votes::{SignedVote, VoteCounter};
|
||||
use super::{
|
||||
Batch, Change, ChangeState, DynamicHoneyBadgerBuilder, EncryptionSchedule, Error, ErrorKind,
|
||||
Input, InternalContrib, JoinPlan, KeyGenMessage, KeyGenState, Message, Params, Result,
|
||||
Batch, Change, ChangeState, DynamicHoneyBadgerBuilder, EncryptionSchedule, Error, Input,
|
||||
InternalContrib, JoinPlan, KeyGenMessage, KeyGenState, Message, Params, Result,
|
||||
SignedKeyGenMsg, Step,
|
||||
};
|
||||
use fault_log::{Fault, FaultKind, FaultLog};
|
||||
|
@ -150,11 +150,11 @@ where
|
|||
.collect();
|
||||
let step = self
|
||||
.honey_badger
|
||||
.handle_input(InternalContrib {
|
||||
.propose(&InternalContrib {
|
||||
contrib,
|
||||
key_gen_messages,
|
||||
votes: self.vote_counter.pending_votes().cloned().collect(),
|
||||
}).map_err(ErrorKind::ProposeHoneyBadger)?;
|
||||
}).map_err(Error::ProposeHoneyBadger)?;
|
||||
self.process_output(step)
|
||||
}
|
||||
|
||||
|
@ -254,13 +254,13 @@ where
|
|||
message: HbMessage<N>,
|
||||
) -> Result<Step<C, N>> {
|
||||
if !self.netinfo.is_node_validator(sender_id) {
|
||||
return Err(ErrorKind::UnknownSender.into());
|
||||
return Err(Error::UnknownSender);
|
||||
}
|
||||
// Handle the message.
|
||||
let step = self
|
||||
.honey_badger
|
||||
.handle_message(sender_id, message)
|
||||
.map_err(ErrorKind::HandleHoneyBadgerMessageHoneyBadger)?;
|
||||
.map_err(Error::HandleHoneyBadgerMessage)?;
|
||||
self.process_output(step)
|
||||
}
|
||||
|
||||
|
@ -337,7 +337,7 @@ where
|
|||
let change = if let Some(kgs) = self.take_ready_key_gen() {
|
||||
// If DKG completed, apply the change, restart Honey Badger, and inform the user.
|
||||
debug!("{}: DKG for complete for: {:?}", self, kgs.public_keys());
|
||||
self.netinfo = kgs.key_gen.into_network_info()?;
|
||||
self.netinfo = kgs.key_gen.into_network_info().map_err(Error::SyncKeyGen)?;
|
||||
let params = self.honey_badger.params().clone();
|
||||
self.restart_honey_badger(batch_epoch + 1, params);
|
||||
ChangeState::Complete(Change::NodeChange(self.netinfo.public_key_map().clone()))
|
||||
|
@ -396,7 +396,8 @@ where
|
|||
let sk = self.netinfo.secret_key().clone();
|
||||
let our_id = self.our_id().clone();
|
||||
let (key_gen, part) =
|
||||
SyncKeyGen::new(&mut self.rng, our_id, sk, pub_keys.clone(), threshold)?;
|
||||
SyncKeyGen::new(&mut self.rng, our_id, sk, pub_keys.clone(), threshold)
|
||||
.map_err(Error::SyncKeyGen)?;
|
||||
self.key_gen_state = Some(KeyGenState::new(key_gen));
|
||||
if let Some(part) = part {
|
||||
self.send_transaction(KeyGenMessage::Part(part))
|
||||
|
@ -423,7 +424,7 @@ where
|
|||
let outcome = if let Some(kgs) = self.key_gen_state.as_mut() {
|
||||
kgs.key_gen
|
||||
.handle_part(&mut self.rng, &sender_id, part)
|
||||
.map_err(ErrorKind::SyncKeyGen)?
|
||||
.map_err(Error::SyncKeyGen)?
|
||||
} else {
|
||||
// No key generation ongoing.
|
||||
let fault_kind = FaultKind::UnexpectedKeyGenPart;
|
||||
|
@ -445,7 +446,7 @@ where
|
|||
let outcome = if let Some(kgs) = self.key_gen_state.as_mut() {
|
||||
kgs.key_gen
|
||||
.handle_ack(sender_id, ack)
|
||||
.map_err(ErrorKind::SyncKeyGen)?
|
||||
.map_err(Error::SyncKeyGen)?
|
||||
} else {
|
||||
// No key generation ongoing.
|
||||
let fault_kind = FaultKind::UnexpectedKeyGenAck;
|
||||
|
@ -463,8 +464,7 @@ where
|
|||
|
||||
/// Signs and sends a `KeyGenMessage` and also tries to commit it.
|
||||
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 ser = bincode::serialize(&kg_msg).map_err(|err| Error::SerializeKeyGen(*err))?;
|
||||
let sig = Box::new(self.netinfo.secret_key().sign(ser));
|
||||
if self.netinfo.is_validator() {
|
||||
let our_id = self.our_id().clone();
|
||||
|
@ -502,8 +502,7 @@ where
|
|||
sig: &Signature,
|
||||
kg_msg: &KeyGenMessage,
|
||||
) -> Result<bool> {
|
||||
let ser =
|
||||
bincode::serialize(kg_msg).map_err(|err| ErrorKind::VerifySignatureBincode(*err))?;
|
||||
let ser = bincode::serialize(kg_msg).map_err(|err| Error::SerializeKeyGen(*err))?;
|
||||
let verify = |opt_pk: Option<&PublicKey>| opt_pk.map_or(false, |pk| pk.verify(&sig, &ser));
|
||||
let kgs = self.key_gen_state.as_ref();
|
||||
let current_key = self.netinfo.public_key(node_id);
|
||||
|
|
|
@ -1,94 +1,34 @@
|
|||
use std::fmt::{self, Display};
|
||||
|
||||
use bincode;
|
||||
use crypto;
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
use failure::Fail;
|
||||
|
||||
use honey_badger;
|
||||
use sync_key_gen;
|
||||
|
||||
/// 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 = "Crypto error: {}", _0)]
|
||||
Crypto(crypto::error::Error),
|
||||
#[fail(display = "ProposeHoneyBadger error: {}", _0)]
|
||||
ProposeHoneyBadger(honey_badger::Error),
|
||||
pub enum Error {
|
||||
/// Failed to serialize a key generation message for signing.
|
||||
#[fail(display = "Error serializing a key gen message: {}", _0)]
|
||||
SerializeKeyGen(bincode::ErrorKind),
|
||||
/// Failed to serialize a vote for signing.
|
||||
#[fail(display = "Error serializing a vote: {}", _0)]
|
||||
SerializeVote(bincode::ErrorKind),
|
||||
/// Failed to propose a contribution in `HoneyBadger`.
|
||||
#[fail(
|
||||
display = "HandleHoneyBadgerMessageHoneyBadger error: {}",
|
||||
display = "Error proposing a contribution in HoneyBadger: {}",
|
||||
_0
|
||||
)]
|
||||
HandleHoneyBadgerMessageHoneyBadger(honey_badger::Error),
|
||||
#[fail(display = "SyncKeyGen error: {}", _0)]
|
||||
ProposeHoneyBadger(honey_badger::Error),
|
||||
/// Failed to handle a `HoneyBadger` message.
|
||||
#[fail(display = "Error handling a HoneyBadger message: {}", _0)]
|
||||
HandleHoneyBadgerMessage(honey_badger::Error),
|
||||
/// Failed to handle a `SyncKeyGen` message.
|
||||
#[fail(display = "Error handling SyncKeyGen message: {}", _0)]
|
||||
SyncKeyGen(sync_key_gen::Error),
|
||||
/// Unknown sender
|
||||
#[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()
|
||||
}
|
||||
|
||||
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<crypto::error::Error> for Error {
|
||||
fn from(e: crypto::error::Error) -> Error {
|
||||
Error {
|
||||
inner: Context::new(ErrorKind::Crypto(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sync_key_gen::Error> for Error {
|
||||
fn from(e: sync_key_gen::Error) -> Error {
|
||||
Error {
|
||||
inner: Context::new(ErrorKind::SyncKeyGen(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of `DynamicHoneyBadger` handling an input or message.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
|
|
@ -87,8 +87,9 @@ 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, ErrorKind, Result};
|
||||
pub use self::error::{Error, Result};
|
||||
|
||||
/// A `DynamicHoneyBadger` step, possibly containing multiple outputs.
|
||||
pub type Step<C, N> = ::DaStep<DynamicHoneyBadger<C, N>>;
|
||||
|
||||
/// The user input for `DynamicHoneyBadger`.
|
||||
|
|
|
@ -6,7 +6,7 @@ use crypto::Signature;
|
|||
use serde::Serialize;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::{Change, ErrorKind, Result};
|
||||
use super::{Change, Error, Result};
|
||||
use fault_log::{FaultKind, FaultLog};
|
||||
use {NetworkInfo, NodeIdT};
|
||||
|
||||
|
@ -49,8 +49,7 @@ where
|
|||
era: self.era,
|
||||
num: self.pending.get(&voter).map_or(0, |sv| sv.vote.num + 1),
|
||||
};
|
||||
let ser_vote =
|
||||
bincode::serialize(&vote).map_err(|err| ErrorKind::SignVoteForBincode(*err))?;
|
||||
let ser_vote = bincode::serialize(&vote).map_err(|err| Error::SerializeVote(*err))?;
|
||||
let signed_vote = SignedVote {
|
||||
vote,
|
||||
voter: voter.clone(),
|
||||
|
@ -149,8 +148,8 @@ where
|
|||
|
||||
/// Returns `true` if the signature is valid.
|
||||
fn validate(&self, signed_vote: &SignedVote<N>) -> Result<bool> {
|
||||
let ser_vote = bincode::serialize(&signed_vote.vote)
|
||||
.map_err(|err| ErrorKind::ValidateBincode(*err))?;
|
||||
let ser_vote =
|
||||
bincode::serialize(&signed_vote.vote).map_err(|err| Error::SerializeVote(*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)))
|
||||
}
|
||||
|
|
|
@ -82,11 +82,14 @@ pub enum FaultKind {
|
|||
/// that the node exhibited ('kind').
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Fault<N> {
|
||||
/// The faulty node's ID.
|
||||
pub node_id: N,
|
||||
/// The kind of fault the node is blamed for.
|
||||
pub kind: FaultKind,
|
||||
}
|
||||
|
||||
impl<N> Fault<N> {
|
||||
/// Creates a new fault, blaming `node_id` for the `kind`.
|
||||
pub fn new(node_id: N, kind: FaultKind) -> Self {
|
||||
Fault { node_id, kind }
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use rand::{Rand, Rng};
|
|||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::{Batch, ErrorKind, MessageContent, Result, Step};
|
||||
use super::{Batch, Error, MessageContent, Result, Step};
|
||||
use fault_log::{Fault, FaultKind, FaultLog};
|
||||
use subset::{self as cs, Subset, SubsetOutput};
|
||||
use threshold_decrypt::{self as td, ThresholdDecrypt};
|
||||
|
@ -77,7 +77,7 @@ where
|
|||
match self {
|
||||
SubsetState::Ongoing(ref mut cs) => cs.handle_input(proposal),
|
||||
SubsetState::Complete(_) => return Ok(cs::Step::default()),
|
||||
}.map_err(|err| ErrorKind::InputSubset(err).into())
|
||||
}.map_err(Error::InputSubset)
|
||||
}
|
||||
|
||||
/// Handles a message in the Subset instance, unless it has already completed.
|
||||
|
@ -85,7 +85,7 @@ where
|
|||
match self {
|
||||
SubsetState::Ongoing(ref mut cs) => cs.handle_message(sender_id, msg),
|
||||
SubsetState::Complete(_) => return Ok(cs::Step::default()),
|
||||
}.map_err(|err| ErrorKind::HandleSubsetMessage(err).into())
|
||||
}.map_err(Error::HandleSubsetMessage)
|
||||
}
|
||||
|
||||
/// Returns the number of contributions that we have already received or, after completion, how
|
||||
|
@ -211,7 +211,7 @@ where
|
|||
require_decryption: bool,
|
||||
) -> Result<Self> {
|
||||
let epoch_id = EpochId { hb_id, epoch };
|
||||
let cs = Subset::new(netinfo.clone(), epoch_id).map_err(ErrorKind::CreateSubset)?;
|
||||
let cs = Subset::new(netinfo.clone(), epoch_id).map_err(Error::CreateSubset)?;
|
||||
Ok(EpochState {
|
||||
epoch,
|
||||
netinfo,
|
||||
|
@ -226,15 +226,14 @@ where
|
|||
|
||||
/// If the instance hasn't terminated yet, inputs our encrypted contribution.
|
||||
pub fn propose<R: Rng>(&mut self, proposal: &C, rng: &mut R) -> Result<Step<C, N>> {
|
||||
let ser_prop =
|
||||
bincode::serialize(&proposal).map_err(|err| ErrorKind::ProposeBincode(*err))?;
|
||||
let ser_prop = bincode::serialize(&proposal).map_err(|err| Error::ProposeBincode(*err))?;
|
||||
let cs_step = self.subset.handle_input(if self.require_decryption {
|
||||
let ciphertext = self
|
||||
.netinfo
|
||||
.public_key_set()
|
||||
.public_key()
|
||||
.encrypt_with_rng(rng, ser_prop);
|
||||
bincode::serialize(&ciphertext).map_err(|err| ErrorKind::ProposeBincode(*err))?
|
||||
bincode::serialize(&ciphertext).map_err(|err| Error::ProposeBincode(*err))?
|
||||
} else {
|
||||
ser_prop
|
||||
})?;
|
||||
|
@ -271,7 +270,7 @@ where
|
|||
entry.insert(DecryptionState::new(self.netinfo.clone()))
|
||||
}
|
||||
}.handle_message(sender_id, share)
|
||||
.map_err(ErrorKind::ThresholdDecrypt)?;
|
||||
.map_err(Error::ThresholdDecrypt)?;
|
||||
self.process_decryption(proposer_id, td_step)
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +391,7 @@ where
|
|||
Err(td::Error::InvalidCiphertext(_)) => {
|
||||
Ok(Fault::new(proposer_id, FaultKind::InvalidCiphertext).into())
|
||||
}
|
||||
Err(err) => Err(ErrorKind::ThresholdDecrypt(err).into()),
|
||||
Err(err) => Err(Error::ThresholdDecrypt(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +1,31 @@
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use bincode;
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
use failure::Fail;
|
||||
|
||||
use subset;
|
||||
use threshold_decrypt;
|
||||
|
||||
/// Honey badger error variants.
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum ErrorKind {
|
||||
#[fail(display = "ProposeBincode error: {}", _0)]
|
||||
pub enum Error {
|
||||
/// Failed to serialize contribution.
|
||||
#[fail(display = "Error serializing contribution: {}", _0)]
|
||||
ProposeBincode(bincode::ErrorKind),
|
||||
/// Failed to instantiate `Subset`.
|
||||
#[fail(display = "Failed to instantiate Subset: {}", _0)]
|
||||
CreateSubset(subset::Error),
|
||||
/// Failed to input contribution to `Subset`.
|
||||
#[fail(display = "Failed to input contribution to Subset: {}", _0)]
|
||||
InputSubset(subset::Error),
|
||||
/// Failed to handle `Subset` message.
|
||||
#[fail(display = "Failed to handle Subset message: {}", _0)]
|
||||
HandleSubsetMessage(subset::Error),
|
||||
/// Failed to decrypt a contribution.
|
||||
#[fail(display = "Threshold decryption error: {}", _0)]
|
||||
ThresholdDecrypt(threshold_decrypt::Error),
|
||||
/// Unknown sender
|
||||
#[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()
|
||||
}
|
||||
|
||||
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 Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of `HoneyBadger` handling an input or a message.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
|
|
@ -8,7 +8,7 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::epoch_state::EpochState;
|
||||
use super::{Batch, Error, ErrorKind, HoneyBadgerBuilder, Message, Result};
|
||||
use super::{Batch, Error, HoneyBadgerBuilder, Message, Result};
|
||||
use {util, Contribution, DistAlgorithm, Fault, FaultKind, NetworkInfo, NodeIdT};
|
||||
|
||||
use super::Params;
|
||||
|
@ -36,6 +36,7 @@ pub struct HoneyBadger<C, N: Rand> {
|
|||
pub(super) rng: Box<dyn Rng + Send + Sync>,
|
||||
}
|
||||
|
||||
/// A `HoneyBadger` step, possibly containing multiple outputs.
|
||||
pub type Step<C, N> = ::DaStep<HoneyBadger<C, N>>;
|
||||
|
||||
impl<C, N> DistAlgorithm for HoneyBadger<C, N>
|
||||
|
@ -107,7 +108,7 @@ where
|
|||
/// This must be called with every message we receive from another node.
|
||||
pub fn handle_message(&mut self, sender_id: &N, message: Message<N>) -> Result<Step<C, N>> {
|
||||
if !self.netinfo.is_node_validator(sender_id) {
|
||||
return Err(ErrorKind::UnknownSender.into());
|
||||
return Err(Error::UnknownSender);
|
||||
}
|
||||
let Message { epoch, content } = message;
|
||||
if epoch > self.epoch + self.params.max_future_epochs {
|
||||
|
@ -200,14 +201,19 @@ where
|
|||
/// How frequently Threshold Encryption should be used.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
|
||||
pub enum EncryptionSchedule {
|
||||
/// Always encrypt. All contributions are encrypted in every epoch.
|
||||
Always,
|
||||
/// Never encrypt. All contributions are plaintext in every epoch.
|
||||
Never,
|
||||
/// Every _n_-th epoch uses encryption. In all other epochs, contributions are plaintext.
|
||||
EveryNthEpoch(u32),
|
||||
/// How many with encryption, followed by how many without encryption.
|
||||
/// With `TickTock(n, m)`, `n` epochs use encryption, followed by `m` epochs that don't.
|
||||
/// `m` out of `n + m` epochs will use plaintext contributions.
|
||||
TickTock(u32, u32),
|
||||
}
|
||||
|
||||
impl EncryptionSchedule {
|
||||
/// Returns `true` if the contributions in the `epoch` should be encrypted.
|
||||
pub fn use_on_epoch(self, epoch: u64) -> bool {
|
||||
match self {
|
||||
EncryptionSchedule::Always => true,
|
||||
|
|
|
@ -12,14 +12,17 @@ use threshold_decrypt;
|
|||
pub enum MessageContent<N: Rand> {
|
||||
/// A message belonging to the subset algorithm in the given epoch.
|
||||
Subset(subset::Message<N>),
|
||||
/// A decrypted share of the output of `proposer_id`.
|
||||
/// A decryption share of the output of `proposer_id`.
|
||||
DecryptionShare {
|
||||
/// The ID of the node that proposed the contribution that is being decrypted.
|
||||
proposer_id: N,
|
||||
/// The decryption share: _f + 1_ of these are required to decrypt the contribution.
|
||||
share: threshold_decrypt::Message,
|
||||
},
|
||||
}
|
||||
|
||||
impl<N: Rand> MessageContent<N> {
|
||||
/// Wraps this content in a `Message` with the given epoch.
|
||||
pub fn with_epoch(self, epoch: u64) -> Message<N> {
|
||||
Message {
|
||||
epoch,
|
||||
|
|
|
@ -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, ErrorKind, Result};
|
||||
pub use self::error::{Error, Result};
|
||||
pub use self::honey_badger::{EncryptionSchedule, HoneyBadger, Step};
|
||||
pub use self::message::{Message, MessageContent};
|
||||
pub use self::params::Params;
|
||||
|
|
53
src/lib.rs
53
src/lib.rs
|
@ -6,34 +6,42 @@
|
|||
//!
|
||||
//! ## Consensus
|
||||
//!
|
||||
//! A consensus algorithm is a protocol that helps a number of nodes agree on some data value.
|
||||
//! Byzantine fault tolerant systems can tolerate a number of faulty nodes _f_ (broken, or even
|
||||
//! controlled by an attacker), as long as the total number _N_ of nodes is greater than _3 f_.
|
||||
//! Asynchronous protocols do not make assumptions about timing: Even if an adversary controls
|
||||
//! network scheduling and can delay message delivery, consensus will still be reached as long as
|
||||
//! all messages are _eventually_ delivered.
|
||||
//!
|
||||
//! The Honey Badger consensus algorithm is both Byzantine fault tolerant and asynchronous. It is
|
||||
//! also modular, and the subalgorithms it is composed of are exposed in this crate as well, and
|
||||
//! usable separately.
|
||||
//!
|
||||
//! Consensus algorithms are fundamental to resilient, distributed systems such as decentralized
|
||||
//! databases and blockchains. Byzantine fault tolerant systems can reach consensus with a number
|
||||
//! of faulty nodes _f_ (including complete takeover by an attacker), as long as the total number
|
||||
//! _N_ of nodes is greater than _3 f_.
|
||||
//!
|
||||
//! The Honey Badger consensus algorithm is both Byzantine fault tolerant and asynchronous. It does
|
||||
//! not make timing assumptions about message delivery. An adversary can control network scheduling
|
||||
//! and delay messages without impacting consensus, and progress can be made in adverse networking
|
||||
//! conditions.
|
||||
//! databases and blockchains.
|
||||
//!
|
||||
//!
|
||||
//! ## Crate Implementation
|
||||
//! ## Usage
|
||||
//!
|
||||
//! This protocol does not function in a standalone context, it must be instantiated in an
|
||||
//! application that handles networking.
|
||||
//! This crate is meant to be used as a component in a distributed application where the consensus
|
||||
//! problem arises. The application will usually run on different nodes, connected to each other
|
||||
//! via a network. The nodes give an input to the algorithm, exchange several messages, and
|
||||
//! eventually the algorithm returns an output, which is guaranteed to be the same in each correct
|
||||
//! node.
|
||||
//!
|
||||
//! * The network must contain a number of nodes that are known to each other by some unique
|
||||
//! identifiers (IDs) and are able to exchange authenticated (cryptographically signed) messages.
|
||||
//! However, the `hbbft` crate only implements the abstract protocols, not the networking. It is
|
||||
//! the application's responsibility to serialize, sign and send the messages to the other nodes.
|
||||
//! That is why in addition to methods for giving input, the algorithms also have a
|
||||
//! `handle_message` method. The application is required to call this for every (validly signed,
|
||||
//! deserialized) message that was received from a peer.
|
||||
//! The methods return a [Step](struct.Step.html) which may contain messages, fault logs and outputs.
|
||||
//! Messages are tagged with a peer they need to be sent to. A fault log is produced if a peer
|
||||
//! didn't follow the protocol, and therefore is now known to be faulty. The output is the result
|
||||
//! of the agreement, and guaranteed to be the same in all nodes.
|
||||
//!
|
||||
//! * The user must define a type of _input_ - the _transactions_ - to the system and nodes must
|
||||
//! handle system networking.
|
||||
//!
|
||||
//! * Messages received from other nodes must be passed into the instance, and messages produced by
|
||||
//! the instance sent to corresponding nodes.
|
||||
//!
|
||||
//! The algorithm outputs _batches_ of transactions. The order and content of these batches is
|
||||
//! guaranteed to be the same for all correct nodes, assuming enough nodes (_N > 3 f_) are
|
||||
//! functional and correct.
|
||||
//! The network must contain a number of nodes that are known to each other by some unique
|
||||
//! identifiers (IDs), which is a generic type argument to the algorithms. Where applicable, the
|
||||
//! type of the input and output is also generic.
|
||||
//!
|
||||
//!
|
||||
//! ## Algorithms
|
||||
|
@ -114,6 +122,7 @@
|
|||
|
||||
// We put algorithm structs in `src/algorithm/algorithm.rs`.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(module_inception))]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate bincode;
|
||||
extern crate byteorder;
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
/// Message sent by a given source.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SourcedMessage<M, N> {
|
||||
/// The ID of the sender.
|
||||
pub source: N,
|
||||
/// The message's content.
|
||||
pub message: M,
|
||||
}
|
||||
|
||||
/// Message destination can be either of the two:
|
||||
///
|
||||
/// 1) `All`: all remote nodes.
|
||||
///
|
||||
/// 2) `Node(id)`: remote node `id`.
|
||||
/// The destination of a message.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Target<N> {
|
||||
/// The message must be sent to all remote nodes.
|
||||
All,
|
||||
/// The message must be sent to the node with the given ID.
|
||||
Node(N),
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,9 @@ impl<N> Target<N> {
|
|||
/// Message with a designated target.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TargetedMessage<M, N> {
|
||||
/// The node or nodes that this message must be delivered to.
|
||||
pub target: Target<N>,
|
||||
/// The content of the message that must be serialized and sent to the target.
|
||||
pub message: M,
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,11 @@ pub struct NetworkInfo<N> {
|
|||
}
|
||||
|
||||
impl<N: NodeIdT> NetworkInfo<N> {
|
||||
/// Creates a new `NetworkInfo` with the given ID and keys.
|
||||
///
|
||||
/// All nodes in the network must share the same public information. Validators' IDs must be
|
||||
/// keys in the `public_keys` map, and their secret key share must match their share in the
|
||||
/// `public_key_set`.
|
||||
pub fn new(
|
||||
our_id: N,
|
||||
secret_key_share: SecretKeyShare,
|
||||
|
|
|
@ -22,13 +22,12 @@
|
|||
//! entries, any two nodes will likely make almost disjoint contributions instead of proposing
|
||||
//! the same transaction multiple times.
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
use std::marker::PhantomData;
|
||||
use std::{cmp, iter};
|
||||
|
||||
use crypto::PublicKey;
|
||||
use derivative::Derivative;
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
use failure::Fail;
|
||||
use rand::{Rand, Rng};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
|
@ -40,57 +39,19 @@ pub use dynamic_honey_badger::{Change, ChangeState, Input};
|
|||
|
||||
/// Queueing honey badger error variants.
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum ErrorKind {
|
||||
pub enum Error {
|
||||
/// Failed to handle input.
|
||||
#[fail(display = "Input error: {}", _0)]
|
||||
Input(dynamic_honey_badger::Error),
|
||||
/// Failed to handle a message.
|
||||
#[fail(display = "Handle message error: {}", _0)]
|
||||
HandleMessage(dynamic_honey_badger::Error),
|
||||
/// Failed to propose a contribution.
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of `QueueingHoneyBadger` handling an input or message.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// A Queueing Honey Badger builder, to configure the parameters and create new instances of
|
||||
|
@ -105,7 +66,7 @@ pub struct QueueingHoneyBadgerBuilder<T, N: Rand + Ord, Q> {
|
|||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
pub type QueueingHoneyBadgerWithStep<T, N, Q> = (QueueingHoneyBadger<T, N, Q>, Step<T, N>);
|
||||
type QueueingHoneyBadgerWithStep<T, N, Q> = (QueueingHoneyBadger<T, N, Q>, Step<T, N>);
|
||||
|
||||
impl<T, N, Q> QueueingHoneyBadgerBuilder<T, N, Q>
|
||||
where
|
||||
|
@ -187,6 +148,7 @@ pub struct QueueingHoneyBadger<T, N: Rand + Ord, Q> {
|
|||
rng: Box<dyn Rng + Send + Sync>,
|
||||
}
|
||||
|
||||
/// A `QueueingHoneyBadger` step, possibly containing multiple outputs.
|
||||
pub type Step<T, N> = ::Step<Message<N>, Batch<T, N>, N>;
|
||||
|
||||
impl<T, N, Q> DistAlgorithm for QueueingHoneyBadger<T, N, Q>
|
||||
|
@ -294,7 +256,7 @@ where
|
|||
where
|
||||
F: FnOnce(&mut DynamicHoneyBadger<Vec<T>, N>) -> dynamic_honey_badger::Result<Step<T, N>>,
|
||||
{
|
||||
let step = f(&mut self.dyn_hb).map_err(ErrorKind::Input)?;
|
||||
let step = f(&mut self.dyn_hb).map_err(Error::Input)?;
|
||||
self.queue
|
||||
.remove_multiple(step.output.iter().flat_map(Batch::iter));
|
||||
Ok(step.join(self.propose()?))
|
||||
|
@ -324,11 +286,12 @@ where
|
|||
step.extend(
|
||||
self.dyn_hb
|
||||
.handle_input(Input::User(proposal))
|
||||
.map_err(ErrorKind::Propose)?,
|
||||
.map_err(Error::Propose)?,
|
||||
);
|
||||
}
|
||||
Ok(step)
|
||||
}
|
||||
}
|
||||
|
||||
/// A batch containing a list of transactions from at least two thirds of the validators.
|
||||
pub type Batch<T, N> = DhbBatch<Vec<T>, N>;
|
||||
|
|
|
@ -3,9 +3,12 @@ use serde_derive::{Deserialize, Serialize};
|
|||
|
||||
use super::SenderQueueableMessage;
|
||||
|
||||
/// A `SenderQueue` message.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum Message<M: SenderQueueableMessage> {
|
||||
/// The announcement that this node has reached the given epoch.
|
||||
EpochStarted(M::Epoch),
|
||||
/// A message of the wrapped algorithm.
|
||||
Algo(M),
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
//! epoch matches the epoch of the message. Thus no queueing is required for incoming messages since
|
||||
//! any incoming messages with non-matching epochs can be safely discarded.
|
||||
|
||||
mod dynamic_honey_badger;
|
||||
mod honey_badger;
|
||||
mod message;
|
||||
|
||||
pub mod dynamic_honey_badger;
|
||||
pub mod honey_badger;
|
||||
pub mod queueing_honey_badger;
|
||||
mod queueing_honey_badger;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Debug;
|
||||
|
@ -19,7 +18,9 @@ use {DaStep, DistAlgorithm, Epoched, NodeIdT, Target};
|
|||
|
||||
pub use self::message::Message;
|
||||
|
||||
/// A message type that is suitable for use with a sender queue.
|
||||
pub trait SenderQueueableMessage {
|
||||
/// The epoch type of the wrapped algorithm.
|
||||
type Epoch: EpochT;
|
||||
|
||||
/// Whether the message needs to be deferred.
|
||||
|
@ -37,6 +38,7 @@ pub trait SenderQueueableMessage {
|
|||
fn first_epoch(&self) -> Self::Epoch;
|
||||
}
|
||||
|
||||
/// An output type that is suitable for use with a sender queue.
|
||||
pub trait SenderQueueableOutput<N, M>
|
||||
where
|
||||
N: NodeIdT,
|
||||
|
@ -46,12 +48,14 @@ where
|
|||
fn added_peers(&self) -> Vec<N>;
|
||||
}
|
||||
|
||||
/// A `DistAlgorithm` that can be wrapped by a sender queue.
|
||||
pub trait SenderQueueableDistAlgorithm: Epoched + DistAlgorithm {
|
||||
/// The maximum number of subsequent future epochs that the `DistAlgorithm` is allowed to handle
|
||||
/// messages for.
|
||||
fn max_future_epochs(&self) -> u64;
|
||||
}
|
||||
|
||||
/// A map with outgoing messages, per epoch and per target node.
|
||||
pub type OutgoingQueue<D> = BTreeMap<
|
||||
<D as DistAlgorithm>::NodeId,
|
||||
BTreeMap<<D as Epoched>::Epoch, Vec<<D as DistAlgorithm>::Message>>,
|
||||
|
@ -79,6 +83,7 @@ where
|
|||
peer_epochs: BTreeMap<D::NodeId, D::Epoch>,
|
||||
}
|
||||
|
||||
/// A `SenderQueue` step. The output corresponds to the wrapped algorithm.
|
||||
pub type Step<D> = ::DaStep<SenderQueue<D>>;
|
||||
|
||||
impl<D> DistAlgorithm for SenderQueue<D>
|
||||
|
@ -131,10 +136,14 @@ where
|
|||
SenderQueueBuilder::new(algo, peer_ids)
|
||||
}
|
||||
|
||||
/// Handles an input. This will call the wrapped algorithm's `handle_input`.
|
||||
pub fn handle_input(&mut self, input: D::Input) -> Result<DaStep<Self>, D::Error> {
|
||||
self.apply(|algo| algo.handle_input(input))
|
||||
}
|
||||
|
||||
/// Handles a message received from `sender_id`.
|
||||
///
|
||||
/// This must be called with every message we receive from another node.
|
||||
pub fn handle_message(
|
||||
&mut self,
|
||||
sender_id: &D::NodeId,
|
||||
|
@ -263,6 +272,7 @@ where
|
|||
D::NodeId: NodeIdT,
|
||||
D::Output: SenderQueueableOutput<D::NodeId, D::Message>,
|
||||
{
|
||||
/// Creates a new builder, with an empty outgoing queue and the specified known peers.
|
||||
pub fn new<I>(algo: D, peer_ids: I) -> Self
|
||||
where
|
||||
I: Iterator<Item = D::NodeId>,
|
||||
|
@ -274,16 +284,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the outgoing queue, if pending messages are already known in advance.
|
||||
pub fn outgoing_queue(mut self, outgoing_queue: OutgoingQueue<D>) -> Self {
|
||||
self.outgoing_queue = outgoing_queue;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the peer epochs that are already known in advance.
|
||||
pub fn peer_epochs(mut self, peer_epochs: BTreeMap<D::NodeId, D::Epoch>) -> Self {
|
||||
self.peer_epochs = peer_epochs;
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates a new sender queue and returns the `Step` with the initial message.
|
||||
pub fn build(self, our_id: D::NodeId) -> (SenderQueue<D>, DaStep<SenderQueue<D>>) {
|
||||
let epoch = self.algo.epoch();
|
||||
let sq = SenderQueue {
|
||||
|
|
|
@ -8,17 +8,22 @@ use broadcast;
|
|||
/// A subset error.
|
||||
#[derive(Clone, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
/// Error creating `BinaryAgreement`.
|
||||
#[fail(display = "Error creating BinaryAgreement: {}", _0)]
|
||||
NewAgreement(binary_agreement::Error),
|
||||
/// Error creating `Broadcast`.
|
||||
#[fail(display = "Error creating Broadcast: {}", _0)]
|
||||
NewBroadcast(broadcast::Error),
|
||||
/// Error handling a `Broadcast` input or message.
|
||||
#[fail(display = "Error handling Broadcast input/message: {}", _0)]
|
||||
HandleBroadcast(broadcast::Error),
|
||||
/// Error handling a `BinaryAgreement` input or message.
|
||||
#[fail(
|
||||
display = "Error handling BinaryAgreement input/message: {}",
|
||||
_0
|
||||
)]
|
||||
HandleAgreement(binary_agreement::Error),
|
||||
/// Unknown proposer.
|
||||
#[fail(display = "Unknown proposer ID")]
|
||||
UnknownProposer,
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ pub enum MessageContent {
|
|||
}
|
||||
|
||||
impl MessageContent {
|
||||
pub fn with<N: Rand>(self, proposer_id: N) -> Message<N> {
|
||||
/// Returns a `Message` with this content and the specified proposer ID.
|
||||
pub(super) fn with<N: Rand>(self, proposer_id: N) -> Message<N> {
|
||||
Message {
|
||||
proposer_id,
|
||||
content: self,
|
||||
|
|
|
@ -12,15 +12,19 @@ use super::{Error, Message, MessageContent, Result};
|
|||
use rand::Rand;
|
||||
use {util, DistAlgorithm, NetworkInfo, NodeIdT, SessionIdT};
|
||||
|
||||
/// A `Subset` step, possibly containing several outputs.
|
||||
pub type Step<N> = ::Step<Message<N>, SubsetOutput<N>, N>;
|
||||
|
||||
/// An output with an accepted contribution or the end of the set.
|
||||
#[derive(Derivative, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derivative(Debug)]
|
||||
pub enum SubsetOutput<N> {
|
||||
/// A contribution was accepted into the set.
|
||||
Contribution(
|
||||
N,
|
||||
#[derivative(Debug(format_with = "util::fmt_hex"))] Vec<u8>,
|
||||
),
|
||||
/// The set is complete.
|
||||
Done,
|
||||
}
|
||||
|
||||
|
|
|
@ -190,14 +190,16 @@ use {NetworkInfo, NodeIdT};
|
|||
/// being invalid.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
/// Error creating `SyncKeyGen`.
|
||||
#[fail(display = "Error creating SyncKeyGen: {}", _0)]
|
||||
Creation(CryptoError),
|
||||
/// Error generating keys.
|
||||
#[fail(display = "Error generating keys: {}", _0)]
|
||||
Generation(CryptoError),
|
||||
#[fail(display = "Error acknowledging part: {}", _0)]
|
||||
Ack(CryptoError),
|
||||
/// Unknown sender
|
||||
#[fail(display = "Unknown sender")]
|
||||
UnknownSender,
|
||||
/// Failed to serialize message.
|
||||
#[fail(display = "Serialization error: {}", _0)]
|
||||
Serialize(String),
|
||||
}
|
||||
|
@ -544,29 +546,39 @@ impl<N: NodeIdT> SyncKeyGen<N> {
|
|||
/// An error in an `Ack` message sent by a faulty node.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum AckFault {
|
||||
/// The number of values differs from the number of nodes.
|
||||
#[fail(display = "The number of values differs from the number of nodes")]
|
||||
ValueCount,
|
||||
/// No corresponding Part received.
|
||||
#[fail(display = "No corresponding Part received")]
|
||||
MissingPart,
|
||||
/// Value decryption failed.
|
||||
#[fail(display = "Value decryption failed")]
|
||||
DecryptValue,
|
||||
/// Value deserialization failed.
|
||||
#[fail(display = "Value deserialization failed")]
|
||||
DeserializeValue,
|
||||
#[fail(display = "Value doesn not match the commitment")]
|
||||
/// Value doesn't match the commitment.
|
||||
#[fail(display = "Value doesn't match the commitment")]
|
||||
ValueCommitment,
|
||||
}
|
||||
|
||||
/// An error in a `Part` message sent by a faulty node.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum PartFault {
|
||||
/// The number of rows differs from the number of nodes.
|
||||
#[fail(display = "The number of rows differs from the number of nodes")]
|
||||
RowCount,
|
||||
/// Received multiple different Part messages from the same sender.
|
||||
#[fail(display = "Received multiple different Part messages from the same sender")]
|
||||
MultipleParts,
|
||||
/// Could not decrypt our row in the Part message.
|
||||
#[fail(display = "Could not decrypt our row in the Part message")]
|
||||
DecryptRow,
|
||||
/// Could not deserialize our row in the Part message.
|
||||
#[fail(display = "Could not deserialize our row in the Part message")]
|
||||
DeserializeRow,
|
||||
/// Row does not match the commitment.
|
||||
#[fail(display = "Row does not match the commitment")]
|
||||
RowCommitment,
|
||||
}
|
||||
|
|
|
@ -25,15 +25,20 @@ use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
|
|||
/// A threshold decryption error.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
/// Redundant input provided.
|
||||
#[fail(display = "Redundant input provided: {:?}", _0)]
|
||||
MultipleInputs(Box<Ciphertext>),
|
||||
/// Invalid ciphertext
|
||||
#[fail(display = "Invalid ciphertext: {:?}", _0)]
|
||||
InvalidCiphertext(Box<Ciphertext>),
|
||||
/// Unknown sender
|
||||
#[fail(display = "Unknown sender")]
|
||||
UnknownSender,
|
||||
/// Decryption failed
|
||||
#[fail(display = "Decryption failed: {:?}", _0)]
|
||||
Decryption(crypto::error::Error),
|
||||
#[fail(display = "Start decryption called before setting ciphertext")]
|
||||
/// Tried to decrypt before setting a cipherext.
|
||||
#[fail(display = "Tried to decrypt before setting ciphertext")]
|
||||
CiphertextIsNone,
|
||||
}
|
||||
|
||||
|
@ -59,6 +64,7 @@ pub struct ThresholdDecrypt<N> {
|
|||
terminated: bool,
|
||||
}
|
||||
|
||||
/// A `ThresholdDecrypt` step. It will contain at most one output.
|
||||
pub type Step<N> = ::DaStep<ThresholdDecrypt<N>>;
|
||||
|
||||
impl<N: NodeIdT> DistAlgorithm for ThresholdDecrypt<N> {
|
||||
|
|
|
@ -31,14 +31,22 @@ use {DistAlgorithm, NetworkInfo, NodeIdT, Target};
|
|||
/// A threshold signing error.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
/// Redundant input provided.
|
||||
#[fail(display = "Redundant input provided")]
|
||||
MultipleMessagesToSign,
|
||||
#[fail(display = "CombineAndVerifySigCrypto error: {}", _0)]
|
||||
/// Error combining and verifying signature shares.
|
||||
#[fail(
|
||||
display = "Error combining and verifying signature shares: {}",
|
||||
_0
|
||||
)]
|
||||
CombineAndVerifySigCrypto(crypto::error::Error),
|
||||
/// Unknown sender
|
||||
#[fail(display = "Unknown sender")]
|
||||
UnknownSender,
|
||||
/// Signature verification failed.
|
||||
#[fail(display = "Signature verification failed")]
|
||||
VerificationFailed,
|
||||
/// Document hash is not set, cannot sign or verify signatures.
|
||||
#[fail(display = "Document hash is not set, cannot sign or verify signatures")]
|
||||
DocumentHashIsNone,
|
||||
}
|
||||
|
@ -46,18 +54,9 @@ pub enum Error {
|
|||
/// A threshold signing result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// A threshold signing message, containing a signature share.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Rand)]
|
||||
pub struct Message(SignatureShare);
|
||||
|
||||
impl Message {
|
||||
pub fn new(sig: SignatureShare) -> Self {
|
||||
Message(sig)
|
||||
}
|
||||
|
||||
pub fn to_sig(&self) -> &SignatureShare {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
pub struct Message(pub SignatureShare);
|
||||
|
||||
/// A threshold signing algorithm instance. On input, broadcasts our threshold signature share. Upon
|
||||
/// receiving at least `num_faulty + 1` shares, attempts to combine them into a signature. If that
|
||||
|
@ -75,6 +74,7 @@ pub struct ThresholdSign<N> {
|
|||
terminated: bool,
|
||||
}
|
||||
|
||||
/// A step returned from `ThresholdSign`. It contains at most one output.
|
||||
pub type Step<N> = ::DaStep<ThresholdSign<N>>;
|
||||
|
||||
impl<N: NodeIdT> DistAlgorithm for ThresholdSign<N> {
|
||||
|
|
|
@ -57,8 +57,14 @@ impl<E> EpochT for E where E: Copy + Message + Default + Eq + Ord + Serialize +
|
|||
#[must_use = "The algorithm step result must be used."]
|
||||
#[derive(Debug)]
|
||||
pub struct Step<M, O, N> {
|
||||
/// 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>,
|
||||
/// 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>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! An interface for a transaction queue
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::{cmp, fmt};
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use rand;
|
|||
|
||||
/// Workaround trait for creating new random number generators
|
||||
pub trait SubRng {
|
||||
/// Returns a new random number generator in a `Box`.
|
||||
fn sub_rng(&mut self) -> Box<dyn rand::Rng + Send + Sync>;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue