Add SenderQueue convenience methods for voting.

This commit is contained in:
Andreas Fackler 2018-11-06 10:17:11 +01:00 committed by Andreas Fackler
parent 2456db2d9e
commit b71f9142f6
5 changed files with 159 additions and 12 deletions

View File

@ -3,7 +3,7 @@ use std::sync::Arc;
use std::{fmt, result};
use bincode;
use crypto::Signature;
use crypto::{PublicKey, Signature};
use derivative::Derivative;
use log::{debug, warn};
use rand::{self, Rand};
@ -118,7 +118,7 @@ where
self.process_output(step)
}
/// Casts a vote to change the set of validators.
/// Casts a vote to change the set of validators or parameters.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
@ -131,6 +131,22 @@ where
Ok(Target::All.message(msg).into())
}
/// Casts a vote to add a node as a validator.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_add(&mut self, node_id: N, pub_key: PublicKey) -> Result<Step<C, N>> {
self.vote_for(Change::NodeChange(NodeChange::Add(node_id, pub_key)))
}
/// Casts a vote to demote a validator to observer.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_remove(&mut self, node_id: N) -> Result<Step<C, N>> {
self.vote_for(Change::NodeChange(NodeChange::Remove(node_id)))
}
/// Handles a message received from `sender_id`.
///
/// This must be called with every message we receive from another node.

View File

@ -28,6 +28,7 @@ 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 rand::{Rand, Rng};
@ -262,6 +263,22 @@ where
.join(self.propose()?))
}
/// Casts a vote to add a node as a validator.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_add(&mut self, node_id: N, pub_key: PublicKey) -> Result<Step<T, N, Q>> {
self.vote_for(Change::NodeChange(NodeChange::Add(node_id, pub_key)))
}
/// Casts a vote to demote a validator to observer.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_remove(&mut self, node_id: N) -> Result<Step<T, N, Q>> {
self.vote_for(Change::NodeChange(NodeChange::Remove(node_id)))
}
/// Handles a message received from `sender_id`.
///
/// This must be called with every message we receive from another node.

View File

@ -0,0 +1,51 @@
//! Convenience methods for a `SenderQueue` wrapping a `DynamicHoneyBadger`.
use crypto::PublicKey;
use rand::Rand;
use serde::{de::DeserializeOwned, Serialize};
use super::{SenderQueue, Step};
use dynamic_honey_badger::{Change, DynamicHoneyBadger};
use {Contribution, NodeIdT};
type Result<C, N> = super::Result<Step<DynamicHoneyBadger<C, N>>, DynamicHoneyBadger<C, N>>;
impl<C, N> SenderQueue<DynamicHoneyBadger<C, N>>
where
C: Contribution + Serialize + DeserializeOwned,
N: NodeIdT + Serialize + DeserializeOwned + Rand,
{
/// Proposes a contribution in the current epoch.
///
/// Returns an error if we already made a proposal in this epoch.
///
/// If we are the only validator, this will immediately output a batch, containing our
/// proposal.
pub fn propose(&mut self, contrib: C) -> Result<C, N> {
self.apply(|algo| algo.propose(contrib))
}
/// Casts a vote to change the set of validators or parameters.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_for(&mut self, change: Change<N>) -> Result<C, N> {
self.apply(|algo| algo.vote_for(change))
}
/// Casts a vote to add a node as a validator.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_add(&mut self, node_id: N, pub_key: PublicKey) -> Result<C, N> {
self.apply(|algo| algo.vote_to_add(node_id, pub_key))
}
/// Casts a vote to demote a validator to observer.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_remove(&mut self, node_id: N) -> Result<C, N> {
self.apply(|algo| algo.vote_to_remove(node_id))
}
}

View File

@ -5,7 +5,9 @@
//! 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 message;
mod queueing_honey_badger;
use std::collections::BTreeMap;
use std::fmt::Debug;
@ -155,11 +157,7 @@ where
}
pub fn handle_input(&mut self, input: D::Input) -> Result<Step<D>, D> {
let mut step = self.algo.handle_input(input)?;
let mut sender_queue_step = self.update_lin_epoch(&step);
self.defer_messages(&mut step);
sender_queue_step.extend(step.map(|output| output, Message::from));
Ok(sender_queue_step)
self.apply(|algo| algo.handle_input(input))
}
pub fn handle_message(
@ -173,6 +171,19 @@ where
}
}
/// Applies `f` to the wrapped algorithm and converts the step in the result to a sender queue
/// step, deferring or dropping messages, where necessary.
pub fn apply<F>(&mut self, f: F) -> Result<Step<D>, D>
where
F: FnOnce(&mut D) -> Result<::Step<D>, D>,
{
let mut step = f(&mut self.algo)?;
let mut sender_queue_step = self.update_lin_epoch(&step);
self.defer_messages(&mut step);
sender_queue_step.extend(step.map(|output| output, Message::from));
Ok(sender_queue_step)
}
/// Handles an epoch start announcement.
fn handle_epoch_started(
&mut self,
@ -239,11 +250,7 @@ where
sender_id: &D::NodeId,
content: D::Message,
) -> Result<Step<D>, D> {
let mut step = self.algo.handle_message(sender_id, content)?;
let mut sender_queue_step = self.update_lin_epoch(&step);
self.defer_messages(&mut step);
sender_queue_step.extend(step.map(|output| output, Message::from));
Ok(sender_queue_step)
self.apply(|algo| algo.handle_message(sender_id, content))
}
/// Updates the current Honey Badger epoch.

View File

@ -0,0 +1,56 @@
//! Convenience methods for a `SenderQueue` wrapping a `QueueingHoneyBadger`.
use crypto::PublicKey;
use rand::Rand;
use serde::{de::DeserializeOwned, Serialize};
use super::{SenderQueue, Step};
use queueing_honey_badger::{Change, QueueingHoneyBadger};
use transaction_queue::TransactionQueue;
use {Contribution, NodeIdT};
type Result<T, N, Q> =
super::Result<Step<QueueingHoneyBadger<T, N, Q>>, QueueingHoneyBadger<T, N, Q>>;
impl<T, N, Q> SenderQueue<QueueingHoneyBadger<T, N, Q>>
where
T: Contribution + Serialize + DeserializeOwned + Clone,
N: NodeIdT + Serialize + DeserializeOwned + Rand,
Q: TransactionQueue<T>,
{
/// Adds a transaction to the queue.
///
/// This can be called at any time to append to the transaction queue. The new transaction will
/// be proposed in some future epoch.
///
/// If no proposal has yet been made for the current epoch, this may trigger one. In this case,
/// a nonempty step will returned, with the corresponding messages. (Or, if we are the only
/// validator, even with the completed batch as an output.)
pub fn push_transaction(&mut self, tx: T) -> Result<T, N, Q> {
self.apply(|algo| algo.push_transaction(tx))
}
/// Casts a vote to change the set of validators or parameters.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_for(&mut self, change: Change<N>) -> Result<T, N, Q> {
self.apply(|algo| algo.vote_for(change))
}
/// Casts a vote to add a node as a validator.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_add(&mut self, node_id: N, pub_key: PublicKey) -> Result<T, N, Q> {
self.apply(|algo| algo.vote_to_add(node_id, pub_key))
}
/// Casts a vote to demote a validator to observer.
///
/// This stores a pending vote for the change. It will be included in some future batch, and
/// once enough validators have been voted for the same change, it will take effect.
pub fn vote_to_remove(&mut self, node_id: N) -> Result<T, N, Q> {
self.apply(|algo| algo.vote_to_remove(node_id))
}
}