mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
## Summary
Implements storage layout testing for the upgradeable
`DataHavenServiceManager` contract to prevent state
corruption during proxy upgrades.
## Changes
### New Files
- **`contracts/storage-snapshots/DataHavenServiceManager.storage.json`**
- Baseline storage layout
snapshot
- **`contracts/storage-snapshots/README.md`** - Documentation for
updating snapshots and known
limitations
- **`contracts/scripts/check-storage-layout.sh`** - CI script that
compares current layout against
snapshot
- **`contracts/test/storage/StorageLayout.t.sol`** - Upgrade simulation
tests verifying state
preservation
- **`.github/workflows/task-storage-layout.yml`** - CI workflow for
storage layout checks
### Modified Files
- **`.github/workflows/CI.yml`** - Added `storage-layout` job to run in
parallel with other checks
## How It Works
**Two-pronged approach:**
1. **Snapshot Diff** - Compares current storage layout against committed
snapshot using `forge inspect`.
Catches unintended variable reordering, type changes, or gap
modifications.
2. **Upgrade Simulation** - Foundry tests that populate state, perform a
proxy upgrade, and verify all
values survive:
- `test_upgradePreservesState` - Verifies core state variables
- `test_upgradePreservesValidatorMappings` - Verifies
`validatorEthAddressToSolochainAddress` mapping
- `test_upgradePreservesMultipleValidators` - Verifies
`validatorsAllowlist` with multiple entries
- `test_functionalityAfterUpgrade` - Verifies contract remains
functional post-upgrade
## Normalization
The snapshot comparison normalizes JSON to avoid false positives:
- Removes `astId` (changes with compiler runs)
- Removes `contract` (contains full file path)
- Removes `.types` section (contains unstable AST IDs embedded in type
keys)
- Sorts by slot number
## Usage
```bash
# Check storage layout against snapshot
./scripts/check-storage-layout.sh
# Run upgrade simulation tests
forge test --match-contract StorageLayoutTest -vvv
# Update snapshot (when intentionally changing storage)
forge inspect DataHavenServiceManager storage --json >
storage-snapshots/DataHavenServiceManager.storage.json
```
## Test Plan
- ./scripts/check-storage-layout.sh passes
- forge test --match-contract StorageLayoutTest -vvv passes (4 tests)
- CI workflow runs successfully
62 lines
2.1 KiB
Bash
Executable file
62 lines
2.1 KiB
Bash
Executable file
#!/bin/bash
|
|
set -e
|
|
|
|
# Storage Layout Check Script
|
|
# Compares current storage layout against committed snapshot to detect unintended changes.
|
|
|
|
CONTRACT="${CONTRACT:-DataHavenServiceManager}"
|
|
SNAPSHOT_DIR="${SNAPSHOT_DIR:-storage-snapshots}"
|
|
SNAPSHOT="${SNAPSHOT:-${SNAPSHOT_DIR}/${CONTRACT}.storage.json}"
|
|
|
|
# Ensure we're in the contracts directory
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR/.."
|
|
|
|
# Check if snapshot exists
|
|
if [ ! -f "$SNAPSHOT" ]; then
|
|
echo "ERROR: Snapshot file not found: $SNAPSHOT"
|
|
echo "Generate it with: mkdir -p $SNAPSHOT_DIR && forge inspect $CONTRACT storage --json > $SNAPSHOT"
|
|
exit 1
|
|
fi
|
|
|
|
# Generate current layout
|
|
echo "Generating current storage layout for $CONTRACT..."
|
|
forge inspect "$CONTRACT" storage --json > /tmp/current_layout.json
|
|
|
|
# Normalize both files for comparison:
|
|
# - Remove astId (changes with compiler runs)
|
|
# - Remove contract field (contains full path)
|
|
# - Remove types section (contains unstable AST IDs)
|
|
# - Sort by slot number
|
|
normalize_json() {
|
|
jq 'del(.types)
|
|
| .storage
|
|
| map(
|
|
del(.astId, .contract)
|
|
# Remove unstable AST ID suffixes from type strings (e.g., t_contract(IGatewayV2)12345)
|
|
| .type |= sub("\\)[0-9]+$"; ")")
|
|
)
|
|
| sort_by(.slot | tonumber)' "$1"
|
|
}
|
|
|
|
echo "Comparing storage layouts..."
|
|
normalize_json "$SNAPSHOT" > /tmp/snap_normalized.json
|
|
normalize_json /tmp/current_layout.json > /tmp/curr_normalized.json
|
|
|
|
if ! diff -q /tmp/snap_normalized.json /tmp/curr_normalized.json > /dev/null 2>&1; then
|
|
echo ""
|
|
echo "=========================================="
|
|
echo "ERROR: Storage layout has changed!"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "Differences found:"
|
|
diff /tmp/snap_normalized.json /tmp/curr_normalized.json || true
|
|
echo ""
|
|
echo "If this change is intentional, update the snapshot:"
|
|
echo " forge inspect $CONTRACT storage --json > $SNAPSHOT"
|
|
echo ""
|
|
echo "WARNING: Unintended storage layout changes can corrupt state during upgrades!"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Storage layout OK - no changes detected"
|