diff --git a/contracts/scripts/check-storage-layout-negative.sh b/contracts/scripts/check-storage-layout-negative.sh index 18d842cf..be79ba9b 100755 --- a/contracts/scripts/check-storage-layout-negative.sh +++ b/contracts/scripts/check-storage-layout-negative.sh @@ -20,7 +20,7 @@ if [ "$EXIT_CODE" -eq 0 ]; then exit 1 fi -if ! printf '%s\n' "$OUTPUT" | grep -q "ERROR: Storage layout has changed!"; then +if ! printf '%s\n' "$OUTPUT" | grep -qE "ERROR: (Storage layout has changed!|__GAP invariant violated!)"; then echo "ERROR: Storage layout check failed, but not for the expected reason." echo "" echo "Output:" diff --git a/contracts/scripts/check-storage-layout.sh b/contracts/scripts/check-storage-layout.sh index 8e2aeb09..390f3298 100755 --- a/contracts/scripts/check-storage-layout.sh +++ b/contracts/scripts/check-storage-layout.sh @@ -59,4 +59,26 @@ if ! diff -q /tmp/snap_normalized.json /tmp/curr_normalized.json > /dev/null 2>& exit 1 fi +# Verify gap invariant: __GAP slot + array size must equal a fixed constant. +# This catches cases where a new variable is added but __GAP is not shrunk accordingly. +EXPECTED_GAP_TOTAL=151 +GAP_SLOT=$(jq '.storage[] | select(.label == "__GAP") | .slot | tonumber' /tmp/current_layout.json) +GAP_SIZE=$(jq -r '.storage[] | select(.label == "__GAP") | .type' /tmp/current_layout.json \ + | grep -oE '[0-9]+' | tail -1) + +if [ -n "$GAP_SLOT" ] && [ -n "$GAP_SIZE" ]; then + GAP_TOTAL=$((GAP_SLOT + GAP_SIZE)) + if [ "$GAP_TOTAL" -ne "$EXPECTED_GAP_TOTAL" ]; then + echo "" + echo "==========================================" + echo "ERROR: __GAP invariant violated!" + echo "==========================================" + echo "" + echo " slot($GAP_SLOT) + size($GAP_SIZE) = $GAP_TOTAL, expected $EXPECTED_GAP_TOTAL" + echo "" + echo "If you added a new state variable, shrink __GAP by the same number of slots." + exit 1 + fi +fi + echo "Storage layout OK - no changes detected"