Skip to content

Upgradeable Proxy Storage Collision for Implementation Constants Across Contract Upgrades #21

Description

@JamesEjembi

Problem Statement / Feature Objective

The core engine uses an upgradeable proxy pattern (ERC-1967-style) for the main beacon state contract. Implementation constants (e.g., MAX_VALIDATORS, SHARD_COUNT) are stored in the implementation contract's storage at fixed slots. When a new implementation is deployed, these constants are re-initialized but the proxy's storage may retain stale values from the previous implementation if the storage layout shifts, causing silent protocol parameter corruption.

Technical Invariants & Bounds

  • Storage slot collision risk: any field added to the implementation before constants shifts their slots.
  • Constants read via delegatecall use implementation contract storage, not proxy.
  • Proxy storage slot for constants is keccak256("beacon.constants") - but implementation may use different derivation.
  • Upgrade must guarantee constant values are preserved across upgrades.
  • Storage collision can cause MAX_VALIDATORS to read as 0, freezing all validator operations.

Codebase Navigation Guide

  • src/proxy/upgrade-beacon.rs - upgrade_implementation() and storage migration.
  • src/state/beacon-state.rs - constant definitions and init_constants().
  • src/proxy/storage-layout.rs - StorageSlot derivation and collision detection.
  • tests/proxy/upgrade_storage_test.rs - upgrade test harness.

Implementation Blueprint

  1. In src/proxy/storage-layout.rs, define all constants in a dedicated ConstantsStore struct stored at a versioned slot: keccak256("beacon.constants.v1").
  2. In upgrade_implementation(), before performing the delegatecall to the new implementation, write the ConstantsStore to the deterministic slot.
  3. The new implementation's init_constants() reads from this slot instead of re-deriving from its own storage.
  4. Add a StorageLayoutCheck script in the CI that compares storage slots between old and new implementations and warns on any collision.
  5. Write an integration test that upgrades the implementation, changes the new implementation's field layout, and verifies all constants are still correctly read.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions