Skip to content

Commit 6684c46

Browse files
committed
[glue] Add glue crate
1 parent 276a027 commit 6684c46

26 files changed

Lines changed: 4069 additions & 2 deletions

File tree

.github/workflows/publish.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,8 @@ jobs:
150150
continue-on-error: true
151151
env:
152152
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
153+
- name: Publish glue
154+
run: cargo publish --manifest-path glue/Cargo.toml
155+
continue-on-error: true
156+
env:
157+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ members = [
99
"consensus",
1010
"cryptography",
1111
"deployer",
12+
"glue",
1213
"macros",
1314
"macros/impl",
1415
"math",
@@ -96,6 +97,7 @@ commonware-conformance-macros = { version = "2026.3.0", path = "conformance/macr
9697
commonware-consensus = { version = "2026.3.0", path = "consensus" }
9798
commonware-cryptography = { version = "2026.3.0", path = "cryptography", default-features = false }
9899
commonware-deployer = { version = "2026.3.0", path = "deployer", default-features = false }
100+
commonware-glue = { version = "2026.3.0", path = "glue" }
99101
commonware-invariants = { version = "2026.3.0", path = "invariants" }
100102
commonware-macros = { version = "2026.3.0", path = "macros", default-features = false }
101103
commonware-macros-impl = { version = "2026.3.0", path = "macros/impl" }

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ _Primitives are designed for deployment in adversarial environments. If you find
2020
* [consensus](./consensus/README.md): Order opaque messages in a Byzantine environment.
2121
* [cryptography](./cryptography/README.md): Generate keys, sign arbitrary messages, and deterministically verify signatures.
2222
* [deployer](./deployer/README.md): Deploy infrastructure across cloud providers.
23+
* [glue](./glue/README.md): Bootstrap applications with commonware primitive compositions.
2324
* [math](./math/README.md): Create and manipulate mathematical objects.
2425
* [p2p](./p2p/README.md): Communicate with authenticated peers over encrypted connections.
2526
* [parallel](./parallel/README.md): Parallelize fold operations with pluggable execution strategies.

consensus/src/marshal/ancestry.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ pub struct AncestorStream<M, B: Block> {
4747
}
4848

4949
impl<M, B: Block> AncestorStream<M, B> {
50+
/// Returns a reference to the next block that will be yielded by the
51+
/// stream, without consuming it.
52+
///
53+
/// Returns `None` if the buffer is empty and the next block is being
54+
/// fetched asynchronously.
55+
pub fn peek(&self) -> Option<&B> {
56+
self.buffered.last()
57+
}
58+
5059
/// Creates a new [AncestorStream] starting from the given ancestry.
5160
///
5261
/// # Panics

examples/sync/src/bin/client.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ where
7676

7777
match resolver.get_sync_target().await {
7878
Ok(new_target) => {
79-
// Check if target has changed
80-
if new_target.root != current_target.root {
79+
// Check if target has changed.
80+
// Compare the full target so range-only changes are not missed.
81+
if new_target != current_target {
8182
// Send new target to the sync client
8283
match update_tx.clone().try_send(new_target.clone()) {
8384
Ok(()) => {

glue/Cargo.toml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[package]
2+
name = "commonware-glue"
3+
edition.workspace = true
4+
publish = true
5+
version.workspace = true
6+
license.workspace = true
7+
description = "Bootstrap applications with commonware primitive compositions."
8+
readme = "README.md"
9+
homepage.workspace = true
10+
repository = "https://github.com/commonwarexyz/monorepo/tree/main/glue"
11+
12+
[lints]
13+
workspace = true
14+
15+
[dependencies]
16+
commonware-consensus.workspace = true
17+
commonware-cryptography.workspace = true
18+
commonware-macros.workspace = true
19+
commonware-p2p = { workspace = true, optional = true }
20+
commonware-runtime.workspace = true
21+
commonware-utils.workspace = true
22+
rand.workspace = true
23+
rand_core.workspace = true
24+
tracing = { workspace = true, optional = true }
25+
26+
[dev-dependencies]
27+
commonware-broadcast.workspace = true
28+
commonware-codec.workspace = true
29+
commonware-consensus = { workspace = true, features = ["mocks"] }
30+
commonware-cryptography = { workspace = true, features = ["mocks"] }
31+
commonware-glue = { path = ".", features = ["test-utils"] }
32+
commonware-p2p.workspace = true
33+
commonware-parallel.workspace = true
34+
commonware-resolver.workspace = true
35+
commonware-storage.workspace = true
36+
futures.workspace = true
37+
tracing.workspace = true
38+
tracing-subscriber.workspace = true
39+
40+
[features]
41+
test-utils = [
42+
"dep:commonware-p2p",
43+
"dep:tracing",
44+
]

glue/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# commonware-glue
2+
3+
[![Crates.io](https://img.shields.io/crates/v/commonware-glue.svg)](https://crates.io/crates/commonware-glue)
4+
5+
Bootstrap applications with commonware primitive compositions.
6+
7+
## Status
8+
9+
Stability varies by primitive. See [README](https://github.com/commonwarexyz/monorepo#stability) for details.

glue/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![doc = include_str!("../README.md")]
2+
#![doc(
3+
html_logo_url = "https://commonware.xyz/imgs/rustdoc_logo.svg",
4+
html_favicon_url = "https://commonware.xyz/favicon.ico"
5+
)]
6+
7+
commonware_macros::stability_mod!(ALPHA, pub mod stateful);
8+
9+
#[cfg(any(test, feature = "test-utils"))]
10+
pub mod simulate;

glue/src/simulate/engine.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//! Engine definition trait and supporting types.
2+
3+
use super::tracker::FinalizationUpdate;
4+
use commonware_cryptography::PublicKey;
5+
use commonware_p2p::simulated::{self, Oracle};
6+
use commonware_runtime::{deterministic, Handle, Quota};
7+
use commonware_utils::channel::mpsc;
8+
use std::future::Future;
9+
10+
/// A registered p2p channel pair (sender, receiver).
11+
pub type ChannelPair<P> = (
12+
simulated::Sender<P, deterministic::Context>,
13+
simulated::Receiver<P>,
14+
);
15+
16+
/// Arguments passed to [`EngineDefinition::init`].
17+
pub struct InitContext<'a, P: PublicKey> {
18+
/// Labeled runtime context for this validator.
19+
pub context: deterministic::Context,
20+
/// Index of this validator in the participant list.
21+
pub index: usize,
22+
/// This validator's public key.
23+
pub public_key: &'a P,
24+
/// Network oracle for peer management.
25+
pub oracle: &'a Oracle<P, deterministic::Context>,
26+
/// Registered p2p channel pairs (same order as `channels()`).
27+
pub channels: Vec<ChannelPair<P>>,
28+
/// All participants in the simulation.
29+
pub participants: &'a [P],
30+
/// Channel for reporting finalization events to the harness.
31+
pub monitor: mpsc::Sender<FinalizationUpdate<P>>,
32+
}
33+
34+
/// Defines how to construct and start one validator's service stack.
35+
///
36+
/// The harness calls these methods for each validator in the simulation.
37+
/// The lifecycle is:
38+
/// 1. `channels()` -- declare which p2p channels are needed.
39+
/// 2. `init()` -- construct the engine (actors, archives, mailboxes).
40+
/// 3. `start()` -- start all actors, return a joinable handle.
41+
///
42+
/// On restart after a crash, `init()` and `start()` are called again
43+
/// with the same validator identity but a fresh runtime context (storage
44+
/// state is preserved by the deterministic runtime).
45+
pub trait EngineDefinition: Clone + Send + 'static {
46+
/// The public key type used by this engine.
47+
type PublicKey: PublicKey;
48+
49+
/// The constructed engine, passed from `init` to `start`.
50+
type Engine: Send + 'static;
51+
52+
/// Per-validator state inspectable by property checkers.
53+
type State: Send + Sync + 'static;
54+
55+
/// The participants for this simulation.
56+
///
57+
/// Called once by the harness to determine the validator set. The engine
58+
/// is responsible for generating keys and any associated state (signing
59+
/// schemes, databases, etc.) during construction.
60+
fn participants(&self) -> Vec<Self::PublicKey>;
61+
62+
/// Which p2p channels to register for each validator.
63+
///
64+
/// Returns `(channel_id, quota)` pairs. The harness registers each
65+
/// on the simulated oracle and passes sender/receiver pairs to
66+
/// `init` in the same order.
67+
fn channels(&self) -> Vec<(u64, Quota)>;
68+
69+
/// Construct the engine for a single validator.
70+
fn init(
71+
&self,
72+
ctx: InitContext<'_, Self::PublicKey>,
73+
) -> impl Future<Output = (Self::Engine, Self::State)> + Send;
74+
75+
/// Start all actors in the engine. Returns a handle the harness
76+
/// can join on (or abort on crash).
77+
fn start(engine: Self::Engine) -> Handle<()>;
78+
}

0 commit comments

Comments
 (0)