mirror of https://github.com/poanetwork/hbbft.git
review comment coverage
This commit is contained in:
parent
5008d11ada
commit
3393052b4b
|
@ -64,10 +64,6 @@ pub fn main() {
|
|||
let args: Args = parse_args();
|
||||
println!("{:?}", args);
|
||||
|
||||
let node = Node::new(
|
||||
args.bind_address,
|
||||
args.remote_addresses,
|
||||
args.value,
|
||||
);
|
||||
let node = Node::new(args.bind_address, args.remote_addresses, args.value);
|
||||
node.run().expect("Node failed");
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ fn main() {
|
|||
println!();
|
||||
let num_good_nodes = args.flag_n - args.flag_f;
|
||||
let txs = (0..args.flag_txs).map(|_| Transaction::new(args.flag_tx_size));
|
||||
let sk_set = SecretKeySet::<Bls12>::new(args.flag_f, &mut rand::thread_rng());
|
||||
let sk_set = SecretKeySet::<Bls12>::random(args.flag_f, &mut rand::thread_rng());
|
||||
let pk_set = sk_set.public_keys();
|
||||
let new_honey_badger = |id: NodeUid, all_ids: BTreeSet<NodeUid>| {
|
||||
let netinfo = Rc::new(NetworkInfo::new(
|
||||
|
|
|
@ -65,12 +65,12 @@ pub struct AgreementMessage {
|
|||
/// Binary Agreement instance
|
||||
pub struct Agreement<NodeUid>
|
||||
where
|
||||
NodeUid: Clone + Debug,
|
||||
NodeUid: Clone + Debug + Eq + Hash,
|
||||
{
|
||||
/// Shared network information.
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
/// Honey Badger algorithm epoch.
|
||||
hb_epoch: u64,
|
||||
/// Session ID, e.g, the Honey Badger algorithm epoch.
|
||||
session_id: u64,
|
||||
/// Agreement algorithm epoch.
|
||||
epoch: u32,
|
||||
/// Bin values. Reset on every epoch update.
|
||||
|
@ -110,9 +110,6 @@ where
|
|||
messages: VecDeque<AgreementMessage>,
|
||||
/// Whether the `Conf` message round has started in the current epoch.
|
||||
conf_round: bool,
|
||||
/// The subset of `bin_values` contained in received `Conf` messages before invoking the Common
|
||||
/// Coin instance.
|
||||
conf_vals: BinValues,
|
||||
/// A common coin instance. It is reset on epoch update.
|
||||
common_coin: CommonCoin<NodeUid, Nonce>,
|
||||
}
|
||||
|
@ -174,11 +171,11 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> DistAlgorithm for Agreement<NodeU
|
|||
}
|
||||
|
||||
impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
||||
pub fn new(netinfo: Rc<NetworkInfo<NodeUid>>, hb_epoch: u64) -> Self {
|
||||
pub fn new(netinfo: Rc<NetworkInfo<NodeUid>>, session_id: u64) -> Self {
|
||||
let invocation_id = netinfo.invocation_id();
|
||||
Agreement {
|
||||
netinfo: netinfo.clone(),
|
||||
hb_epoch,
|
||||
session_id,
|
||||
epoch: 0,
|
||||
bin_values: BinValues::new(),
|
||||
received_bval: BTreeMap::new(),
|
||||
|
@ -193,8 +190,7 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
|||
terminated: false,
|
||||
messages: VecDeque::new(),
|
||||
conf_round: false,
|
||||
conf_vals: BinValues::None,
|
||||
common_coin: CommonCoin::new(netinfo, Nonce::new(invocation_id.as_ref(), hb_epoch, 0)),
|
||||
common_coin: CommonCoin::new(netinfo, Nonce::new(invocation_id.as_ref(), session_id, 0)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,15 +331,7 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
|||
self.extend_common_coin();
|
||||
|
||||
if let Some(coin) = self.common_coin.next_output() {
|
||||
// Check the termination condition: "continue looping until both a value b is output in some
|
||||
// round r, and the value Coin_r' = b for some round r' > r."
|
||||
self.terminated = self.terminated || self.decision == Some(coin);
|
||||
if self.terminated {
|
||||
debug!("Node {:?} Agreement terminated", self.netinfo.our_uid());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let b = if let Some(b) = self.conf_vals.definite() {
|
||||
let b = if let Some(b) = self.count_conf().1.definite() {
|
||||
// Outputting a value is allowed only once.
|
||||
if self.decision.is_none() && b == coin {
|
||||
self.decide(b);
|
||||
|
@ -394,12 +382,11 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
|||
|
||||
fn try_finish_conf_round(&mut self) -> AgreementResult<()> {
|
||||
if self.conf_round {
|
||||
let (count_vals, vals) = self.count_conf();
|
||||
let (count_vals, _) = self.count_conf();
|
||||
if count_vals < self.netinfo.num_nodes() - self.netinfo.num_faulty() {
|
||||
// Continue waiting for (N - f) `Conf` messages
|
||||
return Ok(());
|
||||
}
|
||||
self.conf_vals = vals;
|
||||
// Invoke the comon coin.
|
||||
self.common_coin.input(())?;
|
||||
self.extend_common_coin();
|
||||
|
@ -459,11 +446,10 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
|||
self.received_aux.clear();
|
||||
self.received_conf.clear();
|
||||
self.conf_round = false;
|
||||
self.conf_vals = BinValues::None;
|
||||
self.epoch += 1;
|
||||
let nonce = Nonce::new(
|
||||
self.netinfo.invocation_id().as_ref(),
|
||||
self.hb_epoch,
|
||||
self.session_id,
|
||||
self.epoch,
|
||||
);
|
||||
self.common_coin = CommonCoin::new(self.netinfo.clone(), nonce);
|
||||
|
@ -479,10 +465,10 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
|
|||
struct Nonce(Vec<u8>);
|
||||
|
||||
impl Nonce {
|
||||
pub fn new(invocation_id: &[u8], hb_epoch: u64, agreement_epoch: u32) -> Self {
|
||||
pub fn new(invocation_id: &[u8], session_id: u64, agreement_epoch: u32) -> Self {
|
||||
Nonce(Vec::from(format!(
|
||||
"Nonce for Honey Badger {:?} @ epoch {}:{}",
|
||||
invocation_id, hb_epoch, agreement_epoch
|
||||
"Nonce for Honey Badger {:?}@{}:{}",
|
||||
invocation_id, session_id, agreement_epoch
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fmt::{self, Debug};
|
||||
use std::hash::Hash;
|
||||
use std::iter::once;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -91,7 +92,7 @@ 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> {
|
||||
pub struct Broadcast<N: Clone + Eq + Hash> {
|
||||
/// Shared network data.
|
||||
netinfo: Rc<NetworkInfo<N>>,
|
||||
/// The UID of the sending node.
|
||||
|
@ -114,7 +115,7 @@ pub struct Broadcast<N> {
|
|||
output: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<N: Eq + Debug + Clone + Ord> DistAlgorithm for Broadcast<N> {
|
||||
impl<N: Eq + Debug + Clone + Hash + Ord> DistAlgorithm for Broadcast<N> {
|
||||
type NodeUid = N;
|
||||
// TODO: Allow anything serializable and deserializable, i.e. make this a type parameter
|
||||
// T: Serialize + DeserializeOwned
|
||||
|
@ -163,7 +164,7 @@ impl<N: Eq + Debug + Clone + Ord> DistAlgorithm for Broadcast<N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<N: Eq + Debug + Clone + Ord> Broadcast<N> {
|
||||
impl<N: Eq + Debug + Clone + Hash + Ord> Broadcast<N> {
|
||||
/// 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> {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::mem::replace;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
@ -46,7 +46,7 @@ impl CommonCoinMessage {
|
|||
#[derive(Debug)]
|
||||
pub struct CommonCoin<N, T>
|
||||
where
|
||||
N: Debug,
|
||||
N: Clone + Debug + Eq + Hash,
|
||||
{
|
||||
netinfo: Rc<NetworkInfo<N>>,
|
||||
/// The name of this common coin. It is required to be unique for each common coin round.
|
||||
|
@ -55,8 +55,6 @@ where
|
|||
output: Option<bool>,
|
||||
/// Outgoing message queue.
|
||||
messages: VecDeque<CommonCoinMessage>,
|
||||
/// Incoming messages buffered before we provide input to the common coin.
|
||||
incoming_queue: VecDeque<(N, Signature<Bls12>)>,
|
||||
/// All received threshold signature shares.
|
||||
received_shares: BTreeMap<N, Signature<Bls12>>,
|
||||
/// Whether we provided input to the common coin.
|
||||
|
@ -67,7 +65,7 @@ where
|
|||
|
||||
impl<N, T> DistAlgorithm for CommonCoin<N, T>
|
||||
where
|
||||
N: Clone + Debug + Ord,
|
||||
N: Clone + Debug + Hash + Ord,
|
||||
T: Clone + AsRef<[u8]>,
|
||||
{
|
||||
type NodeUid = N;
|
||||
|
@ -91,19 +89,7 @@ where
|
|||
if self.terminated {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let CommonCoinMessage(share) = message;
|
||||
|
||||
if !self.had_input {
|
||||
self.incoming_queue.push_back((sender_id.clone(), share));
|
||||
return Ok(());
|
||||
} else {
|
||||
let queued_msgs = replace(&mut self.incoming_queue, VecDeque::new());
|
||||
for (sender_id, msg) in queued_msgs {
|
||||
self.handle_share(&sender_id, msg)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.handle_share(sender_id, share)
|
||||
}
|
||||
|
||||
|
@ -131,7 +117,7 @@ where
|
|||
|
||||
impl<N, T> CommonCoin<N, T>
|
||||
where
|
||||
N: Clone + Debug + Ord,
|
||||
N: Clone + Debug + Hash + Ord,
|
||||
T: Clone + AsRef<[u8]>,
|
||||
{
|
||||
pub fn new(netinfo: Rc<NetworkInfo<N>>, nonce: T) -> Self {
|
||||
|
@ -140,7 +126,6 @@ where
|
|||
nonce,
|
||||
output: None,
|
||||
messages: VecDeque::new(),
|
||||
incoming_queue: VecDeque::new(),
|
||||
received_shares: BTreeMap::new(),
|
||||
had_input: false,
|
||||
terminated: false,
|
||||
|
@ -155,63 +140,54 @@ where
|
|||
}
|
||||
|
||||
fn handle_share(&mut self, sender_id: &N, share: Signature<Bls12>) -> Result<()> {
|
||||
let node_indices = self.netinfo.node_indices();
|
||||
if let Some(i) = node_indices.get(sender_id) {
|
||||
let pk_i = self.netinfo.public_key_set().public_key_share(*i);
|
||||
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) {
|
||||
// Silently ignore the invalid share.
|
||||
debug!(
|
||||
"{:?} received invalid share from {:?}",
|
||||
self.netinfo.our_uid(),
|
||||
sender_id
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
debug!(
|
||||
"{:?} received a valid share from {:?}",
|
||||
self.netinfo.our_uid(),
|
||||
sender_id
|
||||
);
|
||||
self.received_shares.insert(sender_id.clone(), share);
|
||||
let received_shares = &self.received_shares;
|
||||
if received_shares.len() > self.netinfo.num_faulty() {
|
||||
// Pass the indices of sender nodes to `combine_signatures`.
|
||||
let shares: BTreeMap<&u64, &Signature<Bls12>> = self
|
||||
.netinfo
|
||||
.all_uids()
|
||||
.iter()
|
||||
.map(|id| (&node_indices[id], received_shares.get(id)))
|
||||
.filter(|(_, share)| share.is_some())
|
||||
.map(|(n, share)| (n, share.unwrap()))
|
||||
.collect();
|
||||
let sig = self.netinfo.public_key_set().combine_signatures(shares)?;
|
||||
|
||||
// Verify the successfully combined signature with the main public key.
|
||||
if !self
|
||||
.netinfo
|
||||
.public_key_set()
|
||||
.public_key()
|
||||
.verify(&sig, &self.nonce)
|
||||
{
|
||||
// Abort
|
||||
error!(
|
||||
"{:?} main public key verification failed",
|
||||
self.netinfo.our_uid()
|
||||
);
|
||||
self.terminated = true;
|
||||
return Err(ErrorKind::VerificationFailed.into());
|
||||
}
|
||||
|
||||
if self.had_input && received_shares.len() > self.netinfo.num_faulty() {
|
||||
let sig = self.combine_and_verify_sig()?;
|
||||
// Output the parity of the verified signature.
|
||||
let parity = sig.parity();
|
||||
self.output = Some(parity);
|
||||
self.terminated = true;
|
||||
debug!("{:?} coin is {}", self.netinfo.our_uid(), parity);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorKind::UnknownSender.into())
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
.keys()
|
||||
.map(|&id| (id, *self.netinfo.node_index(id).unwrap() as u64))
|
||||
.collect();
|
||||
// Convert indices to `u64` which is an interface type for `pairing`.
|
||||
let shares: BTreeMap<&u64, &Signature<Bls12>> = ids_shares
|
||||
.iter()
|
||||
.map(|(id, &share)| (&ids_u64[id], share))
|
||||
.collect();
|
||||
let sig = self.netinfo.public_key_set().combine_signatures(shares)?;
|
||||
if !self
|
||||
.netinfo
|
||||
.public_key_set()
|
||||
.public_key()
|
||||
.verify(&sig, &self.nonce)
|
||||
{
|
||||
// Abort
|
||||
error!(
|
||||
"{:?} main public key verification failed",
|
||||
self.netinfo.our_uid()
|
||||
);
|
||||
Err(ErrorKind::VerificationFailed.into())
|
||||
} else {
|
||||
Ok(sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ impl<E: Engine> PublicKey<E> {
|
|||
}
|
||||
|
||||
/// A signature, or a signature share.
|
||||
#[derive(Clone, PartialOrd)]
|
||||
#[derive(Clone)]
|
||||
pub struct Signature<E: Engine>(E::G2);
|
||||
|
||||
impl<E: Engine> fmt::Debug for Signature<E> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
||||
|
@ -131,16 +132,17 @@ impl<'a, D: DistAlgorithm + 'a> Iterator for OutputIter<'a, D> {
|
|||
|
||||
/// Common data shared between algorithms.
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkInfo<NodeUid> {
|
||||
pub struct NetworkInfo<NodeUid: Clone + Eq + Hash> {
|
||||
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>,
|
||||
}
|
||||
|
||||
impl<NodeUid: Ord> NetworkInfo<NodeUid> {
|
||||
impl<NodeUid: Clone + Hash + Ord> NetworkInfo<NodeUid> {
|
||||
pub fn new(
|
||||
our_uid: NodeUid,
|
||||
all_uids: BTreeSet<NodeUid>,
|
||||
|
@ -151,6 +153,12 @@ impl<NodeUid: Ord> NetworkInfo<NodeUid> {
|
|||
panic!("Missing own ID");
|
||||
}
|
||||
let num_nodes = all_uids.len();
|
||||
let node_indices = all_uids
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.map(|(n, id)| (id, n))
|
||||
.collect();
|
||||
NetworkInfo {
|
||||
our_uid,
|
||||
all_uids,
|
||||
|
@ -158,6 +166,7 @@ impl<NodeUid: Ord> NetworkInfo<NodeUid> {
|
|||
num_faulty: (num_nodes - 1) / 3,
|
||||
secret_key,
|
||||
public_key_set,
|
||||
node_indices,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,18 +199,17 @@ impl<NodeUid: Ord> NetworkInfo<NodeUid> {
|
|||
&self.public_key_set
|
||||
}
|
||||
|
||||
/// The canonical numbering of all nodes.
|
||||
///
|
||||
/// FIXME: To avoid multiple computations of the same result, caching should be introduced.
|
||||
pub fn node_indices(&self) -> BTreeMap<&NodeUid, u64> {
|
||||
self.all_uids
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(n, id)| (id, n as u64))
|
||||
.collect()
|
||||
/// The index of a node in a canonical numbering of all nodes.
|
||||
pub fn node_index(&self, id: &NodeUid) -> Option<&usize> {
|
||||
self.node_indices.get(id)
|
||||
}
|
||||
|
||||
/// Returns the unique ID of the Honey Badger invocation.
|
||||
///
|
||||
/// FIXME: Using the public key as the invocation ID either requires agreeing on the keys on
|
||||
/// each invocation, or makes it unsafe to reuse keys for different invocations. A better
|
||||
/// invocation ID would be one that is distributed to all nodes on each invocation and would be
|
||||
/// independent from the public key, so that reusing keys would be safer.
|
||||
pub fn invocation_id(&self) -> Vec<u8> {
|
||||
self.public_key_set.public_key().to_bytes()
|
||||
}
|
||||
|
|
|
@ -55,7 +55,8 @@ const GOOD_SAMPLE_SET: f64 = 400.0;
|
|||
/// sample set. This check assumes logarithmic growth of the expected number of throws of one coin
|
||||
/// size.
|
||||
fn check_coin_distribution(num_samples: usize, count_true: usize, count_false: usize) {
|
||||
const EXPECTED_SHARE: f64 = 0.48;
|
||||
// Maximum 40% expectation in case of 400 samples or more.
|
||||
const EXPECTED_SHARE: f64 = 0.4;
|
||||
let max_gain = GOOD_SAMPLE_SET.log2();
|
||||
let num_samples_f64 = num_samples as f64;
|
||||
let gain = num_samples_f64.log2().min(max_gain);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
@ -143,7 +144,10 @@ impl<D: DistAlgorithm> Adversary<D> for SilentAdversary {
|
|||
}
|
||||
|
||||
/// A collection of `TestNode`s representing a network.
|
||||
pub struct TestNetwork<A: Adversary<D>, D: DistAlgorithm> {
|
||||
pub struct TestNetwork<A: Adversary<D>, D: DistAlgorithm>
|
||||
where
|
||||
<D as DistAlgorithm>::NodeUid: Hash,
|
||||
{
|
||||
pub nodes: BTreeMap<D::NodeUid, TestNode<D>>,
|
||||
pub adv_nodes: BTreeMap<D::NodeUid, Rc<NetworkInfo<D::NodeUid>>>,
|
||||
adversary: A,
|
||||
|
|
Loading…
Reference in New Issue