Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
9e0bdea
Add Nix support
emlautarom1 Oct 8, 2025
2a84c79
Add `typos`
emlautarom1 Oct 8, 2025
00a2bc9
Apply copilot suggestions
emlautarom1 Oct 9, 2025
e93e262
Merge remote-tracking branch 'origin/main' into emlautarom1/issue5
emlautarom1 Oct 9, 2025
318c011
Update Cargo.lock
emlautarom1 Oct 9, 2025
bd92d4f
Add Dockerfile and .dockerignore
emlautarom1 Oct 8, 2025
3b6eb62
Add placeholder executable
emlautarom1 Oct 9, 2025
43f9d7c
Include cargo tools in Nix
emlautarom1 Oct 9, 2025
b2c4de5
Remove the need for nightly
emlautarom1 Oct 9, 2025
557e18c
Fix checks on placeholder app
emlautarom1 Oct 9, 2025
2efc02b
Adjust target name
emlautarom1 Oct 9, 2025
8159eb6
Build only the CLI
emlautarom1 Oct 9, 2025
1f781b5
Rely on system libraries
emlautarom1 Oct 10, 2025
19ce2bd
Remove duplicated inputs
emlautarom1 Oct 10, 2025
bc12ac4
Use `rust:1.89` and `debian:trixie-slim` as images
emlautarom1 Oct 10, 2025
bd94953
Use bookworm instead of trixie
emlautarom1 Oct 10, 2025
0fd00fa
Formatting
emlautarom1 Oct 10, 2025
c4a19f9
Revert changes to `rustfmt.toml`
emlautarom1 Oct 10, 2025
1b928f2
Revert changes to `pre-push`
emlautarom1 Oct 10, 2025
b71f229
Expose port 3030
emlautarom1 Oct 10, 2025
bb351af
Initial qbft impl
emlautarom1 Oct 15, 2025
84e7326
Accept references to `I`
emlautarom1 Oct 17, 2025
848401e
Define errors as structs
emlautarom1 Oct 20, 2025
89d4642
Initial qbft implementation
emlautarom1 Oct 20, 2025
3f9a947
Rename SomeMsg/Msg
emlautarom1 Oct 21, 2025
eb05ec3
Reduce cloning when ref is enough
emlautarom1 Oct 21, 2025
a620d50
Complete `Run` method
emlautarom1 Oct 21, 2025
8240d37
Use crossbeam for channels
emlautarom1 Oct 21, 2025
49e776c
Fix `q_commit`
emlautarom1 Oct 21, 2025
d0b796e
Initialize remaining state elements
emlautarom1 Oct 21, 2025
c052bbb
Renaming
emlautarom1 Oct 21, 2025
4563d6b
Use `select!` macro
emlautarom1 Oct 22, 2025
8781efd
Apply clippy suggestions
emlautarom1 Oct 22, 2025
cbc47a8
Match reference project structure
emlautarom1 Oct 22, 2025
894bbf4
C
emlautarom1 Oct 22, 2025
de790d6
Add qbft module docs
emlautarom1 Oct 22, 2025
51d4aef
Run `d.log_*` methods
emlautarom1 Oct 22, 2025
e3f4d64
Match visibility modifiers
emlautarom1 Oct 22, 2025
f3cd8e7
Match module docs
emlautarom1 Oct 22, 2025
e9fd7a6
Merge remote-tracking branch 'origin/main' into emlautarom1/qbft
emlautarom1 Oct 22, 2025
84f1ae2
Regen `Cargo.lock`
emlautarom1 Oct 22, 2025
e446d5e
Move dependency to workspace
emlautarom1 Oct 22, 2025
3ec947a
Fix pre-push checks
emlautarom1 Oct 22, 2025
bb852c6
Revert docs change
emlautarom1 Oct 22, 2025
80056fd
Fix typo
emlautarom1 Oct 23, 2025
0754d56
Fix equality comparison with `Default`
emlautarom1 Oct 23, 2025
92c0459
Add internal tests
emlautarom1 Oct 23, 2025
0e58299
Add `as_any` to `SomeMsg` trait to allow downcasting
emlautarom1 Oct 28, 2025
47375c0
Make structs thread safe
emlautarom1 Nov 7, 2025
a92d338
Complete `test_qbft` function
emlautarom1 Nov 7, 2025
226b1a3
Add `happy_0` test
emlautarom1 Nov 7, 2025
c003ff5
Include `rand`
emlautarom1 Nov 7, 2025
d9eda72
Disable test due to deadlock
emlautarom1 Nov 7, 2025
0017196
Sort deps
emlautarom1 Nov 7, 2025
216e049
Run formatter
emlautarom1 Nov 7, 2025
b76a3f4
Apply clippy suggestions
emlautarom1 Nov 7, 2025
563402e
Merge branch 'main' into emlautarom1/qbft
emlautarom1 Nov 7, 2025
6668aa7
Fix wrong check
emlautarom1 Nov 12, 2025
4e1a0ef
Use single `is_leader` function
emlautarom1 Nov 12, 2025
6dc6d5b
Simplify imports
emlautarom1 Nov 12, 2025
8758216
Log when all resuts are received.
emlautarom1 Nov 12, 2025
2b45a9d
Propagate cancellation
emlautarom1 Nov 14, 2025
c586392
Fix deadlock
emlautarom1 Nov 14, 2025
b0a5214
Match original log messages
emlautarom1 Nov 14, 2025
69f050a
Add working tests
emlautarom1 Nov 14, 2025
ea8f9e4
Port remaining test cases
emlautarom1 Nov 26, 2025
e0f2ff9
Add `duplicate_pre_prepare_rules` test
emlautarom1 Nov 26, 2025
29999ed
Formatting
emlautarom1 Nov 26, 2025
0dfa78d
Mutate `input_value`
emlautarom1 Nov 26, 2025
b18d557
Avoid f64 for time
emlautarom1 Nov 27, 2025
d712bf1
Add `fake_clock`
emlautarom1 Nov 27, 2025
d279250
Merge branch 'main' into emlautarom1/qbft
emlautarom1 Nov 27, 2025
8380895
Sort deps
emlautarom1 Nov 27, 2025
827b1ce
Sort module declaration
emlautarom1 Nov 27, 2025
c584a37
Apply Copilot fixes/suggestions
emlautarom1 Nov 27, 2025
7edc8a8
Use `fake_clock`
emlautarom1 Dec 2, 2025
257483e
Add `cargo nextest`
emlautarom1 Dec 2, 2025
3f52c3d
Update CI to use `nextest`
emlautarom1 Dec 2, 2025
3bb831e
Test for clock cancellation
emlautarom1 Dec 2, 2025
7958a29
Update comments
emlautarom1 Dec 2, 2025
e426ab6
Use workspace `rand`
emlautarom1 Dec 2, 2025
f1440c0
Improve retries for flaky tests
emlautarom1 Dec 2, 2025
da43c39
Apply copilot comment suggestions
emlautarom1 Dec 3, 2025
d5e773f
Use explicit error enum
emlautarom1 Dec 3, 2025
14c3c4f
Remove `anyhow`
emlautarom1 Dec 4, 2025
6966d56
Small suggestions
emlautarom1 Dec 4, 2025
cb9b83e
Add `Drop` impl for `FakeClock`
emlautarom1 Dec 11, 2025
f736103
Fire and forget in `bcast`
emlautarom1 Dec 11, 2025
c4c07eb
Ignore all tests
emlautarom1 Dec 11, 2025
693569d
Remove nextest
emlautarom1 Dec 11, 2025
ba5cd10
Merge remote-tracking branch 'origin/main' into emlautarom1/qbft
emlautarom1 Dec 11, 2025
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
64 changes: 48 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 10 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,22 @@ publish = false

[workspace.dependencies]
axum = "0.8.6"
blst = "0.3.13"
cancellation = "0.1.0"
chrono = { version = "0.4", features = ["serde"] }
crossbeam = "0.8.4"
hex = { version = "^0.4.3" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "^1.0" }
tokio = { version = "1", features = ["full"] }
libp2p = { version = "0.56", features = ["full", "secp256k1"] }
prost = "0.14"
prost-types = "0.14"
prost-build = "0.14"
blst = "0.3.13"
prost-types = "0.14"
rand = { version = "0.8", features = ["std_rng"] }
rand_core = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "^1.0" }
thiserror = "2.0.12"
rand = {version = "0.8", features = ["std_rng"]}
uuid = {version = "1.16", features = ["serde", "v4"] }
tokio = { version = "1", features = ["full"] }
libp2p = { version = "0.56", features = ["full", "secp256k1"] }
uuid = { version = "1.16", features = ["serde", "v4"] }
serde_with = { version = "3", features = ["hex", "base64"] }
base64 = { version = "0.22.1" }
sha3 = { version = "0.10.8" }
Expand Down
13 changes: 12 additions & 1 deletion crates/charon-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ license.workspace = true
publish.workspace = true

[dependencies]
cancellation.workspace = true
chrono.workspace = true
crossbeam.workspace = true
hex.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
libp2p.workspace = true
prost.workspace = true
prost-types.workspace = true

[dev-dependencies]
rand.workspace = true
libp2p.workspace = true
prost.workspace = true
prost-types.workspace = true
Expand All @@ -19,4 +30,4 @@ chrono.workspace = true
charon-build-proto.workspace = true

[lints]
workspace = true
workspace = true
1 change: 1 addition & 0 deletions crates/charon-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! This crate provides the fundamental building blocks, data structures, and
//! core algorithms used throughout the Charon system.

pub mod qbft;
/// Types for the Charon core.
pub mod types;

Expand Down
153 changes: 153 additions & 0 deletions crates/charon-core/src/qbft/fake_clock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use crossbeam::channel as mpmc;
use std::{
collections::HashMap,
sync::{Arc, Mutex},
thread,
time::{Duration, Instant},
};

#[derive(Clone)]
pub struct FakeClock {
inner: Arc<Mutex<FakeClockInner>>,
}

struct FakeClockInner {
start: Instant,
now: Instant,
last_id: usize,
clients: HashMap<usize, (mpmc::Sender<Instant>, Instant)>,
}

impl FakeClock {
pub fn new(now: Instant) -> Self {
Self {
inner: Arc::new(Mutex::new(FakeClockInner {
start: now,
now,
last_id: 1,
clients: Default::default(),
})),
}
}

pub fn new_timer(
&self,
duration: Duration,
) -> (
mpmc::Receiver<Instant>,
Box<dyn Fn() + Send + Sync + 'static>,
) {
let (tx, rx) = mpmc::bounded::<Instant>(1);

let client_id = {
let mut inner = self.inner.lock().unwrap();
let id = inner.last_id;
let deadline = inner.now + duration;

inner.last_id += 1;
inner.clients.insert(id, (tx, deadline));

id
};

let inner = Arc::clone(&self.inner);
let cancel = Box::new(move || {
let mut inner = inner.lock().unwrap();
inner.clients.remove(&client_id);
});

(rx, cancel)
}

pub fn advance(&self, duration: Duration) {
// Advance time and collect expired senders under lock, but perform sends
// without holding lock.
let mut expired = vec![];

let now = {
let mut inner = self.inner.lock().unwrap();
inner.now += duration;
let now = inner.now;

for (&id, (ch, deadline)) in inner.clients.iter() {
if *deadline <= now {
expired.push((id, ch.clone()));
}
}

for (id, _) in expired.iter() {
inner.clients.remove(id);
}

now
};

for (_, ch) in expired {
let _ = ch.send(now);
}
}

pub fn elapsed(&self) -> Duration {
let inner = self.inner.lock().unwrap();
inner.now - inner.start
}

pub fn cancel(&self) {
let mut inner = self.inner.lock().unwrap();
inner.clients.clear();
}
}

impl Drop for FakeClock {
fn drop(&mut self) {
self.cancel();
}
}

#[test]
fn multiple_threads_timers() {
let clock = FakeClock::new(Instant::now());

let start = Instant::now();
thread::scope(|s| {
let c1 = clock.clone();
let (ch_1, _) = c1.new_timer(Duration::from_secs(5));
s.spawn(move || {
let _ = ch_1.recv();
});

let c2 = clock.clone();
let (ch_2, _) = c2.new_timer(Duration::from_secs(5));
s.spawn(move || {
let _ = ch_2.recv();
});

clock.advance(Duration::from_secs(6));
});

println!("start={:?}, clock={:?}", start.elapsed(), clock.elapsed());
}

#[test]
fn multiple_threads_cancellation() {
let clock = FakeClock::new(Instant::now());

let start = Instant::now();
thread::scope(|s| {
let c1 = clock.clone();
let (ch_1, _) = c1.new_timer(Duration::from_secs(5));
s.spawn(move || {
let _ = ch_1.recv();
});

let c2 = clock.clone();
let (ch_2, _) = c2.new_timer(Duration::from_secs(5));
s.spawn(move || {
let _ = ch_2.recv();
});

clock.cancel();
});

println!("start={:?}, clock={:?}", start.elapsed(), clock.elapsed());
}
Loading