2018-05-16 05:23:57 -07:00
|
|
|
use std::collections::btree_map::Entry;
|
2018-08-03 02:18:06 -07:00
|
|
|
use std::collections::BTreeMap;
|
2018-06-29 08:10:15 -07:00
|
|
|
use std::marker::PhantomData;
|
2018-07-11 12:15:08 -07:00
|
|
|
use std::sync::Arc;
|
2018-05-12 07:09:07 -07:00
|
|
|
|
|
|
|
use bincode;
|
2018-08-03 02:18:06 -07:00
|
|
|
use crypto::Ciphertext;
|
2018-06-28 08:17:07 -07:00
|
|
|
use itertools::Itertools;
|
2018-07-31 13:27:22 -07:00
|
|
|
use rand::Rand;
|
2018-06-25 04:07:31 -07:00
|
|
|
use serde::{Deserialize, Serialize};
|
2018-05-12 07:09:07 -07:00
|
|
|
|
2018-07-31 13:27:22 -07:00
|
|
|
use super::{Batch, Error, ErrorKind, HoneyBadgerBuilder, Message, MessageContent, Result};
|
2018-07-19 04:56:30 -07:00
|
|
|
use common_subset::{self, CommonSubset};
|
2018-08-03 02:18:06 -07:00
|
|
|
use fault_log::FaultKind;
|
|
|
|
use messaging::{self, DistAlgorithm, NetworkInfo};
|
|
|
|
use threshold_decryption::{self as td, ThresholdDecryption};
|
2018-08-02 14:27:55 -07:00
|
|
|
use traits::{Contribution, NodeUidT};
|
2018-05-12 07:09:07 -07:00
|
|
|
|
|
|
|
/// An instance of the Honey Badger Byzantine fault tolerant consensus algorithm.
|
2018-07-24 04:12:06 -07:00
|
|
|
#[derive(Debug)]
|
2018-08-02 14:27:55 -07:00
|
|
|
pub struct HoneyBadger<C, N: Rand> {
|
2018-05-29 05:17:30 -07:00
|
|
|
/// Shared network data.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) netinfo: Arc<NetworkInfo<N>>,
|
2018-05-16 05:23:57 -07:00
|
|
|
/// The earliest epoch from which we have not yet received output.
|
2018-07-31 13:27:22 -07:00
|
|
|
pub(super) epoch: u64,
|
2018-07-09 05:29:01 -07:00
|
|
|
/// Whether we have already submitted a proposal for the current epoch.
|
2018-07-31 13:27:22 -07:00
|
|
|
pub(super) has_input: bool,
|
2018-05-16 05:23:57 -07:00
|
|
|
/// The Asynchronous Common Subset instance that decides which nodes' transactions to include,
|
|
|
|
/// indexed by epoch.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) common_subsets: BTreeMap<u64, CommonSubset<N>>,
|
2018-06-28 08:17:07 -07:00
|
|
|
/// The maximum number of `CommonSubset` instances that we run simultaneously.
|
2018-07-31 13:27:22 -07:00
|
|
|
pub(super) max_future_epochs: u64,
|
2018-06-28 08:17:07 -07:00
|
|
|
/// Messages for future epochs that couldn't be handled yet.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) incoming_queue: BTreeMap<u64, Vec<(N, MessageContent<N>)>>,
|
2018-08-03 02:18:06 -07:00
|
|
|
/// The threshold decryption algorithm, by epoch and proposer.
|
|
|
|
pub(super) threshold_decryption: BTreeMap<u64, BTreeMap<N, ThresholdDecryption<N>>>,
|
2018-06-19 07:17:16 -07:00
|
|
|
/// Decoded accepted proposals.
|
2018-08-03 02:18:06 -07:00
|
|
|
pub(super) decrypted_contributions: BTreeMap<u64, BTreeMap<N, Vec<u8>>>,
|
2018-07-31 13:27:22 -07:00
|
|
|
pub(super) _phantom: PhantomData<C>,
|
2018-05-14 05:35:06 -07:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
pub type Step<C, N> = messaging::Step<HoneyBadger<C, N>>;
|
2018-07-09 04:35:26 -07:00
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
impl<C, N> DistAlgorithm for HoneyBadger<C, N>
|
2018-06-29 08:10:15 -07:00
|
|
|
where
|
2018-08-02 14:27:55 -07:00
|
|
|
C: Contribution + Serialize + for<'r> Deserialize<'r>,
|
|
|
|
N: NodeUidT + Rand,
|
2018-05-14 05:35:06 -07:00
|
|
|
{
|
2018-08-02 14:27:55 -07:00
|
|
|
type NodeUid = N;
|
2018-07-09 05:29:01 -07:00
|
|
|
type Input = C;
|
2018-08-02 14:27:55 -07:00
|
|
|
type Output = Batch<C, N>;
|
|
|
|
type Message = Message<N>;
|
2018-05-14 05:35:06 -07:00
|
|
|
type Error = Error;
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
fn input(&mut self, input: Self::Input) -> Result<Step<C, N>> {
|
2018-07-23 09:11:45 -07:00
|
|
|
self.propose(&input)
|
2018-05-14 05:35:06 -07:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> Result<Step<C, N>> {
|
2018-07-17 06:54:12 -07:00
|
|
|
if !self.netinfo.is_node_validator(sender_id) {
|
2018-05-20 04:51:33 -07:00
|
|
|
return Err(ErrorKind::UnknownSender.into());
|
2018-05-14 05:35:06 -07:00
|
|
|
}
|
2018-06-19 07:17:16 -07:00
|
|
|
let Message { epoch, content } = message;
|
2018-06-28 08:17:07 -07:00
|
|
|
if epoch > self.epoch + self.max_future_epochs {
|
|
|
|
// Postpone handling this message.
|
|
|
|
self.incoming_queue
|
|
|
|
.entry(epoch)
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
.push((sender_id.clone(), content));
|
2018-07-09 04:35:26 -07:00
|
|
|
} else if epoch == self.epoch {
|
2018-07-23 09:11:45 -07:00
|
|
|
return self.handle_message_content(sender_id, epoch, content);
|
2018-07-09 04:35:26 -07:00
|
|
|
} // And ignore all messages from past epochs.
|
2018-07-23 09:11:45 -07:00
|
|
|
Ok(Step::default())
|
2018-05-14 05:35:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn terminated(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
fn our_id(&self) -> &N {
|
2018-05-29 05:17:30 -07:00
|
|
|
self.netinfo.our_uid()
|
2018-05-14 05:35:06 -07:00
|
|
|
}
|
2018-05-12 07:09:07 -07:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
impl<C, N> HoneyBadger<C, N>
|
2018-06-29 08:10:15 -07:00
|
|
|
where
|
2018-08-02 14:27:55 -07:00
|
|
|
C: Contribution + Serialize + for<'r> Deserialize<'r>,
|
|
|
|
N: NodeUidT + Rand,
|
2018-05-12 07:09:07 -07:00
|
|
|
{
|
2018-06-29 08:10:15 -07:00
|
|
|
/// Returns a new `HoneyBadgerBuilder` configured to use the node IDs and cryptographic keys
|
2018-06-28 14:07:11 -07:00
|
|
|
/// specified by `netinfo`.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub fn builder(netinfo: Arc<NetworkInfo<N>>) -> HoneyBadgerBuilder<C, N> {
|
2018-06-28 14:07:11 -07:00
|
|
|
HoneyBadgerBuilder::new(netinfo)
|
|
|
|
}
|
|
|
|
|
2018-07-09 05:29:01 -07:00
|
|
|
/// Proposes a new item in the current epoch.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub fn propose(&mut self, proposal: &C) -> Result<Step<C, N>> {
|
2018-06-29 08:20:54 -07:00
|
|
|
if !self.netinfo.is_validator() {
|
2018-07-23 09:11:45 -07:00
|
|
|
return Ok(Step::default());
|
2018-06-25 12:09:45 -07:00
|
|
|
}
|
2018-07-23 09:11:45 -07:00
|
|
|
let epoch = self.epoch;
|
|
|
|
let cs_step = {
|
|
|
|
let cs = match self.common_subsets.entry(epoch) {
|
2018-07-12 08:53:12 -07:00
|
|
|
Entry::Occupied(entry) => entry.into_mut(),
|
2018-07-25 14:38:33 -07:00
|
|
|
Entry::Vacant(entry) => entry.insert(
|
|
|
|
CommonSubset::new(self.netinfo.clone(), epoch)
|
2018-08-03 02:18:06 -07:00
|
|
|
.map_err(ErrorKind::CreateCommonSubset)?,
|
2018-07-25 14:38:33 -07:00
|
|
|
),
|
2018-07-12 08:53:12 -07:00
|
|
|
};
|
2018-07-25 14:38:33 -07:00
|
|
|
let ser_prop =
|
|
|
|
bincode::serialize(&proposal).map_err(|err| ErrorKind::ProposeBincode(*err))?;
|
2018-07-12 08:53:12 -07:00
|
|
|
let ciphertext = self.netinfo.public_key_set().public_key().encrypt(ser_prop);
|
|
|
|
self.has_input = true;
|
2018-07-25 14:38:33 -07:00
|
|
|
cs.input(bincode::serialize(&ciphertext).unwrap())
|
2018-08-03 02:18:06 -07:00
|
|
|
.map_err(ErrorKind::InputCommonSubset)?
|
2018-05-16 05:23:57 -07:00
|
|
|
};
|
2018-07-23 09:11:45 -07:00
|
|
|
self.process_output(cs_step, epoch)
|
2018-05-12 07:09:07 -07:00
|
|
|
}
|
|
|
|
|
2018-07-09 05:29:01 -07:00
|
|
|
/// Returns `true` if input for the current epoch has already been provided.
|
|
|
|
pub fn has_input(&self) -> bool {
|
2018-07-12 08:53:12 -07:00
|
|
|
!self.netinfo.is_validator() || self.has_input
|
2018-05-16 05:23:57 -07:00
|
|
|
}
|
|
|
|
|
2018-08-01 01:41:09 -07:00
|
|
|
/// Returns the number of validators from which we have already received a proposal for the
|
|
|
|
/// current epoch.
|
|
|
|
pub(crate) fn received_proposals(&self) -> usize {
|
|
|
|
self.common_subsets
|
|
|
|
.get(&self.epoch)
|
|
|
|
.map_or(0, CommonSubset::received_proposals)
|
|
|
|
}
|
|
|
|
|
2018-06-28 08:17:07 -07:00
|
|
|
/// Handles a message for the given epoch.
|
|
|
|
fn handle_message_content(
|
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
sender_id: &N,
|
2018-06-28 08:17:07 -07:00
|
|
|
epoch: u64,
|
2018-08-02 14:27:55 -07:00
|
|
|
content: MessageContent<N>,
|
|
|
|
) -> Result<Step<C, N>> {
|
2018-06-28 08:17:07 -07:00
|
|
|
match content {
|
|
|
|
MessageContent::CommonSubset(cs_msg) => {
|
|
|
|
self.handle_common_subset_message(sender_id, epoch, cs_msg)
|
|
|
|
}
|
|
|
|
MessageContent::DecryptionShare { proposer_id, share } => {
|
|
|
|
self.handle_decryption_share_message(sender_id, epoch, proposer_id, share)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-14 05:35:06 -07:00
|
|
|
/// Handles a message for the common subset sub-algorithm.
|
2018-05-12 07:09:07 -07:00
|
|
|
fn handle_common_subset_message(
|
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
sender_id: &N,
|
2018-05-12 07:09:07 -07:00
|
|
|
epoch: u64,
|
2018-08-02 14:27:55 -07:00
|
|
|
message: common_subset::Message<N>,
|
|
|
|
) -> Result<Step<C, N>> {
|
2018-07-23 09:11:45 -07:00
|
|
|
let cs_step = {
|
2018-05-16 05:23:57 -07:00
|
|
|
// Borrow the instance for `epoch`, or create it.
|
|
|
|
let cs = match self.common_subsets.entry(epoch) {
|
|
|
|
Entry::Occupied(entry) => entry.into_mut(),
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
if epoch < self.epoch {
|
2018-07-08 09:41:50 -07:00
|
|
|
// Epoch has already terminated. Message is obsolete.
|
2018-07-23 09:11:45 -07:00
|
|
|
return Ok(Step::default());
|
2018-05-16 05:23:57 -07:00
|
|
|
} else {
|
2018-08-03 02:18:06 -07:00
|
|
|
let cs_result = CommonSubset::new(self.netinfo.clone(), epoch);
|
|
|
|
entry.insert(cs_result.map_err(ErrorKind::CreateCommonSubset)?)
|
2018-05-16 05:23:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2018-07-25 14:38:33 -07:00
|
|
|
cs.handle_message(sender_id, message)
|
2018-08-03 02:18:06 -07:00
|
|
|
.map_err(ErrorKind::HandleCommonSubsetMessage)?
|
2018-07-09 04:35:26 -07:00
|
|
|
};
|
2018-08-03 02:18:06 -07:00
|
|
|
self.process_output(cs_step, epoch)
|
2018-05-16 05:23:57 -07:00
|
|
|
}
|
2018-05-15 10:18:05 -07:00
|
|
|
|
2018-06-19 07:17:16 -07:00
|
|
|
/// Handles decryption shares sent by `HoneyBadger` instances.
|
2018-06-20 08:47:52 -07:00
|
|
|
fn handle_decryption_share_message(
|
2018-06-19 07:17:16 -07:00
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
sender_id: &N,
|
2018-06-19 07:17:16 -07:00
|
|
|
epoch: u64,
|
2018-08-02 14:27:55 -07:00
|
|
|
proposer_id: N,
|
2018-08-03 02:18:06 -07:00
|
|
|
share: td::Message,
|
2018-08-02 14:27:55 -07:00
|
|
|
) -> Result<Step<C, N>> {
|
2018-08-03 02:18:06 -07:00
|
|
|
let netinfo = self.netinfo.clone();
|
|
|
|
let td_step = self
|
|
|
|
.threshold_decryption
|
2018-07-12 08:53:12 -07:00
|
|
|
.entry(epoch)
|
|
|
|
.or_insert_with(BTreeMap::new)
|
2018-08-03 02:18:06 -07:00
|
|
|
.entry(proposer_id.clone())
|
|
|
|
.or_insert_with(|| ThresholdDecryption::new(netinfo))
|
|
|
|
.handle_message(sender_id, share)
|
|
|
|
.map_err(ErrorKind::ThresholdDecryption)?;
|
|
|
|
let mut step = self.process_threshold_decryption(epoch, proposer_id, td_step)?;
|
2018-07-12 08:53:12 -07:00
|
|
|
if epoch == self.epoch {
|
2018-08-03 02:18:06 -07:00
|
|
|
step.extend(self.try_output_batches()?);
|
2018-06-20 08:47:52 -07:00
|
|
|
}
|
2018-08-03 02:18:06 -07:00
|
|
|
Ok(step)
|
2018-06-20 08:47:52 -07:00
|
|
|
}
|
2018-06-19 07:17:16 -07:00
|
|
|
|
2018-08-03 02:18:06 -07:00
|
|
|
/// Processes a Threshold Decryption step.
|
|
|
|
fn process_threshold_decryption(
|
|
|
|
&mut self,
|
|
|
|
epoch: u64,
|
|
|
|
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| {
|
|
|
|
MessageContent::DecryptionShare {
|
|
|
|
proposer_id: proposer_id.clone(),
|
|
|
|
share,
|
|
|
|
}.with_epoch(epoch)
|
|
|
|
});
|
|
|
|
if let Some(output) = opt_output.into_iter().next() {
|
|
|
|
self.decrypted_contributions
|
|
|
|
.entry(epoch)
|
|
|
|
.or_insert_with(BTreeMap::new)
|
|
|
|
.insert(proposer_id, output);
|
2018-06-27 05:25:32 -07:00
|
|
|
}
|
2018-08-03 02:18:06 -07:00
|
|
|
Ok(step)
|
2018-06-21 10:38:07 -07:00
|
|
|
}
|
|
|
|
|
2018-07-12 08:53:12 -07:00
|
|
|
/// When contributions of transactions have been decrypted for all valid proposers in this
|
|
|
|
/// epoch, moves those contributions into a batch, outputs the batch and updates the epoch.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn try_output_batch(&mut self) -> Result<Option<Step<C, N>>> {
|
2018-08-03 02:18:06 -07:00
|
|
|
let proposer_ids = match self.threshold_decryption.get(&self.epoch) {
|
2018-07-23 09:11:45 -07:00
|
|
|
Some(cts) => cts.keys().cloned().collect_vec(),
|
2018-08-03 02:18:06 -07:00
|
|
|
None => return Ok(None), // Decryption hasn't even started yet.
|
2018-07-23 09:11:45 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut step = Step::default();
|
|
|
|
|
2018-06-20 08:47:52 -07:00
|
|
|
// Deserialize the output.
|
2018-08-03 02:18:06 -07:00
|
|
|
let contributions: BTreeMap<N, C> = {
|
|
|
|
let decrypted = match self.decrypted_contributions.get(&self.epoch) {
|
|
|
|
Some(dc) if dc.keys().eq(proposer_ids.iter()) => dc,
|
|
|
|
_ => return Ok(None), // Not enough decrypted contributions yet.
|
|
|
|
};
|
|
|
|
decrypted
|
2018-07-23 09:11:45 -07:00
|
|
|
.into_iter()
|
|
|
|
.flat_map(|(proposer_id, ser_contrib)| {
|
|
|
|
// If deserialization fails, the proposer of that item is faulty. Ignore it.
|
2018-08-03 02:18:06 -07:00
|
|
|
if let Ok(contrib) = bincode::deserialize::<C>(ser_contrib) {
|
|
|
|
Some((proposer_id.clone(), contrib))
|
2018-07-23 09:11:45 -07:00
|
|
|
} else {
|
|
|
|
let fault_kind = FaultKind::BatchDeserializationFailed;
|
2018-08-03 02:18:06 -07:00
|
|
|
step.fault_log.append(proposer_id.clone(), fault_kind);
|
2018-07-23 09:11:45 -07:00
|
|
|
None
|
|
|
|
}
|
2018-08-02 12:24:25 -07:00
|
|
|
})
|
2018-08-03 02:18:06 -07:00
|
|
|
.collect()
|
|
|
|
};
|
2018-06-20 08:47:52 -07:00
|
|
|
let batch = Batch {
|
|
|
|
epoch: self.epoch,
|
2018-07-09 05:29:01 -07:00
|
|
|
contributions,
|
2018-06-20 08:47:52 -07:00
|
|
|
};
|
|
|
|
debug!(
|
|
|
|
"{:?} Epoch {} output {:?}",
|
|
|
|
self.netinfo.our_uid(),
|
|
|
|
self.epoch,
|
2018-07-12 08:53:12 -07:00
|
|
|
batch.contributions.keys().collect::<Vec<_>>()
|
2018-06-20 08:47:52 -07:00
|
|
|
);
|
|
|
|
// Queue the output and advance the epoch.
|
2018-07-23 09:11:45 -07:00
|
|
|
step.output.push_back(batch);
|
|
|
|
step.extend(self.update_epoch()?);
|
|
|
|
Ok(Some(step))
|
2018-05-12 07:09:07 -07:00
|
|
|
}
|
2018-05-16 05:23:57 -07:00
|
|
|
|
2018-06-19 07:17:16 -07:00
|
|
|
/// Increments the epoch number and clears any state that is local to the finished epoch.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn update_epoch(&mut self) -> Result<Step<C, N>> {
|
2018-06-19 07:17:16 -07:00
|
|
|
// Clear the state of the old epoch.
|
2018-08-03 02:18:06 -07:00
|
|
|
self.threshold_decryption.remove(&self.epoch);
|
|
|
|
self.decrypted_contributions.remove(&self.epoch);
|
|
|
|
self.common_subsets.remove(&self.epoch);
|
2018-06-19 07:17:16 -07:00
|
|
|
self.epoch += 1;
|
2018-07-09 05:29:01 -07:00
|
|
|
self.has_input = false;
|
2018-06-28 08:17:07 -07:00
|
|
|
let max_epoch = self.epoch + self.max_future_epochs;
|
2018-07-23 09:11:45 -07:00
|
|
|
let mut step = Step::default();
|
2018-06-28 08:17:07 -07:00
|
|
|
// TODO: Once stable, use `Iterator::flatten`.
|
|
|
|
for (sender_id, content) in
|
|
|
|
Itertools::flatten(self.incoming_queue.remove(&max_epoch).into_iter())
|
|
|
|
{
|
2018-07-23 09:11:45 -07:00
|
|
|
step.extend(self.handle_message_content(&sender_id, max_epoch, content)?);
|
2018-06-28 08:17:07 -07:00
|
|
|
}
|
2018-06-20 08:47:52 -07:00
|
|
|
// Handle any decryption shares received for the new epoch.
|
2018-07-23 12:36:09 -07:00
|
|
|
step.extend(self.try_output_batches()?);
|
2018-07-23 09:11:45 -07:00
|
|
|
Ok(step)
|
2018-06-19 07:17:16 -07:00
|
|
|
}
|
|
|
|
|
2018-07-12 08:53:12 -07:00
|
|
|
/// Tries to decrypt contributions from all proposers and output those in a batch.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn try_output_batches(&mut self) -> Result<Step<C, N>> {
|
2018-07-23 09:11:45 -07:00
|
|
|
let mut step = Step::default();
|
|
|
|
while let Some(new_step) = self.try_output_batch()? {
|
|
|
|
step.extend(new_step);
|
2018-07-12 08:53:12 -07:00
|
|
|
}
|
2018-07-23 09:11:45 -07:00
|
|
|
Ok(step)
|
2018-07-12 08:53:12 -07:00
|
|
|
}
|
|
|
|
|
2018-06-19 07:17:16 -07:00
|
|
|
fn send_decryption_shares(
|
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
cs_output: BTreeMap<N, Vec<u8>>,
|
2018-07-23 09:11:45 -07:00
|
|
|
epoch: u64,
|
2018-08-02 14:27:55 -07:00
|
|
|
) -> Result<Step<C, N>> {
|
2018-07-23 09:11:45 -07:00
|
|
|
let mut step = Step::default();
|
2018-06-19 07:17:16 -07:00
|
|
|
for (proposer_id, v) in cs_output {
|
2018-08-03 02:18:06 -07:00
|
|
|
// TODO: Input into ThresholdDecryption. Check errors!
|
2018-07-23 09:11:45 -07:00
|
|
|
let ciphertext: Ciphertext = match bincode::deserialize(&v) {
|
|
|
|
Ok(ciphertext) => ciphertext,
|
|
|
|
Err(err) => {
|
|
|
|
warn!(
|
|
|
|
"Cannot deserialize ciphertext from {:?}: {:?}",
|
|
|
|
proposer_id, err
|
|
|
|
);
|
|
|
|
let fault_kind = FaultKind::InvalidCiphertext;
|
|
|
|
step.fault_log.append(proposer_id, fault_kind);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
2018-08-03 02:18:06 -07:00
|
|
|
let netinfo = self.netinfo.clone();
|
|
|
|
let td_step = match self
|
|
|
|
.threshold_decryption
|
|
|
|
.entry(epoch)
|
|
|
|
.or_insert_with(BTreeMap::new)
|
|
|
|
.entry(proposer_id.clone())
|
|
|
|
.or_insert_with(|| ThresholdDecryption::new(netinfo))
|
|
|
|
.input(ciphertext)
|
|
|
|
{
|
|
|
|
Ok(td_step) => td_step,
|
|
|
|
Err(td::Error::InvalidCiphertext(_)) => {
|
|
|
|
warn!("Invalid ciphertext from {:?}", proposer_id);
|
|
|
|
let fault_kind = FaultKind::ShareDecryptionFailed;
|
|
|
|
step.fault_log.append(proposer_id.clone(), fault_kind);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Err(err) => return Err(ErrorKind::ThresholdDecryption(err).into()),
|
|
|
|
};
|
|
|
|
step.extend(self.process_threshold_decryption(epoch, proposer_id, td_step)?);
|
2018-06-19 07:17:16 -07:00
|
|
|
}
|
2018-07-23 09:11:45 -07:00
|
|
|
if epoch == self.epoch {
|
2018-07-23 12:36:09 -07:00
|
|
|
step.extend(self.try_output_batches()?);
|
2018-07-23 09:11:45 -07:00
|
|
|
}
|
|
|
|
Ok(step)
|
2018-06-19 07:17:16 -07:00
|
|
|
}
|
|
|
|
|
2018-07-18 05:15:47 -07:00
|
|
|
/// Checks whether the current epoch has output, and if it does, sends out our decryption
|
|
|
|
/// shares. The `epoch` argument allows to differentiate between calls which produce output in
|
|
|
|
/// all conditions, `epoch == None`, and calls which only produce output in a given epoch,
|
|
|
|
/// `epoch == Some(given_epoch)`.
|
2018-07-09 04:35:26 -07:00
|
|
|
fn process_output(
|
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
cs_step: common_subset::Step<N>,
|
2018-07-23 09:11:45 -07:00
|
|
|
epoch: u64,
|
2018-08-02 14:27:55 -07:00
|
|
|
) -> Result<Step<C, N>> {
|
2018-07-23 09:11:45 -07:00
|
|
|
let mut step = Step::default();
|
2018-07-23 12:36:09 -07:00
|
|
|
let mut cs_outputs = step.extend_with(cs_step, |cs_msg| {
|
2018-07-23 09:11:45 -07:00
|
|
|
MessageContent::CommonSubset(cs_msg).with_epoch(epoch)
|
|
|
|
});
|
2018-07-23 12:36:09 -07:00
|
|
|
if let Some(cs_output) = cs_outputs.pop_front() {
|
2018-07-23 09:11:45 -07:00
|
|
|
// There is at most one output.
|
|
|
|
step.extend(self.send_decryption_shares(cs_output, epoch)?);
|
2018-06-19 07:17:16 -07:00
|
|
|
}
|
2018-07-23 12:36:09 -07:00
|
|
|
if !cs_outputs.is_empty() {
|
|
|
|
error!("Multiple outputs from a single Common Subset instance.");
|
|
|
|
}
|
2018-07-23 09:11:45 -07:00
|
|
|
Ok(step)
|
2018-06-19 07:17:16 -07:00
|
|
|
}
|
2018-05-12 07:09:07 -07:00
|
|
|
}
|