Contributing to Crucible Simulator
See CONTRIBUTING.md for the process (issues,
branches, PRs, review expectations). This page is the map for what
there is to contribute, aligned with the repository’s structure — the
same surface the issue templates describe.
Where things live
| Area | Path | What lives there |
|---|---|---|
| Domain model | crates/core | accounts, tokens, commitments, balances, operations, transactions, events, errors |
| State engine | crates/state | store, commitment lifecycle, nullifiers, transitions, rollback, snapshots, Merkle |
| Flow engine | crates/flows | the five flows, authorization, validation, ProofProvider boundary |
| High-level API | crates/simulator | Configuration, Environment, Simulator (examples and benches live on the root package) |
| Fixtures | crates/fixtures + fixtures/ + schemas/ | typed fixtures, loader, scenario runner, the corpus, the schemas |
| CLI | cli | the stateful crucible binary |
| Boundaries | crates/adapters/* | Soroban adapter, testnet configuration + runner |
| Root package | examples/, tests/, benches/ | runnable examples, defining-property suites, criterion benchmarks |
Rules of the house
- Determinism is sacred. Never introduce system entropy, unordered collections into anything serialized or hashed, or platform-dependent behavior. If your change alters the state-root scheme, commitment IDs, or event/transaction output, existing deterministic anchors (Merkle root regression tests, fixture outcomes) must be regenerated deliberately and called out in the PR.
- Privacy boundary. Private values (amounts, commitment values,
balances) never enter events, proofs, or published output. Tests may
assert on
inspect_private_*; output may not leak it. - Atomicity. A failed operation must leave no partial state. Failed
operations are still recorded (as
Rejected/Failedtransactions with anoperation_rejectedevent) — do not regress that to silent errors. - One operation, one ledger. Flows advance at most one ledger step per executed operation.
- Do not raise
sha2past 0.10 on its own. This crate’s digests are a published interface:crucible-proverpins a simulator revision and compiles it, and it also depends onstellar-xdr28, which requiressha20.10. Raisingsha2here resolves two SHA-256 implementations into that consumer’s binary and is not a change one repository can make. The analysis, the reproduction, and the acceptance test for a future bump are incrucible-prover/docs/dependency-policy.md. Any change to the hashed encoding itself must be paired with regenerated known-answer vectors incrates/core/src/hashing.rs, which pin the digests by value.
Great first contributions
- A new failure fixture — every bug you find becomes
fixtures/failures/*.jsonwith anexpected_error, and the corpus-replay test keeps it green forever. - A determinism or invariant test — the suites under
tests/on the root package (tests/determinism,tests/state,tests/regression,tests/flows) are where defining properties are pinned. - Flow edge cases — the issue template names the success/failure
surface; flow unit tests in
crates/flows/src/<flow>.rsare the pattern to follow. - Docs — every doc under
docs/matches a spec section; stale docs are bugs.
Local development loop
cargo fmt --all -- --check # formatting
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace # everything, including the fuzz suite
cargo bench -p crucible # objective performance targets