mirror of https://github.com/poanetwork/hbbft.git
Make the BA session ID generic.
This commit is contained in:
parent
6375decbc0
commit
506f031d93
|
@ -1,6 +1,10 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bincode;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::bool_multimap::BoolMultimap;
|
use super::bool_multimap::BoolMultimap;
|
||||||
use super::bool_set::BoolSet;
|
use super::bool_set::BoolSet;
|
||||||
use super::sbv_broadcast::{self, SbvBroadcast};
|
use super::sbv_broadcast::{self, SbvBroadcast};
|
||||||
|
@ -39,10 +43,13 @@ impl<N> From<bool> for CoinState<N> {
|
||||||
pub struct BinaryAgreement<N> {
|
pub struct BinaryAgreement<N> {
|
||||||
/// Shared network information.
|
/// Shared network information.
|
||||||
netinfo: Arc<NetworkInfo<N>>,
|
netinfo: Arc<NetworkInfo<N>>,
|
||||||
/// Session ID, e.g, the Honey Badger algorithm epoch.
|
// We store the session ID twice: once in its serialized form, to create the `ThresholdSign`
|
||||||
session_id: u64,
|
// nonces, and once boxed, for debug output.
|
||||||
/// The ID of the proposer of the value for this Binary Agreement instance.
|
/// Session identifier, to prevent replaying messages in other instances,
|
||||||
proposer_id: N,
|
/// e.g, the Honey Badger algorithm epoch plus the proposer ID.
|
||||||
|
session_id: Box<Debug + Send + Sync>,
|
||||||
|
/// The serialized session identifier.
|
||||||
|
ser_session_id: Vec<u8>,
|
||||||
/// Binary Agreement algorithm epoch.
|
/// Binary Agreement algorithm epoch.
|
||||||
epoch: u32,
|
epoch: u32,
|
||||||
/// This epoch's Synchronized Binary Value Broadcast instance.
|
/// This epoch's Synchronized Binary Value Broadcast instance.
|
||||||
|
@ -96,18 +103,16 @@ impl<N: NodeIdT> DistAlgorithm for BinaryAgreement<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: NodeIdT> BinaryAgreement<N> {
|
impl<N: NodeIdT> BinaryAgreement<N> {
|
||||||
/// Creates a new `BinaryAgreement` instance. The `session_id` and `proposer_id` are used to
|
/// Creates a new `BinaryAgreement` instance with the given session identifier, to prevent
|
||||||
/// uniquely identify this instance: its messages cannot be replayed in an instance with
|
/// replaying messages in other instances.
|
||||||
/// different values.
|
pub fn new<T>(netinfo: Arc<NetworkInfo<N>>, session_id: T) -> Result<Self>
|
||||||
// TODO: Use a generic type argument for that instead of something `Subset`-specific.
|
where
|
||||||
pub fn new(netinfo: Arc<NetworkInfo<N>>, session_id: u64, proposer_id: N) -> Result<Self> {
|
T: Serialize + Sync + Send + Debug + 'static,
|
||||||
if !netinfo.is_node_validator(&proposer_id) {
|
{
|
||||||
return Err(Error::UnknownProposer);
|
|
||||||
}
|
|
||||||
Ok(BinaryAgreement {
|
Ok(BinaryAgreement {
|
||||||
netinfo: netinfo.clone(),
|
netinfo: netinfo.clone(),
|
||||||
session_id,
|
ser_session_id: bincode::serialize(&session_id)?,
|
||||||
proposer_id,
|
session_id: Box::new(session_id),
|
||||||
epoch: 0,
|
epoch: 0,
|
||||||
sbv_broadcast: SbvBroadcast::new(netinfo),
|
sbv_broadcast: SbvBroadcast::new(netinfo),
|
||||||
received_conf: BTreeMap::new(),
|
received_conf: BTreeMap::new(),
|
||||||
|
@ -127,7 +132,7 @@ impl<N: NodeIdT> BinaryAgreement<N> {
|
||||||
}
|
}
|
||||||
// Set the initial estimated value to the input value.
|
// Set the initial estimated value to the input value.
|
||||||
self.estimated = Some(input);
|
self.estimated = Some(input);
|
||||||
debug!("{:?}/{:?} Input {}", self.our_id(), self.proposer_id, input);
|
debug!("{:?}/{:?} Input {}", self.our_id(), self.session_id, input);
|
||||||
let sbvb_step = self.sbv_broadcast.handle_input(input)?;
|
let sbvb_step = self.sbv_broadcast.handle_input(input)?;
|
||||||
self.handle_sbvb_step(sbvb_step)
|
self.handle_sbvb_step(sbvb_step)
|
||||||
}
|
}
|
||||||
|
@ -316,20 +321,19 @@ impl<N: NodeIdT> BinaryAgreement<N> {
|
||||||
|
|
||||||
/// Creates the initial coin state for the current epoch, i.e. sets it to the predetermined
|
/// Creates the initial coin state for the current epoch, i.e. sets it to the predetermined
|
||||||
/// value, or initializes a `ThresholdSign` instance.
|
/// value, or initializes a `ThresholdSign` instance.
|
||||||
fn coin_state(&self) -> CoinState<N> {
|
fn coin_state(&self) -> Result<CoinState<N>> {
|
||||||
match self.epoch % 3 {
|
Ok(match self.epoch % 3 {
|
||||||
0 => CoinState::Decided(true),
|
0 => CoinState::Decided(true),
|
||||||
1 => CoinState::Decided(false),
|
1 => CoinState::Decided(false),
|
||||||
_ => {
|
_ => {
|
||||||
let nonce = Nonce::new(
|
let nonce = Nonce::new(
|
||||||
self.netinfo.invocation_id().as_ref(),
|
self.netinfo.invocation_id().as_ref(),
|
||||||
self.session_id,
|
&self.ser_session_id,
|
||||||
self.netinfo.node_index(&self.proposer_id).unwrap(),
|
|
||||||
self.epoch,
|
self.epoch,
|
||||||
);
|
)?;
|
||||||
CoinState::InProgress(Box::new(ThresholdSign::new(self.netinfo.clone(), nonce)))
|
CoinState::InProgress(Box::new(ThresholdSign::new(self.netinfo.clone(), nonce)))
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decides on a value and broadcasts a `Term` message with that value.
|
/// Decides on a value and broadcasts a `Term` message with that value.
|
||||||
|
@ -345,7 +349,7 @@ impl<N: NodeIdT> BinaryAgreement<N> {
|
||||||
debug!(
|
debug!(
|
||||||
"{:?}/{:?} (is_validator: {}) decision: {}",
|
"{:?}/{:?} (is_validator: {}) decision: {}",
|
||||||
self.netinfo.our_id(),
|
self.netinfo.our_id(),
|
||||||
self.proposer_id,
|
self.session_id,
|
||||||
self.netinfo.is_validator(),
|
self.netinfo.is_validator(),
|
||||||
b
|
b
|
||||||
);
|
);
|
||||||
|
@ -387,11 +391,11 @@ impl<N: NodeIdT> BinaryAgreement<N> {
|
||||||
}
|
}
|
||||||
self.conf_values = None;
|
self.conf_values = None;
|
||||||
self.epoch += 1;
|
self.epoch += 1;
|
||||||
self.coin_state = self.coin_state();
|
self.coin_state = self.coin_state()?;
|
||||||
debug!(
|
debug!(
|
||||||
"{:?} BinaryAgreement instance {:?} started epoch {}, {} terminated",
|
"{:?} BinaryAgreement instance {:?} started epoch {}, {} terminated",
|
||||||
self.netinfo.our_id(),
|
self.netinfo.our_id(),
|
||||||
self.proposer_id,
|
self.session_id,
|
||||||
self.epoch,
|
self.epoch,
|
||||||
self.received_conf.len(),
|
self.received_conf.len(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -68,6 +68,10 @@ mod bool_multimap;
|
||||||
pub mod bool_set;
|
pub mod bool_set;
|
||||||
mod sbv_broadcast;
|
mod sbv_broadcast;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use bincode;
|
||||||
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use rand;
|
use rand;
|
||||||
|
|
||||||
use self::bool_set::BoolSet;
|
use self::bool_set::BoolSet;
|
||||||
|
@ -82,8 +86,23 @@ pub enum Error {
|
||||||
HandleThresholdSign(threshold_sign::Error),
|
HandleThresholdSign(threshold_sign::Error),
|
||||||
#[fail(display = "Error invoking the common coin: {}", _0)]
|
#[fail(display = "Error invoking the common coin: {}", _0)]
|
||||||
InvokeCoin(threshold_sign::Error),
|
InvokeCoin(threshold_sign::Error),
|
||||||
#[fail(display = "Unknown proposer")]
|
// Strings because `io` and `bincode` errors lack `Eq` and `Clone`.
|
||||||
UnknownProposer,
|
#[fail(display = "Error writing epoch for nonce: {}", _0)]
|
||||||
|
Io(String),
|
||||||
|
#[fail(display = "Error serializing session ID for nonce: {}", _0)]
|
||||||
|
Serialize(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(err: io::Error) -> Error {
|
||||||
|
Error::Io(format!("{:?}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bincode::Error> for Error {
|
||||||
|
fn from(err: bincode::Error) -> Error {
|
||||||
|
Error::Io(format!("{:?}", err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An Binary Agreement result.
|
/// An Binary Agreement result.
|
||||||
|
@ -151,14 +170,13 @@ struct Nonce(Vec<u8>);
|
||||||
impl Nonce {
|
impl Nonce {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
invocation_id: &[u8],
|
invocation_id: &[u8],
|
||||||
session_id: u64,
|
session_id: &[u8],
|
||||||
proposer_id: usize,
|
|
||||||
binary_agreement_epoch: u32,
|
binary_agreement_epoch: u32,
|
||||||
) -> Self {
|
) -> Result<Self> {
|
||||||
Nonce(Vec::from(format!(
|
let mut vec = invocation_id.to_vec();
|
||||||
"Nonce for Honey Badger {:?}@{}:{}:{}",
|
vec.write_u32::<BigEndian>(binary_agreement_epoch)?;
|
||||||
invocation_id, session_id, binary_agreement_epoch, proposer_id
|
vec.extend(session_id);
|
||||||
)))
|
Ok(Nonce(vec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,8 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
&self.public_keys
|
&self.public_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The index of a node in a canonical numbering of all nodes.
|
/// The index of a node in a canonical numbering of all nodes. This is the index where the
|
||||||
|
/// node appears in `all_ids`.
|
||||||
pub fn node_index(&self, id: &N) -> Option<usize> {
|
pub fn node_index(&self, id: &N) -> Option<usize> {
|
||||||
self.node_indices.get(id).cloned()
|
self.node_indices.get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,13 @@ impl<N: NodeIdT + Rand> Subset<N> {
|
||||||
|
|
||||||
// Create all Binary Agreement instances.
|
// Create all Binary Agreement instances.
|
||||||
let mut ba_instances: BTreeMap<N, BinaryAgreement<N>> = BTreeMap::new();
|
let mut ba_instances: BTreeMap<N, BinaryAgreement<N>> = BTreeMap::new();
|
||||||
for proposer_id in netinfo.all_ids() {
|
for (proposer_idx, proposer_id) in netinfo.all_ids().enumerate() {
|
||||||
ba_instances.insert(
|
ba_instances.insert(
|
||||||
proposer_id.clone(),
|
proposer_id.clone(),
|
||||||
BinaryAgreement::new(netinfo.clone(), session_id, proposer_id.clone())
|
BinaryAgreement::new(
|
||||||
.map_err(Error::NewBinaryAgreement)?,
|
netinfo.clone(),
|
||||||
|
BaSessionId(session_id, proposer_idx as u32),
|
||||||
|
).map_err(Error::NewBinaryAgreement)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,3 +368,9 @@ impl<N: NodeIdT + Rand> Subset<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A session identifier for a `BinaryAgreement` instance run as a `Subset` sub-algorithm. It
|
||||||
|
/// consists of the `Subset` instance's own session ID, and the index of the proposer whose
|
||||||
|
/// contribution this `BinaryAgreement` is about.
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct BaSessionId(u64, u32);
|
||||||
|
|
|
@ -85,7 +85,7 @@ where
|
||||||
);
|
);
|
||||||
let adversary = |_| new_adversary(num_good_nodes, num_faulty_nodes);
|
let adversary = |_| new_adversary(num_good_nodes, num_faulty_nodes);
|
||||||
let new_ba = |netinfo: Arc<NetworkInfo<NodeId>>| {
|
let new_ba = |netinfo: Arc<NetworkInfo<NodeId>>| {
|
||||||
BinaryAgreement::new(netinfo, 0, NodeId(0)).expect("Binary Agreement instance")
|
BinaryAgreement::new(netinfo, 0).expect("Binary Agreement instance")
|
||||||
};
|
};
|
||||||
let network = TestNetwork::new(num_good_nodes, num_faulty_nodes, adversary, new_ba);
|
let network = TestNetwork::new(num_good_nodes, num_faulty_nodes, adversary, new_ba);
|
||||||
test_binary_agreement(network, input);
|
test_binary_agreement(network, input);
|
||||||
|
|
Loading…
Reference in New Issue