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-07-11 12:15:08 -07:00
|
|
|
use std::sync::Arc;
|
2018-05-12 07:09:07 -07:00
|
|
|
|
|
|
|
use bincode;
|
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-08-03 06:24:49 -07:00
|
|
|
use super::epoch_state::EpochState;
|
2018-07-31 13:27:22 -07:00
|
|
|
use super::{Batch, Error, ErrorKind, HoneyBadgerBuilder, Message, MessageContent, Result};
|
2018-08-03 02:18:06 -07:00
|
|
|
use messaging::{self, DistAlgorithm, NetworkInfo};
|
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-08-03 06:24:49 -07:00
|
|
|
/// The subalgorithms for ongoing epochs.
|
|
|
|
pub(super) epochs: BTreeMap<u64, EpochState<C, 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-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-08-07 09:25:50 -07:00
|
|
|
self.handle_message(sender_id, message)
|
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-08-03 06:24:49 -07:00
|
|
|
self.has_input = true;
|
|
|
|
let ser_prop =
|
|
|
|
bincode::serialize(&proposal).map_err(|err| ErrorKind::ProposeBincode(*err))?;
|
|
|
|
let ciphertext = self.netinfo.public_key_set().public_key().encrypt(ser_prop);
|
2018-08-07 09:25:50 -07:00
|
|
|
let epoch = self.epoch;
|
|
|
|
let mut step = self.epoch_state_mut(epoch)?.propose(&ciphertext)?;
|
2018-08-03 06:24:49 -07:00
|
|
|
step.extend(self.try_output_batches()?);
|
|
|
|
Ok(step)
|
2018-05-12 07:09:07 -07:00
|
|
|
}
|
|
|
|
|
2018-08-07 09:25:50 -07:00
|
|
|
/// Handles a message received from `sender_id`.
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
let Message { epoch, content } = message;
|
|
|
|
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));
|
|
|
|
} else if epoch == self.epoch {
|
|
|
|
let mut step = self
|
|
|
|
.epoch_state_mut(epoch)?
|
|
|
|
.handle_message_content(sender_id, content)?;
|
|
|
|
step.extend(self.try_output_batches()?);
|
|
|
|
return Ok(step);
|
|
|
|
} // And ignore all messages from past epochs.
|
|
|
|
Ok(Step::default())
|
|
|
|
}
|
|
|
|
|
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 {
|
2018-08-03 06:24:49 -07:00
|
|
|
self.epochs
|
2018-08-01 01:41:09 -07:00
|
|
|
.get(&self.epoch)
|
2018-08-03 06:24:49 -07:00
|
|
|
.map_or(0, EpochState::received_proposals)
|
2018-08-01 01:41:09 -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 06:24:49 -07:00
|
|
|
self.epochs.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-08-07 09:25:50 -07:00
|
|
|
if let Some(messages) = self.incoming_queue.remove(&max_epoch) {
|
|
|
|
let epoch_state = self.epoch_state_mut(max_epoch)?;
|
|
|
|
for (sender_id, content) in messages {
|
|
|
|
step.extend(epoch_state.handle_message_content(&sender_id, content)?);
|
|
|
|
}
|
2018-06-28 08:17:07 -07:00
|
|
|
}
|
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();
|
2018-08-03 06:24:49 -07:00
|
|
|
while let Some((batch, fault_log)) = self
|
|
|
|
.epochs
|
|
|
|
.get(&self.epoch)
|
|
|
|
.and_then(EpochState::try_output_batch)
|
|
|
|
{
|
|
|
|
// Queue the output and advance the epoch.
|
|
|
|
step.output.push_back(batch);
|
|
|
|
step.fault_log.extend(fault_log);
|
|
|
|
step.extend(self.update_epoch()?);
|
2018-07-23 12:36:09 -07:00
|
|
|
}
|
2018-07-23 09:11:45 -07:00
|
|
|
Ok(step)
|
2018-06-19 07:17:16 -07:00
|
|
|
}
|
2018-08-07 09:25:50 -07:00
|
|
|
|
|
|
|
/// Returns a mutable reference to the state of the given `epoch`. Initializes a new one, if it
|
|
|
|
/// doesn't exist yet.
|
|
|
|
fn epoch_state_mut(&mut self, epoch: u64) -> Result<&mut EpochState<C, N>> {
|
|
|
|
Ok(match self.epochs.entry(epoch) {
|
|
|
|
Entry::Occupied(entry) => entry.into_mut(),
|
|
|
|
Entry::Vacant(entry) => entry.insert(EpochState::new(self.netinfo.clone(), epoch)?),
|
|
|
|
})
|
|
|
|
}
|
2018-05-12 07:09:07 -07:00
|
|
|
}
|