1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Copyright 2018 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

//! This is an implementation of PARSEC (Protocol for Asynchronous, Reliable, Secure and Efficient
//! Consensus).  For details of the protocol, see
//! [the RFC](https://github.com/maidsafe/rfcs/tree/master/text/0049-parsec/0049-parsec.md) and
//! [the whitepaper](http://docs.maidsafe.net/Whitepapers/pdf/PARSEC.pdf).
//!
//! # What is a consensus protocol?
//!
//! Distributed systems consist of multiple processes, which we shall call "peers", which perform
//! calculations independently. Many distributed systems deal with some kind of state that is
//! shared between the peers. It is a big challenge in such a setting to make sure that all the
//! peers have the same notion of what this shared state is.
//!
//! Let us imagine a distributed system that controls some kinds of financial transactions. The
//! peers in the system maintain a record of who has how much money and when a client wants to
//! transfer some amount, they can contact any of them and place an order. A malicious party could
//! contact several peers and place different transfer orders, and if the peers can't agree about
//! their order, bad things can happen.
//!
//! For example, let us assume that Eve has £1000 and wants to cheat the system, so she contacts
//! one peer and tells it to transfer £1000 to Alice, then she contacts a second peer and tells it
//! to transfer £1000 to Bob. The system can't execute both orders, because Eve has insufficient
//! funds for that - the peers need to decide which of those two orders to approve, and all of them
//! have to make the same decision, or the shared state of account balances will no longer be
//! shared and the network will effectively split in two.
//!
//! This is where consensus protocols (or algorithms) come into play. They are sets of rules for
//! the peers to follow that let them _propose_ some values and make all the peers eventually
//! _decide_ on a value. They satisfy the following properties:
//!
//! * Validity - only a value proposed by a correct peer can be decided as the final value.
//! * Integrity - once a peer decides on a value, it never decides on another value.
//! * Agreement - all correct peers decide on the same value.
//! * Termination - all correct peers eventually decide on some value.
//!
//! Those properties talk of "correct" peers - that is because there is a class of consensus
//! protocols, called _Byzantine Fault Tolerant_ (BFT) protocols, that ensure all these properties
//! even if some peers in the system don't follow the protocol. Not following the protocol may come
//! in different flavours, for example, a peer can just fail and stop responding, or it might be
//! malicious and try to get other peers to disagree or to agree on some forged value. Correct
//! peers are the peers that follow the protocol, ie. they are neither failed, nor malicious.
//!
//! # Synchrony in consensus protocols
//!
//! Apart from whether a protocol is BFT or not, there is another important property of consensus
//! algorithms, and it is their synchrony assumptions.
//!
//! All consensus protocols require the peers in the system to exchange messages in order to arrive
//! at the final value. For example, the peers need to communicate the proposed values to each
//! other. However, no network works without delays and there is always some nonzero time interval
//! between the sending of a message and its reception. Various consensus protocols have various
//! limitations regarding these delays. There are a few main classes of protocols:
//!
//! * Synchronous - the delays in the network have to be bounded by a known value for the
//! properties mentioned above to hold. Such an assumption allows the peers to wait for a response
//! for a defined period. If they don't hear back from another peer during that period, they can
//! consider it failed.
//! * Partially synchronous - the delays in the network are assumed to be bounded, but the bound is
//! unknown. This means that we can't set a timeout ahead of time, so a different approach must be
//! taken. Timeouts are usually still employed, but a timeout doesn't necessarily mean a failure.
//! * Asynchronous - the delays in the network can be arbitrarily large. In fact, no assumptions
//! about them is made, the only assumption is that all messages are delivered eventually. In
//! particular, the delays can be controlled by a malicious adversary (for example, using a DDoS
//! attack).
//!
//! Protocols that work in an asynchronous setting are the most robust, and hence very much
//! desired. There are multiple such algorithms, but they are usually very complex or inefficient.
//!
//! # PARSEC
//!
//! The PARSEC consensus algorithm is Byzantine Fault Tolerant, and works under assumptions that
//! lie between partial synchrony and asynchrony (the precise synchrony assumption is still to be
//! determined). As such, it is suited for many cases where one would usually apply an asynchronous
//! protocol.
//!
//! In PARSEC, peers that are part of the system (often called a "section" in the code, after a
//! unit in SAFE Network) vote for transactions, and the output of the algorithm is a sequence of
//! blocks that contain these transactions in an agreed order.
//!
//! ## Usage
//!
//! The typical usage of the crate would consist of the following:
//!
//! * Calling [`Parsec::from_genesis`](struct.Parsec.html#method.from_genesis) if the peer is a
//! member of the initial section, or
//! [`Parsec::from_existing`](struct.Parsec.html#method.from_existing) if the peer joins an
//! existing section, to construct a `Parsec` instance.
//! * Calling [`Parsec::vote_for`](struct.Parsec.html#method.vote_for) whenever the peer is
//! supposed to vote for a transaction (be it an application-specific, opaque payload, or a section
//! mutation: a peer joining or being removed).
//! * Calling [`Parsec::create_gossip`](struct.Parsec.html#method.create_gossip) at random points
//! to exchange information with other peers. The function returns a message containing a gossip
//! request to be sent to the gossip partner.
//! * Calling [`Parsec::handle_request`](struct.Parsec.html#method.handle_request) when a gossip
//! request is received. This returns a response to be sent to the author of the request.
//! * Calling [`Parsec::handle_response`](struct.Parsec.html#method.handle_response) when a
//! response is received.
//! * Calling [`Parsec::poll`](struct.Parsec.html#method.poll) to see whether there are new agreed
//! blocks - this is typically called after `handle_request` or `handle_response` until it returns
//! `None`.
//!
//! The crate doesn't include any networking layer - sending and receiving messages is the
//! consumer's responsibility.

#![doc(
    html_logo_url = "https://raw.githubusercontent.com/maidsafe/QA/master/Images/maidsafe_logo.png",
    html_favicon_url = "https://maidsafe.net/img/favicon.ico",
    test(attr(forbid(warnings)))
)]
#![forbid(
    arithmetic_overflow,
    mutable_transmutes,
    no_mangle_const_items,
    unknown_crate_types,
    warnings
)]
#![deny(
    bad_style,
    deprecated,
    improper_ctypes,
    missing_docs,
    non_shorthand_field_patterns,
    overflowing_literals,
    stable_features,
    unconditional_recursion,
    unknown_lints,
    unsafe_code,
    unused,
    unused_allocation,
    unused_attributes,
    unused_comparisons,
    unused_features,
    unused_parens,
    while_true
)]
#![warn(
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
    unused_results
)]
#![allow(
    box_pointers,
    missing_copy_implementations,
    missing_debug_implementations,
    variant_size_differences,
    clippy::new_ret_no_self
)]

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(feature = "testing")]
#[macro_use]
extern crate proptest as proptest_crate;
#[macro_use]
extern crate serde_derive;
#[cfg(any(test, feature = "testing", feature = "dump-graphs"))]
#[macro_use]
extern crate unwrap;

macro_rules! log_or_panic {
    ($($arg:tt)*) => {
        if cfg!(any(test, feature = "testing")) && !::std::thread::panicking() {
            panic!($($arg)*);
        } else {
            log::error!($($arg)*);
        }
    };
}

#[doc(hidden)]
#[cfg(any(test, feature = "testing"))]
#[macro_use]
pub mod dev_utils;

mod block;
mod dump_graph;
mod error;
mod gossip;
mod hash;
mod id;
mod key_gen;
mod meta_voting;
mod network_event;
mod observation;
mod parsec;
mod parsec_helpers;
mod peer_list;
mod vote;

#[cfg(all(test, feature = "mock"))]
mod functional_tests;

#[doc(hidden)]
/// **NOT FOR PRODUCTION USE**: Mock types which trivially implement the required Parsec traits.
///
/// This can be used to swap proper cryptographic functionality for inexpensive (in some cases
/// no-op) replacements.  This is useful to allow tests to run quickly, but should not be used
/// outside of testing code.
#[cfg(any(test, feature = "mock"))]
pub mod mock;

#[cfg(feature = "dump-graphs")]
pub use crate::dump_graph::{DumpGraphMode, DIR, DUMP_MODE};
pub use crate::{
    block::Block,
    error::{Error, Result},
    gossip::{EventHash, PackedEvent, Request, Response},
    id::{Proof, PublicId, SecretId},
    key_gen::dkg_result::*,
    network_event::NetworkEvent,
    observation::{ConsensusMode, Malice, Observation},
    parsec::Parsec,
    vote::Vote,
};

use serde::ser::Serialize;
use std::fmt::Debug;

fn serialise<T: Serialize + Debug>(data: &T) -> Vec<u8> {
    match bincode::serialize(data) {
        Ok(serialised) => serialised,
        Err(error) => {
            log_or_panic!("Failed to serialise {:?}: {}", data, error);
            vec![]
        }
    }
}