MinBFT is a Rust implementation based on the equally named Byzantine fault-tolerant consensus algorithm presented in the paper Efficient Byzantine Fault-Tolerance.
MinBFT requires a Unique Sequential Identifier Generator (USIG) implementation. A USIG implementation compatible with this MinBFT implementation can be found here. Note that this implementation does not use Trusted Execution Environments and, thus, should not be used in untrusted environments.
This implementation was created as part of the ABCperf project. An integration in ABCperf also exists.
use anyhow::Result;
use std::{num::NonZeroU64, time::Duration};
use serde::{Deserialize, Serialize};
use shared_ids::{ReplicaId, ClientId, RequestId};
use usig::{Usig, noop::UsigNoOp};
use minbft::{MinBft, Config, Output, RequestPayload, PeerMessage, timeout::{TimeoutType}};
// The payload of a client request must be implemented by the user.
#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
struct SamplePayload {}
impl RequestPayload for SamplePayload {
fn id(&self) -> RequestId {
todo!()
}
fn verify(&self, id: ClientId) -> Result<()> {
todo!()
}
}
// The output should be handled by the user.
fn handle_output<U: Usig>(output: Output<SamplePayload, U>) {
let Output { broadcasts, responses, timeout_requests, .. } = output;
for broadcast in broadcasts.iter() {
// broadcast message to all peers, i.e., send messages contained
// in `broadcasts` of struct Output over the network to other
// replicas.
todo!();
}
for response in responses.iter() {
todo!();
}
for timeout_request in timeout_requests.iter() {
todo!();
}
}
fn main() {
// define the amount of replicas that form the atomic broadcast
let n = NonZeroU64::new(10).unwrap();
// define the maximum amount of faulty replicas (`n >= t / 2 + 1`)
let t = n.get() / 2;
// define the ID of one of the replicas
let replica_id = ReplicaId::from_u64(0);
let config = Config {
n: n.try_into().unwrap(),
t,
id: replica_id,
max_batch_size: Some(1.try_into().expect("> 0")),
batch_timeout: Duration::from_secs(1),
initial_timeout_duration: Duration::from_secs(1),
checkpoint_period: NonZeroU64::new(2).unwrap(),
};
// can be exchanged with a different USIG implementation
let usig = UsigNoOp::default();
let (mut minbft, output) = MinBft::<SamplePayload, _>::new(
usig,
config,
)
.unwrap();
// handle output to setup connection with peers
handle_output(output);
// all peers are now ready for client requests as they have
// successfully communicated with each replica for the first time.
// create and send client message to be handled by replicas.
let some_client_message: SamplePayload = todo!();
let output = minbft.handle_client_message(ClientId::from_u64(0), some_client_message);
handle_output(output);
// after the atomic broadcast achieves consensus,
// a response to the client request can be seen in the output struct.
}
Feel free to reach out via GitHub, matrix, or mail.
Licensed under MIT license.