mirror of https://github.com/poanetwork/hbbft.git
Merge pull request #63 from poanetwork/afck-hb-whose-batch
Return proposer info from HoneyBadger.
This commit is contained in:
commit
1436d85455
|
@ -329,7 +329,7 @@ where
|
|||
/// The timestamped batches for a particular epoch that have already been output.
|
||||
#[derive(Clone, Default)]
|
||||
struct EpochInfo {
|
||||
nodes: BTreeMap<NodeUid, (Duration, Batch<Transaction>)>,
|
||||
nodes: BTreeMap<NodeUid, (Duration, Batch<Transaction, NodeUid>)>,
|
||||
}
|
||||
|
||||
impl EpochInfo {
|
||||
|
@ -338,7 +338,7 @@ impl EpochInfo {
|
|||
&mut self,
|
||||
id: NodeUid,
|
||||
time: Duration,
|
||||
batch: &Batch<Transaction>,
|
||||
batch: &Batch<Transaction, NodeUid>,
|
||||
network: &TestNetwork<HoneyBadger<Transaction, NodeUid>>,
|
||||
) {
|
||||
if self.nodes.contains_key(&id) {
|
||||
|
@ -355,7 +355,7 @@ impl EpochInfo {
|
|||
.minmax()
|
||||
.into_option()
|
||||
.unwrap();
|
||||
let txs = batch.transactions.len();
|
||||
let txs = batch.len();
|
||||
println!(
|
||||
"{:>5} {:6} {:6} {:5} {:9} {:>9}B",
|
||||
batch.epoch.to_string().cyan(),
|
||||
|
@ -379,7 +379,7 @@ fn simulate_honey_badger(
|
|||
let node_busy = |node: &mut TestNode<HoneyBadger<Transaction, NodeUid>>| {
|
||||
node.outputs
|
||||
.iter()
|
||||
.map(|&(_, ref batch)| batch.transactions.len())
|
||||
.map(|&(_, ref batch)| batch.len())
|
||||
.sum::<usize>() < num_txs
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ pub mod bin_values;
|
|||
|
||||
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::mem::replace;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -68,10 +67,7 @@ pub struct AgreementMessage {
|
|||
}
|
||||
|
||||
/// Binary Agreement instance
|
||||
pub struct Agreement<NodeUid>
|
||||
where
|
||||
NodeUid: Clone + Debug + Eq + Hash,
|
||||
{
|
||||
pub struct Agreement<NodeUid> {
|
||||
/// Shared network information.
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
/// Session ID, e.g, the Honey Badger algorithm epoch.
|
||||
|
@ -121,7 +117,7 @@ where
|
|||
common_coin: CommonCoin<NodeUid, Nonce>,
|
||||
}
|
||||
|
||||
impl<NodeUid: Clone + Debug + Eq + Hash + Ord> DistAlgorithm for Agreement<NodeUid> {
|
||||
impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for Agreement<NodeUid> {
|
||||
type NodeUid = NodeUid;
|
||||
type Input = bool;
|
||||
type Output = bool;
|
||||
|
@ -177,7 +173,7 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> DistAlgorithm for Agreement<NodeU
|
|||
}
|
||||
}
|
||||
|
||||
impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
||||
impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
|
||||
pub fn new(
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
session_id: u64,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fmt::{self, Debug};
|
||||
use std::hash::Hash;
|
||||
use std::iter::once;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -92,11 +91,11 @@ impl Debug for BroadcastMessage {
|
|||
/// eventually be able to decode (i.e. receive at least `f + 1` `Echo` messages).
|
||||
/// * So a node with `2 * f + 1` `Ready`s and `f + 1` `Echos` will decode and _output_ the value,
|
||||
/// knowing that every other good node will eventually do the same.
|
||||
pub struct Broadcast<N: Clone + Eq + Hash> {
|
||||
pub struct Broadcast<NodeUid> {
|
||||
/// Shared network data.
|
||||
netinfo: Rc<NetworkInfo<N>>,
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
/// The UID of the sending node.
|
||||
proposer_id: N,
|
||||
proposer_id: NodeUid,
|
||||
data_shard_num: usize,
|
||||
coding: Coding,
|
||||
/// Whether we have already multicast `Echo`.
|
||||
|
@ -106,17 +105,17 @@ pub struct Broadcast<N: Clone + Eq + Hash> {
|
|||
/// Whether we have already output a value.
|
||||
decided: bool,
|
||||
/// The proofs we have received via `Echo` messages, by sender ID.
|
||||
echos: BTreeMap<N, Proof<Vec<u8>>>,
|
||||
echos: BTreeMap<NodeUid, Proof<Vec<u8>>>,
|
||||
/// The root hashes we received via `Ready` messages, by sender ID.
|
||||
readys: BTreeMap<N, Vec<u8>>,
|
||||
readys: BTreeMap<NodeUid, Vec<u8>>,
|
||||
/// The outgoing message queue.
|
||||
messages: VecDeque<TargetedMessage<BroadcastMessage, N>>,
|
||||
messages: VecDeque<TargetedMessage<BroadcastMessage, NodeUid>>,
|
||||
/// The output, if any.
|
||||
output: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<N: Eq + Debug + Clone + Hash + Ord> DistAlgorithm for Broadcast<N> {
|
||||
type NodeUid = N;
|
||||
impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
|
||||
type NodeUid = NodeUid;
|
||||
// TODO: Allow anything serializable and deserializable, i.e. make this a type parameter
|
||||
// T: Serialize + DeserializeOwned
|
||||
type Input = Vec<u8>;
|
||||
|
@ -136,7 +135,11 @@ impl<N: Eq + Debug + Clone + Hash + Ord> DistAlgorithm for Broadcast<N> {
|
|||
self.handle_value(our_uid, proof)
|
||||
}
|
||||
|
||||
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> BroadcastResult<()> {
|
||||
fn handle_message(
|
||||
&mut self,
|
||||
sender_id: &NodeUid,
|
||||
message: Self::Message,
|
||||
) -> BroadcastResult<()> {
|
||||
if !self.netinfo.all_uids().contains(sender_id) {
|
||||
return Err(ErrorKind::UnknownSender.into());
|
||||
}
|
||||
|
@ -147,7 +150,7 @@ impl<N: Eq + Debug + Clone + Hash + Ord> DistAlgorithm for Broadcast<N> {
|
|||
}
|
||||
}
|
||||
|
||||
fn next_message(&mut self) -> Option<TargetedMessage<Self::Message, N>> {
|
||||
fn next_message(&mut self) -> Option<TargetedMessage<Self::Message, NodeUid>> {
|
||||
self.messages.pop_front()
|
||||
}
|
||||
|
||||
|
@ -159,15 +162,15 @@ impl<N: Eq + Debug + Clone + Hash + Ord> DistAlgorithm for Broadcast<N> {
|
|||
self.decided
|
||||
}
|
||||
|
||||
fn our_id(&self) -> &N {
|
||||
fn our_id(&self) -> &NodeUid {
|
||||
self.netinfo.our_uid()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Eq + Debug + Clone + Hash + Ord> Broadcast<N> {
|
||||
impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
|
||||
/// Creates a new broadcast instance to be used by node `our_id` which expects a value proposal
|
||||
/// from node `proposer_id`.
|
||||
pub fn new(netinfo: Rc<NetworkInfo<N>>, proposer_id: N) -> BroadcastResult<Self> {
|
||||
pub fn new(netinfo: Rc<NetworkInfo<NodeUid>>, proposer_id: NodeUid) -> BroadcastResult<Self> {
|
||||
let parity_shard_num = 2 * netinfo.num_faulty();
|
||||
let data_shard_num = netinfo.num_nodes() - parity_shard_num;
|
||||
let coding = Coding::new(data_shard_num, parity_shard_num)?;
|
||||
|
@ -266,7 +269,7 @@ impl<N: Eq + Debug + Clone + Hash + Ord> Broadcast<N> {
|
|||
}
|
||||
|
||||
/// Handles a received echo and verifies the proof it contains.
|
||||
fn handle_value(&mut self, sender_id: &N, p: Proof<Vec<u8>>) -> BroadcastResult<()> {
|
||||
fn handle_value(&mut self, sender_id: &NodeUid, p: Proof<Vec<u8>>) -> BroadcastResult<()> {
|
||||
// If the sender is not the proposer, this is not the first `Value` or the proof is invalid,
|
||||
// ignore.
|
||||
if *sender_id != self.proposer_id {
|
||||
|
@ -299,7 +302,7 @@ impl<N: Eq + Debug + Clone + Hash + Ord> Broadcast<N> {
|
|||
}
|
||||
|
||||
/// Handles a received `Echo` message.
|
||||
fn handle_echo(&mut self, sender_id: &N, p: Proof<Vec<u8>>) -> BroadcastResult<()> {
|
||||
fn handle_echo(&mut self, sender_id: &NodeUid, p: Proof<Vec<u8>>) -> BroadcastResult<()> {
|
||||
// If the proof is invalid or the sender has already sent `Echo`, ignore.
|
||||
if self.echos.contains_key(sender_id) {
|
||||
info!(
|
||||
|
@ -333,7 +336,7 @@ impl<N: Eq + Debug + Clone + Hash + Ord> Broadcast<N> {
|
|||
}
|
||||
|
||||
/// Handles a received `Ready` message.
|
||||
fn handle_ready(&mut self, sender_id: &N, hash: &[u8]) -> BroadcastResult<()> {
|
||||
fn handle_ready(&mut self, sender_id: &NodeUid, hash: &[u8]) -> BroadcastResult<()> {
|
||||
// If the sender has already sent a `Ready` before, ignore.
|
||||
if self.readys.contains_key(sender_id) {
|
||||
info!(
|
||||
|
@ -389,13 +392,13 @@ impl<N: Eq + Debug + Clone + Hash + Ord> Broadcast<N> {
|
|||
}
|
||||
|
||||
/// Returns `i` if `node_id` is the `i`-th ID among all participating nodes.
|
||||
fn index_of_node(&self, node_id: &N) -> Option<usize> {
|
||||
fn index_of_node(&self, node_id: &NodeUid) -> Option<usize> {
|
||||
self.netinfo.all_uids().iter().position(|id| id == node_id)
|
||||
}
|
||||
|
||||
/// Returns `true` if the proof is valid and has the same index as the node ID. Otherwise
|
||||
/// logs an info message.
|
||||
fn validate_proof(&self, p: &Proof<Vec<u8>>, id: &N) -> bool {
|
||||
fn validate_proof(&self, p: &Proof<Vec<u8>>, id: &NodeUid) -> bool {
|
||||
if !p.validate(&p.root_hash) {
|
||||
info!(
|
||||
"Node {:?} received invalid proof: {:?}",
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
@ -44,11 +43,8 @@ impl CommonCoinMessage {
|
|||
/// receiving at least `num_faulty + 1` shares, attempts to combine them into a signature. If that
|
||||
/// signature is valid, the instance outputs it and terminates; otherwise the instance aborts.
|
||||
#[derive(Debug)]
|
||||
pub struct CommonCoin<N, T>
|
||||
where
|
||||
N: Clone + Debug + Eq + Hash,
|
||||
{
|
||||
netinfo: Rc<NetworkInfo<N>>,
|
||||
pub struct CommonCoin<NodeUid, T> {
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
/// The name of this common coin. It is required to be unique for each common coin round.
|
||||
nonce: T,
|
||||
/// The result of combination of at least `num_faulty + 1` threshold signature shares.
|
||||
|
@ -56,19 +52,19 @@ where
|
|||
/// Outgoing message queue.
|
||||
messages: VecDeque<CommonCoinMessage>,
|
||||
/// All received threshold signature shares.
|
||||
received_shares: BTreeMap<N, Signature<Bls12>>,
|
||||
received_shares: BTreeMap<NodeUid, Signature<Bls12>>,
|
||||
/// Whether we provided input to the common coin.
|
||||
had_input: bool,
|
||||
/// Termination flag.
|
||||
terminated: bool,
|
||||
}
|
||||
|
||||
impl<N, T> DistAlgorithm for CommonCoin<N, T>
|
||||
impl<NodeUid, T> DistAlgorithm for CommonCoin<NodeUid, T>
|
||||
where
|
||||
N: Clone + Debug + Hash + Ord,
|
||||
NodeUid: Clone + Debug + Ord,
|
||||
T: Clone + AsRef<[u8]>,
|
||||
{
|
||||
type NodeUid = N;
|
||||
type NodeUid = NodeUid;
|
||||
type Input = ();
|
||||
type Output = bool;
|
||||
type Message = CommonCoinMessage;
|
||||
|
@ -115,12 +111,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<N, T> CommonCoin<N, T>
|
||||
impl<NodeUid, T> CommonCoin<NodeUid, T>
|
||||
where
|
||||
N: Clone + Debug + Hash + Ord,
|
||||
NodeUid: Clone + Debug + Ord,
|
||||
T: Clone + AsRef<[u8]>,
|
||||
{
|
||||
pub fn new(netinfo: Rc<NetworkInfo<N>>, nonce: T) -> Self {
|
||||
pub fn new(netinfo: Rc<NetworkInfo<NodeUid>>, nonce: T) -> Self {
|
||||
CommonCoin {
|
||||
netinfo,
|
||||
nonce,
|
||||
|
@ -139,7 +135,7 @@ where
|
|||
self.handle_share(&id, share)
|
||||
}
|
||||
|
||||
fn handle_share(&mut self, sender_id: &N, share: Signature<Bls12>) -> Result<()> {
|
||||
fn handle_share(&mut self, sender_id: &NodeUid, share: Signature<Bls12>) -> Result<()> {
|
||||
if let Some(i) = self.netinfo.node_index(sender_id) {
|
||||
let pk_i = self.netinfo.public_key_set().public_key_share(*i as u64);
|
||||
if !pk_i.verify(&share, &self.nonce) {
|
||||
|
@ -163,8 +159,9 @@ where
|
|||
|
||||
fn combine_and_verify_sig(&self) -> Result<Signature<Bls12>> {
|
||||
// Pass the indices of sender nodes to `combine_signatures`.
|
||||
let ids_shares: BTreeMap<&N, &Signature<Bls12>> = self.received_shares.iter().collect();
|
||||
let ids_u64: BTreeMap<&N, u64> = ids_shares
|
||||
let ids_shares: BTreeMap<&NodeUid, &Signature<Bls12>> =
|
||||
self.received_shares.iter().collect();
|
||||
let ids_u64: BTreeMap<&NodeUid, u64> = ids_shares
|
||||
.keys()
|
||||
.map(|&id| (id, *self.netinfo.node_index(id).unwrap() as u64))
|
||||
.collect();
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
use agreement;
|
||||
|
@ -47,7 +46,7 @@ pub enum Message<NodeUid> {
|
|||
#[derive(Deref, DerefMut)]
|
||||
struct MessageQueue<NodeUid>(VecDeque<TargetedMessage<Message<NodeUid>, NodeUid>>);
|
||||
|
||||
impl<NodeUid: Clone + Debug + Eq + Hash + Ord> MessageQueue<NodeUid> {
|
||||
impl<NodeUid: Clone + Debug + Ord> MessageQueue<NodeUid> {
|
||||
/// Appends to the queue the messages from `agr`, wrapped with `proposer_id`.
|
||||
fn extend_agreement(&mut self, proposer_id: &NodeUid, agr: &mut Agreement<NodeUid>) {
|
||||
let convert = |msg: TargetedMessage<AgreementMessage, NodeUid>| {
|
||||
|
@ -88,7 +87,7 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> MessageQueue<NodeUid> {
|
|||
/// remaining ones, where we haven't provided input yet.
|
||||
/// * Once all `Agreement` instances have decided, `CommonSubset` returns the set of all proposed
|
||||
/// values for which the decision was "yes".
|
||||
pub struct CommonSubset<NodeUid: Clone + Debug + Eq + Hash + Ord> {
|
||||
pub struct CommonSubset<NodeUid> {
|
||||
/// Shared network information.
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
broadcast_instances: BTreeMap<NodeUid, Broadcast<NodeUid>>,
|
||||
|
@ -103,7 +102,7 @@ pub struct CommonSubset<NodeUid: Clone + Debug + Eq + Hash + Ord> {
|
|||
decided: bool,
|
||||
}
|
||||
|
||||
impl<NodeUid: Clone + Debug + Eq + Hash + Ord> DistAlgorithm for CommonSubset<NodeUid> {
|
||||
impl<NodeUid: Clone + Debug + Ord> DistAlgorithm for CommonSubset<NodeUid> {
|
||||
type NodeUid = NodeUid;
|
||||
type Input = ProposedValue;
|
||||
type Output = BTreeMap<NodeUid, ProposedValue>;
|
||||
|
@ -147,7 +146,7 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> DistAlgorithm for CommonSubset<No
|
|||
}
|
||||
}
|
||||
|
||||
impl<NodeUid: Clone + Debug + Eq + Hash + Ord> CommonSubset<NodeUid> {
|
||||
impl<NodeUid: Clone + Debug + Ord> CommonSubset<NodeUid> {
|
||||
pub fn new(netinfo: Rc<NetworkInfo<NodeUid>>, session_id: u64) -> CommonSubsetResult<Self> {
|
||||
// Create all broadcast instances.
|
||||
let mut broadcast_instances: BTreeMap<NodeUid, Broadcast<NodeUid>> = BTreeMap::new();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::collections::btree_map::Entry;
|
||||
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||
use std::collections::{BTreeMap, HashSet, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
@ -32,42 +32,46 @@ error_chain!{
|
|||
}
|
||||
|
||||
/// An instance of the Honey Badger Byzantine fault tolerant consensus algorithm.
|
||||
pub struct HoneyBadger<T, N: Clone + Debug + Eq + Hash + Ord + Clone> {
|
||||
pub struct HoneyBadger<Tx, NodeUid> {
|
||||
/// Shared network data.
|
||||
netinfo: Rc<NetworkInfo<N>>,
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
/// The buffer of transactions that have not yet been included in any output batch.
|
||||
buffer: Vec<T>,
|
||||
buffer: Vec<Tx>,
|
||||
/// The earliest epoch from which we have not yet received output.
|
||||
epoch: u64,
|
||||
/// The Asynchronous Common Subset instance that decides which nodes' transactions to include,
|
||||
/// indexed by epoch.
|
||||
common_subsets: BTreeMap<u64, CommonSubset<N>>,
|
||||
common_subsets: BTreeMap<u64, CommonSubset<NodeUid>>,
|
||||
/// The target number of transactions to be included in each batch.
|
||||
// TODO: Do experiments and recommend a batch size. It should be proportional to
|
||||
// `num_nodes * num_nodes * log(num_nodes)`.
|
||||
batch_size: usize,
|
||||
/// The messages that need to be sent to other nodes.
|
||||
messages: MessageQueue<N>,
|
||||
messages: MessageQueue<NodeUid>,
|
||||
/// The outputs from completed epochs.
|
||||
output: VecDeque<Batch<T>>,
|
||||
output: VecDeque<Batch<Tx, NodeUid>>,
|
||||
}
|
||||
|
||||
impl<T, N> DistAlgorithm for HoneyBadger<T, N>
|
||||
impl<Tx, NodeUid> DistAlgorithm for HoneyBadger<Tx, NodeUid>
|
||||
where
|
||||
T: Ord + Serialize + DeserializeOwned + Debug,
|
||||
N: Eq + Hash + Ord + Clone + Debug,
|
||||
Tx: Eq + Hash + Serialize + DeserializeOwned + Debug,
|
||||
NodeUid: Ord + Clone + Debug,
|
||||
{
|
||||
type NodeUid = N;
|
||||
type Input = T;
|
||||
type Output = Batch<T>;
|
||||
type Message = Message<N>;
|
||||
type NodeUid = NodeUid;
|
||||
type Input = Tx;
|
||||
type Output = Batch<Tx, NodeUid>;
|
||||
type Message = Message<NodeUid>;
|
||||
type Error = Error;
|
||||
|
||||
fn input(&mut self, input: Self::Input) -> HoneyBadgerResult<()> {
|
||||
self.add_transactions(iter::once(input))
|
||||
}
|
||||
|
||||
fn handle_message(&mut self, sender_id: &N, message: Self::Message) -> HoneyBadgerResult<()> {
|
||||
fn handle_message(
|
||||
&mut self,
|
||||
sender_id: &NodeUid,
|
||||
message: Self::Message,
|
||||
) -> HoneyBadgerResult<()> {
|
||||
if !self.netinfo.all_uids().contains(sender_id) {
|
||||
return Err(ErrorKind::UnknownSender.into());
|
||||
}
|
||||
|
@ -78,7 +82,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn next_message(&mut self) -> Option<TargetedMessage<Self::Message, N>> {
|
||||
fn next_message(&mut self) -> Option<TargetedMessage<Self::Message, NodeUid>> {
|
||||
self.messages.pop_front()
|
||||
}
|
||||
|
||||
|
@ -90,25 +94,25 @@ where
|
|||
false
|
||||
}
|
||||
|
||||
fn our_id(&self) -> &N {
|
||||
fn our_id(&self) -> &NodeUid {
|
||||
self.netinfo.our_uid()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use a threshold encryption scheme to encrypt the proposed transactions.
|
||||
impl<T, N> HoneyBadger<T, N>
|
||||
impl<Tx, NodeUid> HoneyBadger<Tx, NodeUid>
|
||||
where
|
||||
T: Ord + Serialize + DeserializeOwned + Debug,
|
||||
N: Eq + Hash + Ord + Clone + Debug,
|
||||
Tx: Eq + Hash + Serialize + DeserializeOwned + Debug,
|
||||
NodeUid: Ord + Clone + Debug,
|
||||
{
|
||||
/// Returns a new Honey Badger instance with the given parameters, starting at epoch `0`.
|
||||
pub fn new<TI>(
|
||||
netinfo: Rc<NetworkInfo<N>>,
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
batch_size: usize,
|
||||
txs: TI,
|
||||
) -> HoneyBadgerResult<Self>
|
||||
where
|
||||
TI: IntoIterator<Item = T>,
|
||||
TI: IntoIterator<Item = Tx>,
|
||||
{
|
||||
let mut honey_badger = HoneyBadger {
|
||||
netinfo,
|
||||
|
@ -124,7 +128,10 @@ where
|
|||
}
|
||||
|
||||
/// Adds transactions into the buffer.
|
||||
pub fn add_transactions<I: IntoIterator<Item = T>>(&mut self, txs: I) -> HoneyBadgerResult<()> {
|
||||
pub fn add_transactions<I: IntoIterator<Item = Tx>>(
|
||||
&mut self,
|
||||
txs: I,
|
||||
) -> HoneyBadgerResult<()> {
|
||||
self.buffer.extend(txs);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -165,9 +172,9 @@ where
|
|||
/// Handles a message for the common subset sub-algorithm.
|
||||
fn handle_common_subset_message(
|
||||
&mut self,
|
||||
sender_id: &N,
|
||||
sender_id: &NodeUid,
|
||||
epoch: u64,
|
||||
message: common_subset::Message<N>,
|
||||
message: common_subset::Message<NodeUid>,
|
||||
) -> HoneyBadgerResult<()> {
|
||||
{
|
||||
// Borrow the instance for `epoch`, or create it.
|
||||
|
@ -199,26 +206,32 @@ where
|
|||
let old_epoch = self.epoch;
|
||||
while let Some(ser_batches) = self.take_current_output() {
|
||||
// Deserialize the output.
|
||||
let transactions: BTreeSet<T> = ser_batches
|
||||
let transactions: BTreeMap<NodeUid, Vec<Tx>> = ser_batches
|
||||
.into_iter()
|
||||
.flat_map(|(_, ser_batch)| {
|
||||
.filter_map(|(proposer_id, ser_batch)| {
|
||||
// If serialization fails, the proposer of that batch is faulty. Ignore it.
|
||||
bincode::deserialize::<Vec<T>>(&ser_batch).unwrap_or_else(|_| Vec::new())
|
||||
bincode::deserialize::<Vec<Tx>>(&ser_batch)
|
||||
.ok()
|
||||
.map(|proposed| (proposer_id, proposed))
|
||||
})
|
||||
.collect();
|
||||
// Remove the output transactions from our buffer.
|
||||
self.buffer.retain(|tx| !transactions.contains(tx));
|
||||
let batch = Batch {
|
||||
epoch: self.epoch,
|
||||
transactions,
|
||||
};
|
||||
{
|
||||
let tx_set: HashSet<&Tx> = batch.iter().collect();
|
||||
// Remove the output transactions from our buffer.
|
||||
self.buffer.retain(|tx| !tx_set.contains(&tx));
|
||||
}
|
||||
debug!(
|
||||
"{:?} Epoch {} output {:?}",
|
||||
self.netinfo.our_uid(),
|
||||
self.epoch,
|
||||
transactions
|
||||
batch.transactions,
|
||||
);
|
||||
// Queue the output and advance the epoch.
|
||||
self.output.push_back(Batch {
|
||||
epoch: self.epoch,
|
||||
transactions,
|
||||
});
|
||||
self.output.push_back(batch);
|
||||
self.epoch += 1;
|
||||
}
|
||||
// If we have moved to a new epoch, propose a new batch of transactions.
|
||||
|
@ -229,7 +242,7 @@ where
|
|||
}
|
||||
|
||||
/// Returns the output of the current epoch's `CommonSubset` instance, if any.
|
||||
fn take_current_output(&mut self) -> Option<BTreeMap<N, Vec<u8>>> {
|
||||
fn take_current_output(&mut self) -> Option<BTreeMap<NodeUid, Vec<u8>>> {
|
||||
self.common_subsets
|
||||
.get_mut(&self.epoch)
|
||||
.and_then(CommonSubset::next_output)
|
||||
|
@ -256,28 +269,45 @@ where
|
|||
|
||||
/// A batch of transactions the algorithm has output.
|
||||
#[derive(Clone)]
|
||||
pub struct Batch<T> {
|
||||
pub struct Batch<Tx, NodeUid> {
|
||||
pub epoch: u64,
|
||||
pub transactions: BTreeSet<T>,
|
||||
pub transactions: BTreeMap<NodeUid, Vec<Tx>>,
|
||||
}
|
||||
|
||||
impl<Tx, NodeUid: Ord> Batch<Tx, NodeUid> {
|
||||
/// Returns an iterator over all transactions included in the batch.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Tx> {
|
||||
self.transactions.values().flat_map(|vec| vec)
|
||||
}
|
||||
|
||||
/// Returns the number of transactions in the batch (without detecting duplicates).
|
||||
pub fn len(&self) -> usize {
|
||||
self.transactions.values().map(Vec::len).sum()
|
||||
}
|
||||
|
||||
/// Returns `true` if the batch contains no transactions.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.transactions.values().all(Vec::is_empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// A message sent to or received from another node's Honey Badger instance.
|
||||
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message<N> {
|
||||
pub enum Message<NodeUid> {
|
||||
/// A message belonging to the common subset algorithm in the given epoch.
|
||||
CommonSubset(u64, common_subset::Message<N>),
|
||||
CommonSubset(u64, common_subset::Message<NodeUid>),
|
||||
// TODO: Decryption share.
|
||||
}
|
||||
|
||||
/// The queue of outgoing messages in a `HoneyBadger` instance.
|
||||
#[derive(Deref, DerefMut)]
|
||||
struct MessageQueue<N>(VecDeque<TargetedMessage<Message<N>, N>>);
|
||||
struct MessageQueue<NodeUid>(VecDeque<TargetedMessage<Message<NodeUid>, NodeUid>>);
|
||||
|
||||
impl<N: Clone + Debug + Eq + Hash + Ord> MessageQueue<N> {
|
||||
impl<NodeUid: Clone + Debug + Ord> MessageQueue<NodeUid> {
|
||||
/// Appends to the queue the messages from `cs`, wrapped with `epoch`.
|
||||
fn extend_with_epoch(&mut self, epoch: u64, cs: &mut CommonSubset<N>) {
|
||||
let convert = |msg: TargetedMessage<common_subset::Message<N>, N>| {
|
||||
fn extend_with_epoch(&mut self, epoch: u64, cs: &mut CommonSubset<NodeUid>) {
|
||||
let convert = |msg: TargetedMessage<common_subset::Message<NodeUid>, NodeUid>| {
|
||||
msg.map(|cs_msg| Message::CommonSubset(epoch, cs_msg))
|
||||
};
|
||||
self.extend(cs.message_iter().map(convert));
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
||||
|
@ -132,17 +131,17 @@ impl<'a, D: DistAlgorithm + 'a> Iterator for OutputIter<'a, D> {
|
|||
|
||||
/// Common data shared between algorithms.
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkInfo<NodeUid: Clone + Eq + Hash> {
|
||||
pub struct NetworkInfo<NodeUid> {
|
||||
our_uid: NodeUid,
|
||||
all_uids: BTreeSet<NodeUid>,
|
||||
num_nodes: usize,
|
||||
num_faulty: usize,
|
||||
secret_key: SecretKey<Bls12>,
|
||||
public_key_set: PublicKeySet<Bls12>,
|
||||
node_indices: HashMap<NodeUid, usize>,
|
||||
node_indices: BTreeMap<NodeUid, usize>,
|
||||
}
|
||||
|
||||
impl<NodeUid: Clone + Hash + Ord> NetworkInfo<NodeUid> {
|
||||
impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
|
||||
pub fn new(
|
||||
our_uid: NodeUid,
|
||||
all_uids: BTreeSet<NodeUid>,
|
||||
|
|
|
@ -33,7 +33,7 @@ where
|
|||
let node_busy = |node: &mut TestNode<HoneyBadger<usize, NodeUid>>| {
|
||||
let mut min_missing = 0;
|
||||
for batch in node.outputs() {
|
||||
for tx in &batch.transactions {
|
||||
for tx in batch.iter() {
|
||||
if *tx >= min_missing {
|
||||
min_missing = tx + 1;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ where
|
|||
if min_missing < num_txs {
|
||||
return true;
|
||||
}
|
||||
if node.outputs().last().unwrap().transactions.is_empty() {
|
||||
if node.outputs().last().unwrap().is_empty() {
|
||||
let last = node.outputs().last().unwrap().epoch;
|
||||
node.queue.retain(|(_, ref msg)| match msg {
|
||||
honey_badger::Message::CommonSubset(e, _) => *e < last,
|
||||
|
|
Loading…
Reference in New Issue