Skip to content

distributed-lab/bpcon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Weighted BPCon Rust Library

License: GPL v3 Rust CI🌌 Docs 🌌

This is a rust library implementing weighted BPCon consensus.

Documentation

Library is documented with rustdoc. Compiled documentation for main branch is available at GitBook.

Usage

Add dependency in your Cargo.toml

[dependencies]
bpcon = {version = "0.1.0", git = "https://github.com/distributed-lab/bpcon"}

Implement Value trait

This is a core trait, which defines what type are you selecting in your consensus. It may be the next block in blockchain, or leader for some operation, or anything else you need.

Below is a simple example, where we will operate on selection for u64 type. Using it you may interpret ID for leader of distributed operation, for instance.

...
use bpcon::value::Value;

#[derive(Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Debug, Hash)]
pub(crate) struct MyValue(u64);

impl Value for MyValue {}

Implement ValueSelector trait

BPCon allows you to define specific conditions how proposer (leader) will select value and how other members will verify its selection.

Here is a simple example:

...
use bpcon::value::ValueSelector;

#[derive(Clone)]
pub struct MyValueSelector;

impl ValueSelector<MyValue> for MyValueSelector {
    /// Verifies if the given value `v` has been correctly selected according to the protocol rules.
    ///
    /// In this basic implementation, we'll consider a value as "correctly selected" if it matches
    /// the majority of the values in the provided `HashMap`.
    fn verify(&self, v: &MyValue, m: &HashMap<u64, Option<MyValue>>) -> bool {
        // Count how many times the value `v` appears in the `HashMap`
        let count = m.values().filter(|&val| val.as_ref() == Some(v)).count();

        // For simplicity, consider the value verified if it appears in more than half of the entries
        count > m.len() / 2
    }

    /// Selects a value based on the provided `HashMap` of party votes.
    ///
    /// This implementation selects the value that appears most frequently in the `HashMap`.
    /// If there is a tie, it selects the smallest value (as per the natural ordering of `u64`).
    fn select(&self, m: &HashMap<u64, Option<MyValue>>) -> MyValue {
        let mut frequency_map = HashMap::new();

        // Count the frequency of each value in the `HashMap`
        for value in m.values().flatten() {
            *frequency_map.entry(value).or_insert(0) += 1;
        }

        // Find the value with the highest frequency. In case of a tie, select the smallest value.
        frequency_map
            .into_iter()
            .max_by_key(|(value, count)| (*count, value.0))
            .map(|(value, _)| value.clone())
            .expect("No valid value found")
    }
}

Decide on a LeaderElector

LeaderElector trait allows you to define specific conditions, how to select leader for consensus.

NOTE: it is important to provide deterministic mechanism, because each participant will compute leader for itself and in case it is not deterministic, state divergence occurs.

We also provide ready-to-use DefaultLeaderElector which is using weighted randomization.

Configure your ballot

As a next step, you need to decide on parameters for your ballot:

  1. Amount of parties and their weight.
  2. Threshold weight.
  3. Time bounds.

Example:

use bpcon::config::BPConConfig;

let cfg = BPConConfig::with_default_timeouts(vec![1, 1, 1, 1, 1, 1], 4);

Feel free to explore config.rs for more information.

Create parties

Having BPConConfig, ValueSelector and LeaderElector defined, instantiate your parties. Check out new method on a Party struct.

Launch ballot on parties and handle messages

Each party interfaces communication with external system via channels. In a way, you shall propagate outgoing messages to other parties like:

  1. Listen for outgoing message using msg_out_receiver.
  2. Forward it to other parties using msg_in_sender.

We welcome you to check test_end_to_end_ballot in party.rs for example.