Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: primary implementation of the protocol #6

Merged
merged 21 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Deploy Rust Docs to GitHub Pages

on:
push:
branches:
- main

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true

- name: Build Rust Documentation
run: |
cargo doc --no-deps --document-private-items
echo "<meta http-equiv=\"refresh\" content=\"0; url=\">" > target/doc/index.html

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./target/doc

deploy:
runs-on: ubuntu-latest
needs: build

permissions:
pages: write
id-token: write

environment:
name: docs
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
135 changes: 135 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: Rust CI

on:
pull_request:
branches:
- main
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-

- name: Cache Cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true

- name: Run cargo check
uses: actions-rs/cargo@v1
continue-on-error: false
with:
command: check

test:
name: Test Suite
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, beta, nightly]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-

- name: Cache Cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-

- name: Install ${{ matrix.rust }} toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}

- name: Run cargo test
uses: actions-rs/cargo@v1
continue-on-error: false
with:
command: test
args: --all-features --verbose

lints:
name: Lints
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-

- name: Cache Cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy

- name: Run cargo fmt
uses: actions-rs/cargo@v1
continue-on-error: false
with:
command: fmt
args: --all -- --check

- name: Run cargo clippy
uses: actions-rs/cargo@v1
continue-on-error: false
with:
command: clippy
args: --all-targets -- -D warnings
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.204", features = ["derive"] }
rand = "0.9.0-alpha.2"
log = "0.4.22"
rkyv = { version = "0.7.44", features = ["validation"]}
serde = { version = "1.0.207", features = ["derive"] }
bincode = "1.3.3"
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# BPCon Rust Library

[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)

This is a generic rust implementation of the `BPCon` consensus mechanism.

## Library Structure

### src/party.rs

Main entity in this implementation is `Party` - it represents member of the consensus.

External system shall create desired amount of parties.

We have 2 communication channels - one for sending `MessageWire` - encoded in bytes message and routing information,
and the other for pitching consensus events - this allows for external system to impose custom limitations and rules
regarding runway.

### src/message.rs

Definitions of the general message struct, routing information and type-specific contents.

### src/lib.rs

Here we present a trait for the value on which consensus is being conducted. Additionally, there is a trait for
defining custom value selection rules, called `ValueSelector`.

56 changes: 54 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,56 @@
//! Definition of the BPCon errors.

use std::fmt;

#[derive(Debug)]
pub enum BallotError {
// TODO: define errors.
}
MessageParsing(String),
ValueParsing(String),
InvalidState(String),
Communication(String),
LeaderElection(String),
}

impl fmt::Display for BallotError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
BallotError::MessageParsing(ref err) => write!(f, "Message parsing error: {}", err),
BallotError::ValueParsing(ref err) => write!(f, "Value parsing error: {}", err),
BallotError::InvalidState(ref err) => write!(f, "Invalid state error: {}", err),
BallotError::Communication(ref err) => write!(f, "Communication error: {}", err),
BallotError::LeaderElection(ref err) => write!(f, "Leader election error: {}", err),
}
}
}

impl std::error::Error for BallotError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
// Since these are all simple String errors, there is no underlying source error.
None
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_ballot_error_message_parsing() {
let error = BallotError::MessageParsing("Parsing failed".into());
if let BallotError::MessageParsing(msg) = error {
assert_eq!(msg, "Parsing failed");
} else {
panic!("Expected MessageParsing error");
}
}

#[test]
fn test_ballot_error_invalid_state() {
let error = BallotError::InvalidState("Invalid state transition".into());
if let BallotError::InvalidState(msg) = error {
assert_eq!(msg, "Invalid state transition");
} else {
panic!("Expected InvalidState error");
}
}
}
17 changes: 11 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

mod error;
pub mod message;
pub mod party;
mod error;

/// General trait for value itself.
pub trait Value: Eq {}
pub trait Value: Eq + Serialize + for<'a> Deserialize<'a> + Clone {}

/// Trait for value selector and verificator.
/// Value selection and verification may depend on different conditions for different values.
/// Note that value selection should follow the rules of BPCon: only safe values can be selected.
/// Party can not vote for different values, even in different ballots.
pub trait ValueSelector<V: Value> {
/// Verifies if a value is selected correctly.
fn verify(v: V) -> bool;
/// Verifies if a value is selected correctly. Accepts 2b messages from parties.
fn verify(&self, v: &V, m: &HashMap<u64, Option<V>>) -> bool;

/// Select value depending on inner conditions.
fn select() -> V;
/// Select value depending on inner conditions. Accepts 2b messages from parties.
fn select(&self, m: &HashMap<u64, Option<V>>) -> V;

// TODO: add other fields to update selector state.
}
Loading
Loading