Context
Summit's consensus state carries a dynamic epoch schedule that maps block heights to epochs after epoch-length protocol changes. Finalizer code uses that schedule to decide epoch-boundary behavior such as last-block handling, pending checkpoint creation, deferred withdrawals, and epoch advancement.
The intended root invariant is that the SSZ state root authenticates every consensus-state field needed by consumers that verify checkpoint state or SSZ proofs. That includes fields that determine which block heights are treated as epoch boundaries.
Claim
The SSZ state root omits the serialized dynamic epoch schedule even though finalizer boundary logic depends on it, so identical roots can represent different height-to-epoch mappings.
A malicious proof provider or root-only state provider can present a state root that authenticates the ordinary SSZ-tree fields while supplying a different serialized dynamic epoch schedule, causing consumers that trust the root for epoch-boundary state to accept unauthenticated schedule behavior.
Flow
The path is reachable after epoch-length protocol updates because those updates mutate DynamicEpocher without changing an SSZ-tree leaf. The start condition is a consumer that relies on the SSZ state root or SSZ proofs to authenticate schedule-dependent state; this should not be read as proof that Summit's normal checkpoint import accepts arbitrary schedule bytes under the same root, because that path also binds raw checkpoint bytes through the checkpoint digest and finalized-header chain.
Impact
Root or proof consumers can authenticate a state root without authenticating the epoch schedule that drives checkpoint timing, deferred withdrawal handling, and epoch advancement. A stale or malicious schedule paired with the same root can cause such consumers to classify heights as different epoch-boundary positions, but the normal checkpoint-import path is not claimed to install that schedule solely from the root.
Root Cause
The dynamic epoch schedule is serialized in ConsensusState and used by finalizer logic, but SszStateTree::rebuild has no field for it and epoch-length updates do not update any committed SSZ leaf.
Code
Related Issues/PRs
Related issues cover adjacent SSZ state-root and proof omissions involving dynamic epoch schedules, boundary mutations, pending state, and proof responses.
Fix
- Add a committed SSZ leaf or collection root for the dynamic epoch schedule.
- Update it whenever
DynamicEpocher changes.
- Include schedule proof support if external clients need to verify boundary decisions.
- Add collision-style tests for states with identical fields but different epoch schedules.
Context
Summit's consensus state carries a dynamic epoch schedule that maps block heights to epochs after epoch-length protocol changes. Finalizer code uses that schedule to decide epoch-boundary behavior such as last-block handling, pending checkpoint creation, deferred withdrawals, and epoch advancement.
The intended root invariant is that the SSZ state root authenticates every consensus-state field needed by consumers that verify checkpoint state or SSZ proofs. That includes fields that determine which block heights are treated as epoch boundaries.
Claim
The SSZ state root omits the serialized dynamic epoch schedule even though finalizer boundary logic depends on it, so identical roots can represent different height-to-epoch mappings.
A malicious proof provider or root-only state provider can present a state root that authenticates the ordinary SSZ-tree fields while supplying a different serialized dynamic epoch schedule, causing consumers that trust the root for epoch-boundary state to accept unauthenticated schedule behavior.
Flow
The path is reachable after epoch-length protocol updates because those updates mutate
DynamicEpocherwithout changing an SSZ-tree leaf. The start condition is a consumer that relies on the SSZ state root or SSZ proofs to authenticate schedule-dependent state; this should not be read as proof that Summit's normal checkpoint import accepts arbitrary schedule bytes under the same root, because that path also binds raw checkpoint bytes through the checkpoint digest and finalized-header chain.Impact
Root or proof consumers can authenticate a state root without authenticating the epoch schedule that drives checkpoint timing, deferred withdrawal handling, and epoch advancement. A stale or malicious schedule paired with the same root can cause such consumers to classify heights as different epoch-boundary positions, but the normal checkpoint-import path is not claimed to install that schedule solely from the root.
Root Cause
The dynamic epoch schedule is serialized in
ConsensusStateand used by finalizer logic, butSszStateTree::rebuildhas no field for it and epoch-length updates do not update any committed SSZ leaf.Code
ConsensusStatestoresepocher: DynamicEpocher: https://github.com/SeismicSystems/summit/blob/ed2c5c8/types/src/consensus_state.rs#L45.EpochLengthdoes not update an SSZ-tree field: https://github.com/SeismicSystems/summit/blob/ed2c5c8/types/src/consensus_state.rs#L700.rebuild_ssz_tree()passes many consensus fields intoSszStateTree::rebuild, but notepocher: https://github.com/SeismicSystems/summit/blob/ed2c5c8/types/src/consensus_state.rs#L757.SszStateTree::rebuildsignature has no dynamic epoch schedule parameter: https://github.com/SeismicSystems/summit/blob/ed2c5c8/types/src/ssz_state_tree.rs#L874.Related Issues/PRs
Related issues cover adjacent SSZ state-root and proof omissions involving dynamic epoch schedules, boundary mutations, pending state, and proof responses.
Fix
DynamicEpocherchanges.