Invariants / CN-STORE-07

CN-STORE-07

CN release enforced

Single materialize authority for rolled-back state: the function that materializes (LedgerState, PraosChainDepState) at a target point uses ONLY one SnapshotStore lookup + ChainDb::iter_from_slot

  • apply_block_with_verdicts (+ apply_epoch_boundary when crossing). No bypass; no parallel rolled-back-state computation path. Mirror of CN-CONS-08 (admission gate) for the rollback path. Single- public-function discipline; type-level + CI grep enforcement.

Source

docs/planning/ledger-snapshot-rollback-invariants.md §1 (I-5)

Cluster
PHASE4-N-I
Authority surface
rollback materialization

Enforcement trace

Tests 5

  • materialize_returns_rollback_too_deep_when_no_snapshot
  • materialize_with_snapshot_at_target_returns_snapshot_state
  • materialize_with_snapshot_below_target_replays_forward
  • materialize_fails_closed_on_invalid_block
  • materialize_replay_forward_equals_direct_apply

Cross-references

Strengthened in

Attack rationale

A parallel materializer can produce a rolled-back state inconsistent with what block_validity would compute, allowing peer-controlled state divergence.

Evidence notes

Enforcement is type-level: materialize_rolled_back_state is the sole pub fn returning the rolled-back state tuple. The function takes narrow read-only traits (SnapshotReader, BlockSource), not concrete chain stores — test-side and production-side go through the same single composition.

Evidence

  • ci_check_rollback_materialize_closure.sh enforces single-authority via grep: no other pub fn in rollback/* returns (LedgerState, PraosChainDepState). The driver composes one SnapshotReader::nearest_le + BlockSource::blocks_in_range + per-block block_validity (positive grep for block_validity call site).

  • The function takes narrow read-only traits (SnapshotReader, BlockSource), not concrete chain stores — production impls in ade_runtime (S4) go through the same single composition path.

  • N-J: the second production SnapshotReader impl (PersistentSnapshotCache) goes through the SAME single materialize composition — cross-impl equivalence with InMemorySnapshotCache proven via persistent_cache_matches_in_memory_cache_semantics. CN-STORE-08 (the snapshot-encoder counterpart to CN-STORE-07) also lands.

  • PHASE4-N-K strengthening: bootstrap warm-start branch routes directly through materialize_rolled_back_state (see ade_runtime::bootstrap), and ade_node binary calls bootstrap_initial_state exactly once (ci/ci_check_node_binary_uses_single_bootstrap.sh). bootstrap_warm_start_equals_direct_materialize proves bootstrap-warm-start = direct-materialize equivalence.