This commit is contained in:
Weiliang Li 2019-08-13 16:38:55 +09:00 committed by Andreas Fackler
parent 10748c4d4a
commit 63b9ab8857
10 changed files with 139 additions and 63 deletions

4
.gitignore vendored
View File

@ -24,4 +24,6 @@ Cargo.lock
/bak
*.gz
massif*
massif*
.vscode/

1
.rustfmt.toml Normal file
View File

@ -0,0 +1 @@
edition = "2018"

View File

@ -7,18 +7,18 @@ Tolerant consensus algorithm](https://github.com/poanetwork/hbbft).
### Running a test peer
1. `git clone https://github.com/poanetwork/hydrabadger`
2. `cd hydrabadger`
3. `./run-node 0`
1. `git clone https://github.com/poanetwork/hydrabadger`
2. `cd hydrabadger`
3. `./run-node 0`
#### Additional peers
1. Open a new terminal window.
2. `cd {...}/hydrabadger`
3. `./run-node 1`
4. (Repeat 1 and 2), `./run-node 2`, `./run-node 3`, `./run-node 4`
* Note: If your terminal has tabs, open multiple tabs and use
ctrl-pgup/pgdown to cycle between tabs quickly.
1. Open a new terminal window.
2. `cd {...}/hydrabadger`
3. `./run-node 1`
4. (Repeat 1 and 2), `./run-node 2`, `./run-node 3`, `./run-node 4`
- Note: If your terminal has tabs, open multiple tabs and use
ctrl-pgup/pgdown to cycle between tabs quickly.
Each peer will generate a number of random transactions at regular intervals,
process them accordingly, and output complete batches. If your terminal is
@ -43,16 +43,16 @@ very well yet.
### Unimplemented
* **Many edge cases and exceptions:** disconnects, reconnects, etc.
* Connecting to a network which is in the process of key generation causes
the entire network to fail. For now, wait until the network starts
outputting batches before connecting additional peer nodes.
* **Error handling** is atrocious, most errors are simply printed to the log.
* **Usage as a library** is still a work in progress as the API settles.
* **Much, much more...**
- **Many edge cases and exceptions:** disconnects, reconnects, etc.
- Connecting to a network which is in the process of key generation causes
the entire network to fail. For now, wait until the network starts
outputting batches before connecting additional peer nodes.
- **Error handling** is atrocious, most errors are simply printed to the log.
- **Usage as a library** is still a work in progress as the API settles.
- **Much, much more...**
### License
[![License: LGPL v3.0](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
This project is licensed under the GNU Lesser General Public License v3.0. See the [LICENSE](LICENSE) file for details.
This project is licensed under the GNU Lesser General Public License v3.0. See the [LICENSE](LICENSE) file for details.

View File

@ -11,7 +11,7 @@ extern crate serde_derive;
use chrono::Local;
use clap::{App, Arg, ArgMatches};
use hydrabadger::{Blockchain, Config, Hydrabadger, MiningError, Uid};
use rand::{Rng, distributions::Standard};
use rand::{distributions::Standard, Rng};
use std::collections::HashSet;
use std::env;
use std::io::Write;
@ -97,7 +97,12 @@ pub struct Transaction(pub Vec<u8>);
impl Transaction {
fn random(len: usize) -> Transaction {
Transaction(rand::thread_rng().sample_iter(&Standard).take(len).collect())
Transaction(
rand::thread_rng()
.sample_iter(&Standard)
.take(len)
.collect(),
)
}
}

View File

@ -9,7 +9,7 @@ use super::{Error, Hydrabadger, InputOrMessage, State, StateDsct, StateMachine};
use crate::peer::Peers;
use crate::{
key_gen, BatchTx, Contribution, InAddr, InternalMessage, InternalMessageKind, InternalRx,
NetworkState, OutAddr, Step, Uid, WireMessage, WireMessageKind, NodeId,
NetworkState, NodeId, OutAddr, Step, Uid, WireMessage, WireMessageKind,
};
use crossbeam::queue::SegQueue;
use hbbft::{
@ -90,7 +90,11 @@ impl<C: Contribution, N: NodeId> Handler<C, N> {
Ok(())
}
fn handle_iom(&self, iom: InputOrMessage<C, N>, state: &mut StateMachine<C, N>) -> Result<(), Error> {
fn handle_iom(
&self,
iom: InputOrMessage<C, N>,
state: &mut StateMachine<C, N>,
) -> Result<(), Error> {
trace!("hydrabadger::Handler: About to handle_iom: {:?}", iom);
if let Some(step_res) = state.handle_iom(iom) {
let step = step_res.map_err(Error::HbStep)?;
@ -518,7 +522,7 @@ impl<C: Contribution, N: NodeId> Handler<C, N> {
let peers = self.hdb.peers();
let new_id = Uid::new();
// tx.unbounded_send(key_gen::Message::instance_id().unwrap();
let instance_id = key_gen::InstanceId::User(new_id.clone());
let instance_id = key_gen::InstanceId::User(new_id);
let key_gen = key_gen::Machine::generate(
self.hdb.node_id(),
self.hdb.secret_key().clone(),
@ -541,9 +545,10 @@ impl<C: Contribution, N: NodeId> Handler<C, N> {
) => {
debug!("Received hello from {:?}", src_nid_new);
let mut peers = self.hdb.peers_mut();
match peers
.establish_validator(src_out_addr, (src_nid_new.clone(), src_in_addr, src_pk))
{
match peers.establish_validator(
src_out_addr,
(src_nid_new.clone(), src_in_addr, src_pk),
) {
true => debug_assert!(src_nid_new == src_nid.unwrap()),
false => debug_assert!(src_nid.is_none()),
}
@ -738,7 +743,10 @@ impl<C: Contribution, N: NodeId> Future for Handler<C, N> {
);
}
Target::All => {
peers.wire_to_all(WireMessage::message(self.hdb.node_id().clone(), hb_msg.message));
peers.wire_to_all(WireMessage::message(
self.hdb.node_id().clone(),
hb_msg.message,
));
}
}
}

View File

@ -1,12 +1,11 @@
//! A hydrabadger consensus node.
//!
use serde::de::DeserializeOwned;
use super::{Error, Handler, StateDsct, StateMachine};
use crate::peer::{PeerHandler, Peers};
use crate::{
key_gen, BatchRx, Change, Contribution, EpochRx, EpochTx, InAddr, InternalMessage, InternalTx,
OutAddr, WireMessage, WireMessageKind, WireMessages, NodeId,
NodeId, OutAddr, WireMessage, WireMessageKind, WireMessages,
};
use futures::{
future::{self, Either},
@ -14,7 +13,7 @@ use futures::{
};
use hbbft::crypto::{PublicKey, SecretKey};
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
use rand::{self, Rng};
use serde::de::DeserializeOwned;
use std::{
collections::HashSet,
net::SocketAddr,
@ -122,7 +121,7 @@ pub struct Hydrabadger<C: Contribution, N: NodeId> {
impl<C: Contribution, N: NodeId + DeserializeOwned + 'static> Hydrabadger<C, N> {
/// Returns a new Hydrabadger node.
pub fn new(addr: SocketAddr, cfg: Config, nid: N) -> Self {
let secret_key: SecretKey = rand::rngs::OsRng::new().expect("Unable to create rng").gen();
let secret_key = SecretKey::random();
let (peer_internal_tx, peer_internal_rx) = mpsc::unbounded();
let (batch_tx, batch_rx) = mpsc::unbounded();
@ -310,7 +309,8 @@ impl<C: Contribution, N: NodeId + DeserializeOwned + 'static> Hydrabadger<C, N>
/// Returns a future that handles incoming connections on `socket`.
fn handle_incoming(self, socket: TcpStream) -> impl Future<Item = (), Error = ()> {
info!("Incoming connection from '{}'", socket.peer_addr().unwrap());
let wire_msgs: WireMessages<C, N> = WireMessages::new(socket, self.inner.secret_key.clone());
let wire_msgs: WireMessages<C, N> =
WireMessages::new(socket, self.inner.secret_key.clone());
wire_msgs
.into_future()

View File

@ -3,7 +3,7 @@
use super::Error;
use crate::hydrabadger::hydrabadger::Hydrabadger;
use crate::peer::Peers;
use crate::{Contribution, NetworkState, Uid, WireMessage, NodeId};
use crate::{Contribution, NetworkState, NodeId, Uid, WireMessage};
use crossbeam::queue::SegQueue;
use futures::sync::mpsc;
use hbbft::{
@ -64,7 +64,6 @@ pub(super) enum State<N> {
sync_key_gen: Option<SyncKeyGen<N>>,
public_key: Option<PublicKey>,
public_keys: BTreeMap<N, PublicKey>,
part_count: usize,
ack_count: usize,
},
@ -75,7 +74,12 @@ pub(super) enum State<N> {
}
/// Forwards an `Ack` to a `SyncKeyGen` instance.
fn handle_ack<N: NodeId>(nid: &N, ack: Ack, ack_count: &mut usize, sync_key_gen: &mut SyncKeyGen<N>) {
fn handle_ack<N: NodeId>(
nid: &N,
ack: Ack,
ack_count: &mut usize,
sync_key_gen: &mut SyncKeyGen<N>,
) {
trace!("KEY GENERATION: Handling ack from '{:?}'...", nid);
let ack_outcome = sync_key_gen
.handle_ack(nid, ack.clone())

View File

@ -7,7 +7,7 @@
use super::{key_gen, Config, Error, InputOrMessage};
use crate::peer::Peers;
use crate::{ActiveNetworkInfo, Contribution, NetworkNodeInfo, NetworkState, Step, NodeId};
use crate::{ActiveNetworkInfo, Contribution, NetworkNodeInfo, NetworkState, NodeId, Step};
use crossbeam::queue::SegQueue;
use hbbft::{
crypto::{PublicKey, SecretKey},
@ -208,8 +208,12 @@ impl<C: Contribution, N: NodeId> StateMachine<C, N> {
State::DeterminingNetworkState {
ref mut iom_queue, ..
} => {
let (dhb, dhb_step) =
DynamicHoneyBadger::new_joining(local_nid, local_sk, jp, &mut StdRng::from_entropy())?;
let (dhb, dhb_step) = DynamicHoneyBadger::new_joining(
local_nid,
local_sk,
jp,
&mut StdRng::from_entropy(),
)?;
step_queue.push(dhb_step);
iom_queue_ret = iom_queue.take().unwrap();
@ -275,7 +279,12 @@ impl<C: Contribution, N: NodeId> StateMachine<C, N> {
let mut node_ids: BTreeMap<N, PublicKey> = peers
.validators()
.map(|p| (p.node_id().cloned().unwrap(), p.public_key().cloned().unwrap()))
.map(|p| {
(
p.node_id().cloned().unwrap(),
p.public_key().cloned().unwrap(),
)
})
.collect();
node_ids.insert(local_nid.clone(), local_sk.public_key());
@ -391,8 +400,11 @@ impl<C: Contribution, N: NodeId> StateMachine<C, N> {
let peer_infos = peers
.peers()
.filter_map(|peer| {
peer.pub_info()
.map(|(nid, &in_addr, &pk)| NetworkNodeInfo { nid: nid.clone(), in_addr, pk })
peer.pub_info().map(|(nid, &in_addr, &pk)| NetworkNodeInfo {
nid: nid.clone(),
in_addr,
pk,
})
})
.collect::<Vec<_>>();
match self.state {
@ -467,7 +479,9 @@ impl<C: Contribution, N: NodeId> StateMachine<C, N> {
match iom {
InputOrMessage::Contribution(contrib) => dhb.propose(contrib, &mut rng),
InputOrMessage::Change(change) => dhb.vote_for(change),
InputOrMessage::Message(src_nid, msg) => dhb.handle_message(&src_nid, msg, &mut rng),
InputOrMessage::Message(src_nid, msg) => {
dhb.handle_message(&src_nid, msg, &mut rng)
}
}
});

View File

@ -23,8 +23,8 @@ extern crate env_logger;
extern crate log;
#[macro_use]
extern crate failure;
extern crate crossbeam;
extern crate chrono;
extern crate crossbeam;
extern crate crypto;
extern crate num_bigint;
extern crate num_traits;
@ -69,7 +69,10 @@ use hbbft::{
sync_key_gen::{Ack, Part},
Contribution as HbbftContribution, CpStep as MessagingStep, NodeIdT,
};
use rand::{distributions::{Standard, Distribution}, Rng};
use rand::{
distributions::{Distribution, Standard},
Rng,
};
use serde::{de::DeserializeOwned, Serialize};
use std::{
collections::BTreeMap,
@ -146,8 +149,14 @@ pub struct Uid(pub(crate) Uuid);
impl Uid {
/// Returns a new, random `Uid`.
pub fn new() -> Uid {
Uid(Uuid::new_v4())
pub fn new() -> Self {
Self::default()
}
}
impl Default for Uid {
fn default() -> Self {
Self(Uuid::new_v4())
}
}
@ -215,7 +224,11 @@ pub struct NetworkNodeInfo<N> {
pub(crate) pk: PublicKey,
}
type ActiveNetworkInfo<N> = (Vec<NetworkNodeInfo<N>>, PublicKeySet, BTreeMap<N, PublicKey>);
type ActiveNetworkInfo<N> = (
Vec<NetworkNodeInfo<N>>,
PublicKeySet,
BTreeMap<N, PublicKey>,
);
/// The current state of the network.
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -474,7 +487,10 @@ impl<C: Contribution, N: NodeId> InternalMessage<C, N> {
}
/// Returns a new `InternalMessage` without a uid.
pub fn new_without_uid(src_addr: OutAddr, kind: InternalMessageKind<C, N>) -> InternalMessage<C, N> {
pub fn new_without_uid(
src_addr: OutAddr,
kind: InternalMessageKind<C, N>,
) -> InternalMessage<C, N> {
InternalMessage::new(None, src_addr, kind)
}

View File

@ -4,14 +4,11 @@
use crate::hydrabadger::{Error, Hydrabadger};
use crate::{
Contribution, InAddr, InternalMessage, OutAddr, Uid, WireMessage, WireMessageKind,
WireMessages, WireRx, WireTx, NodeId,
Contribution, InAddr, InternalMessage, NodeId, OutAddr, Uid, WireMessage, WireMessageKind,
WireMessages, WireRx, WireTx,
};
use futures::sync::mpsc;
use hbbft::{
crypto::PublicKey,
dynamic_honey_badger::Input as HbInput,
};
use hbbft::{crypto::PublicKey, dynamic_honey_badger::Input as HbInput};
use serde::{Deserialize, Serialize};
use std::{
borrow::Borrow,
@ -135,7 +132,11 @@ impl<C: Contribution, N: NodeId> Future for PeerHandler<C, N> {
self.hdb.send_internal(InternalMessage::wire(
Some(src_nid.clone()),
self.out_addr,
WireMessage::welcome_received_change_add(src_nid.clone(), pk, net_state),
WireMessage::welcome_received_change_add(
src_nid.clone(),
pk,
net_state,
),
));
}
WireMessageKind::HelloFromValidator(src_nid, in_addr, pk, net_state) => {
@ -144,7 +145,12 @@ impl<C: Contribution, N: NodeId> Future for PeerHandler<C, N> {
self.hdb.send_internal(InternalMessage::wire(
Some(src_nid.clone()),
self.out_addr,
WireMessage::hello_from_validator(src_nid.clone(), in_addr, pk, net_state),
WireMessage::hello_from_validator(
src_nid.clone(),
in_addr,
pk,
net_state,
),
));
}
WireMessageKind::Message(src_nid, msg) => {
@ -274,9 +280,15 @@ impl<C: Contribution, N: NodeId> Peer<C, N> {
/// Sets a peer state to `State::EstablishedObserver` and stores public info.
fn establish_observer(&mut self) {
self.state = match self.state {
State::PendingJoinInfo { ref nid, in_addr, pk } => {
State::EstablishedObserver { nid: nid.clone(), in_addr, pk }
}
State::PendingJoinInfo {
ref nid,
in_addr,
pk,
} => State::EstablishedObserver {
nid: nid.clone(),
in_addr,
pk,
},
_ => panic!(
"Peer::establish_observer: Can only establish observer when \
peer state is`PendingJoinInfo`."
@ -300,14 +312,22 @@ impl<C: Contribution, N: NodeId> Peer<C, N> {
);
}
},
State::EstablishedObserver { ref nid, in_addr, pk } => {
State::EstablishedObserver {
ref nid,
in_addr,
pk,
} => {
if pub_info.is_some() {
panic!(
"Peer::establish_validator: `pub_info` must be `None` \
when upgrading an observer node."
);
}
State::EstablishedValidator { nid: nid.clone(), in_addr, pk }
State::EstablishedValidator {
nid: nid.clone(),
in_addr,
pk,
}
}
_ => panic!(
"Peer::establish_validator: Can only establish validator when \
@ -457,7 +477,10 @@ impl<C: Contribution, N: NodeId> Peers<C, N> {
No peer found with outgoing address: {}",
out_addr.borrow()
));
match self.out_addrs.insert(pub_info.0.clone(), *out_addr.borrow()) {
match self
.out_addrs
.insert(pub_info.0.clone(), *out_addr.borrow())
{
Some(_out_addr_pub) => {
let pi_pub = peer
.pub_info()
@ -512,7 +535,10 @@ impl<C: Contribution, N: NodeId> Peers<C, N> {
No peer found with outgoing address: {}",
out_addr.borrow()
));
match self.out_addrs.insert(pub_info.0.clone(), *out_addr.borrow()) {
match self
.out_addrs
.insert(pub_info.0.clone(), *out_addr.borrow())
{
Some(_out_addr_pub) => {
let pi_pub = peer
.pub_info()