Skip to content

Commit d28e265

Browse files
committed
[glue] Add glue crate
1 parent bb6cdbb commit d28e265

51 files changed

Lines changed: 16611 additions & 6 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/publish.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ jobs:
130130
continue-on-error: true
131131
env:
132132
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
133+
- name: Publish glue
134+
run: cargo publish --manifest-path glue/Cargo.toml
135+
continue-on-error: true
136+
env:
137+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
133138
- name: Publish chat
134139
run: cargo publish --manifest-path examples/chat/Cargo.toml
135140
continue-on-error: true

Cargo.lock

Lines changed: 29 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
@@ -11,6 +11,7 @@ members = [
1111
"cryptography",
1212
"deployer",
1313
"formatting",
14+
"glue",
1415
"macros",
1516
"macros/impl",
1617
"math",
@@ -114,6 +115,7 @@ commonware-consensus = { version = "2026.4.0", path = "consensus" }
114115
commonware-cryptography = { version = "2026.4.0", path = "cryptography", default-features = false }
115116
commonware-deployer = { version = "2026.4.0", path = "deployer", default-features = false }
116117
commonware-formatting = { version = "2026.4.0", path = "formatting", default-features = false }
118+
commonware-glue = { version = "2026.4.0", path = "glue" }
117119
commonware-invariants = { version = "2026.4.0", path = "invariants" }
118120
commonware-macros = { version = "2026.4.0", path = "macros", default-features = false }
119121
commonware-macros-impl = { version = "2026.4.0", path = "macros/impl" }

README.md

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

glue/Cargo.toml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
arbitrary = { workspace = true, optional = true, features = ["derive"] }
17+
bytes.workspace = true
18+
commonware-actor.workspace = true
19+
commonware-codec.workspace = true
20+
commonware-consensus.workspace = true
21+
commonware-cryptography.workspace = true
22+
commonware-macros.workspace = true
23+
commonware-p2p.workspace = true
24+
commonware-parallel.workspace = true
25+
commonware-resolver.workspace = true
26+
commonware-runtime.workspace = true
27+
commonware-storage.workspace = true
28+
commonware-utils.workspace = true
29+
futures.workspace = true
30+
prometheus-client.workspace = true
31+
rand.workspace = true
32+
rand_core.workspace = true
33+
thiserror.workspace = true
34+
tracing.workspace = true
35+
36+
[dev-dependencies]
37+
commonware-broadcast.workspace = true
38+
commonware-codec.workspace = true
39+
commonware-conformance.workspace = true
40+
commonware-consensus = { workspace = true, features = ["mocks"] }
41+
commonware-cryptography = { workspace = true, features = ["mocks"] }
42+
commonware-formatting.workspace = true
43+
commonware-p2p.workspace = true
44+
commonware-parallel.workspace = true
45+
commonware-resolver.workspace = true
46+
commonware-storage.workspace = true
47+
tracing-subscriber.workspace = true
48+
49+
[features]
50+
test-utils = []
51+
arbitrary = [
52+
"commonware-codec/arbitrary",
53+
"commonware-consensus/arbitrary",
54+
"commonware-cryptography/arbitrary",
55+
"commonware-p2p/arbitrary",
56+
"commonware-resolver/arbitrary",
57+
"commonware-runtime/arbitrary",
58+
"commonware-storage/arbitrary",
59+
"commonware-utils/arbitrary",
60+
"dep:arbitrary",
61+
]

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/conformance.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
["commonware_glue::stateful::db::p2p::handler::tests::conformance::CodecConformance<Request<mmr::Family>>"]
2+
n_cases = 65536
3+
hash = "44c363dc52376203a66269a71e13f7271c1a9beb1f8ee9dd9864a3ce7ae2c281"
4+
5+
["commonware_glue::stateful::db::p2p::handler::tests::conformance::CodecConformance<Response<mmr::Family,u64,sha256::Digest>>"]
6+
n_cases = 65536
7+
hash = "7ca1ff124e5835f5be5d9b915233b9df088db121a0f5c3baa54b9ab8daf8bd78"

glue/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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_scope!(ALPHA {
8+
pub mod stateful;
9+
10+
#[cfg(any(test, feature = "test-utils"))]
11+
pub mod simulate;
12+
});

glue/src/simulate/action.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//! Simulation action types for testing.
2+
3+
use commonware_cryptography::PublicKey;
4+
use commonware_p2p::simulated::Link;
5+
use commonware_runtime::deterministic;
6+
use std::time::Duration;
7+
8+
/// Crash strategy for a simulation run.
9+
#[derive(Clone)]
10+
pub enum Crash<P: PublicKey> {
11+
/// Periodically crash random validators and restart them after
12+
/// a downtime period.
13+
Random {
14+
/// How often to trigger crashes.
15+
frequency: Duration,
16+
/// How long crashed validators stay offline.
17+
downtime: Duration,
18+
/// Number of validators to crash each time.
19+
count: usize,
20+
},
21+
22+
/// Delay some validators from starting until after N finalizations.
23+
Delay {
24+
/// Number of validators to delay.
25+
count: usize,
26+
/// Number of finalizations before starting delayed validators.
27+
after: u64,
28+
},
29+
30+
/// Time-indexed action schedule for precise control.
31+
Schedule(Schedule<P>),
32+
}
33+
34+
/// A time-ordered sequence of simulation actions.
35+
#[derive(Clone)]
36+
pub struct Schedule<P: PublicKey> {
37+
/// Time-indexed actions.
38+
pub events: Vec<(Duration, Action<P>)>,
39+
}
40+
41+
impl<P: PublicKey> Schedule<P> {
42+
/// Create an empty schedule.
43+
pub const fn new() -> Self {
44+
Self { events: vec![] }
45+
}
46+
47+
/// Add an action at the given simulation time.
48+
pub fn at(mut self, time: Duration, action: Action<P>) -> Self {
49+
self.events.push((time, action));
50+
self
51+
}
52+
}
53+
54+
impl<P: PublicKey> Default for Schedule<P> {
55+
fn default() -> Self {
56+
Self::new()
57+
}
58+
}
59+
60+
/// A single simulation action to apply at a specific time.
61+
#[derive(Clone)]
62+
pub enum Action<P: PublicKey> {
63+
/// Update deterministic storage fault injection.
64+
SetStorageFault(deterministic::FaultConfig),
65+
66+
/// Reset all directed links, restoring full connectivity with the given link.
67+
Heal(Link),
68+
69+
/// Update a specific directed link by removing and re-adding it.
70+
UpdateLink {
71+
/// Source peer.
72+
from: P,
73+
/// Destination peer.
74+
to: P,
75+
/// New link configuration.
76+
link: Link,
77+
},
78+
79+
/// Crash a specific validator.
80+
Crash(P),
81+
82+
/// Restart a previously crashed validator.
83+
Restart(P),
84+
}

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)