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

CI: enhance CI to check storage layout backwards compatibility #112

Merged
merged 9 commits into from
Oct 21, 2024

Conversation

adu-web3
Copy link
Collaborator

@adu-web3 adu-web3 commented Oct 17, 2024

Description

Since we have decided to freeze the contract storage layout, to make deployed contracts upgradeable, we need to keep backwards compatibility for contract storage layout, so that these deployed contracts would be upgradeable in the next release.

By comparing storage layout against deployed contracts, we ensure future pull requests would not break the upgradeability for most of the contracts(client chain contracts). For ExocoreGateway, we can compare against the main branch to make it since cast storage does not work with Exocore chain for now.

Summary by CodeRabbit

  • New Features

    • Enhanced the compare-storage-layout job with new checks for deployed contracts and improved failure message clarity.
    • Introduced a new script to compare storage layouts of deployed smart contracts against expected layouts.
  • Chores

    • Updated .gitignore to ignore .secrets files for better security practices.

Copy link
Contributor

coderabbitai bot commented Oct 17, 2024

Walkthrough

The pull request introduces several modifications to enhance the GitHub Actions workflow for comparing storage layouts of smart contracts. It updates the compare-storage-layout job by adding new environment variables and steps, removing outdated checks, and improving failure messages. Additionally, a new script for comparing deployed storage layouts against expected layouts is introduced. The .gitignore file is also updated to ignore files named .secrets.

Changes

File Change Summary
.github/workflows/forge-ci.yml - Added environment variables: ALCHEMY_API_KEY, ETHERSCAN_API_KEY.
- Removed steps for ClientChainGateway and Bootstrap.
- Introduced new steps for ExocoreGateway and caching layout files.
- Updated comparison script for broader checks and improved failure messages.
.gitignore - Added entry: .secrets to ignore files named .secrets.
.github/workflows/compare_deployed_storage_layout.py - New script created to compare deployed storage layouts with expected layouts.
- Added functions: get_deployed_addresses(), get_storage_layout(), load_and_parse_layout().

Possibly related PRs

Suggested reviewers

  • bwhour
  • leonz789

Poem

In the land of code, where rabbits play,
New checks and scripts hop in today.
With secrets tucked away, safe and sound,
Our storage layouts dance all around.
So let’s celebrate, with joy and cheer,
For every change brings us closer, my dear! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Outside diff range and nitpick comments (3)
.github/workflows/forge-ci.yml (2)

162-174: LGTM: Target branch checkout and layout generation

The addition of steps to checkout the target branch and generate a layout file for ExocoreGateway is well-implemented. This allows for accurate comparison of storage layouts between the current changes and the target branch.

Suggestion for improvement:
Consider adding error handling for the forge inspect command. If the command fails, it might be helpful to capture and log the error for easier debugging.

You could modify the "Generate target branch layout files" step as follows:

- name: Generate target branch layout files
  run: |
    forge inspect src/core/ExocoreGateway.sol:ExocoreGateway storage-layout --pretty > ExocoreGateway_target.txt || echo "Error generating layout file for ExocoreGateway"

190-193: LGTM: Comparison scripts execution

The execution of two separate comparison scripts is well-implemented. This allows for comprehensive checking of storage layouts for both local contracts (Bootstrap and ClientChainGateway) and deployed contracts.

Suggestion for improvement:
Consider adding more verbose output or logging for these script executions. This could help in debugging if issues arise.

You could modify the steps as follows:

- name: Run the comparison script for Bootstrap and ClientChainGateway
  run: |
    echo "Starting comparison for Bootstrap and ClientChainGateway..."
    python .github/workflows/compare_storage_layout.py
    echo "Comparison for Bootstrap and ClientChainGateway completed."

- name: Run the comparison script for deployed contracts
  run: |
    echo "Starting comparison for deployed contracts..."
    python .github/workflows/compare_deployed_storage_layout.py
    echo "Comparison for deployed contracts completed."
.github/workflows/compare_deployed_storage_layout.py (1)

86-87: Include stack trace in error output for debugging

When an exception is caught, only the error message is printed. Including the stack trace can aid in debugging by providing more context about the error source.

 import traceback

 except Exception as e:
     print(f"Error: {e}")
+    traceback.print_exc()
     exit(1)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 09197a8 and 044fb76.

📒 Files selected for processing (4)
  • .github/workflows/compare_deployed_storage_layout.py (1 hunks)
  • .github/workflows/compare_storage_layout.py (1 hunks)
  • .github/workflows/forge-ci.yml (3 hunks)
  • .gitignore (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🪛 Ruff
.github/workflows/compare_storage_layout.py

9-9: Statement ends with an unnecessary semicolon

Remove unnecessary semicolon

(E703)


46-46: Loop control variable index not used within loop body

Rename unused index to _index

(B007)


55-55: f-string without any placeholders

Remove extraneous f prefix

(F541)

🔇 Additional comments (4)
.github/workflows/forge-ci.yml (4)

140-142: LGTM: Environment variables added for API access

The addition of ALCHEMY_API_KEY and ETHERSCAN_API_KEY as environment variables is appropriate. This change aligns with the PR objectives of comparing storage layouts of deployed contracts, which likely requires access to these APIs. Using GitHub secrets for storing these keys is a good security practice.


175-183: LGTM: PR branch checkout and target layout restoration

The steps to checkout the PR branch and restore the target layout file are well-implemented. This ensures an accurate comparison between the PR changes and the target branch while efficiently using the cached layout file.


204-204: LGTM: Improved failure comment

The updated failure comment provides more specific information about potential issues, mentioning both local contract mismatches and incompatibility with deployed contracts on Sepolia. This improvement aligns well with the PR objectives and will help developers quickly understand and address any storage layout compatibility issues.


Line range hint 140-204: Overall assessment: Well-implemented enhancements to CI process

The changes to the compare-storage-layout job in this workflow file are well-implemented and align closely with the PR objectives. The additions effectively enhance the CI process to check storage layout backwards compatibility for both local and deployed contracts. The use of caching, separate comparison scripts, and improved error reporting contribute to a robust and informative CI process.

A few minor suggestions have been made for potential improvements, mainly around error handling and verbose logging. These suggestions, if implemented, could further enhance the debugging process if issues arise.

Great job on implementing these important changes to ensure contract upgradeability!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (6)
.github/workflows/compare_storage_layout.py (3)

6-25: LGTM! Consider using a more specific exception type.

The parse_output function effectively processes the command output and creates a structured DataFrame. The use of pandas for data manipulation is appropriate for this task.

Consider using a more specific exception type, such as ValueError, instead of the generic Exception on line 18. This aligns with the learning from previous reviews that it's acceptable to use generic exceptions in CI job scripts, but using more specific types can still improve error handling clarity.

-        raise Exception(f"No valid storage layout data found for {contract_name}")
+        raise ValueError(f"No valid storage layout data found for {contract_name}")

28-35: LGTM! Consider consistent error handling.

The get_current_layout function effectively executes the forge inspect command and processes its output. The use of subprocess and error handling is appropriate.

For consistency with the previous suggestion, consider using ValueError instead of Exception on line 33:

-        raise Exception(f"Error getting current layout for {contract_name}: {result.stderr}")
+        raise ValueError(f"Error getting current layout for {contract_name}: {result.stderr}")

37-55: LGTM! Consider renaming unused variable.

The compare_layouts function effectively compares the old and new layouts, focusing on non-gap variables and reporting mismatches. The comparison logic aligns well with the PR objectives.

Consider renaming the unused loop variable index to _ to indicate that it's intentionally unused:

-    for index, row in old_layout.iterrows():
+    for _, row in old_layout.iterrows():

This change improves code readability and addresses the static analysis hint.

🧰 Tools
🪛 Ruff

46-46: Loop control variable index not used within loop body

Rename unused index to _index

(B007)

.github/workflows/forge-ci.yml (3)

162-174: LGTM: Steps added for target branch layout generation.

The addition of steps to checkout the target branch and generate a storage layout file for ExocoreGateway is well-implemented. Caching the layout file is an efficient approach for later comparison.

Consider adding a comment explaining the purpose of these steps for better readability:

# Generate and cache storage layout for the target branch
- name: Checkout target branch
  uses: actions/checkout@v4
  with:
    ref: ${{ github.event.pull_request.base.ref }}
    submodules: recursive
# ... (rest of the steps)

190-193: LGTM: Comparison scripts added for comprehensive layout checks.

The addition of steps to run comparison scripts for Bootstrap, ClientChainGateway, and deployed contracts is well-implemented and aligns with the PR objectives.

Consider adding error handling and logging to these steps:

- name: Run the comparison script for Bootstrap and ClientChainGateway
  run: python .github/workflows/compare_storage_layout.py
  continue-on-error: true
  id: bootstrap_client_comparison

- name: Run the comparison script for deployed contracts
  run: python .github/workflows/compare_deployed_storage_layout.py
  continue-on-error: true
  id: deployed_comparison

- name: Check comparison results
  if: steps.bootstrap_client_comparison.outcome == 'failure' || steps.deployed_comparison.outcome == 'failure'
  run: |
    echo "Storage layout comparison failed. Check the logs for details."
    exit 1

This approach will provide more granular information about which comparison failed.


204-204: Improved failure message, but could be more actionable.

The updated failure message provides more specific information about potential issues, which is an improvement.

Consider making the message more actionable:

body: |
  Storage layout compatibility check failed. This could be due to:
  1. A mismatch between Bootstrap and ClientChainGateway
  2. Incompatibility with deployed contracts on Sepolia
  
  Action items:
  - Review the CI logs for detailed error messages
  - Check for unintended changes in contract storage variables
  - If changes are intentional, update the comparison scripts or deployed contracts as necessary
  
  For assistance, please contact the core development team.

This format provides clear next steps for developers to resolve the issue.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 044fb76 and 5d5b914.

📒 Files selected for processing (4)
  • .github/workflows/compare_deployed_storage_layout.py (1 hunks)
  • .github/workflows/compare_storage_layout.py (1 hunks)
  • .github/workflows/forge-ci.yml (3 hunks)
  • .gitignore (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/compare_deployed_storage_layout.py
  • .gitignore
🧰 Additional context used
📓 Learnings (1)
.github/workflows/compare_storage_layout.py (2)
Learnt from: adu-web3
PR: ExocoreNetwork/exocore-contracts#112
File: .github/workflows/compare_storage_layout.py:28-28
Timestamp: 2024-10-17T03:13:58.602Z
Learning: In `.github/workflows/compare_storage_layout.py`, validation of `contract_name` is not required as it does not accept untrusted input.
Learnt from: adu-web3
PR: ExocoreNetwork/exocore-contracts#112
File: .github/workflows/compare_storage_layout.py:18-18
Timestamp: 2024-10-17T03:09:51.221Z
Learning: In Python scripts used for CI jobs (such as `.github/workflows/compare_storage_layout.py`), it is acceptable to use generic `Exception` types for error handling.
🪛 Ruff
.github/workflows/compare_storage_layout.py

46-46: Loop control variable index not used within loop body

Rename unused index to _index

(B007)

🔇 Additional comments (5)
.github/workflows/compare_storage_layout.py (2)

59-81: LGTM! Main execution block is well-structured.

The main execution block effectively utilizes the new functions and implements appropriate error handling. The error messages are clear and informative, and the exit codes are used correctly to indicate success or failure.

The changes align well with the PR objectives of enhancing the CI process to check storage layout backwards compatibility.


1-81: Overall assessment: Significant improvements to the storage layout comparison process.

The changes to this script represent a substantial improvement in the approach to comparing storage layouts:

  1. The transition from file parsing to using the forge inspect command output is likely to be more robust and maintainable.
  2. The use of pandas for data manipulation enhances the script's efficiency and readability.
  3. The new structure with separate functions for parsing, retrieving layouts, and comparing them improves the overall organization of the code.

These changes align well with the PR objectives of enhancing the CI process to check storage layout backwards compatibility. The new implementation should provide a more reliable mechanism for detecting potential issues in contract upgrades.

Great job on this refactoring! The new implementation significantly improves the reliability and maintainability of the storage layout comparison process.

🧰 Tools
🪛 Ruff

46-46: Loop control variable index not used within loop body

Rename unused index to _index

(B007)

.github/workflows/forge-ci.yml (3)

140-142: LGTM: Environment variables added for API access.

The addition of ALCHEMY_API_KEY and ETHERSCAN_API_KEY as environment variables is appropriate. This change aligns with the PR objectives of comparing storage layouts of deployed contracts, which likely requires access to these APIs. Using GitHub secrets for storing API keys is a good security practice.


175-183: LGTM: Steps added to return to PR branch and restore layout file.

The addition of steps to checkout back to the PR branch and restore the cached target branch layout file is well-implemented. This approach ensures that the workflow can compare the current PR changes against the target branch's storage layout.


Line range hint 140-204: Overall, excellent enhancements to the CI workflow.

The changes to the compare-storage-layout job significantly improve the process of checking storage layout compatibility. The additions align well with the PR objectives and follow good practices. The workflow now provides a comprehensive comparison of storage layouts for both local contracts and deployed contracts, which is crucial for maintaining upgradeability.

A few minor suggestions have been made to improve readability and error handling, but these are not critical. Great job on implementing this important feature!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
.github/workflows/compare_deployed_storage_layout.py (2)

21-23: Consider using the logging module instead of print statements

Using the logging module provides better control over logging levels and outputs. It allows for more flexible logging configurations and is a best practice for larger applications.

Apply this diff to enhance logging practices:

+import logging

+logging.basicConfig(level=logging.INFO)

 def get_storage_layout(contract_name, address, rpc_url, etherscan_api_key):
     if not address:
-        print(f"Skipping {contract_name} as it's not deployed.")
+        logging.info(f"Skipping {contract_name} as it's not deployed.")
         return pd.DataFrame()
     
     result = subprocess.run(['cast', 'storage', address, '--rpc-url', rpc_url, '--etherscan-api-key', etherscan_api_key], capture_output=True, text=True)
-    print(f"finish executing: cast storage {address} --rpc-url ...")
+    logging.info(f"Finished executing: cast storage {address} --rpc-url ...")

...

 # In the main execution block
-            print(f"Checking {contract_name}...")
+            logging.info(f"Checking {contract_name}...")

-                print(f"No deployed layout found for {contract_name}.")
+                logging.warning(f"No deployed layout found for {contract_name}.")

...

-    print("Checking ExocoreGateway...")
+    logging.info("Checking ExocoreGateway...")

...

-                print("Mismatches found for current contracts:")
+                logging.error("Mismatches found for current contracts:")
                 for contract, mismatches in all_mismatches.items():
-                    print(f"{contract}:")
+                    logging.error(f"{contract}:")
                     for mismatch in mismatches:
-                        print(f"  {mismatch}")
+                        logging.error(f"  {mismatch}")

...

-            print(f"Error: {e}")
+            logging.error(f"Error: {e}")

Also applies to: 26-27, 54-55, 57-58, 69-70, 77-81, 85-86


9-18: Add docstrings to functions for better documentation

Adding docstrings to your functions enhances code readability and maintainability by providing clear descriptions of their purpose, parameters, and return values.

Here's an example for the get_deployed_addresses function:

 def get_deployed_addresses():
+    """
+    Reads deployed contract addresses from 'script/deployedContracts.json' and returns a dictionary mapping contract names to their addresses.
+
+    Returns:
+        dict: A dictionary containing contract names and their deployed addresses.
+    """
     with open('script/deployedContracts.json', 'r') as f:
         data = json.load(f)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 5d5b914 and ab62821.

📒 Files selected for processing (1)
  • .github/workflows/compare_deployed_storage_layout.py (1 hunks)
🧰 Additional context used
📓 Learnings (1)
.github/workflows/compare_deployed_storage_layout.py (1)
Learnt from: adu-web3
PR: ExocoreNetwork/exocore-contracts#112
File: .github/workflows/compare_deployed_storage_layout.py:10-12
Timestamp: 2024-10-17T03:16:14.054Z
Learning: The `deployedContracts.json` file in the `script/` directory is enforced to be created for each release, so exception handling for its absence in `compare_deployed_storage_layout.py` is not necessary.
🔇 Additional comments (1)
.github/workflows/compare_deployed_storage_layout.py (1)

10-12: ⚠️ Potential issue

Add exception handling for JSON decoding errors

If deployedContracts.json contains invalid JSON, json.load(f) will raise a json.JSONDecodeError. Consider adding error handling to manage this scenario gracefully.

Apply this diff to enhance error handling:

 def get_deployed_addresses():
+    try:
         with open('script/deployedContracts.json', 'r') as f:
             data = json.load(f)
+    except json.JSONDecodeError as e:
+        raise Exception(f"Error decoding 'deployedContracts.json': {e}")
     return {
         'Bootstrap': data['clientChain'].get('bootstrapLogic'),
         'ClientChainGateway': data['clientChain'].get('clientGatewayLogic'),
         'Vault': data['clientChain'].get('vaultImplementation'),
         'RewardVault': data['clientChain'].get('rewardVaultImplementation'),
         'ExoCapsule': data['clientChain'].get('capsuleImplementation')
     }
⛔ Skipped due to learnings
Learnt from: adu-web3
PR: ExocoreNetwork/exocore-contracts#112
File: .github/workflows/compare_deployed_storage_layout.py:10-12
Timestamp: 2024-10-17T03:16:14.054Z
Learning: The `deployedContracts.json` file in the `script/` directory is enforced to be created for each release, so exception handling for its absence in `compare_deployed_storage_layout.py` is not necessary.

@adu-web3 adu-web3 added this pull request to the merge queue Oct 21, 2024
@MaxMustermann2 MaxMustermann2 removed this pull request from the merge queue due to a manual request Oct 21, 2024
@adu-web3 adu-web3 added this pull request to the merge queue Oct 21, 2024
Merged via the queue into main with commit d21c7d6 Oct 21, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants