2018-08-02 11:11:32 -07:00
|
|
|
use rand::Rand;
|
|
|
|
use std::sync::Arc;
|
2018-10-02 07:24:51 -07:00
|
|
|
use std::{fmt, mem};
|
2018-08-02 11:11:32 -07:00
|
|
|
|
|
|
|
use bincode;
|
|
|
|
use crypto::Signature;
|
2018-10-02 07:24:51 -07:00
|
|
|
use rand;
|
2018-08-02 11:11:32 -07:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
use super::votes::{SignedVote, VoteCounter};
|
|
|
|
use super::{
|
|
|
|
Batch, Change, ChangeState, DynamicHoneyBadgerBuilder, Error, ErrorKind, Input,
|
|
|
|
InternalContrib, KeyGenMessage, KeyGenState, Message, Result, SignedKeyGenMsg, Step,
|
|
|
|
};
|
|
|
|
use fault_log::{Fault, FaultKind, FaultLog};
|
|
|
|
use honey_badger::{self, HoneyBadger, Message as HbMessage};
|
|
|
|
use messaging::{DistAlgorithm, NetworkInfo, Target};
|
|
|
|
use sync_key_gen::{Ack, Part, PartOutcome, SyncKeyGen};
|
2018-08-29 09:08:35 -07:00
|
|
|
use traits::{Contribution, NodeIdT};
|
2018-10-02 07:24:51 -07:00
|
|
|
use util::SubRng;
|
2018-08-02 11:11:32 -07:00
|
|
|
|
|
|
|
/// A Honey Badger instance that can handle adding and removing nodes.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub struct DynamicHoneyBadger<C, N: Rand> {
|
2018-08-02 11:11:32 -07:00
|
|
|
/// Shared network data.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) netinfo: NetworkInfo<N>,
|
2018-08-02 11:11:32 -07:00
|
|
|
/// The maximum number of future epochs for which we handle messages simultaneously.
|
|
|
|
pub(super) max_future_epochs: usize,
|
|
|
|
/// The first epoch after the latest node change.
|
|
|
|
pub(super) start_epoch: u64,
|
|
|
|
/// The buffer and counter for the pending and committed change votes.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) vote_counter: VoteCounter<N>,
|
2018-08-02 11:11:32 -07:00
|
|
|
/// Pending node transactions that we will propose in the next epoch.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) key_gen_msg_buffer: Vec<SignedKeyGenMsg<N>>,
|
2018-08-02 11:11:32 -07:00
|
|
|
/// The `HoneyBadger` instance with the current set of nodes.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) honey_badger: HoneyBadger<InternalContrib<C, N>, N>,
|
2018-08-02 11:11:32 -07:00
|
|
|
/// The current key generation process, and the change it applies to.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) key_gen_state: Option<KeyGenState<N>>,
|
2018-08-02 11:11:32 -07:00
|
|
|
/// A queue for messages from future epochs that cannot be handled yet.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) incoming_queue: Vec<(N, Message<N>)>,
|
2018-10-02 07:24:51 -07:00
|
|
|
/// A random number generator used for secret key generation.
|
|
|
|
// Boxed to avoid overloading the algorithm's type with more generics.
|
|
|
|
pub(super) rng: Box<dyn rand::Rng>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<C, N> fmt::Debug for DynamicHoneyBadger<C, N>
|
|
|
|
where
|
|
|
|
C: fmt::Debug,
|
|
|
|
N: Rand + fmt::Debug,
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_struct("DynamicHoneyBadger")
|
|
|
|
.field("netinfo", &self.netinfo)
|
|
|
|
.field("max_future_epochs", &self.max_future_epochs)
|
|
|
|
.field("start_epoch", &self.start_epoch)
|
|
|
|
.field("vote_counter", &self.vote_counter)
|
|
|
|
.field("key_gen_msg_buffer", &self.key_gen_msg_buffer)
|
|
|
|
.field("honey_badger", &self.honey_badger)
|
|
|
|
.field("key_gen_state", &self.key_gen_state)
|
|
|
|
.field("incoming_queue", &self.incoming_queue)
|
|
|
|
.field("rng", &"<RNG>")
|
|
|
|
.finish()
|
|
|
|
}
|
2018-08-02 11:11:32 -07:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
impl<C, N> DistAlgorithm for DynamicHoneyBadger<C, N>
|
2018-08-02 11:11:32 -07:00
|
|
|
where
|
2018-08-02 14:27:55 -07:00
|
|
|
C: Contribution + Serialize + for<'r> Deserialize<'r>,
|
2018-08-29 09:08:35 -07:00
|
|
|
N: NodeIdT + Serialize + for<'r> Deserialize<'r> + Rand,
|
2018-08-02 11:11:32 -07:00
|
|
|
{
|
2018-08-29 09:08:35 -07:00
|
|
|
type NodeId = N;
|
2018-08-02 14:27:55 -07:00
|
|
|
type Input = Input<C, N>;
|
|
|
|
type Output = Batch<C, N>;
|
|
|
|
type Message = Message<N>;
|
2018-08-02 11:11:32 -07:00
|
|
|
type Error = Error;
|
|
|
|
|
2018-08-29 08:28:02 -07:00
|
|
|
fn handle_input(&mut self, input: Self::Input) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
// User contributions are forwarded to `HoneyBadger` right away. Votes are signed and
|
|
|
|
// broadcast.
|
|
|
|
match input {
|
|
|
|
Input::User(contrib) => self.propose(contrib),
|
|
|
|
Input::Change(change) => self.vote_for(change),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-02 11:11:32 -07:00
|
|
|
let epoch = message.start_epoch();
|
|
|
|
if epoch < self.start_epoch {
|
|
|
|
// Obsolete message.
|
|
|
|
Ok(Step::default())
|
|
|
|
} else if epoch > self.start_epoch {
|
|
|
|
// Message cannot be handled yet. Save it for later.
|
|
|
|
let entry = (sender_id.clone(), message);
|
|
|
|
self.incoming_queue.push(entry);
|
|
|
|
Ok(Step::default())
|
|
|
|
} else {
|
|
|
|
match message {
|
|
|
|
Message::HoneyBadger(_, hb_msg) => {
|
|
|
|
self.handle_honey_badger_message(sender_id, hb_msg)
|
|
|
|
}
|
|
|
|
Message::KeyGen(_, kg_msg, sig) => self
|
|
|
|
.handle_key_gen_message(sender_id, kg_msg, *sig)
|
|
|
|
.map(FaultLog::into),
|
|
|
|
Message::SignedVote(signed_vote) => self
|
|
|
|
.vote_counter
|
|
|
|
.add_pending_vote(sender_id, signed_vote)
|
|
|
|
.map(FaultLog::into),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn terminated(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
fn our_id(&self) -> &N {
|
2018-08-29 09:08:35 -07:00
|
|
|
self.netinfo.our_id()
|
2018-08-02 11:11:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:27:55 -07:00
|
|
|
impl<C, N> DynamicHoneyBadger<C, N>
|
2018-08-02 11:11:32 -07:00
|
|
|
where
|
2018-08-02 14:27:55 -07:00
|
|
|
C: Contribution + Serialize + for<'r> Deserialize<'r>,
|
2018-08-29 09:08:35 -07:00
|
|
|
N: NodeIdT + Serialize + for<'r> Deserialize<'r> + Rand,
|
2018-08-02 11:11:32 -07:00
|
|
|
{
|
|
|
|
/// Returns a new `DynamicHoneyBadgerBuilder`.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub fn builder() -> DynamicHoneyBadgerBuilder<C, N> {
|
2018-08-02 11:11:32 -07:00
|
|
|
DynamicHoneyBadgerBuilder::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `true` if input for the current epoch has already been provided.
|
|
|
|
pub fn has_input(&self) -> bool {
|
|
|
|
self.honey_badger.has_input()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Proposes a contribution in the current epoch.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub fn propose(&mut self, contrib: C) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
let step = self
|
|
|
|
.honey_badger
|
2018-08-29 08:28:02 -07:00
|
|
|
.handle_input(InternalContrib {
|
2018-08-02 11:11:32 -07:00
|
|
|
contrib,
|
|
|
|
key_gen_messages: self.key_gen_msg_buffer.clone(),
|
|
|
|
votes: self.vote_counter.pending_votes().cloned().collect(),
|
2018-08-31 06:57:10 -07:00
|
|
|
}).map_err(ErrorKind::ProposeHoneyBadger)?;
|
2018-08-02 11:11:32 -07:00
|
|
|
self.process_output(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Cast a vote to change the set of validators.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub fn vote_for(&mut self, change: Change<N>) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
if !self.netinfo.is_validator() {
|
|
|
|
return Ok(Step::default()); // TODO: Return an error?
|
|
|
|
}
|
|
|
|
let signed_vote = self.vote_counter.sign_vote_for(change)?.clone();
|
|
|
|
let msg = Message::SignedVote(signed_vote);
|
|
|
|
Ok(Target::All.message(msg).into())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the information about the node IDs in the network, and the cryptographic keys.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub fn netinfo(&self) -> &NetworkInfo<N> {
|
2018-08-02 11:11:32 -07:00
|
|
|
&self.netinfo
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `true` if we should make our contribution for the next epoch, even if we don't have
|
|
|
|
/// content ourselves, to avoid stalling the network.
|
|
|
|
///
|
|
|
|
/// By proposing only if this returns `true`, you can prevent an adversary from making the
|
|
|
|
/// network output empty baches indefinitely, but it also means that the network won't advance
|
|
|
|
/// if fewer than _f + 1_ nodes have pending contributions.
|
|
|
|
pub fn should_propose(&self) -> bool {
|
|
|
|
if self.has_input() {
|
|
|
|
return false; // We have already proposed.
|
|
|
|
}
|
|
|
|
if self.honey_badger.received_proposals() > self.netinfo.num_faulty() {
|
|
|
|
return true; // At least one correct node wants to move on to the next epoch.
|
|
|
|
}
|
|
|
|
let is_our_vote = |signed_vote: &SignedVote<_>| signed_vote.voter() == self.our_id();
|
|
|
|
if self.vote_counter.pending_votes().any(is_our_vote) {
|
|
|
|
return true; // We have pending input to vote for a validator change.
|
|
|
|
}
|
|
|
|
let kgs = match self.key_gen_state {
|
|
|
|
None => return false, // No ongoing key generation.
|
|
|
|
Some(ref kgs) => kgs,
|
|
|
|
};
|
|
|
|
// If either we or the candidate have a pending key gen message, we should propose.
|
|
|
|
let ours_or_candidates = |msg: &SignedKeyGenMsg<_>| {
|
|
|
|
msg.1 == *self.our_id() || Some(&msg.1) == kgs.change.candidate()
|
|
|
|
};
|
|
|
|
self.key_gen_msg_buffer.iter().any(ours_or_candidates)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles a message for the `HoneyBadger` instance.
|
|
|
|
fn handle_honey_badger_message(
|
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
sender_id: &N,
|
|
|
|
message: HbMessage<N>,
|
|
|
|
) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
// Handle the message.
|
|
|
|
let step = self
|
|
|
|
.honey_badger
|
|
|
|
.handle_message(sender_id, message)
|
|
|
|
.map_err(ErrorKind::HandleHoneyBadgerMessageHoneyBadger)?;
|
|
|
|
self.process_output(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles a vote or key generation message and tries to commit it as a transaction. These
|
|
|
|
/// messages are only handled once they appear in a batch output from Honey Badger.
|
|
|
|
fn handle_key_gen_message(
|
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
sender_id: &N,
|
2018-08-02 11:11:32 -07:00
|
|
|
kg_msg: KeyGenMessage,
|
|
|
|
sig: Signature,
|
2018-08-02 14:27:55 -07:00
|
|
|
) -> Result<FaultLog<N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
if !self.verify_signature(sender_id, &sig, &kg_msg)? {
|
|
|
|
info!("Invalid signature from {:?} for: {:?}.", sender_id, kg_msg);
|
|
|
|
let fault_kind = FaultKind::InvalidKeyGenMessageSignature;
|
|
|
|
return Ok(Fault::new(sender_id.clone(), fault_kind).into());
|
|
|
|
}
|
|
|
|
let kgs = match self.key_gen_state {
|
|
|
|
Some(ref mut kgs) => kgs,
|
|
|
|
None => {
|
|
|
|
info!(
|
|
|
|
"Unexpected key gen message from {:?}: {:?}.",
|
|
|
|
sender_id, kg_msg
|
|
|
|
);
|
|
|
|
return Ok(Fault::new(sender_id.clone(), FaultKind::UnexpectedKeyGenMessage).into());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// If the joining node is correct, it will send at most (N + 1)² + 1 key generation
|
|
|
|
// messages.
|
|
|
|
if Some(sender_id) == kgs.change.candidate() {
|
|
|
|
let n = self.netinfo.num_nodes() + 1;
|
|
|
|
if kgs.candidate_msg_count > n * n {
|
|
|
|
info!(
|
|
|
|
"Too many key gen messages from candidate {:?}: {:?}.",
|
|
|
|
sender_id, kg_msg
|
|
|
|
);
|
|
|
|
let fault_kind = FaultKind::TooManyCandidateKeyGenMessages;
|
|
|
|
return Ok(Fault::new(sender_id.clone(), fault_kind).into());
|
|
|
|
}
|
|
|
|
kgs.candidate_msg_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
let tx = SignedKeyGenMsg(self.start_epoch, sender_id.clone(), kg_msg, sig);
|
|
|
|
self.key_gen_msg_buffer.push(tx);
|
|
|
|
Ok(FaultLog::default())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Processes all pending batches output by Honey Badger.
|
2018-09-03 03:29:03 -07:00
|
|
|
pub(super) fn process_output(
|
2018-08-02 11:11:32 -07:00
|
|
|
&mut self,
|
2018-08-02 14:27:55 -07:00
|
|
|
hb_step: honey_badger::Step<InternalContrib<C, N>, N>,
|
|
|
|
) -> Result<Step<C, N>> {
|
|
|
|
let mut step: Step<C, N> = Step::default();
|
2018-08-02 11:11:32 -07:00
|
|
|
let start_epoch = self.start_epoch;
|
|
|
|
let output = step.extend_with(hb_step, |hb_msg| Message::HoneyBadger(start_epoch, hb_msg));
|
|
|
|
for hb_batch in output {
|
|
|
|
// Create the batch we output ourselves. It will contain the _user_ transactions of
|
|
|
|
// `hb_batch`, and the current change state.
|
|
|
|
let mut batch = Batch::new(hb_batch.epoch + self.start_epoch);
|
|
|
|
|
|
|
|
// Add the user transactions to `batch` and handle votes and DKG messages.
|
|
|
|
for (id, int_contrib) in hb_batch.contributions {
|
|
|
|
let InternalContrib {
|
|
|
|
votes,
|
|
|
|
key_gen_messages,
|
|
|
|
contrib,
|
|
|
|
} = int_contrib;
|
|
|
|
step.fault_log
|
|
|
|
.extend(self.vote_counter.add_committed_votes(&id, votes)?);
|
|
|
|
batch.contributions.insert(id.clone(), contrib);
|
|
|
|
self.key_gen_msg_buffer
|
|
|
|
.retain(|skgm| !key_gen_messages.contains(skgm));
|
|
|
|
for SignedKeyGenMsg(epoch, s_id, kg_msg, sig) in key_gen_messages {
|
|
|
|
if epoch < self.start_epoch {
|
|
|
|
info!("Obsolete key generation message: {:?}.", kg_msg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if !self.verify_signature(&s_id, &sig, &kg_msg)? {
|
|
|
|
info!(
|
|
|
|
"Invalid signature in {:?}'s batch from {:?} for: {:?}.",
|
|
|
|
id, s_id, kg_msg
|
|
|
|
);
|
|
|
|
let fault_kind = FaultKind::InvalidKeyGenMessageSignature;
|
|
|
|
step.fault_log.append(id.clone(), fault_kind);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
step.extend(match kg_msg {
|
|
|
|
KeyGenMessage::Part(part) => self.handle_part(&s_id, part)?,
|
|
|
|
KeyGenMessage::Ack(ack) => self.handle_ack(&s_id, ack)?.into(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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!", self.our_id(), kgs.change);
|
2018-08-06 07:53:37 -07:00
|
|
|
self.netinfo = kgs.key_gen.into_network_info()?;
|
2018-09-03 03:29:03 -07:00
|
|
|
let step_on_restart = self.restart_honey_badger(batch.epoch + 1)?;
|
|
|
|
step.extend(step_on_restart);
|
2018-08-02 11:11:32 -07:00
|
|
|
batch.set_change(ChangeState::Complete(kgs.change), &self.netinfo);
|
|
|
|
} else if let Some(change) = self.vote_counter.compute_winner().cloned() {
|
|
|
|
// If there is a new change, restart DKG. Inform the user about the current change.
|
|
|
|
step.extend(self.update_key_gen(batch.epoch + 1, &change)?);
|
|
|
|
batch.set_change(ChangeState::InProgress(change), &self.netinfo);
|
|
|
|
}
|
|
|
|
step.output.push_back(batch);
|
|
|
|
}
|
|
|
|
// If `start_epoch` changed, we can now handle some queued messages.
|
|
|
|
if start_epoch < self.start_epoch {
|
|
|
|
let queue = mem::replace(&mut self.incoming_queue, Vec::new());
|
|
|
|
for (sender_id, msg) in queue {
|
|
|
|
step.extend(self.handle_message(&sender_id, msg)?);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the winner of the vote has changed, restarts Key Generation for the set of nodes implied
|
|
|
|
/// by the current change.
|
2018-08-02 14:27:55 -07:00
|
|
|
pub(super) fn update_key_gen(&mut self, epoch: u64, change: &Change<N>) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
if self.key_gen_state.as_ref().map(|kgs| &kgs.change) == Some(change) {
|
|
|
|
return Ok(Step::default()); // The change is the same as before. Continue DKG as is.
|
|
|
|
}
|
|
|
|
debug!("{:?} Restarting DKG for {:?}.", self.our_id(), change);
|
|
|
|
// Use the existing key shares - with the change applied - as keys for DKG.
|
|
|
|
let mut pub_keys = self.netinfo.public_key_map().clone();
|
|
|
|
if match *change {
|
|
|
|
Change::Remove(ref id) => pub_keys.remove(id).is_none(),
|
|
|
|
Change::Add(ref id, ref pk) => pub_keys.insert(id.clone(), pk.clone()).is_some(),
|
|
|
|
} {
|
|
|
|
info!("{:?} No-op change: {:?}", self.our_id(), change);
|
|
|
|
}
|
2018-09-03 03:29:03 -07:00
|
|
|
let mut step = self.restart_honey_badger(epoch)?;
|
2018-08-02 11:11:32 -07:00
|
|
|
// TODO: This needs to be the same as `num_faulty` will be in the _new_
|
|
|
|
// `NetworkInfo` if the change goes through. It would be safer to deduplicate.
|
|
|
|
let threshold = (pub_keys.len() - 1) / 3;
|
|
|
|
let sk = self.netinfo.secret_key().clone();
|
2018-08-29 09:08:35 -07:00
|
|
|
let our_id = self.our_id().clone();
|
2018-10-02 07:24:51 -07:00
|
|
|
let (key_gen, part) = SyncKeyGen::new(&mut self.rng, our_id, sk, pub_keys, threshold)?;
|
2018-08-02 11:11:32 -07:00
|
|
|
self.key_gen_state = Some(KeyGenState::new(key_gen, change.clone()));
|
|
|
|
if let Some(part) = part {
|
2018-09-03 03:29:03 -07:00
|
|
|
let step_on_send = self.send_transaction(KeyGenMessage::Part(part))?;
|
|
|
|
step.extend(step_on_send);
|
2018-08-02 11:11:32 -07:00
|
|
|
}
|
2018-09-03 03:29:03 -07:00
|
|
|
Ok(step)
|
2018-08-02 11:11:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts a new `HoneyBadger` instance and resets the vote counter.
|
2018-09-03 03:29:03 -07:00
|
|
|
fn restart_honey_badger(&mut self, epoch: u64) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
self.start_epoch = epoch;
|
|
|
|
self.key_gen_msg_buffer.retain(|kg_msg| kg_msg.0 >= epoch);
|
|
|
|
let netinfo = Arc::new(self.netinfo.clone());
|
|
|
|
let counter = VoteCounter::new(netinfo.clone(), epoch);
|
|
|
|
mem::replace(&mut self.vote_counter, counter);
|
2018-09-03 03:29:03 -07:00
|
|
|
let (hb, hb_step) = HoneyBadger::builder(netinfo)
|
2018-08-02 11:11:32 -07:00
|
|
|
.max_future_epochs(self.max_future_epochs)
|
2018-10-02 07:24:51 -07:00
|
|
|
.rng(self.rng.sub_rng())
|
2018-08-02 11:11:32 -07:00
|
|
|
.build();
|
2018-09-03 03:29:03 -07:00
|
|
|
self.honey_badger = hb;
|
|
|
|
self.process_output(hb_step)
|
2018-08-02 11:11:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles a `Part` message that was output by Honey Badger.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn handle_part(&mut self, sender_id: &N, part: Part) -> Result<Step<C, N>> {
|
2018-10-02 07:24:51 -07:00
|
|
|
// Awkward construction due to borrowck shortcomings; we need to borrow two struct fields
|
|
|
|
// mutably and have the borrow end early enough for us to call `send_transaction`.
|
|
|
|
// FIXME: This part should be cleaned up and restructured.
|
|
|
|
let res = {
|
|
|
|
let kgs = self.key_gen_state.as_mut();
|
|
|
|
let rng = &mut self.rng;
|
|
|
|
let handle = |kgs: &mut KeyGenState<N>| kgs.key_gen.handle_part(rng, &sender_id, part);
|
|
|
|
kgs.and_then(handle)
|
|
|
|
};
|
|
|
|
|
|
|
|
match res {
|
2018-08-02 11:11:32 -07:00
|
|
|
Some(PartOutcome::Valid(ack)) => self.send_transaction(KeyGenMessage::Ack(ack)),
|
|
|
|
Some(PartOutcome::Invalid(fault_log)) => Ok(fault_log.into()),
|
|
|
|
None => Ok(Step::default()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles an `Ack` message that was output by Honey Badger.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn handle_ack(&mut self, sender_id: &N, ack: Ack) -> Result<FaultLog<N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
if let Some(kgs) = self.key_gen_state.as_mut() {
|
|
|
|
Ok(kgs.key_gen.handle_ack(sender_id, ack))
|
|
|
|
} else {
|
|
|
|
Ok(FaultLog::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Signs and sends a `KeyGenMessage` and also tries to commit it.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn send_transaction(&mut self, kg_msg: KeyGenMessage) -> Result<Step<C, N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
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() {
|
2018-08-29 09:08:35 -07:00
|
|
|
let our_id = self.netinfo.our_id().clone();
|
2018-08-02 11:11:32 -07:00
|
|
|
let signed_msg =
|
2018-08-29 09:08:35 -07:00
|
|
|
SignedKeyGenMsg(self.start_epoch, our_id, kg_msg.clone(), *sig.clone());
|
2018-08-02 11:11:32 -07:00
|
|
|
self.key_gen_msg_buffer.push(signed_msg);
|
|
|
|
}
|
|
|
|
let msg = Message::KeyGen(self.start_epoch, kg_msg, sig);
|
|
|
|
Ok(Target::All.message(msg).into())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the current Key Generation process is ready, returns the `KeyGenState`.
|
|
|
|
///
|
|
|
|
/// We require the minimum number of completed proposals (`SyncKeyGen::is_ready`) and if a new
|
|
|
|
/// node is joining, we require in addition that the new node's proposal is complete. That way
|
|
|
|
/// the new node knows that it's key is secret, without having to trust any number of nodes.
|
2018-08-02 14:27:55 -07:00
|
|
|
fn take_ready_key_gen(&mut self) -> Option<KeyGenState<N>> {
|
2018-08-02 11:11:32 -07:00
|
|
|
if self
|
|
|
|
.key_gen_state
|
|
|
|
.as_ref()
|
|
|
|
.map_or(false, KeyGenState::is_ready)
|
|
|
|
{
|
|
|
|
self.key_gen_state.take()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `true` if the signature of `kg_msg` by the node with the specified ID is valid.
|
|
|
|
/// Returns an error if the payload fails to serialize.
|
|
|
|
///
|
|
|
|
/// This accepts signatures from both validators and the currently joining candidate, if any.
|
|
|
|
fn verify_signature(
|
|
|
|
&self,
|
2018-08-02 14:27:55 -07:00
|
|
|
node_id: &N,
|
2018-08-02 11:11:32 -07:00
|
|
|
sig: &Signature,
|
|
|
|
kg_msg: &KeyGenMessage,
|
|
|
|
) -> Result<bool> {
|
|
|
|
let ser =
|
|
|
|
bincode::serialize(kg_msg).map_err(|err| ErrorKind::VerifySignatureBincode(*err))?;
|
|
|
|
let get_candidate_key = || {
|
|
|
|
self.key_gen_state
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|kgs| kgs.candidate_key(node_id))
|
|
|
|
};
|
|
|
|
let pk_opt = self.netinfo.public_key(node_id).or_else(get_candidate_key);
|
|
|
|
Ok(pk_opt.map_or(false, |pk| pk.verify(&sig, ser)))
|
|
|
|
}
|
|
|
|
}
|