4 releases (stable)

1.0.3 May 29, 2024
1.0.2 May 10, 2024
1.0.0 Apr 26, 2024
0.10.0 Sep 29, 2023
0.0.0-reserved Aug 16, 2023

#180 in Parser implementations

Download history 3/week @ 2024-08-02 2/week @ 2024-08-30 15/week @ 2024-09-20 6/week @ 2024-09-27

423 downloads per month
Used in 3 crates (2 directly)

MIT license

545KB
10K SLoC

MinBFT

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.

MinBFT in Action

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.
}

Contact

Feel free to reach out via GitHub, matrix, or mail.

License

Licensed under MIT license.

Dependencies

~3.5–5MB
~107K SLoC