Harden disk SMT failover recovery#161
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces significant changes to the BFT client and round management logic to support durable proposals, including improved recovery mechanisms, better error handling for root mismatches, and optimized SMT persistence. The reviewer identified a potential issue where an invalid durable proposal could wedge the system upon restart, and provided an actionable suggestion to abandon the proposal in such cases. I have kept this feedback as it highlights a critical improvement opportunity for system resilience.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR hardens disk-backed Sparse Merkle Tree (SMT) high-availability recovery by shifting durable replay/recovery sources toward Mongo “aggregator_records + blocks” (proposal-scoped), tightening finality visibility semantics, and adding metrics + regression tests to protect failover/crash paths.
Changes:
- Reworks Mongo storage model/indexes for aggregator records (hashed
stateId,{blockNumber, proposalId}) and removesblock_recordsas a durable mapping source. - Updates SMT root hashing semantics (raw root hex by default) while keeping legacy path proof compatibility via a test-only helper.
- Improves disk SMT persistence / replay / recovery paths and adds extensive regression coverage + new proof build latency metrics.
Reviewed changes
Copilot reviewed 55 out of 55 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/api/merkle_tree_path_verify_test.go | Adjusts proof-root assertions to align with updated root encoding behavior. |
| internal/storage/mongodb/test_helpers_test.go | Adds Mongo testcontainer helper for mongodb storage tests. |
| internal/storage/mongodb/index_test.go | Updates expected Mongo index set for aggregator records after storage model change. |
| internal/storage/mongodb/connection.go | Removes BlockRecordsStorage wiring and index creation. |
| internal/storage/mongodb/block.go | Adds block status/proposal fields, status migration, and “any finalization” retrieval helpers. |
| internal/storage/mongodb/block_records.go | Deletes Mongo block_records storage implementation. |
| internal/storage/mongodb/aggregator_record.go | Adds proposal-aware/finality-aware record queries; changes indexes to hashed + compound. |
| internal/storage/mongodb/aggregator_record_test.go | Updates/expands tests for proposal IDs, finality visibility, and duplicate handling. |
| internal/storage/interfaces/interfaces.go | Removes BlockRecordsStorage interface and storage accessor. |
| internal/smt/smt.go | Changes root hash getters to return raw roots; keeps legacy path support note. |
| internal/smt/smt_test.go | Updates golden roots to raw hex; adjusts legacy path root expectations. |
| internal/smt/smt_debug_test.go | Updates debug test to use legacy path root helper. |
| internal/smt/legacy_path_test.go | Adds helper to compute legacy (imprinted) root hex for legacy path tests. |
| internal/smt/inclusion_cert_test.go | Updates golden vectors / assertions to raw root hex semantics. |
| internal/smt/golden_vectors_test.go | Updates golden root vectors to raw root hex semantics. |
| internal/smt/disk/rocksstore/store.go | Refactors proof response key construction via a shared prefix helper. |
| internal/smt/disk/persist/tree.go | Improves snapshot forking over uncommitted overlays; reduces stats overhead; releases buffers on close. |
| internal/smt/disk/persist/tree_test.go | Updates tests to match append-only node semantics and new fork behavior. |
| internal/smt/backend/disk_backend.go | Refactors locking (commit stats RWMutex) and adds per-commit timing reporting. |
| internal/smt/backend/backend.go | Introduces CommitTimingProvider / CommitTiming for commit timing reporting. |
| internal/service/service.go | Adds inclusion-cert build timing metrics; hardens nil checks in proof path. |
| internal/service/service_test.go | Updates tests to match AggregatorRecord model changes (removes FinalizedAt). |
| internal/service/proof_diagnostics.go | Replaces proof path atomic logging with histogram-based inclusion-cert timing metrics. |
| internal/service/aggregate_test.go | Updates test model-to-API mapping expectations after record model change. |
| internal/round/smt_persistence_integration_test.go | Ensures durable proposal is stored before finalization in restart workflow test. |
| internal/round/round_process_regression_test.go | Adds regression for stale certification handling + finality visibility expectations. |
| internal/round/round_manager.go | Adds proposal IDs to rounds; makes mini-batch size configurable; refactors precollector lifecycle. |
| internal/round/precollector.go | Simplifies precollector to one-shot handoff with optional record staging + stats. |
| internal/round/precollection_test.go | Updates tests for new precollector behavior and adds staging + validation coverage. |
| internal/round/parent_round_manager.go | Adds activation context management and async StartNextRound behavior for parent mode. |
| internal/round/finalize_duplicate_test.go | Shifts duplicate recovery to durable proposal model; adds proposal ID semantics tests. |
| internal/round/disk_smt_startup.go | Replays disk SMT using finalized blocks + aggregator records (not block_records); improves replay correctness. |
| internal/round/disk_smt_startup_test.go | Updates disk startup tests to use aggregator-record replay model and cover “latest advances during replay”. |
| internal/round/disk_ha_failover_integration_rocksdb_test.go | Updates HA failover test to use aggregator records (proposal scoped) instead of block_records. |
| internal/round/disk_bft_integration_rocksdb_test.go | Updates BFT integration tests to validate persisted aggregator-record “block records” behavior. |
| internal/models/finality_status.go | Adds explicit finality status constants and normalization helpers. |
| internal/models/block.go | Adds Status and ProposalID fields to blocks and BSON conversions. |
| internal/models/block_record.go | Removes BlockRecords model. |
| internal/models/aggregator_record.go | Adds ProposalID, removes FinalizedAt, adjusts BSON serialization defaults. |
| internal/models/aggregator_record_test.go | Updates serialization test for AggregatorRecord model changes. |
| internal/metrics/metrics.go | Adds SMTInclusionCertBuildDuration histogram metric. |
| internal/ha/block_syncer.go | Switches replay to aggregator records and blocks; adds helper for next finalized block lookup. |
| internal/ha/block_syncer_test.go | Updates block syncer tests to store proposal-scoped aggregator records instead of block_records. |
| internal/config/config.go | Adds COLLECT_MINI_BATCH_SIZE configuration with env default + validation. |
| internal/config/config_test.go | Adds config validation and env override tests for collect mini-batch size. |
| internal/bft/client.go | Adds durable proposal resume/finalize/abandon flows; strengthens UC sequence checks and root validation. |
| internal/bft/client_stub.go | Makes stub lifecycle cancelable and goroutine-safe; avoids starting rounds after Stop. |
| internal/bft/client_stub_test.go | Adds tests for new durable proposal behaviors, UC sequencing, and local-root validation. |
| docs/disk-backed-smt-performance.md | Documents disk-backed SMT E2E performance checkpoints and config. |
| cmd/performance-test/types.go | Extends perf log parsing fields and ensures JSON-RPC params are encoded before sending. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Review: Harden disk SMT failover recoveryReviewed via a multi-agent pass (subsystem mapping → dimension finders → adversarial verification) plus a manual re-trace of the core paths. Findings below are deduped against the existing Copilot/Gemini comments — those are cross-referenced in a table at the bottom rather than repeated. Recommendation: changes requested. Two issues can hard-wedge a node, and the migration gaps silently corrupt or hide data on any non-clean upgrade. Design is otherwise coherent (double root-check before finalize, 🔴 Critical / blocking1. Memory/Mongo backend: a crash mid-
→ Startup fails on every subsequent boot until manual DB surgery. This is a regression (old 2. Upgrade-in-place silently drops re-proposed records (legacy unique 🟠 High3.
Fix: backfill 4. Certified-root mismatch can fail to halt the node — 5. 6. Abandoned-proposal records leak unbounded — 🟡 Medium
Test coverage gaps
Already covered by Copilot / Gemini (cross-referenced, not repeated)
Strengths
|
|
@MastaP This PR still intentionally assumes a clean DB; no in-place migration/backfill is included. |
Re-review: feedback addressed + regression checkRe-reviewed the four fix commits since the first pass ( Recommendation: close to mergeable. All blocking items from the first review are genuinely fixed and well-tested; no blocking regressions were introduced by the fixes. Two non-trivial items remain (one is a footgun in the new guard's guidance). 1. Feedback status
Spot-checks that confirm the criticals hold end-to-end:
2. Regressions introduced by the fixesNo blocking regressions. Of the candidate issues surfaced, all but one were refuted under verification (not triggerable / actually an improvement / the new test does catch its regression). One survives, at low severity: 🟡 Low — asymmetric, un-interfaced finalizing marker ( (Trivial: Two things worth doing before merge
The remaining unaddressed items (resumed-proposal stall, proof |
This PR hardens the disk-backed SMT HA path for crash/failover recovery.
Summary:
Operational note
This branch changes the disk-SMT durable storage model and Mongo indexes. It is intended to run from a clean local state unless a migration/backfill is added separately.