mirror of https://github.com/poanetwork/hbbft.git
Merge pull request #95 from poanetwork/afck-docs
Move broadcast docs to module-level.
This commit is contained in:
commit
fd6fefc24b
|
@ -1,3 +1,46 @@
|
|||
//! # Broadcast
|
||||
//!
|
||||
//! The Reliable Broadcast Protocol assumes a network of `N` nodes that send signed messages to
|
||||
//! each other, with at most `f` of them faulty, where `3 * f < N`. Handling the networking and
|
||||
//! signing is the responsibility of this crate's user; a message is only handed to the Broadcast
|
||||
//! instance after it has been verified to be "from node i". One of the nodes is the "proposer"
|
||||
//! who sends a value. It needs to be determined beforehand, and all nodes need to know and agree
|
||||
//! who it is. Under the above conditions, the protocol guarantees that either all or none
|
||||
//! of the correct nodes output a value, and that if the proposer is correct, all correct nodes
|
||||
//! output the proposed value.
|
||||
//!
|
||||
//! ## How it works
|
||||
//!
|
||||
//! * The proposer uses a Reed-Solomon code to split the value into `N` chunks, `f + 1` of which
|
||||
//! suffice to reconstruct the value. These chunks are put into a Merkle tree, so that with the
|
||||
//! tree's root hash `h`, branch `bi` and chunk `si`, the `i`-th chunk `si` can be verified by
|
||||
//! anyone as belonging to the Merkle tree with root hash `h`. These values are "proof" number `i`:
|
||||
//! `pi = (h, bi, si)`.
|
||||
//! * The proposer sends `Value(pi)` to node `i`. It translates to: "I am the proposer, and `pi`
|
||||
//! contains the `i`-th share of my value."
|
||||
//! * Every (correct) node that receives `Value(pi)` from the proposer sends it on to everyone else
|
||||
//! as `Echo(pi)`. An `Echo` translates to: "I have received `pi` directly from the proposer." If
|
||||
//! the proposer sends another `Value` message it is ignored.
|
||||
//! * So every node that receives at least `f + 1` `Echo` messages with the same root hash can
|
||||
//! decode a value.
|
||||
//! * Every node that has received `N - f` `Echo`s with the same root hash from different nodes
|
||||
//! knows that at least `f + 1` _correct_ nodes have sent an `Echo` with that hash to everyone, and
|
||||
//! therefore everyone will eventually receive at least `f + 1` of them. So upon receiving `N - f`
|
||||
//! `Echo`s, they send a `Ready(h)` to everyone. It translates to: "I know that everyone will
|
||||
//! eventually be able to decode the value with root hash `h`." Moreover, since every correct node
|
||||
//! only sends one kind of `Echo` message, there is no danger of receiving `N - f` `Echo`s with two
|
||||
//! different root hashes.
|
||||
//! * Even without enough `Echo` messages, if a node receives `f + 1` `Ready` messages, it knows
|
||||
//! that at least one _correct_ node has sent `Ready`. It therefore also knows that everyone will
|
||||
//! be able to decode eventually, and multicasts `Ready` itself.
|
||||
//! * If a node has received `2 * f + 1` `Ready`s (with matching root hash) from different nodes,
|
||||
//! it knows that at least `f + 1` _correct_ nodes have sent it. Therefore, every correct node will
|
||||
//! eventually receive `f + 1`, and multicast it itself. Therefore, every correct node will
|
||||
//! eventually receive `2 * f + 1` `Ready`s, too. _And_ we know at this point that every correct
|
||||
//! node will 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 correct node will eventually do the same.
|
||||
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fmt::{self, Debug};
|
||||
use std::iter::once;
|
||||
|
@ -51,45 +94,6 @@ impl Debug for BroadcastMessage {
|
|||
}
|
||||
|
||||
/// Reliable Broadcast algorithm instance.
|
||||
///
|
||||
/// The Reliable Broadcast Protocol assumes a network of `N` nodes that send signed messages to
|
||||
/// each other, with at most `f` of them malicious, where `3 * f < N`. Handling the networking and
|
||||
/// signing is the responsibility of this crate's user: only when a message has been verified to be
|
||||
/// "from node i", it can be handed to the `Broadcast` instance. One of the nodes is the "proposer"
|
||||
/// who sends a value. Under the above conditions, the protocol guarantees that either all or none
|
||||
/// of the good nodes output a value, and that if the proposer is good, all good nodes output the
|
||||
/// proposed value.
|
||||
///
|
||||
/// The algorithm works as follows:
|
||||
///
|
||||
/// * The proposer uses a Reed-Solomon code to split the value into `N` chunks, `f + 1` of which
|
||||
/// suffice to reconstruct the value. These chunks are put into a Merkle tree, so that with the
|
||||
/// tree's root hash `h`, branch `bi` and chunk `si`, the `i`-th chunk `si` can be verified by
|
||||
/// anyone to belong to the Merkle tree with root hash `h`. These values are "proof" number `i`:
|
||||
/// `pi`.
|
||||
/// * The proposer sends `Value(pi)` to node `i`. It translates to: "I am the proposer, and `pi`
|
||||
/// contains the `i`-th share of my value."
|
||||
/// * Every (good) node that receives `Value(pi)` from the proposer sends it on to everyone else as
|
||||
/// `Echo(pi)`. An `Echo` translates to: "I have received `pi` directly from the proposer." If the
|
||||
/// proposer sends another `Value` message, that is ignored.
|
||||
/// * So every node that has received at least `f + 1` `Echo` messages with the same root
|
||||
/// hash will be able to decode a value.
|
||||
/// * Every node that has received `N - f` `Echo`s with the same root hash from different nodes
|
||||
/// knows that at least `f + 1` _good_ nodes have sent an `Echo` with that hash to everyone, and
|
||||
/// therefore everyone will eventually receive at least `f + 1` of them. So upon receiving `N - f`
|
||||
/// `Echo`s, they send a `Ready(h)` to everyone to indicate that. `Ready` translates to: "I know
|
||||
/// that everyone will eventually be able to decode the value." Moreover, since every good node
|
||||
/// only ever sends one kind of `Echo` message, this cannot happen for two different root hashes.
|
||||
/// * Even without enough `Echo` messages, if a node receives `f + 1` `Ready` messages, it knows
|
||||
/// that at least one _good_ node has sent `Ready`. It therefore also knows that everyone will be
|
||||
/// able to decode eventually, and multicasts `Ready` itself.
|
||||
/// * If a node has received `2 * f + 1` `Ready`s (with matching root hash) from different nodes,
|
||||
/// it knows that at least `f + 1` _good_ nodes have sent it. Therefore, every good node will
|
||||
/// eventually receive `f + 1`, and multicast it itself. Therefore, every good node will eventually
|
||||
/// receive `2 * f + 1` `Ready`s, too. _And_ we know at this point that every good node will
|
||||
/// 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<NodeUid> {
|
||||
/// Shared network data.
|
||||
netinfo: Rc<NetworkInfo<NodeUid>>,
|
||||
|
|
Loading…
Reference in New Issue