mirror of https://github.com/poanetwork/hbbft.git
Remove protoc dep, use new MerkleTree methods.
This commit is contained in:
parent
01e89a7c48
commit
50d007b954
|
@ -17,11 +17,11 @@ serde = "1.0.55"
|
|||
serde_derive = { version = "1.0.55", optional = true }
|
||||
|
||||
[features]
|
||||
serialization-protobuf = [ "protobuf", "protoc-rust" ]
|
||||
serialization-protobuf = [ "protobuf", "protobuf-codegen-pure" ]
|
||||
serialization-serde = [ "merkle/serialization-serde", "serde_derive" ]
|
||||
|
||||
[build-dependencies]
|
||||
protoc-rust = { version = "1.6.0", optional = true }
|
||||
protobuf-codegen-pure = { version = "1.6.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
colored = "1.6"
|
||||
|
|
40
README.md
40
README.md
|
@ -15,46 +15,8 @@ An example is included to run a simulation of a network:
|
|||
|
||||
$ cargo run --example simulation -- --nodes 10 --faulty 1 --txs 1000 --batch 100
|
||||
|
||||
# Requirements
|
||||
|
||||
`hbbft` has optional protobuf support. To use protobuf, enable the feature
|
||||
`serialization-protobuf` in your `Cargo.toml`, and make sure you have
|
||||
Google's Protocol Buffer Compiler, `protoc` binary, located somewhere in
|
||||
your `$PATH`. You must be using Protocol Buffer Compiler version 3 or greater.
|
||||
Running any of the following install methods will save a `protoc` binary at
|
||||
`/usr/local/bin/protoc`.
|
||||
|
||||
*Note:* as of writing this, the latest stable release of `protoc` is
|
||||
v3.5.1. You can find out what is the latest compiler version is
|
||||
[here](https://github.com/google/protobuf/releases), if you are not
|
||||
installing `protoc` on Debian 9 or Ubuntu 17, change your cURL URL and zip
|
||||
file names accordingly.
|
||||
|
||||
## Installing `protoc` on Debian 9 (Strech) and Ubuntu 17 (Artful)
|
||||
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install -y protobuf-compiler
|
||||
|
||||
## Installing `protoc` on other versions of Debian and Ubuntu
|
||||
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install -y unzip
|
||||
$ cd <some temporary working directory>
|
||||
$ curl -OL https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-linux-x86_64.zip
|
||||
$ sudo unzip protoc-3.5.1-linux-x86_64.zip -d /usr/local bin/protoc
|
||||
$ sudo chown $(whoami) /usr/local/bin/protoc
|
||||
$ rm protoc-3.5.1-linux-x86_64.zip
|
||||
|
||||
## Installing `protoc` on OSX
|
||||
|
||||
$ cd <some temporary working directory>
|
||||
$ curl -OL https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-osx-x86_64.zip
|
||||
$ sudo unzip protoc-3.5.1-osx-x86_64.zip -d /usr/local bin/protoc
|
||||
$ rm protoc-3.5.1-osx-x86_64.zip
|
||||
|
||||
# Building
|
||||
|
||||
Once you have verified that the `protoc` binary is in your `$PATH`, you can
|
||||
build `hbbft` using cargo:
|
||||
You can build `hbbft` using cargo:
|
||||
|
||||
$ cargo build [--release]
|
||||
|
|
24
build.rs
24
build.rs
|
@ -1,30 +1,10 @@
|
|||
#[cfg(feature = "serialization-protobuf")]
|
||||
mod feature_protobuf {
|
||||
extern crate protoc_rust;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn protoc_exists() -> bool {
|
||||
let name = "PATH";
|
||||
match env::var_os(name) {
|
||||
Some(paths) => {
|
||||
for path in env::split_paths(&paths) {
|
||||
if path.join("protoc").exists() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => println!("PATH environment variable is not defined."),
|
||||
}
|
||||
false
|
||||
}
|
||||
extern crate protobuf_codegen_pure;
|
||||
|
||||
pub fn main() {
|
||||
if !protoc_exists() {
|
||||
panic!("protoc cannot be found. Install the protobuf compiler in the system path.");
|
||||
}
|
||||
println!("cargo:rerun-if-changed=proto/message.proto");
|
||||
protoc_rust::run(protoc_rust::Args {
|
||||
protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
|
||||
out_dir: "src/proto",
|
||||
input: &["proto/message.proto"],
|
||||
includes: &["proto"],
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use fmt::{HexBytes, HexList, HexProof};
|
||||
use merkle::proof::{Lemma, Positioned, Proof};
|
||||
use merkle::MerkleTree;
|
||||
use merkle::{MerkleTree, Proof};
|
||||
use reed_solomon_erasure as rse;
|
||||
use reed_solomon_erasure::ReedSolomon;
|
||||
use ring::digest;
|
||||
#[cfg(feature = "serialization-serde")]
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||
use std::fmt::{self, Debug};
|
||||
use std::iter;
|
||||
|
@ -14,27 +11,15 @@ use messaging::{DistAlgorithm, Target, TargetedMessage};
|
|||
|
||||
/// The three kinds of message sent during the reliable broadcast stage of the
|
||||
/// consensus algorithm.
|
||||
#[cfg_attr(feature = "serialization-serde", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum BroadcastMessage {
|
||||
#[cfg_attr(feature = "serialization-serde", serde(deserialize_with = "deserialize_proof"))]
|
||||
Value(Proof<Vec<u8>>),
|
||||
#[cfg_attr(feature = "serialization-serde", serde(deserialize_with = "deserialize_proof"))]
|
||||
Echo(Proof<Vec<u8>>),
|
||||
Ready(Vec<u8>),
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialization-serde")]
|
||||
#[allow(unused)]
|
||||
fn deserialize_proof<'de, D>(d: D) -> Result<Proof<Vec<u8>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let data: ::merkle::proof::ProofData<Vec<u8>> = Deserialize::deserialize(d)?;
|
||||
Ok(data.into_proof(&digest::SHA256))
|
||||
}
|
||||
|
||||
impl fmt::Debug for BroadcastMessage {
|
||||
impl Debug for BroadcastMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
BroadcastMessage::Value(ref v) => write!(f, "Value({:?})", HexProof(&v)),
|
||||
|
@ -381,11 +366,6 @@ impl<N: Eq + Debug + Clone + Ord> Broadcast<N> {
|
|||
self.all_uids.iter().position(|id| id == node_id)
|
||||
}
|
||||
|
||||
/// Returns the index of this proof's leave in the Merkle tree.
|
||||
fn index_of_proof(&self, proof: &Proof<Vec<u8>>) -> usize {
|
||||
index_of_lemma(&proof.lemma, self.num_nodes)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
|
@ -397,7 +377,7 @@ impl<N: Eq + Debug + Clone + Ord> Broadcast<N> {
|
|||
);
|
||||
false
|
||||
} else if self.index_of_node(id) != Some(p.value[0] as usize)
|
||||
|| self.index_of_proof(&p) != p.value[0] as usize
|
||||
|| p.index(self.num_nodes) != p.value[0] as usize
|
||||
{
|
||||
info!(
|
||||
"Node {:?} received proof for wrong position: {:?}.",
|
||||
|
@ -556,33 +536,3 @@ where
|
|||
|
||||
t[1..(payload_len + 1)].to_vec().into()
|
||||
}
|
||||
|
||||
/// Computes the Merkle tree leaf index of a value in a given lemma.
|
||||
pub fn index_of_lemma(lemma: &Lemma, n: usize) -> usize {
|
||||
let m = n.next_power_of_two();
|
||||
match (lemma.sub_lemma.as_ref(), lemma.sibling_hash.as_ref()) {
|
||||
(None, Some(&Positioned::Right(_))) | (None, None) => 0,
|
||||
(None, Some(&Positioned::Left(_))) => 1,
|
||||
(Some(l), None) => index_of_lemma(l, n),
|
||||
(Some(l), Some(&Positioned::Left(_))) => (m >> 1) + index_of_lemma(l, n - (m >> 1)),
|
||||
(Some(l), Some(&Positioned::Right(_))) => index_of_lemma(l, m >> 1),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_index_of_lemma() {
|
||||
for &n in &[3, 4, 13, 16, 127, 128, 129, 255] {
|
||||
let shards: Vec<[u8; 1]> = (0..n).map(|i| [i as u8]).collect();
|
||||
let mtree = MerkleTree::from_vec(&digest::SHA256, shards);
|
||||
for (i, val) in mtree.iter().enumerate() {
|
||||
let p = mtree.gen_proof(val.clone()).expect("generate proof");
|
||||
let idx = index_of_lemma(&p.lemma, n);
|
||||
assert_eq!(i, idx, "Wrong index {} for leaf {}/{}.", idx, i, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
src/fmt.rs
37
src/fmt.rs
|
@ -1,4 +1,4 @@
|
|||
use merkle::proof::{Lemma, Positioned, Proof};
|
||||
use merkle::Proof;
|
||||
use std::fmt;
|
||||
|
||||
/// Wrapper for a byte array, whose `Debug` implementation outputs shortened hexadecimal strings.
|
||||
|
@ -40,43 +40,10 @@ impl<'a, T: AsRef<[u8]>> fmt::Debug for HexProof<'a, T> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Proof {{ algorithm: {:?}, root_hash: {:?}, lemma for leaf #{}, value: {:?} }}",
|
||||
"Proof {{ algorithm: {:?}, root_hash: {:?}, value: {:?}, .. }}",
|
||||
self.0.algorithm,
|
||||
HexBytes(&self.0.root_hash),
|
||||
path_of_lemma(&self.0.lemma),
|
||||
HexBytes(&self.0.value.as_ref())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// The path of a lemma in a Merkle tree
|
||||
struct BinaryPath(Vec<bool>);
|
||||
|
||||
/// The path of the lemma, as a binary string
|
||||
fn path_of_lemma(mut lemma: &Lemma) -> BinaryPath {
|
||||
let mut result = Vec::new();
|
||||
loop {
|
||||
match lemma.sibling_hash {
|
||||
None => (),
|
||||
Some(Positioned::Left(_)) => result.push(true),
|
||||
Some(Positioned::Right(_)) => result.push(false),
|
||||
}
|
||||
lemma = match lemma.sub_lemma.as_ref() {
|
||||
Some(lemma) => lemma,
|
||||
None => return BinaryPath(result),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BinaryPath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for b in &self.0 {
|
||||
if *b {
|
||||
write!(f, "1")?;
|
||||
} else {
|
||||
write!(f, "0")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue