Rezzy is a high-performance, dependency-free Rust engine
for Matrix State Resolution — both a research model and
highly-efficient reference implementation for state
resolution v2, v2.1, v2.1.1 (experimental), and
V2.2 (experimental [MSC4242]).
| Room Version | State Resolution | Notes |
|---|---|---|
| 1 * | V1 | Legacy — depth-based ordering |
| 2 * | V2 | Mainline sort + iterative auth |
| 3–6 | V2 | Event ID format changes only |
| 7–10 | V2 | Knocking, restricted joins |
| 11 | V2 | Redaction rules update |
| 12 | V2.1 | MSC4297 — conflicted subgraph expansion |
| org.matrix.msc4242 * | V2.2 | Experimental — State DAGs |
* Room versions 1–2 are legacy and not actively supported.
- Auth check engine.
- Full state resolution pipeline.
- Topological & mainline sorting.
n-wayfork resolution.- In-place bitshift heaps and roaring bitmaps for fast graph computations.
- Lazy projection: Fast, memory-efficient state resolution by only loading required membership events.
Development in this repository strictly follows Test-Driven Development (TDD):
- Write tests first. New features or bug fixes must begin with failing tests that codify the expected behavior.
- Implement the logic. Write the minimal code required to make the tests pass.
- Prove the fix. After the dust settles on an implementation, we verify that the new tests fail when run against the old code, proving the tests are valid and the fix is strictly necessary.
Everything re-exports from the crate root —
use rezzy::* gets you LeanEvent, SharedState,
StateResVersion, HashMap, the works.
resolve_iterative_sort— the main entry point. Unconflicted state, conflicted events, auth context, and version → winningSharedState.resolve_lattice_fold— parallel alternative (lattice fold instead of sequential mainline sort).resolve_iterative_sort_with_deltas— diagnostic variant, also emits per-eventResolutionDeltatraces.compute_state_at/compute_state_at_streaming— reconstruct resolved state at any DAG position. Streaming variant bounds memory to frontier width.auth::check_auth— spec-compliant auth engine. ImplementStateProviderto plug in your own backend.- Generic
EventIdtrait —String,u32,u64,ruma::OwnedEventIdall just work. EventContenttrait — skip JSON parsing in the hot path.serde_json::Valueworks via default impl.- Generic
EventIdsupport across delta compression (StateDelta,CompactedCheckpoint) and core data structures. - Explicit API/return variants
(
ForwardExtremityResult,validate_forward_extremity) for "soft-fail" evaluation and forward extremity validation.
rezzy is designed for extreme performance out of the
box.
For the even better tuning, use the release-max-perf
Cargo profile:
[profile.release-max-perf]
inherits = "release"
strip = "symbols"
lto = "fat"
codegen-units = 1
panic = "abort"If you are building the binary for a specific machine,
you can unlock native CPU instructions (i.e., avx-512)
with:
RUSTFLAGS="-C target-cpu=native" make build installThe res/ submodule contains large test fixtures. It
uses update = none in .gitmodules so downstream Cargo
consumers don't fetch it. For local development, init it
with:
git -c submodule.res.update=checkout submodule update --init --recursiveThen generate synthetic fixtures and run the test suite:
make testTo install and run test coverage:
cargo install cargo-llvm-cov
make covBecause we care about raw performance and mechanical
efficiency, rezzy is built on a foundation of
blazingly fast ideas. Under the hood of our production
code, you will find:
- Causal domination operator (CDO) pre-filtering
- Experimental V2.1.1 State Resolution with supplemental narrowing
- Batched/strip-mined SWAR (SIMD within a register) matrix sweeps
O(1)causal coordinatization projection- Filtered commutative join-semilattice folding
- Integer "interning" (
ShortID) graph-based traversal - Flat-array "stride matrices"
- Fully-featured, spec-compliant authorization engine
- Reverse topological power ordering (Kahn's algorithm)
Arc-based copy-on-write (CoW) structural sharingO(1)fast-path merge resolution via "pointer-equality bypass"- Native n-way state resolution (resolve/merge arbitrary DAG forks in a single pass)
- Zero-allocation stack-safe DAG crawling
- Generic
BuildHasherdecoupling - Supremum deletion attack (Byzantine fault mitigation)
- Optimal conflicted state sub-graph computation (MSC4297)
- Roaring bitmaps (SIMD-optimized set operations)
FNV-1a128-bit lexicographical state hashing- Compacted delta chains with auto-snapshot (bounded reconstruction cost)
- Per-event resolution tracing
(
ResolutionDelta+ phase tracking) - Checkpoint/partial-join resolution (trusted snapshot as unconflicted base)
- Batch state computation with shared topological traversal
no_stdcompatible (alloc-only, no system dependencies)
Rezzy is synchronous by design. It accepts a fully
materialized HashMap and returns resolved state without
performing any I/O. This is not a limitation, it's a
design choice.
State resolution does not operate on the entire room
history. It operates on the Auth Difference:
auth(C) - auth(U) — the auth-chain events reachable
from conflicted events C that aren't already in the
agreed-upon unconflicted state U.
Determining the auth difference is relatively easy and quick: either compute it on the fly (recursively in 20-50 database hops), or pre-compute and store in a "chain closure" index (for near-instant runtime performance).
┌───────────────────────────────────────────────┐
│ Homeserver (async I/O) │
│ Bulk-fetch auth difference in 1-50 queries │
├───────────────────────────────────────────────┤
│ Rezzy (sync: pure-CPU) │
│ Topological sort + iterative auth in µs-ms │
├───────────────────────────────────────────────┤
│ Homeserver (async I/O) │
│ Persist PDUs/resolved state; notify clients │
└───────────────────────────────────────────────┘
Typical working set: 10–50 conflicting events for a
normal fork, fitting entirely in L1 cache.
Both Synapse and Rust servers pre-compute the transitive
closure of the auth chain, but they cannot
realistically do this for the timeline DAG
(prev_events).
Homeservers should pre-compute and store the transitive
closure of the auth chain for every event (as a
RoaringTreemap of ShortEventIds).
The auth chain should only contain state events that
authorize other state events (e.g., m.room.create,
m.room.power_levels, and membership transitions). Even
in a room with 1,000,000 chat messages, the auth chain
for a given event typically contains fewer than
50–100 events.
Live computing and storing of a 100-integer roaring
bitmap auth_chain per event is extremely cheap, and
it greatly speeds up real-time federation!
Because we don't have the timeline DAG's closure, we have two different techniques at our disposal:
For state resolution: We only need the
auth difference (auth(C) - auth(U)). Because we
have the pre-computed transitive auth chain bitmaps for
the conflicted tips C, we can perform this set
difference entirely in memory on integers and fetch the
exact list of missing PDUs in a single batch database
query—no timeline walking required.
For state reconstruction (state_at): Instead of
walking the timeline DAG backward to build state, we use
compressed state snapshots and delta chains (keyed by
shortstatehash). It fetches a recent state snapshot and
applies a small sequence of forward deltas, bypassing the
need for full traversal.
The generic EventContent trait: homeservers implement
EventContent on their own content type to provide
pre-extracted fields (membership, join_rule, ban,
kick power levels, etc.) without JSON parsing in the
hot path. serde_json::Value remains the default via a
blanket impl.
resolve_iterative_sort_with_deltas emits per-step
ResolutionDeltas alongside the final resolved state,
capturing event_id, acceptance status, replaced event,
and phase (power/non-power) for every conflicted event
processed.
Compute state at N events in topological order,
sharing the ancestor traversal and topological sort
across all targets.
Like compute_state_at_batch but yields each resolved
state to a callback as soon as it's ready, bounding peak
memory to the streaming of the DAG's live frontier width.
Pure function that returns the list of
(event_type, state_key) pairs required in auth state
for a given event type.
resolve_iterative_sort is generic over Id: EventId,
and EventId has a blanket impl for any
T: Clone + Eq + Hash + Ord + Debug. This means u32,
u64, and any interned short ID type work out of the
box:
let unconflicted: imbl::OrdMap<(String, String), u64> = /* ... */;
let events: HashMap<u64, LeanEvent<u64>> = /* ... */;
let auth_ctx: HashMap<u64, LeanEvent<u64>> = /* ... */;
let resolved: imbl::OrdMap<(String, String), u64> =
resolve_iterative_sort(unconflicted, events, &auth_ctx, StateResVersion::V2);resolve_iterative_sort supports this — pass a trusted
state snapshot as unconflicted_state. The conflicted
events and auth context only need to cover the divergent
portion of the DAG.
Full delta chain support with Synapse-like compaction:
compute_state_delta/apply_state_delta— single-event delta mathcompute_compacted_delta_chain_from_resolved— bulk backfill with auto-snapshot everyMAX_DELTA_CHAIN_HOPS(default:100) eventsreconstruct_state_at/reconstruct_state_batch— reconstruct state from stored delta chains- All checkpoint types derive
Serialize/Deserializefor direct storage in RocksDB, bincode, etc.