Deterministic simulation testing for distributed systems in Rust. Write your distributed system once, test it with deterministic simulation and chaos injection, then deploy with real networking — using identical application code.
Inspired by FoundationDB's simulation testing and Antithesis.
Note: This is a hobby-grade project under active development.
moonpool Facade crate (features: sim / tokio / transport)
├── moonpool-transport RPC, peer connections, wire format
│ └── moonpool-transport-derive #[service] proc-macro
├── moonpool-sim Simulation engine, chaos testing, assertion wiring
│ ├── moonpool-assertions Assertion accounting (pure std, zero deps, wasm-able)
│ └── moonpool-explorer Fork-based multiverse exploration (optional, libc)
└── moonpool-core Provider traits and core types
The simulation runtime compiles to wasm32-unknown-unknown (build moonpool-sim
with --no-default-features); only the fork-based explorer is Linux-first.
| Use case | Crate |
|---|---|
| Full framework (recommended) | moonpool |
| Provider traits only | moonpool-core |
| Simulation without transport | moonpool-sim |
| Transport without simulation | moonpool-transport |
| Assertion accounting only | moonpool-assertions |
| Fork-based exploration internals | moonpool-explorer |
| Proc-macro internals | moonpool-transport-derive |
The code you test is the code you ship — write it once against the provider
traits, then deploy on the real TokioProviders backend. Keep the simulation
runtime and the fork-based explorer out of your release binary with a lean
dependency stanza:
[dependencies]
moonpool = { version = "0.8", default-features = false, features = ["tokio", "transport"] }That pulls the provider contract, TokioProviders/TokioTransport, and the
transport layer — no moonpool-sim, no moonpool-explorer, no libc fork
machinery. See moonpool/examples/retrying_worker.rs
for a worker that runs on Tokio in main and is driven through the simulator by
its own #[test], and the "Using Providers in Production" chapter of the book.
-
Provider pattern — Application code depends on traits (
TimeProvider,NetworkProvider,TaskProvider,RandomProvider,StorageProvider), not concrete implementations. Same code runs in simulation and production. - Deterministic simulation — Same seed = identical execution. Logical time skips idle periods. Years of uptime simulated in seconds.
-
Chaos testing — Network delays, disconnects, partitions, bit flips, partial writes, storage corruption.
buggify!fires with 25% probability at fault injection points. -
Assertion suite — 15 Antithesis-style assertion macros (
assert_always!,assert_sometimes!, numeric comparisons, compound assertions). Multi-seed testing runs until allsometimesassertions fire. -
Fork-based exploration — When assertions discover new behavior,
fork()explores alternate timelines with different RNG seeds. Adaptive energy budgets and coverage bitmaps guide exploration. -
#[service]macro — Auto-generates RPC server/client boilerplate from a single trait definition.
# Enter development environment (Nix required)
nix develop
# Run tests
nix develop --command cargo nextest run
# Build documentation
nix develop --command cargo doc --open- The Sim Book — User guide covering philosophy, architecture, and practical details
- API Documentation — Rustdoc with architecture diagrams and usage examples
- Repository
Apache 2.0
