Skip to content

Commit

Permalink
Merge branch 'main' into josef/executor
Browse files Browse the repository at this point in the history
  • Loading branch information
josef-widder authored Nov 13, 2023
2 parents d02f187 + b2d63ed commit f397501
Show file tree
Hide file tree
Showing 61 changed files with 4,413 additions and 54 deletions.
10 changes: 6 additions & 4 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Coverage

on:
push:
branches: master
branches: main
paths:
- Code/**
pull_request:
Expand All @@ -12,6 +12,9 @@ on:
jobs:
coverage:
runs-on: ubuntu-latest
defaults:
run:
working-directory: Code
env:
CARGO_TERM_COLOR: always
steps:
Expand All @@ -20,17 +23,16 @@ jobs:
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: nightly
components: llvm-tools-preview
- name: Install cargo-nextest
uses: taiki-e/install-action@cargo-nextest
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate code coverage
working-directory: Code
run: cargo llvm-cov nextest --all-features --workspace --lcov --output-path lcov.info
- name: Generate text report
working-directory: Code
run: cargo llvm-cov report --text
run: cargo llvm-cov report
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
Expand Down
14 changes: 6 additions & 8 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ name: Rust

on:
push:
branches: master
branches: main
paths:
- Code/**
pull_request:
paths:
- Code/**

# permissions:
# checks: write

env:
CARGO_INCREMENTAL: 0
CARGO_PROFILE_DEV_DEBUG: 1
Expand All @@ -24,6 +21,9 @@ jobs:
test:
name: Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: Code
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -32,10 +32,8 @@ jobs:
- name: Install cargo-nextest
uses: taiki-e/install-action@cargo-nextest
- name: Build code
working-directory: Code
run: cargo nextest run --workspace --all-features --no-run
- name: Run tests
working-directory: Code
run: cargo nextest run --workspace --all-features

clippy:
Expand All @@ -49,10 +47,10 @@ jobs:
with:
components: clippy
- name: Run clippy
uses: auguwu/clippy[email protected]
uses: actions-rs/clippy@master
with:
token: ${{secrets.GITHUB_TOKEN}}
args: --manifest-path Code/Cargo.toml
args: --all-features --all-targets --manifest-path Code/Cargo.toml

fmt:
name: Formatting
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# macOS Finder and Windows Thumbs.db files
.DS_Store
Thumbs.db

# Generated by Cargo
# will have compiled files and executables
debug/
Expand Down
Empty file removed Code/.gitkeep
Empty file.
23 changes: 22 additions & 1 deletion Code/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
[workspace]
resolver = "2"

members = []
members = [
"common",
"driver",
"round",
"vote",
"test",
]

[workspace.package]
version = "0.1.0"
edition = "2021"
repository = "https://github.com/informalsystems/malachite"
license = "Apache-2.0"
publish = false

[workspace.dependencies]
async-trait = "0.1"
futures = "0.3"
ed25519-consensus = "2.1.0"
rand = { version = "0.8.5", features = ["std_rng"] }
sha2 = "0.10.8"
signature = "2.1.0"
1 change: 1 addition & 0 deletions Code/QUESTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- How do we deal with errors?
11 changes: 11 additions & 0 deletions Code/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
is proposal complete
if polka not nil, then need to see proof of lock (2f+1 votes)
then send proposal

count votes for cur, prev, 1/2 next round

if complete proposal from a past round => to current one
if we have some threshold (f+1) of votes for a future round => skip to that round

context (get proposer, get value)
signing context
12 changes: 12 additions & 0 deletions Code/common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "malachite-common"
description = "Common datatypes and interfaces for the Malachite consensus engine"

version.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true
publish.workspace = true

[dependencies]
signature.workspace = true
58 changes: 58 additions & 0 deletions Code/common/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use crate::{
Address, Height, Proposal, PublicKey, Round, SignedVote, SigningScheme, Validator,
ValidatorSet, Value, ValueId, Vote,
};

/// This trait allows to abstract over the various datatypes
/// that are used in the consensus engine.
pub trait Context
where
Self: Sized,
{
type Address: Address;
type Height: Height;
type Proposal: Proposal<Self>;
type Validator: Validator<Self>;
type ValidatorSet: ValidatorSet<Self>;
type Value: Value;
type Vote: Vote<Self>;
type SigningScheme: SigningScheme; // TODO: Do we need to support multiple signing schemes?

// FIXME: Remove altogether
const DUMMY_VALUE: Self::Value;

/// Sign the given vote our private key.
fn sign_vote(&self, vote: Self::Vote) -> SignedVote<Self>;

/// Verify the given vote's signature using the given public key.
/// TODO: Maybe move this as concrete methods in `SignedVote`?
fn verify_signed_vote(
&self,
signed_vote: &SignedVote<Self>,
public_key: &PublicKey<Self>,
) -> bool;

/// Build a new proposal for the given value at the given height, round and POL round.
fn new_proposal(
height: Self::Height,
round: Round,
value: Self::Value,
pol_round: Round,
) -> Self::Proposal;

/// Build a new prevote vote by the validator with the given address,
/// for the value identified by the given value id, at the given round.
fn new_prevote(
round: Round,
value_id: Option<ValueId<Self>>,
address: Self::Address,
) -> Self::Vote;

/// Build a new precommit vote by the validator with the given address,
/// for the value identified by the given value id, at the given round.
fn new_precommit(
round: Round,
value_id: Option<ValueId<Self>>,
address: Self::Address,
) -> Self::Vote;
}
14 changes: 14 additions & 0 deletions Code/common/src/height.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use core::fmt::Debug;

// TODO: Keep the trait or just add the bounds to Consensus::Height?
/// Defines the requirements for a height type.
///
/// A height denotes the number of blocks (values) created since the chain began.
///
/// A height of 0 represents a chain which has not yet produced a block.
pub trait Height
where
// TODO: Require Copy as well?
Self: Clone + Debug + PartialEq + Eq + PartialOrd + Ord,
{
}
44 changes: 44 additions & 0 deletions Code/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Common data types and abstractions for the consensus engine.
#![no_std]
#![forbid(unsafe_code)]
#![deny(unused_crate_dependencies, trivial_casts, trivial_numeric_casts)]
#![warn(
// missing_docs,
rustdoc::broken_intra_doc_links,
rustdoc::private_intra_doc_links,
variant_size_differences
)]
#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::panic))]
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]

mod context;
mod height;
mod proposal;
mod round;
mod signed_vote;
mod signing;
mod timeout;
mod validator_set;
mod value;
mod vote;

// Re-export `signature` crate for convenience
pub use ::signature;

/// Type alias to make it easier to refer the `ValueId` type of a given `Consensus` engine.
pub type ValueId<Ctx> = <<Ctx as Context>::Value as Value>::Id;
pub type PublicKey<Ctx> = <<Ctx as Context>::SigningScheme as SigningScheme>::PublicKey;
pub type PrivateKey<Ctx> = <<Ctx as Context>::SigningScheme as SigningScheme>::PrivateKey;
pub type Signature<Ctx> = <<Ctx as Context>::SigningScheme as SigningScheme>::Signature;

pub use context::Context;
pub use height::Height;
pub use proposal::Proposal;
pub use round::Round;
pub use signed_vote::SignedVote;
pub use signing::SigningScheme;
pub use timeout::{Timeout, TimeoutStep};
pub use validator_set::{Address, Validator, ValidatorSet, VotingPower};
pub use value::Value;
pub use vote::{Vote, VoteType};
22 changes: 22 additions & 0 deletions Code/common/src/proposal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use core::fmt::Debug;

use crate::{Context, Round};

/// Defines the requirements for a proposal type.
pub trait Proposal<Ctx>
where
Self: Clone + Debug + PartialEq + Eq,
Ctx: Context,
{
/// The height for which the proposal is for.
fn height(&self) -> Ctx::Height;

/// The round for which the proposal is for.
fn round(&self) -> Round;

/// The value that is proposed.
fn value(&self) -> &Ctx::Value;

/// The POL round for which the proposal is for.
fn pol_round(&self) -> Round;
}
104 changes: 104 additions & 0 deletions Code/common/src/round.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use core::cmp;

/// A round number.
///
/// Can be either:
/// - `Round::Nil` (ie. `-1`)
/// - `Round::Some(r)` where `r >= 0`
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Round {
/// No round, ie. `-1`
Nil,

/// Some round `r` where `r >= 0`
Some(i64),
}

impl Round {
/// The initial, zero round.
pub const INITIAL: Round = Round::new(0);
pub const NIL: Round = Round::new(-1);

/// Create a new round.
///
/// If `round < 0`, then `Round::Nil` is returned.
/// Otherwise, `Round::Some(round)` is returned.
pub const fn new(round: i64) -> Self {
if round < 0 {
Self::Nil
} else {
Self::Some(round)
}
}

/// Convert the round to an `i64`.
///
/// `Round::Nil` is converted to `-1`.
/// `Round::Some(r)` is converted to `r`.
pub fn as_i64(&self) -> i64 {
match self {
Round::Nil => -1,
Round::Some(r) => *r,
}
}

/// Wether the round is defined, ie. `Round::Some(r)` where `r >= 0`.
pub fn is_defined(&self) -> bool {
matches!(self, Round::Some(r) if *r >= 0)
}

/// Wether the round is `Round::Nil`.
pub fn is_nil(&self) -> bool {
matches!(self, Round::Nil)
}

/// Increment the round.
///
/// If the round is nil, then the initial zero round is returned.
/// Otherwise, the round is incremented by one.
pub fn increment(&self) -> Round {
match self {
Round::Nil => Round::new(0),
Round::Some(r) => Round::new(r + 1),
}
}
}

impl PartialOrd for Round {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for Round {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_i64().cmp(&other.as_i64())
}
}

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

#[test]
fn test_round() {
// Test Round::new()
assert_eq!(Round::new(-42), Round::Nil);
assert_eq!(Round::new(-1), Round::Nil);
assert_eq!(Round::new(0), Round::Some(0));
assert_eq!(Round::new(1), Round::Some(1));
assert_eq!(Round::new(2), Round::Some(2));

// Test Round::as_i64()
assert_eq!(Round::Nil.as_i64(), -1);
assert_eq!(Round::Some(0).as_i64(), 0);
assert_eq!(Round::Some(1).as_i64(), 1);
assert_eq!(Round::Some(2).as_i64(), 2);

// Test Round::is_defined()
assert!(!Round::Nil.is_defined());
assert!(Round::Some(0).is_defined());
assert!(Round::Some(1).is_defined());
assert!(Round::Some(2).is_defined());
}
}
Loading

0 comments on commit f397501

Please sign in to comment.