Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: incompatible storage layout for Bootstrap and ClientChainGateway #72

Merged
merged 5 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/compare_storage_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python

import pandas as pd
import os

def parse_layout(file_path):
expected_headers = ['Unnamed: 0', 'Name', 'Type', 'Slot', 'Offset', 'Bytes', 'Contract', 'Unnamed: 7']

if not os.path.isfile(file_path):
raise FileNotFoundError(f"Error: File {file_path} does not exist.")

# Read the file using pandas, with '|' as the delimiter
df = pd.read_csv(file_path, delimiter='|', engine='python', header=0)

# Trim leading/trailing whitespace from all columns
df.columns = [col.strip() for col in df.columns]
df = df.apply(lambda x: x.strip() if isinstance(x, str) else x)

# Check headers
if not all([df.columns[i] == expected_headers[i] for i in range(len(expected_headers))]):
raise ValueError(f"Error: Headers in {file_path} do not match expected headers.")

# Drop the second row (assuming it's a separator row)
df = df.drop(df.index[1])

# Combine relevant columns into a single string for comparison
df['Combined'] = df[['Name', 'Type', 'Slot', 'Offset', 'Bytes']].apply(lambda row: '|'.join(row.values), axis=1)

return df['Combined'].tolist()

def compare_layouts(clientChainGateway_entries, bootstrap_entries):
mismatches = []
length = len(bootstrap_entries)

if length > len(clientChainGateway_entries):
mismatches.append("Error: Bootstrap entries are more than ClientChainGateway entries.")
return mismatches

for i in range(length):
if bootstrap_entries[i] != clientChainGateway_entries[i]:
mismatches.append(f"Mismatch at position {i + 1}: {bootstrap_entries[i]} != {clientChainGateway_entries[i]}")

return mismatches

if __name__ == "__main__":
try:
clientChainGateway_entries = parse_layout("ClientChainGateway.md")
bootstrap_entries = parse_layout("Bootstrap.md")

if not clientChainGateway_entries:
raise ValueError("Error: No valid entries found in ClientChainGateway.md.")

if not bootstrap_entries:
raise ValueError("Error: No valid entries found in Bootstrap.md.")

mismatches = compare_layouts(clientChainGateway_entries, bootstrap_entries)

if mismatches:
print(f"Mismatches found: {len(mismatches)}")
for mismatch in mismatches:
print(mismatch)
exit(1)
else:
print("All entries in Bootstrap are present in ClientChainGateway at the correct positions.")
except Exception as e:
print(e)
exit(1)

67 changes: 58 additions & 9 deletions .github/workflows/forge-ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
name: Forge CI to build, test and format
name: Forge CI to build, test, format and compare storage layout

on:
merge_group:
Expand All @@ -24,7 +23,8 @@ jobs:
installation-dir: ${{ needs.setup.outputs.installation-dir }}
cache-key: ${{ needs.setup.outputs.cache-key }}
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Restore cached Foundry toolchain
Expand Down Expand Up @@ -62,7 +62,8 @@ jobs:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
Expand All @@ -79,9 +80,9 @@ jobs:
./cache
./broadcast
key: ${{ runner.os }}-build-${{ github.sha }}
- name: Run tests
- name: Test
run: forge test -vvv
- name: Run test snapshot
- name: Set test snapshot as summary
run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
- name: Add comment for test failure
if: failure()
Expand All @@ -96,11 +97,12 @@ jobs:
body: 'The tests have failed. Please check the logs.'
})

fmt:
format:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
Expand All @@ -119,7 +121,7 @@ jobs:
key: ${{ runner.os }}-build-${{ github.sha }}
- name: Check formatting
run: forge fmt --check
- name: Add comment for format failure
- name: Add comment for format check failure
if: failure()
uses: actions/github-script@v6
with:
Expand All @@ -131,3 +133,50 @@ jobs:
repo: context.repo.repo,
body: 'The code is not formatted correctly. Please run `forge fmt` and push the changes.'
})

compare-storage-layout:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
path: ${{ needs.build.outputs.installation-dir }}
key: ${{ needs.build.outputs.cache-key }}
- name: Add Foundry to PATH
run: echo "${{ needs.build.outputs.installation-dir }}" >> $GITHUB_PATH
- name: Restore build artifacts
uses: actions/cache/restore@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: ${{ runner.os }}-build-${{ github.sha }}
- name: Run forge inspect storage layout on ClientChainGateway
run: forge inspect --pretty src/core/ClientChainGateway.sol:ClientChainGateway storageLayout > ClientChainGateway.md
- name: Run forge inspect storage layout on Bootstrap
run: forge inspect --pretty src/core/Bootstrap.sol:Bootstrap storageLayout > Bootstrap.md
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12.4'
- name: Install pandas
run: pip install --root-user-action=ignore pandas==2.2.2
- name: Run the comparison script
run: python .github/workflows/compare_storage_layout.py
- name: Add comment for storage layout mismatch failure
if: failure()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'The storage layout of Bootstrap and ClientChainGateway is not the same. Please check the logs.'
})
2 changes: 1 addition & 1 deletion .github/workflows/foundry-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
installation_path=$(which forge)
installation_dir=$(dirname $installation_path)
echo "installation-dir=$installation_dir" >> "$GITHUB_OUTPUT"
- name: Cached Foundry toolchain
- name: Cache the Foundry toolchain
uses: actions/cache/save@v3
with:
path: ${{ steps.find-path.outputs.installation-dir }}
Expand Down
36 changes: 36 additions & 0 deletions docs/bootstrap_storage.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
| Name | Type | Slot | Offset | Bytes | Contract |
adu-web3 marked this conversation as resolved.
Show resolved Hide resolved
|-------------------------------|--------------------------------------------------------------------|------|--------|-------|----------------------------------|
| _initialized | uint8 | 0 | 0 | 1 | src/core/Bootstrap.sol:Bootstrap |
| _initializing | bool | 0 | 1 | 1 | src/core/Bootstrap.sol:Bootstrap |
| __gap | uint256[50] | 1 | 0 | 1600 | src/core/Bootstrap.sol:Bootstrap |
| _paused | bool | 51 | 0 | 1 | src/core/Bootstrap.sol:Bootstrap |
| __gap | uint256[49] | 52 | 0 | 1568 | src/core/Bootstrap.sol:Bootstrap |
| _owner | address | 101 | 0 | 20 | src/core/Bootstrap.sol:Bootstrap |
| __gap | uint256[49] | 102 | 0 | 1568 | src/core/Bootstrap.sol:Bootstrap |
| _status | uint256 | 151 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| __gap | uint256[49] | 152 | 0 | 1568 | src/core/Bootstrap.sol:Bootstrap |
| peers | mapping(uint32 => bytes32) | 201 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| _whiteListFunctionSelectors | mapping(enum GatewayStorage.Action => bytes4) | 202 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| inboundNonce | mapping(uint32 => mapping(bytes32 => uint64)) | 203 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| __gap | uint256[40] | 204 | 0 | 1280 | src/core/Bootstrap.sol:Bootstrap |
| exocoreSpawnTime | uint256 | 244 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| offsetDuration | uint256 | 245 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| depositsByToken | mapping(address => uint256) | 246 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| registeredValidators | address[] | 247 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| ethToExocoreAddress | mapping(address => string) | 248 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| validators | mapping(string => struct IValidatorRegistry.Validator) | 249 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| commissionEdited | mapping(string => bool) | 250 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| delegationsByValidator | mapping(string => mapping(address => uint256)) | 251 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| depositors | address[] | 252 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| isDepositor | mapping(address => bool) | 253 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| totalDepositAmounts | mapping(address => mapping(address => uint256)) | 254 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| withdrawableAmounts | mapping(address => mapping(address => uint256)) | 255 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| delegations | mapping(address => mapping(string => mapping(address => uint256))) | 256 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| bootstrapped | bool | 257 | 0 | 1 | src/core/Bootstrap.sol:Bootstrap |
| customProxyAdmin | address | 257 | 1 | 20 | src/core/Bootstrap.sol:Bootstrap |
| clientChainGatewayLogic | address | 258 | 0 | 20 | src/core/Bootstrap.sol:Bootstrap |
| clientChainInitializationData | bytes | 259 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| whitelistTokens | address[] | 260 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| isWhitelistedToken | mapping(address => bool) | 261 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| tokenToVault | mapping(address => contract IVault) | 262 | 0 | 32 | src/core/Bootstrap.sol:Bootstrap |
| __gap | uint256[40] | 263 | 0 | 1280 | src/core/Bootstrap.sol:Bootstrap |
41 changes: 41 additions & 0 deletions docs/clientchaingateway_storage.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
| Name | Type | Slot | Offset | Bytes | Contract |
adu-web3 marked this conversation as resolved.
Show resolved Hide resolved
|-------------------------------|--------------------------------------------------------------------|------|--------|-------|----------------------------------------------------|
| _initialized | uint8 | 0 | 0 | 1 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _initializing | bool | 0 | 1 | 1 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[50] | 1 | 0 | 1600 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _paused | bool | 51 | 0 | 1 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[49] | 52 | 0 | 1568 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _owner | address | 101 | 0 | 20 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[49] | 102 | 0 | 1568 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _status | uint256 | 151 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[49] | 152 | 0 | 1568 | src/core/ClientChainGateway.sol:ClientChainGateway |
| peers | mapping(uint32 => bytes32) | 201 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _whiteListFunctionSelectors | mapping(enum GatewayStorage.Action => bytes4) | 202 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| inboundNonce | mapping(uint32 => mapping(bytes32 => uint64)) | 203 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[40] | 204 | 0 | 1280 | src/core/ClientChainGateway.sol:ClientChainGateway |
| exocoreSpawnTime | uint256 | 244 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| offsetDuration | uint256 | 245 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| depositsByToken | mapping(address => uint256) | 246 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| registeredValidators | address[] | 247 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| ethToExocoreAddress | mapping(address => string) | 248 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| validators | mapping(string => struct IValidatorRegistry.Validator) | 249 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| commissionEdited | mapping(string => bool) | 250 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| delegationsByValidator | mapping(string => mapping(address => uint256)) | 251 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| depositors | address[] | 252 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| isDepositor | mapping(address => bool) | 253 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| totalDepositAmounts | mapping(address => mapping(address => uint256)) | 254 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| withdrawableAmounts | mapping(address => mapping(address => uint256)) | 255 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| delegations | mapping(address => mapping(string => mapping(address => uint256))) | 256 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| bootstrapped | bool | 257 | 0 | 1 | src/core/ClientChainGateway.sol:ClientChainGateway |
| customProxyAdmin | address | 257 | 1 | 20 | src/core/ClientChainGateway.sol:ClientChainGateway |
| clientChainGatewayLogic | address | 258 | 0 | 20 | src/core/ClientChainGateway.sol:ClientChainGateway |
| clientChainInitializationData | bytes | 259 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| whitelistTokens | address[] | 260 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| isWhitelistedToken | mapping(address => bool) | 261 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| tokenToVault | mapping(address => contract IVault) | 262 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[40] | 263 | 0 | 1280 | src/core/ClientChainGateway.sol:ClientChainGateway |
| outboundNonce | uint64 | 303 | 0 | 8 | src/core/ClientChainGateway.sol:ClientChainGateway |
| ownerToCapsule | mapping(address => contract IExoCapsule) | 304 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _registeredRequests | mapping(uint64 => bytes) | 305 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| _registeredRequestActions | mapping(uint64 => enum GatewayStorage.Action) | 306 | 0 | 32 | src/core/ClientChainGateway.sol:ClientChainGateway |
| __gap | uint256[40] | 307 | 0 | 1280 | src/core/ClientChainGateway.sol:ClientChainGateway |
Loading
Loading