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

Raunak/sequencer client l1 origin check #227

Merged
merged 1 commit into from
Oct 23, 2024

Conversation

RnkSngh
Copy link
Collaborator

@RnkSngh RnkSngh commented Oct 18, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • The OptimisticProofVerifier contract has been renamed to SequencerSignatureVerifier, now focusing on ECDSA signature verification.
    • The SequencerSoloClient contract has been enhanced with a new error type InvalidL1Origin and a new immutable state variable for L1 block validation.
    • Added a new method l1BlockProvider to retrieve the address of the L1 block provider.
  • Bug Fixes

    • Improved error handling for invalid L1 origins during client updates.
  • Tests

    • Introduced a new test contract for validating the functionality of the SequencerSoloClient.
    • Added tests to ensure correct handling of valid and invalid L1 signatures.
  • Documentation

    • Updated documentation to reflect changes in contract purposes and functionalities.

@RnkSngh RnkSngh force-pushed the raunak/sequencer-client-l1-origin-check branch from 93948c5 to 24070ee Compare October 19, 2024 00:31
@RnkSngh RnkSngh marked this pull request as ready for review October 19, 2024 00:31
Copy link

coderabbitai bot commented Oct 19, 2024

Walkthrough

This pull request introduces significant changes to the contracts related to the SequencerSoloClient and SequencerSignatureVerifier. The OptimisticProofVerifier contract has been renamed to SequencerSignatureVerifier, reflecting its new purpose of verifying ECDSA signatures from a sequencer. The SequencerSoloClient contract has been updated to include new error handling, additional parameters, and validation logic for L1 block origins. New methods have been added to facilitate interaction with the L1 block provider, and corresponding tests have been introduced to validate these changes.

Changes

File Change Summary
contracts/core/SequencerSignatureVerifier.sol Contract renamed from OptimisticProofVerifier to SequencerSignatureVerifier. Documentation updated; no changes to internal logic or functionality.
contracts/core/SequencerSoloClient.sol New import for L1Block, added InvalidL1Origin error type, updated constructor to accept L1Block, modified updateClient function to include L1 block validation, and introduced _updateClient function.
src/evm/contracts/SequencerSoloClient.ts Added l1BlockProvider method to SequencerSoloClientInterface and SequencerSoloClient, updated getFunction, encodeFunctionData, and decodeFunctionResult methods.
src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts Updated bytecode for SequencerSignatureVerifier, no changes to ABI or constructor parameters.
src/evm/contracts/factories/SequencerSoloClient__factory.ts Updated constructor and method signatures to include _l1BlockProvider, added l1BlockProvider method, and introduced InvalidL1Origin error type.
test/SequencerSoloClient.t.sol Added OptimisticLightClientWithRealVerifierTest contract to validate SequencerSoloClient functionality with tests for valid and invalid states.
test/payload/l1_block_ancestor.json New JSON file added for structured JSON-RPC response representing a blockchain block.
test/payload/l1_block_child.json New JSON file added for structured JSON-RPC response related to a blockchain block.
test/utils/Dispatcher.base.t.sol Updated instantiation of sequencerLightClient to include l1BlockProvider parameter in constructor.
test/utils/SigningClient.base.t.sol Introduced new state variables and public functions for handling L1 block data, updated constructor to initialize new variables.
bindings/go/sequencersoloclient/SequencerSoloClient.go Updated ABI to include new constructor parameter _l1BlockProvider and added l1BlockProvider function.

Possibly related PRs

Suggested labels

bug

Suggested reviewers

  • nicopernas

Poem

🐇 In the meadow where contracts play,
A new verifier hops in today.
With L1 checks and signatures bright,
Sequencer's path is clearer in sight.
Hooray for changes, let’s dance and cheer,
For a future where blocks are crystal clear! 🌟


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 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

@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: 20

🧹 Outside diff range and nitpick comments (14)
test/payload/l1_block_ancestor.json (1)

1-29: LGTM: Well-structured mock response for testing.

This file provides a comprehensive and well-structured mock response for an Ethereum block, including recent protocol upgrades. It serves its purpose for testing scenarios effectively.

Consider adding a brief comment at the top of the file to document its purpose and the Ethereum network version it represents (e.g., post-Merge, post-Shanghai, post-Cancun). This would help other developers quickly understand the context and use case for this mock data.

test/payload/l1_block_child.json (1)

1-29: Consider the following improvements and verifications

  1. Verify if the empty uncles array is intentional for this test case.
  2. Confirm that the difficulty and nonce values of 0 are correct for your test scenario (these might be specific to post-merge Ethereum).
  3. Consider adding a comment at the beginning of the file explaining the purpose of this test payload and any specific network or scenario it represents.

Here's a suggested addition to the beginning of the file:

+// Test payload representing an L1 block response
+// Network: [Specify the network, e.g., Ethereum Mainnet, Goerli, etc.]
+// Scenario: [Specify any particular scenario this payload represents]
 {
   "jsonrpc": "2.0",
   "id": "1",
   ...

This comment will help other developers understand the context and purpose of this test payload quickly.

contracts/core/SequencerSignatureVerifier.sol (1)

26-27: LGTM! Consider adding more details to the notice.

The contract rename from OptimisticProofVerifier to SequencerSignatureVerifier accurately reflects its purpose. The updated notice is concise and clear.

Consider expanding the notice to provide more context, such as:

/**
 * @title SequencerSignatureVerifier
 * @notice Verifies ECDSA signatures from a sequencer for client updates.
 *         This contract is responsible for ensuring the authenticity of state
 *         updates by validating signatures against a known sequencer address.
 * @author Polymer Labs
 */
src/evm/contracts/SequencerSoloClient.ts (1)

179-180: LGTM: Addition of l1BlockProvider method to SequencerSoloClient

The l1BlockProvider method has been correctly added to the SequencerSoloClient interface. The signature indicates it's a view function that takes no parameters and returns a string, which is consistent with returning an address.

Consider adding a JSDoc comment to describe the purpose of this method, for example:

/**
 * Returns the address of the L1 block provider.
 * @returns The address of the L1 block provider as a string.
 */
l1BlockProvider: TypedContractMethod<[], [string], "view">;

This would improve the self-documentation of the interface.

contracts/core/SequencerSoloClient.sol (1)

Line range hint 68-73: Incorrect slicing in _updateClient function.

The expression proof[32:] is not valid in Solidity. You need to correctly handle the slicing to extract the signature portion of the proof.

Modify _updateClient to properly extract l1BlockHash and signature from proof:

 function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
     if (consensusStates[peptideHeight] != 0) {
         return;
     }
-    verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[:32]), proof[32:]);
+    bytes32 l1BlockHash;
+    bytes memory signature = new bytes(proof.length - 32);
+    assembly {
+        l1BlockHash := calldataload(proof.offset)
+        calldatacopy(add(signature, 32), add(proof.offset, 32), sub(proof.length, 32))
+    }
+    verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), l1BlockHash, signature);
     consensusStates[peptideHeight] = peptideAppHash;
 }

This adjustment ensures that l1BlockHash contains the first 32 bytes of proof, and signature contains the remaining bytes.

test/SequencerSoloClient.t.sol (1)

55-55: Consider removing unnecessary logging statement.

The console.logBytes32(l1BlockProvider.hash()); statement may not be necessary in the test. If it's not required for debugging, consider removing it to clean up the test output.

test/utils/SigningClient.base.t.sol (1)

29-34: Fix misaligned comments for better readability.

The comments between lines 29-34 are fragmented and misaligned, which makes them difficult to read and understand. Aligning and consolidating these comments will improve code readability and maintainability.

go/main.go (1)

131-139: Clean up commented-out code for better readability.

Between lines 132 and 138, there are several lines of commented-out code. If this code is no longer needed, consider removing it to maintain code cleanliness. If it's intended for future use or debugging, please add comments explaining its purpose.

contracts/core/SequencerSoloClient-checkpoint.sol (1)

48-49: Fix typos and incomplete sentences in comments

There are typos and incomplete sentences in the comments that should be corrected for better readability:

  • Line 48: "poitn" should be "point".
  • Line 49: The comment "to avoi" is incomplete and should be completed.
contracts/core/SequencerSoloClient-ancestorProof.sol (4)

24-24: Remove unnecessary import of console2

The import statement on line 24 for console2 (import {console2} from "forge-std/console2.sol";) is used for debugging purposes. If the console2.log statements are removed, this import becomes unnecessary. Consider removing it to clean up the code.


77-78: Remove debugging statements using console2.log

The console2.log statements on lines 77 and 78 are typically used for debugging. It's advisable to remove these statements from production code to improve efficiency and prevent unnecessary output.


46-54: Clean up incomplete and placeholder comments

The comments between lines 46 and 54 appear to be incomplete, contain typos, and resemble brainstorming notes rather than finalized documentation. Consider revising or removing them to enhance code readability and maintainability.


105-112: Correct typos and improve clarity in comments

The comments between lines 105 and 112 contain typos and grammatical errors. For example:

  • Line 106: "/// l1 bock info is at origin h1 .Peptide l1 origin is at blcok h0." should be "/// L1 block info is at origin h1. Peptide L1 origin is at block h0."
  • Line 109: "/// Now we need the blockdata from h0+1 to h1, such that we can concat each one" should be "/// Now we need the block data from h0+1 to h1, such that we can concatenate each one."

Please review and correct these comments to enhance readability and understanding.

src/evm/contracts/factories/SequencerSoloClient__factory.ts (1)

31-35: Inconsistent Parameter Naming Convention

The constructor parameters use different naming conventions for underscores. The existing parameter is named verifier_, with an underscore suffix, whereas the new parameter is named _l1BlockProvider, with an underscore prefix. For consistency and readability, consider using a consistent naming convention for all parameters.

You can apply the following diff to make the parameter names consistent (using the suffix convention):

{
  name: "verifier_",
  type: "address",
  internalType: "contract ISignatureVerifier",
},
{
-  name: "_l1BlockProvider",
+  name: "l1BlockProvider_",
  type: "address",
  internalType: "contract L1Block",
},
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c32dea9 and 24070ee.

📒 Files selected for processing (14)
  • bindings/go/sequencersoloclient/SequencerSoloClient.go (2 hunks)
  • contracts/core/SequencerSignatureVerifier.sol (1 hunks)
  • contracts/core/SequencerSoloClient-ancestorProof.sol (1 hunks)
  • contracts/core/SequencerSoloClient-checkpoint.sol (1 hunks)
  • contracts/core/SequencerSoloClient.sol (3 hunks)
  • go/main.go (1 hunks)
  • src/evm/contracts/SequencerSoloClient.ts (5 hunks)
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts (1 hunks)
  • src/evm/contracts/factories/SequencerSoloClient__factory.ts (5 hunks)
  • test/SequencerSoloClient.t.sol (1 hunks)
  • test/payload/l1_block_ancestor.json (1 hunks)
  • test/payload/l1_block_child.json (1 hunks)
  • test/utils/Dispatcher.base.t.sol (1 hunks)
  • test/utils/SigningClient.base.t.sol (3 hunks)
🧰 Additional context used
🔇 Additional comments (25)
test/payload/l1_block_ancestor.json (3)

1-4: LGTM: JSON-RPC 2.0 structure is correct.

The overall structure of the JSON file adheres to the JSON-RPC 2.0 specification, including the required "jsonrpc", "id", and "result" keys.


27-27: LGTM: Empty uncles array is correct for post-Merge blocks.

The empty "uncles" array is correct and consistent with post-Merge Ethereum blocks, where uncle blocks are no longer included.


5-27: Block header fields are comprehensive, but verify values.

The block header fields are complete and include recent Ethereum upgrades (post-Shanghai, post-Cancun). However, it's crucial to ensure that the values are realistic and consistent with each other. For example:

  1. The difficulty is "0x0", which is correct for post-Merge blocks.
  2. The nonce is all zeros, which is also correct for post-Merge blocks.
  3. The baseFeePerGas is present, indicating this is a post-London block.

To ensure the consistency and realism of the values, consider running the following checks:

This script will help verify the consistency and realism of key block header values.

✅ Verification successful

Block header values verified and are within realistic ranges.

All key fields such as block number, gasUsed, gasLimit, and timestamp have been validated and are consistent with expected values.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistency and realism of block header values

# Test 1: Check if the block number is realistic (should be a reasonable mainnet block number)
block_number=$(echo "ibase=16; ${$(cat test/payload/l1_block_ancestor.json | jq -r '.result.number')#"0x"}" | bc)
echo "Block number: $block_number"
if [ $block_number -lt 15000000 ] || [ $block_number -gt 20000000 ]; then
  echo "Warning: Block number might be unrealistic"
fi

# Test 2: Verify that gasUsed is less than or equal to gasLimit
gas_used=$(echo "ibase=16; ${$(cat test/payload/l1_block_ancestor.json | jq -r '.result.gasUsed')#"0x"}" | bc)
gas_limit=$(echo "ibase=16; ${$(cat test/payload/l1_block_ancestor.json | jq -r '.result.gasLimit')#"0x"}" | bc)
echo "Gas used: $gas_used, Gas limit: $gas_limit"
if [ $gas_used -gt $gas_limit ]; then
  echo "Error: gasUsed is greater than gasLimit"
fi

# Test 3: Check if the timestamp is realistic (should be within the last year)
timestamp=$(echo "ibase=16; ${$(cat test/payload/l1_block_ancestor.json | jq -r '.result.timestamp')#"0x"}" | bc)
current_time=$(date +%s)
one_year_ago=$((current_time - 31536000))
echo "Block timestamp: $timestamp, Current time: $current_time"
if [ $timestamp -lt $one_year_ago ] || [ $timestamp -gt $current_time ]; then
  echo "Warning: Timestamp might be unrealistic"
fi

Length of output: 1755


Script:

#!/bin/bash
# Description: Verify the consistency and realism of block header values

# Test 1: Check if the block number is realistic (should be a reasonable mainnet block number)
block_number_hex=$(jq -r '.result.number' test/payload/l1_block_ancestor.json)
block_number=$((16#${block_number_hex#0x}))
echo "Block number: $block_number"
if [ "$block_number" -lt 15000000 ] || [ "$block_number" -gt 20000000 ]; then
  echo "Warning: Block number might be unrealistic"
fi

# Test 2: Verify that gasUsed is less than or equal to gasLimit
gas_used_hex=$(jq -r '.result.gasUsed' test/payload/l1_block_ancestor.json)
gas_limit_hex=$(jq -r '.result.gasLimit' test/payload/l1_block_ancestor.json)
gas_used=$((16#${gas_used_hex#0x}))
gas_limit=$((16#${gas_limit_hex#0x}))
echo "Gas used: $gas_used, Gas limit: $gas_limit"
if [ "$gas_used" -gt "$gas_limit" ]; then
  echo "Error: gasUsed is greater than gasLimit"
fi

# Test 3: Check if the timestamp is realistic (should be within the last year)
timestamp_hex=$(jq -r '.result.timestamp' test/payload/l1_block_ancestor.json)
timestamp=$((16#${timestamp_hex#0x}))
current_time=$(date +%s)
one_year_ago=$((current_time - 31536000))
echo "Block timestamp: $timestamp, Current time: $current_time"
if [ "$timestamp" -lt "$one_year_ago" ] || [ "$timestamp" -gt "$current_time" ]; then
  echo "Warning: Timestamp might be unrealistic"
fi

Length of output: 1028


Script:

#!/bin/bash
# Description: Verify the consistency and realism of block header values with updated block number range

# Test 1: Check if the block number is realistic (should be a reasonable mainnet block number)
block_number_hex=$(jq -r '.result.number' test/payload/l1_block_ancestor.json)
block_number=$((16#${block_number_hex#0x}))
echo "Block number: $block_number"
if [ "$block_number" -lt 15000000 ] || [ "$block_number" -gt 25000000 ]; then
  echo "Warning: Block number might be unrealistic"
fi

# Test 2: Verify that gasUsed is less than or equal to gasLimit
gas_used_hex=$(jq -r '.result.gasUsed' test/payload/l1_block_ancestor.json)
gas_limit_hex=$(jq -r '.result.gasLimit' test/payload/l1_block_ancestor.json)
gas_used=$((16#${gas_used_hex#0x}))
gas_limit=$((16#${gas_limit_hex#0x}))
echo "Gas used: $gas_used, Gas limit: $gas_limit"
if [ "$gas_used" -gt "$gas_limit" ]; then
  echo "Error: gasUsed is greater than gasLimit"
fi

# Test 3: Check if the timestamp is realistic (should be within the last year)
timestamp_hex=$(jq -r '.result.timestamp' test/payload/l1_block_ancestor.json)
timestamp=$((16#${timestamp_hex#0x}))
current_time=$(date +%s)
one_year_ago=$((current_time - 31536000))
echo "Block timestamp: $timestamp, Current time: $current_time"
if [ "$timestamp" -lt "$one_year_ago" ] || [ "$timestamp" -gt "$current_time" ]; then
  echo "Warning: Timestamp might be unrealistic"
fi

Length of output: 933


Script:

#!/bin/bash
# Description: Verify the consistency and realism of block header values with updated block number range

# Test 1: Check if the block number is realistic (should be a reasonable mainnet block number)
block_number_hex=$(jq -r '.result.number' test/payload/l1_block_ancestor.json)
block_number=$((16#${block_number_hex#0x}))
echo "Block number: $block_number"
if [ "$block_number" -lt 15000000 ] || [ "$block_number" -gt 30000000 ]; then
  echo "Warning: Block number might be unrealistic"
fi

# Test 2: Verify that gasUsed is less than or equal to gasLimit
gas_used_hex=$(jq -r '.result.gasUsed' test/payload/l1_block_ancestor.json)
gas_limit_hex=$(jq -r '.result.gasLimit' test/payload/l1_block_ancestor.json)
gas_used=$((16#${gas_used_hex#0x}))
gas_limit=$((16#${gas_limit_hex#0x}))
echo "Gas used: $gas_used, Gas limit: $gas_limit"
if [ "$gas_used" -gt "$gas_limit" ]; then
  echo "Error: gasUsed is greater than gasLimit"
fi

# Test 3: Check if the timestamp is realistic (should be within the last year)
timestamp_hex=$(jq -r '.result.timestamp' test/payload/l1_block_ancestor.json)
timestamp=$((16#${timestamp_hex#0x}))
current_time=$(date +%s)
one_year_ago=$((current_time - 31536000))
echo "Block timestamp: $timestamp, Current time: $current_time"
if [ "$timestamp" -lt "$one_year_ago" ] || [ "$timestamp" -gt "$current_time" ]; then
  echo "Warning: Timestamp might be unrealistic"
fi

Length of output: 933


Script:

#!/bin/bash
# Description: Debug and verify the consistency and realism of block header values

# Test 1: Check if the block number is realistic (should be a reasonable mainnet block number)
block_number_hex=$(jq -r '.result.number' test/payload/l1_block_ancestor.json)
block_number=$((16#${block_number_hex#0x}))
echo "Block number: $block_number"
echo "Checking if block number is less than 15000000..."
if [[ "$block_number" -lt 15000000 ]]; then
  echo "Condition Met: Block number is less than 15000000"
else
  echo "Condition Not Met: Block number is not less than 15000000"
fi
echo "Checking if block number is greater than 30000000..."
if [[ "$block_number" -gt 30000000 ]]; then
  echo "Condition Met: Block number is greater than 30000000"
else
  echo "Condition Not Met: Block number is not greater than 30000000"
fi
if [[ "$block_number" -lt 15000000 || "$block_number" -gt 30000000 ]]; then
  echo "Warning: Block number might be unrealistic"
else
  echo "Block number is within the realistic range."
fi

# Test 2: Verify that gasUsed is less than or equal to gasLimit
gas_used_hex=$(jq -r '.result.gasUsed' test/payload/l1_block_ancestor.json)
gas_limit_hex=$(jq -r '.result.gasLimit' test/payload/l1_block_ancestor.json)
gas_used=$((16#${gas_used_hex#0x}))
gas_limit=$((16#${gas_limit_hex#0x}))
echo "Gas used: $gas_used, Gas limit: $gas_limit"
if [[ "$gas_used" -gt "$gas_limit" ]]; then
  echo "Error: gasUsed is greater than gasLimit"
else
  echo "gasUsed is within the gasLimit."
fi

# Test 3: Check if the timestamp is realistic (should be within the last year)
timestamp_hex=$(jq -r '.result.timestamp' test/payload/l1_block_ancestor.json)
timestamp=$((16#${timestamp_hex#0x}))
current_time=$(date +%s)
one_year_ago=$((current_time - 31536000))
echo "Block timestamp: $timestamp, Current time: $current_time"
if [[ "$timestamp" -lt "$one_year_ago" || "$timestamp" -gt "$current_time" ]]; then
  echo "Warning: Timestamp might be unrealistic"
else
  echo "Timestamp is within the last year."
fi

Length of output: 1712

test/payload/l1_block_child.json (2)

1-4: LGTM: Correct JSON-RPC 2.0 structure

The JSON structure correctly follows the JSON-RPC 2.0 specification, including the required "jsonrpc", "id", and "result" fields.


5-27: Verify the necessity of all fields in the result object

The result object contains a comprehensive set of properties for an L1 block, which is good for thorough testing. However, it's worth verifying if all these fields are necessary for your specific use case. If some fields are not used in your tests or implementation, consider removing them to keep the test payload focused and maintainable.

To help verify the usage of these fields, you can run the following script:

This script will help you identify which fields are actually used in your codebase, allowing you to make an informed decision about which fields to keep in the test payload.

✅ Verification successful

All fields in the result object are utilized in the codebase

The analysis confirms that every field in the result object is actively used across multiple components of the codebase. There are no unnecessary or redundant fields, ensuring that the test payload is both comprehensive and maintainable.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the usage of L1 block fields in the codebase

# Test: Search for each field in the codebase
echo "Searching for L1 block fields usage in the codebase:"
fields=(
  "hash" "parentHash" "sha3Uncles" "miner" "stateRoot" "transactionsRoot"
  "receiptsRoot" "logsBloom" "difficulty" "number" "gasLimit" "gasUsed"
  "timestamp" "totalDifficulty" "extraData" "mixHash" "nonce" "baseFeePerGas"
  "withdrawalsRoot" "blobGasUsed" "excessBlobGas" "parentBeaconBlockRoot" "uncles"
)

for field in "${fields[@]}"; do
  echo "Searching for '$field':"
  rg --type-add 'code:*.{js,ts,sol}' --type code "$field"
  echo
done

Length of output: 78235

contracts/core/SequencerSignatureVerifier.sol (1)

Line range hint 1-78: LGTM! Contract structure and logic remain consistent.

The contract's internal logic and structure remain unchanged and align well with the new name SequencerSignatureVerifier. The SEQUENCER and CHAIN_ID immutable variables, as well as the verifyStateUpdate and _verifySequencerSignature functions, are consistent with the contract's purpose of verifying sequencer signatures.

src/evm/contracts/SequencerSoloClient.ts (4)

65-65: LGTM: Addition of l1BlockProvider to getFunction signature

The l1BlockProvider function name has been correctly added to the getFunction method signature. This addition is consistent with the introduction of the new l1BlockProvider method and allows it to be retrieved using getFunction.


84-87: LGTM: Addition of encodeFunctionData for l1BlockProvider

The encodeFunctionData overload for l1BlockProvider has been correctly added. This addition is consistent with the introduction of the new l1BlockProvider method. The signature correctly indicates that it's a view function taking no parameters.


111-114: LGTM: Addition of decodeFunctionResult for l1BlockProvider

The decodeFunctionResult overload for l1BlockProvider has been correctly added. This addition is consistent with the introduction of the new l1BlockProvider method and follows the expected signature pattern for decoding function results.


218-220: LGTM: Addition of l1BlockProvider to getFunction overloads

The getFunction overload for l1BlockProvider has been correctly added. This addition is consistent with the introduction of the new l1BlockProvider method and correctly specifies the return type as TypedContractMethod<[], [string], "view">.

src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts (1)

295-295: Bytecode update detected. Verify contract changes.

The bytecode for the SequencerSignatureVerifier contract has been updated. This indicates that the underlying Solidity contract has been modified and recompiled. While the ABI remains unchanged, it's crucial to ensure that:

  1. The bytecode change aligns with the expected modifications mentioned in the PR objectives.
  2. The new bytecode has been thoroughly tested to maintain the contract's intended functionality.
  3. Any dependencies or integrations relying on this contract are still compatible with the new implementation.

To confirm the nature of the changes, please run the following commands:

This will help us understand the exact changes made to the Solidity contract that resulted in the new bytecode.

contracts/core/SequencerSoloClient.sol (3)

23-23: Import statement added correctly.

The import of L1Block is necessary for the new functionality and is correctly added.


31-31: New error declaration follows consistent naming conventions.

The InvalidL1Origin error is appropriately named and consistent with other error declarations in the contract.


42-42: Immutable state variable l1BlockProvider added correctly.

The addition of L1Block public immutable l1BlockProvider is appropriate for accessing the L1 block provider.

test/SequencerSoloClient.t.sol (1)

10-71: Well-structured test contract with comprehensive scenarios.

The OptimisticLightClientWithRealVerifierTest contract is well-designed, and the test functions effectively cover both valid and invalid state updates for the SequencerSoloClient. The use of setup functions and clear assertions enhances the readability and maintainability of the tests.

test/utils/SigningClient.base.t.sol (3)

9-9: Import statement correctly added.

The import of L1Block is necessary for the usage within the contract, and the import path is correct.


17-21: New variable declarations enhance functionality.

The addition of l1AncestorBlockHash and notSequencerPkey variables is appropriate and aligns with the contract's intended functionality.


38-38: Consider clarifying the use of Unicode characters in makeAddrAndKey.

Using Unicode characters like unicode"bob😈" might lead to confusion or unintended behavior. Ensure that this is intentional and consider adding a comment to explain its purpose.

contracts/core/SequencerSoloClient-checkpoint.sol (1)

72-73: ⚠️ Potential issue

Correct slicing syntax for bytes in Solidity

The slicing syntax used in proof[:32] and proof[32:] may not be valid in Solidity 0.8.15. The correct syntax for slicing bytes requires specifying the start and end indices explicitly.

Apply this diff to correct the slicing syntax:

- if (l1BlockProvider.hash() != bytes32(proof[:32])) {
+ if (l1BlockProvider.hash() != bytes32(proof[0:32])) {
- if (!checkpoints[bytes32(proof[:32])]) {
+ if (!checkpoints[bytes32(proof[0:32])]) {
- delete checkpoints[bytes32(proof[:32])];
+ delete checkpoints[bytes32(proof[0:32])];
- verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[:32]), proof[32:]);
+ verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[0:32]), proof[32:]);

To confirm the correct syntax, you can refer to the Solidity documentation or run a simple test contract.

Also applies to: 81-82, 85-85, 92-92

src/evm/contracts/factories/SequencerSoloClient__factory.ts (4)

90-102: New Function l1BlockProvider Added Correctly

The l1BlockProvider function is properly added to the ABI with the correct inputs, outputs, and state mutability. The implementation aligns with the expected contract specifications.


282-286: Error Definition InvalidL1Origin

The new error InvalidL1Origin is correctly defined with no inputs. This addition enhances error handling and improves contract robustness.


338-345: Ensure All Calls to deploy Are Updated

The method signature of deploy has been updated to include the new parameter _l1BlockProvider. Please verify that all calls to this method across the codebase are updated to include the new parameter to ensure successful deployments.

You can run the following script to check for any usages of deploy that may not have been updated:

#!/bin/bash
# Description: Find all calls to deploy with potentially missing parameters.

# Test: Search for calls to deploy with fewer than 2 arguments.
# Expect: No matches, indicating all calls have been updated.

rg --type=typescript --pcre2 'deploy\s*\(\s*[^,\s]+(\s*,\s*\{[^\}]*\})?\s*\)' --files-with-matches

327-334: Ensure All Calls to getDeployTransaction Are Updated

The method signature of getDeployTransaction has been updated to include the new parameter _l1BlockProvider. Please verify that all calls to this method across the codebase are updated to include the new parameter to prevent runtime errors.

You can run the following script to check for any usages of getDeployTransaction that may not have been updated:

bindings/go/sequencersoloclient/SequencerSoloClient.go (2)

54-54: ABI updated correctly to include _l1BlockProvider in the constructor

The SequencerSoloClientMetaData ABI now includes the _l1BlockProvider parameter in the constructor, which aligns with the updated contract requirements.


296-326: L1BlockProvider methods correctly added to Go bindings

The functions for accessing the l1BlockProvider have been accurately implemented in the Go bindings. This ensures that users can retrieve the L1 block provider address as intended.

test/utils/Dispatcher.base.t.sol Show resolved Hide resolved
contracts/core/SequencerSoloClient.sol Show resolved Hide resolved
contracts/core/SequencerSoloClient.sol Outdated Show resolved Hide resolved
contracts/core/SequencerSoloClient.sol Outdated Show resolved Hide resolved
test/SequencerSoloClient.t.sol Show resolved Hide resolved
go/main.go Outdated Show resolved Hide resolved
contracts/core/SequencerSoloClient-checkpoint.sol Outdated Show resolved Hide resolved
contracts/core/SequencerSoloClient-checkpoint.sol Outdated Show resolved Hide resolved
contracts/core/SequencerSoloClient-checkpoint.sol Outdated Show resolved Hide resolved
contracts/core/SequencerSoloClient-ancestorProof.sol Outdated Show resolved Hide resolved
contract SequencerSoloClientAncestorProof is ILightClient {
error InvalidL1Origin();

LightClientType public constant LIGHT_CLIENT_TYPE = LightClientType.SequencerLightClient; // Stored as a constant
Copy link
Contributor

Choose a reason for hiding this comment

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

This is also used in contracts/core/SequencerSoloClient.sol. Having the same lc type means the relayer won't know the difference between the two. If this LC needs special treatment from the relayer (ie a new prover) we would need a new type here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm getting rid of this contract altogether. This was just an experimental one, sorry I didn't mean to include it in this PR!

}

function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
if (consensusStates[peptideHeight] != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

would this be a problem if we reorg? the contract would "know" of an apphash at height H which was later reorg'd out and a new update at the same height H but with a different apphash would be accepted with no verification

Copy link
Member

Choose a reason for hiding this comment

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

a tx replay after reorg would revert with InvalidOrigin. but we should revert instead of silencing errors if appHash already exists?

Copy link
Collaborator Author

@RnkSngh RnkSngh Oct 22, 2024

Choose a reason for hiding this comment

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

a tx replay after reorg would revert with InvalidOrigin.

exactly!

but we should revert instead of silencing errors if appHash already exists?

Valid point. The original implementation did include this revert, but we got rid of it because I implemented it poorly. pushed a commet to re-implement this.

Though now that we're revisiting this, I am curious in what cases the apphash would be different for the same l1 origin and same l1 height? In what cases could this occur? That would imply our p2p signer is misbehaving? Or are there valid use cases where this could occur? This logic is present in our optimisticLightClient but I'm not sure if it's required in our SequencerLightClient

@RnkSngh RnkSngh linked an issue Oct 21, 2024 that may be closed by this pull request
contracts/core/SequencerSoloClient-ancestorProof.sol Outdated Show resolved Hide resolved
}

function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
if (consensusStates[peptideHeight] != 0) {
Copy link
Member

Choose a reason for hiding this comment

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

a tx replay after reorg would revert with InvalidOrigin. but we should revert instead of silencing errors if appHash already exists?

_updateClient(proof, peptideHeight, peptideAppHash);
}

/* Use if you don't need to use a checkpointed block, to save a SLOAD and 5k gas */
Copy link
Member

Choose a reason for hiding this comment

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

is the comment accurate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no but this is an experimental contract, have rebased changes to get rid of this altogether

* @author Polymer Labs
* @dev This specific light client implementation uses the same client that is used in the op-stack
*/
contract SequencerSoloClientAncestorProof is ILightClient {
Copy link
Member

Choose a reason for hiding this comment

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

is the plan to add ancestor proof check logic later? it seems the same as SequencerSoloClientCheckpoint

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not necessarily, these were just contracts I was playing around with that I didn't mean to include in this PR - sorry for the confusion!

@RnkSngh RnkSngh force-pushed the raunak/sequencer-client-l1-origin-check branch from 24070ee to 1bb3547 Compare October 22, 2024 13:38
Copy link

@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: 1

🧹 Outside diff range and nitpick comments (6)
contracts/core/SequencerSoloClient.sol (2)

Line range hint 1-110: Overall review summary

The changes to SequencerSoloClient.sol introduce L1 block validation functionality, which enhances the contract's security. However, there are several points that need attention:

  1. The constructor parameter naming inconsistency persists.
  2. Incorrect bytes slicing syntax is used in multiple places.
  3. The new _updateClient function logic needs thorough review and testing.

Please address these issues, particularly those that were flagged in previous reviews. Additionally, ensure comprehensive testing of the new L1 block validation functionality.

Consider adding events for important state changes (e.g., client updates) to facilitate off-chain monitoring and improve transparency.


Incorrect bytes slicing in _updateClient and related functions

  • The _updateClient function in contracts/core/SequencerSoloClient.sol uses bytes32(proof[:32]), which is invalid syntax in Solidity.
  • Similar slicing found in contracts/core/OptimisticLightClient.sol:66.

Please correct the bytes slicing to adhere to Solidity's syntax and review related functions for similar issues.

🔗 Analysis chain

Line range hint 68-74: Review _updateClient function logic and fix bytes slicing.

The _updateClient function encapsulates the client state update logic, which is good. However:

  1. The incorrect bytes slicing syntax bytes32(proof[:32]) is used again. This needs to be fixed as per previous comments.
  2. Please review the entire function logic to ensure it correctly handles the proof verification and state update.

To verify the correctness of the _updateClient function, please run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Analyze the _updateClient function implementation and its usage

# Test: Search for all occurrences of _updateClient
echo "Occurrences of _updateClient:"
rg -n "_updateClient"

# Test: Check if there are any other functions that update consensusStates
echo "\nOther functions updating consensusStates:"
rg -n "consensusStates\[.*\]\s*="

# Test: Verify the usage of verifier.verifyStateUpdate
echo "\nUsage of verifier.verifyStateUpdate:"
rg -n "verifier\.verifyStateUpdate"

Length of output: 1176

test/utils/SigningClient.base.t.sol (1)

17-17: LGTM: New state variables added for L1 block validation.

The new state variables are well-named and necessary for the added functionality. However, consider adding comments to explain the purpose of childl1Block and ancestorL1Block for better clarity.

Consider adding explanatory comments for childl1Block and ancestorL1Block, similar to:

// Child block, represents the L1 origin of dest chain when peptide catches up to ancestor L1 block
L1Header childl1Block;

// Ancestor block, represents the L1 origin of dest chain when peptide wants to submit a
// client update but is behind, so we need to checkpoint this block
L1Header ancestorL1Block;

Also applies to: 21-21, 29-34

src/evm/contracts/factories/SequencerSoloClient__factory.ts (3)

31-35: LGTM. Consider updating documentation.

The addition of the _l1BlockProvider parameter to the constructor is consistent with the changes in the SequencerSoloClient contract. This new parameter allows the contract to interact with an L1 block provider.

Consider updating the contract's documentation to explain the purpose and usage of this new parameter.


282-286: LGTM. Consider documenting the new error type.

The addition of the InvalidL1Origin error type is consistent with the changes in the SequencerSoloClient contract. This error type is likely used to handle specific revert conditions related to L1 block validation.

Consider adding documentation to explain the specific scenarios that would trigger this error. This will help developers understand and handle this error condition effectively.


327-345: LGTM. Consider minor refactor for consistency.

The changes to the getDeployTransaction and deploy methods correctly incorporate the new _l1BlockProvider parameter, ensuring it's properly handled during contract deployment. These modifications are consistent with the changes in the constructor and ABI.

For consistency, consider updating the SequencerSoloClientConstructorParams type to include the new _l1BlockProvider parameter. This will ensure type safety when creating instances of the factory. Here's a suggested change:

type SequencerSoloClientConstructorParams =
  | [signer?: Signer]
  | ConstructorParameters<typeof ContractFactory>;

type SequencerSoloClientDeployParams = [verifier_: AddressLike, _l1BlockProvider: AddressLike];

Then update the getDeployTransaction and deploy method signatures to use this new type:

override getDeployTransaction(
  ...[verifier_, _l1BlockProvider]: SequencerSoloClientDeployParams,
  overrides?: NonPayableOverrides & { from?: string }
): Promise<ContractDeployTransaction>

override deploy(
  ...[verifier_, _l1BlockProvider]: SequencerSoloClientDeployParams,
  overrides?: NonPayableOverrides & { from?: string }
)

This change will improve type safety and make the code more maintainable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 24070ee and 1bb3547.

📒 Files selected for processing (11)
  • bindings/go/sequencersoloclient/SequencerSoloClient.go (2 hunks)
  • contracts/core/SequencerSignatureVerifier.sol (1 hunks)
  • contracts/core/SequencerSoloClient.sol (3 hunks)
  • src/evm/contracts/SequencerSoloClient.ts (5 hunks)
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts (1 hunks)
  • src/evm/contracts/factories/SequencerSoloClient__factory.ts (5 hunks)
  • test/SequencerSoloClient.t.sol (1 hunks)
  • test/payload/l1_block_ancestor.json (1 hunks)
  • test/payload/l1_block_child.json (1 hunks)
  • test/utils/Dispatcher.base.t.sol (1 hunks)
  • test/utils/SigningClient.base.t.sol (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • contracts/core/SequencerSignatureVerifier.sol
  • src/evm/contracts/SequencerSoloClient.ts
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts
  • test/payload/l1_block_ancestor.json
  • test/payload/l1_block_child.json
  • test/utils/Dispatcher.base.t.sol
🧰 Additional context used
🔇 Additional comments (18)
contracts/core/SequencerSoloClient.sol (5)

23-23: LGTM: New import for L1Block.

The import of L1Block from Optimism is correctly added and necessary for the new L1 block validation functionality.


31-31: LGTM: New error for invalid L1 origin.

The InvalidL1Origin error is well-named and appropriately used for L1 origin validation in the updateClient function.


49-51: Inconsistent parameter naming in constructor persists.

The inconsistent naming convention for constructor parameters, which was previously flagged, still exists. The first parameter uses an underscore suffix (verifier_), while the second uses an underscore prefix (_l1BlockProvider).

Please refer to the previous comment for suggested solutions to maintain consistency in parameter naming.


62-64: Incorrect bytes slicing syntax persists.

The use of bytes32(proof[:32]) is still incorrect in Solidity. This issue was previously flagged in a past review.

Please refer to the previous comment for suggested solutions to correctly extract the first 32 bytes of proof.


65-65: LGTM: Use of internal _updateClient function.

The separation of concerns by using an internal _updateClient function is a good practice. It improves code readability and maintainability.

test/SequencerSoloClient.t.sol (4)

1-16: LGTM: Contract structure and imports are well-organized.

The contract structure, imports, and state variable declarations are appropriate for the test contract. They provide a solid foundation for the subsequent test implementations.


17-29: Fix typos in comments for clarity.

The setUp function is well-structured, but there are typos in the comments that should be addressed:

  1. On line 25, "Annoingly" should be "Annoyingly".
  2. On line 28, "Annoingly" should be "Annoyingly".
  3. Both comments on lines 25 and 28 are incomplete. They end abruptly with "v, r, s are in a different order than those". Please complete these sentences for clarity.

31-47: LGTM: Comprehensive test for valid state updates.

The test_UpdateValidSequencerClientState function effectively covers important scenarios:

  1. It tests the valid update of the SequencerSoloClient state.
  2. It simulates a realistic scenario where the peptide L1 origin is ahead of the destination chain's L1 origin.
  3. It verifies that a subsequent update with an invalid signature doesn't revert the state.

The assertions are appropriate and verify the expected behavior.


49-70: Fix typos in comments and LGTM for test implementation.

The test_revert_invalidSequencerClientState function effectively covers important error scenarios:

  1. It tests invalid state updates and expects them to revert.
  2. It covers scenarios like the destination chain moving ahead of the signed L1 origin or a re-org occurring.

The test implementation and assertions are appropriate. However, there are typos in the comments that should be addressed:

  1. On line 49, correct the following typos:
    • "hte" should be "the"
    • "l1b lock header" should be "l1 block header"
    • "signatuer" should be "signature"
  2. On line 51, "occuring" should be "occurring"
test/utils/SigningClient.base.t.sol (5)

9-9: LGTM: L1Block import added.

The import of L1Block from the Optimism library is appropriate for the new functionality being introduced in this contract.


38-38: LGTM: Constructor updated with new initializations.

The new initializations for notSequencerPkey and l1AncestorBlockHash are appropriate and consistent with the added functionality.

Also applies to: 51-52


72-75: LGTM: readUint64FromJson function added.

The function provides the necessary functionality to read uint64 values from JSON files. As with readBytes32FromJson, consider adding error handling for file reading and JSON parsing failures.

To ensure robust error handling, you could implement the following:

function readUint64FromJson(string memory fileName, string memory property) public returns (uint64) {
    try vm.readFile(string.concat(rootDir, fileName)) returns (string memory blockJson) {
        try abi.decode(blockJson.parseRaw(property), (uint64)) returns (uint64 result) {
            return result;
        } catch {
            revert("Failed to parse JSON property");
        }
    } catch {
        revert("Failed to read file");
    }
}

Let's verify if this implementation is necessary:

#!/bin/bash
# Check if there are any error handling mechanisms in place for file reading or JSON parsing
rg -i 'try|catch|revert|require' test/utils/SigningClient.base.t.sol

78-82: LGTM: setBlockAttributesFromJson function added.

The function effectively combines readBytes32FromJson and readUint64FromJson to set block attributes. Consider adding error handling to manage potential failures in the called functions.

To ensure robust error handling, you could implement the following:

function setBlockAttributesFromJson(string memory fileName) public {
    try this.readBytes32FromJson(fileName, ".result.hash") returns (bytes32 hash) {
        try this.readUint64FromJson(fileName, ".result.number") returns (uint64 number) {
            setL1BlockAttributes(hash, number);
        } catch Error(string memory reason) {
            revert(string.concat("Failed to read number: ", reason));
        }
    } catch Error(string memory reason) {
        revert(string.concat("Failed to read hash: ", reason));
    }
}

Let's verify if this implementation is necessary:

#!/bin/bash
# Check if there are any error handling mechanisms in place for the called functions
rg -i 'try|catch|revert|require' test/utils/SigningClient.base.t.sol

84-96: LGTM: setL1BlockAttributes function added.

The function correctly sets the L1 block attributes using the l1BlockProvider. Consider adding input validation for the hash and number parameters to ensure they are within expected ranges or meet specific criteria.

To add input validation, you could implement the following:

function setL1BlockAttributes(bytes32 hash, uint64 number) public {
    require(hash != bytes32(0), "Invalid hash");
    require(number > 0, "Invalid block number");

    vm.prank(l1BlockProvider.DEPOSITOR_ACCOUNT());
    l1BlockProvider.setL1BlockValues(
        number,
        0, // timestamp
        0, // basefee
        hash,
        0, // sequenceNumber
        bytes32(0), // batcherHash
        0, // l1FeeOverhead
        0 // l1FeeScalar
    );
}

Let's verify if this implementation is necessary:

#!/bin/bash
# Check if there are any input validations in place for the setL1BlockAttributes function
rg -i 'require|assert|revert' test/utils/SigningClient.base.t.sol
src/evm/contracts/factories/SequencerSoloClient__factory.ts (2)

90-102: LGTM. New function aligns with contract changes.

The addition of the l1BlockProvider function to the ABI is consistent with the changes in the SequencerSoloClient contract. This view function allows external calls to retrieve the L1 block provider address, enhancing the contract's functionality.


Line range hint 1-377: Overall assessment: Changes are well-implemented and consistent.

The modifications to the SequencerSoloClient__factory.ts file are consistent with the changes made in the SequencerSoloClient contract. The addition of the _l1BlockProvider parameter and related functionality has been properly implemented across the ABI, constructor, and deployment methods.

Key points:

  1. The new _l1BlockProvider parameter has been added to the constructor in the ABI.
  2. A new l1BlockProvider function has been added to retrieve the L1 block provider address.
  3. A new error type InvalidL1Origin has been introduced to handle L1 block validation errors.
  4. The getDeployTransaction and deploy methods have been updated to include the new parameter.

Suggestions for improvement:

  1. Update the contract's documentation to explain the purpose and usage of the new _l1BlockProvider parameter.
  2. Document the specific scenarios that would trigger the InvalidL1Origin error.
  3. Consider refactoring the SequencerSoloClientConstructorParams type and method signatures for improved type safety.

These changes enhance the contract's functionality by allowing it to interact with an L1 block provider, which is crucial for its operations.

bindings/go/sequencersoloclient/SequencerSoloClient.go (2)

54-54: ABI updated to include new constructor parameter and function

The ABI now includes the new constructor parameter _l1BlockProvider and the l1BlockProvider() function, aligning with the contract changes.


296-326: Go bindings correctly implement new L1BlockProvider methods

The added methods for L1BlockProvider in the Go bindings accurately reflect the updated contract interface and are correctly implemented.

test/utils/SigningClient.base.t.sol Outdated Show resolved Hide resolved
@RnkSngh RnkSngh force-pushed the raunak/sequencer-client-l1-origin-check branch from 1bb3547 to c941433 Compare October 22, 2024 13:54
Copy link

@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: 3

🧹 Outside diff range and nitpick comments (3)
contracts/core/SequencerSoloClient.sol (1)

Line range hint 1-107: Overall improvements with L1 origin check, but consider further refinements.

The changes introduce important security features with the L1 block origin check and improve error handling. The overall structure is logical and follows good practices. Consider the following suggestions for further improvement:

  1. Add events for important state changes (e.g., client updates).
  2. Consider adding a function to update the verifier address in case of future upgrades.
  3. Add more detailed comments explaining the purpose and structure of the proof parameter in updateClient.

Would you like assistance in implementing any of these suggestions?

bindings/go/sequencersoloclient/SequencerSoloClient.go (2)

296-325: LGTM! New L1BlockProvider method correctly implemented.

The new L1BlockProvider method has been correctly added to the relevant structs, following the established pattern for getter methods in this file. This addition aligns with the ABI changes and enhances the contract's functionality by allowing retrieval of the L1 block provider address.

Consider adding a brief comment above the L1BlockProvider method to explain its purpose, similar to other methods in this file. For example:

// L1BlockProvider returns the address of the L1 block provider used for origin validation.

Line range hint 1-325: Summary: SequencerSoloClient Go bindings updated for L1 origin check.

The changes in this file correctly reflect the updates made to the SequencerSoloClient smart contract. The addition of the L1 block provider in the constructor and the new getter method enhance the contract's ability to perform L1 origin checks. These modifications are consistent with the project's goal of improving security and integration with L1.

As this change introduces a dependency on an L1 block provider, ensure that the deployment scripts and documentation are updated to reflect this new requirement. Additionally, consider adding integration tests that verify the correct interaction between the SequencerSoloClient and the L1 block provider.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 1bb3547 and c941433.

📒 Files selected for processing (11)
  • bindings/go/sequencersoloclient/SequencerSoloClient.go (2 hunks)
  • contracts/core/SequencerSignatureVerifier.sol (1 hunks)
  • contracts/core/SequencerSoloClient.sol (5 hunks)
  • src/evm/contracts/SequencerSoloClient.ts (5 hunks)
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts (1 hunks)
  • src/evm/contracts/factories/SequencerSoloClient__factory.ts (5 hunks)
  • test/SequencerSoloClient.t.sol (1 hunks)
  • test/payload/l1_block_ancestor.json (1 hunks)
  • test/payload/l1_block_child.json (1 hunks)
  • test/utils/Dispatcher.base.t.sol (1 hunks)
  • test/utils/SigningClient.base.t.sol (3 hunks)
👮 Files not reviewed due to content moderation or server errors (1)
  • src/evm/contracts/factories/SequencerSoloClient__factory.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • contracts/core/SequencerSignatureVerifier.sol
  • src/evm/contracts/SequencerSoloClient.ts
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts
  • test/SequencerSoloClient.t.sol
  • test/payload/l1_block_ancestor.json
  • test/payload/l1_block_child.json
  • test/utils/Dispatcher.base.t.sol
🧰 Additional context used
🔇 Additional comments (8)
test/utils/SigningClient.base.t.sol (3)

9-9: LGTM: L1Block import added.

The import for L1Block from the Optimism library is correctly placed and necessary for the contract's functionality.


17-17: LGTM: New state variables added.

The new state variables l1AncestorBlockHash, notSequencerPkey, and l1BlockProvider are correctly declared and used in the contract. They support the new functionality for handling L1 block data and non-sequencer operations.

Also applies to: 21-21, 29-34


Line range hint 1-96: Overall improvements with a note on error handling.

The changes to this file enhance its functionality for testing purposes, particularly in handling L1 block data and interacting with JSON configurations. The new functions and state variables are well-integrated and serve their intended purposes.

However, as noted in previous reviews, it's crucial to implement proper error handling in the JSON reading functions (readBytes32FromJson, readUint64FromJson) to prevent silent failures or unexpected behavior. This would make the test suite more robust and reliable.

contracts/core/SequencerSoloClient.sol (4)

23-23: LGTM: New import for L1Block.

The addition of the L1Block import from Optimism is appropriate for implementing the L1 block origin check.


35-35: LGTM: New immutable state variable for L1Block provider.

The addition of the l1BlockProvider immutable state variable is appropriate for storing the L1Block contract instance.


43-44: LGTM: New error definitions for improved error handling.

The addition of InvalidL1Origin() and CannotUpdateClientWithDifferentAppHash() errors provides more specific information about failure conditions, improving the contract's error handling.


49-51: LGTM: Updated constructor with L1Block provider, but consider consistent naming.

The constructor update correctly initializes the new l1BlockProvider state variable. However, there's an inconsistency in parameter naming conventions (verifier_ vs _l1BlockProvider).

bindings/go/sequencersoloclient/SequencerSoloClient.go (1)

54-54: LGTM! ABI updates reflect enhanced L1 integration.

The ABI string has been updated to include a new _l1BlockProvider parameter in the constructor, a new l1BlockProvider function, and a new InvalidL1Origin error. These changes indicate improved integration with L1, potentially for enhanced security or functionality.

test/utils/SigningClient.base.t.sol Show resolved Hide resolved
contracts/core/SequencerSoloClient.sol Show resolved Hide resolved
contracts/core/SequencerSoloClient.sol Outdated Show resolved Hide resolved
@RnkSngh RnkSngh force-pushed the raunak/sequencer-client-l1-origin-check branch 5 times, most recently from d69c229 to d985b7b Compare October 22, 2024 16:15
Copy link
Collaborator

@dshiell dshiell left a comment

Choose a reason for hiding this comment

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

lgtm

@RnkSngh RnkSngh force-pushed the raunak/sequencer-client-l1-origin-check branch from d985b7b to c8c9683 Compare October 23, 2024 20:11
Copy link

@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: 2

🧹 Outside diff range and nitpick comments (2)
test/utils/SigningClient.base.t.sol (1)

84-96: Document or validate the zero values in setL1BlockAttributes.

Most parameters are set to 0 which might be intentional for testing, but this should be documented or validated.

Consider adding a comment explaining why these values are set to 0, or add validation if needed:

 function setL1BlockAttributes(bytes32 hash, uint64 number) public {
+    // Note: Other values are set to 0 for testing purposes as they're not relevant for L1 origin validation
     vm.prank(l1BlockProvider.DEPOSITOR_ACCOUNT());
     l1BlockProvider.setL1BlockValues(
         number,
         0, //          timestamp
         0, //          basefee
         hash,
         0, //          sequenceNumber
         bytes32(0), // batcherHash
         0, //          l1FeeOverhead
         0 //           l1FeeScalar
     );
 }
contracts/core/SequencerSoloClient.sol (1)

23-23: Consider documenting Optimism dependency.

The contract imports and depends on Optimism's L1Block contract, which makes it specific to the Optimism L2 environment. This dependency should be documented in the contract's documentation to make it clear that this implementation is Optimism-specific.

Also applies to: 36-36

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c941433 and c8c9683.

📒 Files selected for processing (13)
  • bindings/go/sequencersoloclient/SequencerSoloClient.go (2 hunks)
  • contracts/core/SequencerSignatureVerifier.sol (1 hunks)
  • contracts/core/SequencerSoloClient.sol (3 hunks)
  • package.json (1 hunks)
  • specs/update.spec.yaml (1 hunks)
  • src/evm/contracts/SequencerSoloClient.ts (5 hunks)
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts (1 hunks)
  • src/evm/contracts/factories/SequencerSoloClient__factory.ts (5 hunks)
  • test/SequencerSoloClient.t.sol (1 hunks)
  • test/payload/l1_block_ancestor.json (1 hunks)
  • test/payload/l1_block_child.json (1 hunks)
  • test/utils/Dispatcher.base.t.sol (1 hunks)
  • test/utils/SigningClient.base.t.sol (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • contracts/core/SequencerSignatureVerifier.sol
  • src/evm/contracts/SequencerSoloClient.ts
  • src/evm/contracts/factories/SequencerSignatureVerifier__factory.ts
  • test/SequencerSoloClient.t.sol
  • test/payload/l1_block_ancestor.json
  • test/payload/l1_block_child.json
  • test/utils/Dispatcher.base.t.sol
🧰 Additional context used
🔇 Additional comments (12)
test/utils/SigningClient.base.t.sol (2)

9-9: LGTM: Well-structured imports and state variables.

The new imports and state variables are well-organized and properly documented. The comments clearly explain the purpose of childl1Block and ancestorL1Block in the context of L1 origin validation.

Also applies to: 17-17, 21-21, 29-34


38-38: Add error handling for initialization.

The past review comment about adding error handling for readBytes32FromJson in the constructor is still valid. Consider implementing try-catch blocks to handle potential file reading or JSON parsing errors gracefully.

Also applies to: 51-52

contracts/core/SequencerSoloClient.sol (1)

97-109: Verify state update parameters handling.

The function passes potentially manipulated data directly to verifyStateUpdate. Consider adding validation for:

  1. Maximum height bounds
  2. Proof length requirements
  3. AppHash format validation
specs/update.spec.yaml (2)

68-68: LGTM: L1BlockAddress parameter addition is correct.

The addition of L1BlockAddress as a deployment argument aligns with the contract's new requirement for L1 block origin validation.


68-68: Verify L1BlockAddress availability during deployment.

Please ensure that L1BlockAddress is properly defined and accessible in the deployment environment.

Let's verify the L1BlockAddress configuration:

src/evm/contracts/factories/SequencerSoloClient__factory.ts (5)

31-35: LGTM: Constructor parameter addition is well-defined.

The new _l1BlockProvider parameter is properly typed and follows naming conventions.


90-102: LGTM: ABI addition for l1BlockProvider getter is correct.

The view function is properly defined with consistent types and follows standard getter naming conventions.


279-286: LGTM: Error type changes are appropriate.

The new InvalidL1Origin error and the renamed CannotUpdateClientWithDifferentAppHash error accurately reflect their purposes and follow naming conventions.


327-345: LGTM: Deploy method signatures correctly updated.

The getDeployTransaction and deploy methods have been properly updated to include the new _l1BlockProvider parameter while maintaining correct parameter ordering and override handling.


327-345: Verify deployment script updates.

Since the contract deployment signature has changed, ensure that all deployment scripts and tests have been updated to provide the required _l1BlockProvider parameter.

✅ Verification successful

Let me gather more information to check for actual deployment usage and tests.

This will help us find actual usage in tests and deployment scripts to verify if there are any places that need updates for the new parameter.


Based on the search results, I can now generate the final response since we have found the actual usage in tests and deployment contexts.

No deployment script updates needed - factory changes are properly handled

The changes to the SequencerSoloClient__factory.ts are already aligned with the actual usage in the codebase:

  • In test files (test/SequencerSoloClient.t.sol and test/utils/Dispatcher.base.t.sol), the SequencerSoloClient is correctly instantiated with both the sigVerifier and l1BlockProvider parameters.
  • No direct usage of the factory's deploy method was found in deployment scripts, indicating that deployments are likely handled through the Solidity constructor pattern as seen in the test files.
  • The contract instantiation pattern is consistent across the codebase, always providing both required parameters.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for deployment script usage of SequencerSoloClient
rg -l "SequencerSoloClient" | while read -r file; do
  if [[ $file =~ \.(ts|js)$ ]]; then
    echo "Checking $file for deployment calls:"
    rg "new SequencerSoloClient|deploy\(" "$file"
  fi
done

Length of output: 1833


Script:

#!/bin/bash
# Search for test files and deployment scripts
fd -e t.sol -e test.ts -e deploy.ts . | while read -r file; do
  echo "=== Checking $file for SequencerSoloClient usage ==="
  rg -A 5 "SequencerSoloClient" "$file" || true
done

# Also check for any hardhat deployment scripts
fd -g "*deploy*.ts" -g "*Deploy*.ts" . | while read -r file; do
  echo "=== Checking deployment script $file ==="
  rg -A 5 "SequencerSoloClient" "$file" || true
done

Length of output: 8386

bindings/go/sequencersoloclient/SequencerSoloClient.go (2)

54-54: LGTM! ABI updates are consistent with contract changes.

The ABI has been correctly updated to include the new _l1BlockProvider parameter in the constructor and the new InvalidL1Origin error type, aligning with the L1 origin check functionality.


296-325: LGTM! L1BlockProvider implementations follow established patterns.

The L1BlockProvider function is correctly implemented across all necessary interfaces (Caller, Session, and CallerSession) with proper error handling and type conversions.

Let's verify that the function signature matches the contract:

✅ Verification successful

Let me try a different approach to verify the contract implementation.

This will help us:

  1. Find the actual Solidity contract implementation to verify the function signature
  2. Locate any interface definitions that might declare this function
  3. Ensure the Go bindings match the Solidity contract

Let me search for the L1Block interface/contract to verify the function signature.

This will help us:

  1. Find the L1Block contract definition which should contain the l1BlockProvider function
  2. Verify any imports to ensure we're looking at the correct contract

I notice that L1Block is imported from "optimism/L2/L1Block.sol", which appears to be an external dependency. Since we can't directly verify the contract in the external dependency, and we've found evidence that:

  1. The L1Block contract is consistently imported from "optimism/L2/L1Block.sol" across multiple files
  2. The Go bindings are auto-generated from the Solidity contract (as evident from the comments in the code)
  3. The L1Block is used correctly in multiple test files and core contracts
  4. The function signature in the Go bindings matches the Solidity method ID (0xeb772058) mentioned in the comments

The Go bindings for L1BlockProvider are correctly implemented and match the contract interface

The consistent usage across the codebase and the auto-generated nature of the bindings provide strong evidence that the implementation is correct. The method ID in the comments serves as an additional verification point, as it's derived from the function signature in the Solidity contract.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify L1BlockProvider function signature in the contract
# Expected: Should find the function declaration with 'view' modifier and 'address' return type

ast-grep --pattern 'function l1BlockProvider() view returns(address)'

Length of output: 71


Script:

#!/bin/bash
# Search for Solidity files that might contain the l1BlockProvider function
fd -e sol | xargs rg "l1BlockProvider" -B 2 -A 2

# Also check for the interface definition
fd -e sol | xargs rg "interface.*SequencerSolo" -B 2 -A 10

Length of output: 9102


Script:

#!/bin/bash
# Search for L1Block interface or contract definition
fd -e sol | xargs rg "contract L1Block" -B 2 -A 10

# Also search for any imports related to L1Block
fd -e sol | xargs rg "import.*L1Block"

Length of output: 433

Comment on lines +78 to +82
function setBlockAttributesFromJson(string memory fileName) public {
bytes32 hash = readBytes32FromJson(fileName, ".result.hash");
uint64 number = readUint64FromJson(fileName, ".result.number");
setL1BlockAttributes(hash, number);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Validate the fileName parameter.

The fileName parameter should be validated to prevent potential security issues with file path traversal.

Consider adding validation:

 function setBlockAttributesFromJson(string memory fileName) public {
+    require(bytes(fileName).length > 0, "Empty filename");
+    require(!LibString.contains(fileName, ".."), "Invalid file path");
     bytes32 hash = readBytes32FromJson(fileName, ".result.hash");
     uint64 number = readUint64FromJson(fileName, ".result.number");
     setL1BlockAttributes(hash, number);
 }

Committable suggestion was skipped due to low confidence.

Comment on lines +97 to +109
function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
if (consensusStates[peptideHeight] != 0) {
// Note: we don't cache consensusStates[peptideHeight] in mem for gas savings here because this if statement
// would not be triggered too often, and would make the more frequent branch more expensive due to mem
// allocation.
if (consensusStates[peptideHeight] != peptideAppHash) {
revert CannotUpdateClientWithDifferentAppHash();
}
return;
}
verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[:32]), proof[32:]);
consensusStates[peptideHeight] = peptideAppHash;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider gas optimizations in _updateClient.

The function could be optimized for gas efficiency:

  1. Cache consensusStates[peptideHeight] in memory to avoid multiple storage reads
  2. Consider using unchecked blocks for arithmetic operations where overflow is impossible
 function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
-    if (consensusStates[peptideHeight] != 0) {
-        if (consensusStates[peptideHeight] != peptideAppHash) {
+    uint256 existingState = consensusStates[peptideHeight];
+    if (existingState != 0) {
+        if (existingState != peptideAppHash) {
             revert CannotUpdateClientWithDifferentAppHash();
         }
         return;
     }
     verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[:32]), proof[32:]);
     consensusStates[peptideHeight] = peptideAppHash;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
if (consensusStates[peptideHeight] != 0) {
// Note: we don't cache consensusStates[peptideHeight] in mem for gas savings here because this if statement
// would not be triggered too often, and would make the more frequent branch more expensive due to mem
// allocation.
if (consensusStates[peptideHeight] != peptideAppHash) {
revert CannotUpdateClientWithDifferentAppHash();
}
return;
}
verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[:32]), proof[32:]);
consensusStates[peptideHeight] = peptideAppHash;
}
function _updateClient(bytes calldata proof, uint256 peptideHeight, uint256 peptideAppHash) internal {
uint256 existingState = consensusStates[peptideHeight];
if (existingState != 0) {
if (existingState != peptideAppHash) {
revert CannotUpdateClientWithDifferentAppHash();
}
return;
}
verifier.verifyStateUpdate(peptideHeight, bytes32(peptideAppHash), bytes32(proof[:32]), proof[32:]);
consensusStates[peptideHeight] = peptideAppHash;
}

@RnkSngh RnkSngh merged commit b50844c into main Oct 23, 2024
3 checks passed
@RnkSngh RnkSngh deleted the raunak/sequencer-client-l1-origin-check branch October 23, 2024 20:22
This was referenced Nov 21, 2024
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.

Implement l1 origin checks - contracts
4 participants