hubble-commit: atproto commit operations #
synchronous operation inversion for sync 1.1 commit validation
given a partial mst and op list from a commit, inverts all the ops and returns the previous root cid, to validate against prevData.
let prev = hubble_commit::invert_ops(&blocks, commit.data, &ops, OpOrder::AsGiven)?;
if prev != commit.prev_data {
// inductive proof fail!
}
atproto sync limits commits to 200 ops and 2MB total CAR size (including records, which are not used at all), so it should be fast enough to directly call invert_ops in an async context.
operation order (OpOrder) #
generally, just use AsGiven. there's this fun thing where the minimal set of blocks required to satisfy the inductive proof actually depend on the order of op inversion.
the current atproto sync draft REQUIRES that producers slightly over-include blocks (the adjacent-key requirement), so that the order doesn't matter.
if you set HighestKeyFirst, then invert_ops will always accept commits from producers which can be proven but don't necessarily meet the spec requirement.
(we don't actually assert the requirement either way, we just either might fail, or won't fail, and we take a preference to rejecting spec-non-compliant commits by letting them possibly fail. fix your producers.
or use HighestKeyFirst and let the badness ossify.)
tests #
cargo test -p hubble-commit
runs unit tests, atproto-interop-tests vectors, and a 228-case subset of mst-test-suite vendored under tests/fixtures/mst-test-suite.
the full 16,384-case exhaustive mst-test-suite is included a submodule:
git submodule update --init hubble-commit/tests/mst-test-suite
cargo test -p hubble-commit --test mst_diff_suite -- --ignored
scripts/select-mst-cases.py regenerates the vendored subset from a checkout.
the captured commits come from corpus/, which also benches
against a larger capture.
fuzzing lives in fuzz/: CARv1 framing and inversion, both
seeded from the vendored trees.
vendored code #
src/cid.rs is dasl's Cid, vendored until dasl releases the Hash derive that's sitting unreleased on main 🙃.