This file provides guidance to AI agents when working with code in this repository.
Malachite is a Byzantine Fault Tolerant (BFT) consensus engine implementing the Tendermint consensus algorithm in Rust. It is a Cargo workspace rooted at code/Cargo.toml (not the repo root).
All commands run from the code/ directory:
cargo build # Build the workspace
cargo lint # Clippy with all features
cargo fmt --check # Check formatting
cargo nextest run -p <CRATE> # Run tests for a specific crate
cargo nextest run -p <CRATE> -E 'test(test_name)' # Run a single test
cargo all-tests # All tests except MBT
cargo mbt # Model-based tests (requires Quint)Integration test packages:
arc-malachitebft-test— test app integration testsarc-malachitebft-discovery-test— discovery protocol tests
Note: Published crate names use the arc-malachitebft-* prefix, but workspace dependency aliases use malachitebft-* (e.g., malachitebft-engine). When specifying -p to cargo, use the published name.
Malachite's consensus logic is pure and stateless — it performs no I/O. Instead, it uses a coroutine-based effect system:
- The
Contexttrait (core-types) parameterizes all consensus types (Address, Height, Value, Vote, Proposal, ValidatorSet, SigningScheme, etc.) - The consensus
handle()function is a coroutine (viagenawaiter) that yields Effects (sign, publish, decide, WAL append, etc.) and receives Resume values back - The
process!macro (core-consensus/src/macros.rs) drives this loop: feed an Input → run coroutine → handle yielded Effect → resume with result → repeat - Actors (via
ractor) handle effects asynchronously in the engine layer
Core consensus (pure, no I/O, no_std-friendly):
core-types—Contexttrait and all type traits (Value, Vote, Proposal, etc.)core-state-machine— single-round Tendermint state machinecore-votekeeper— vote aggregation and quorum trackingcore-driver— multi-round orchestrationcore-consensus— effect/input system,process!macro, top-level handlers
Engine layer (async, actor-based):
engine— actor wiring: Node (supervisor), Consensus, Host, Network, WAL, Sync actorsapp/app-channel— high-level channel-based application interfacenetwork— libp2p-based P2P layerdiscovery— peer discovery protocolsync— block synchronization protocolwal— write-ahead log for crash recoveryconfig/metrics/codec/proto/peer/signing/signing-ed25519/signing-ecdsa
Test:
test/— integration test app, framework, MBT, CLI, mempool utilities
- Channel-based (
app-channel) — highest level, batteries-included (networking, sync, WAL) - Actor-based (
engine) — swap individual actors (e.g., custom network layer) - Core library (
core-consensus) — fully agnostic, bring your own everything
- The
perform!macro inside effect handlers yields an effect and destructures the resume value in one expression ConsensusState<Ctx>holds theDriver<Ctx>(round state machine), input queue, proposal keeper, and timing metadata- Message flow: Network/Host/Timer → Consensus Actor →
process!(input, state, on: effect)→ Effect Handler routes to other actors → Resume value fed back
- Commit messages: conventional commits with Jira references, e.g.,
feat: Discovery peers request rate limiter - Rust edition 2021, MSRV 1.88
- Workspace lints:
clippy::disallowed_types = "deny"— checkcode/clippy.tomlfor the disallowed types list
All checks run automatically on PRs. Checks under rust.yml and quint.yml are skipped when their respective directories (code/, specs/) have no changes.
| Workflow | Jobs | Triggers on |
|---|---|---|
Rust (rust.yml) |
Unit tests, Integration tests (discovery, test app), Clippy, Formatting, no_std compatibility, MSRV, Standalone feature checks | code/ changes |
Quint (quint.yml) |
Typecheck, Test | specs/ changes |
Semver (semver.yml) |
Detect semver violations (posts PR comment if breaking) | code/ changes |
Coverage (coverage.yml) |
Code coverage report (posted as PR comment) | code/ or specs/ changes |
Spelling (typos.yml) |
Typo check via typos |
Always |
PR (pr.yml) |
PR title lint (conventional commits) | Always |
AI PR (ai-pr.yml) |
Automated Claude Code review on open/sync; PR notes on ai-pr-notes label |
Always |
Run these from the code/ directory to catch issues locally:
cargo fmt --all # Fix formatting
cargo lint # Clippy with all features
cargo all-tests # All tests except MBTIf you changed specs, also run from the repo root:
cargo mbt # Model-based tests (requires Quint)PR titles must follow conventional commits (e.g., feat: Add feature). The pr.yml check enforces this.
ADRs in docs/architecture/ document key design decisions. Consult these when working on the relevant subsystems:
- ADR-001 — High-level architecture: repository layout, component overview (networking, host, consensus driver, state machine, vote keeper), and how they compose
- ADR-002 — Actor system design: why ractor was chosen, actor decomposition (Consensus, Gossip, Mempool, WAL, Persistence, Timers, Host), and message flow between actors
- ADR-003 — Value propagation modes: three modes for disseminating proposed values (
ProposalOnly,PartsOnly,ProposalAndParts) and when to use each - ADR-004 — Coroutine-based effect system: the
process!/perform!macro design, why coroutines were chosen over callbacks/traits/message-passing, and the Effect→Resume contract - ADR-005 — Value sync protocol: how nodes catch up on decided values, peer management, request/response protocol, and integration with the consensus engine
- ADR-006 — Proof-of-Validator protocol: cryptographic validator identity proofs for connection prioritization and mesh optimization
- ADR-007 — Write-Ahead Log (WAL): crash-recovery model, what gets logged (votes, proposals, timeouts), replay on restart to ensure consistency
Formal specifications live in specs/ using Quint (a TLA+-like language). Subdirectories cover consensus, network, block-streaming, and synchronization protocols.
Alongside the executable Quint spec, specs/consensus/ contains English documents describing the Tendermint protocol and Malachite's implementation. Consult these when reasoning about protocol semantics, state transitions, or Byzantine behavior:
- specs/consensus/README.md — Entry point: index and orientation for the consensus specification, with references to the Tendermint paper
- specs/consensus/overview.md — Protocol overview: summary of Tendermint at the protocol level — rounds, steps (propose/prevote/precommit), locking, and safety/liveness assumptions — as well as the discussion of the practical requirements not discussed in the paper — proposer selection, validity predicate, network properties, etc.
- specs/consensus/pseudo-code.md — Algorithm pseudo-code: Algorithm 1 from page 6 of the Tendermint paper, copied verbatim for easy cross-reference from the rest of the spec and the code
- specs/consensus/design.md — Malachite design: how the implementation separates vote keeper, driver, and state machine; principles underlying the consensus state machine
- specs/consensus/message-handling.md — Message handling: discussion on how processes should handle messages for rounds and heights different from their current one (future/past rounds, lagging/leading heights)
- specs/consensus/misbehavior.md — Byzantine misbehavior: taxonomy of misbehaviors that can lead to disagreement — equivocation and amnesia — and how each can be detected
- specs/consensus/accountable-tm/README.md — Accountable Tendermint: variant that enables the detection of amnesia attacks, in particular when agreement is violated
- specs/consensus/accountable-tm/pseudo-code.md — Accountable Tendermint pseudo-code: changes in the original pseudo-code in order to implement this variant
specs/block-streaming/ contains the Quint spec for streaming proposal parts (used when a proposed value is split into ordered INIT/DATA/FIN messages and reassembled by the receiver):
- specs/block-streaming/README.md — Proposal parts streaming: overview of the Quint model (
part_stream.qnt, backed bybinary_heap.qntandspells.qnt) withquint verifyinvocations for the safety invariant and termination property, plus example counter-examples
specs/synchronization/ documents the protocols nodes use to catch up when they fall behind the tip of the chain:
- specs/synchronization/README.md — Index: entry point listing the synchronization protocols
- specs/synchronization/valuesync/README.md — ValueSync (MVP): full English specification of the ValueSync protocol (originally "Blocksync") — motivation, client/server/consensus composition, status/request/response message formats, synchronization strategy, the Quint formalization in
valuesync/quint/, state-machine variants (with and without consensus), and known issues
specs/network/ covers the libp2p-based networking stack — how nodes find each other and how they disseminate messages:
- specs/network/README.md — Index: overview of the network layer and pointers to the peer-discovery and gossip protocols
- specs/network/discovery/README.md — Peer discovery: problem statement and model of the discovery protocol — bootstrap nodes, joining without knowing the full network, and assumptions about honest/Byzantine behavior
- specs/network/discovery/ipd-protocol.md — Iterative Peer Discovery (IPD): detailed description of the IPD algorithm — properties (discoverability, Byzantine-resilience, termination), assumptions, and protocol steps
- specs/network/gossip/README.md — Gossip protocol: placeholder/stub for documentation of the
gossipsub-based message dissemination layer (minimal content today)