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

Local state using remote registers #562

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

Conversation

sideninja
Copy link
Member

@sideninja sideninja commented Sep 20, 2024

Description

This PR adds state read and execution using remote registers API from the AN.


For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the standards mentioned here.
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a BlockExecutor for executing transactions in the EVM context on the Flow blockchain.
    • Enhanced caching mechanisms for register values and slab indices to improve performance.
    • Added new events and functions to the Storage contract for better state tracking.
  • Refactor

    • Reorganized codebase by transitioning client types from requester to evm across multiple services.
    • Simplified transaction execution logic and improved error handling in the EVMClient.
  • Bug Fixes

    • Updated client types in the event subscription functionality to ensure proper integration with the new evm services.
  • Chores

    • Removed outdated test files related to the requester package and updated test cases to reflect new client integrations.
    • Updated dependency versions in go.mod files to ensure compatibility with the latest changes.

Copy link
Contributor

coderabbitai bot commented Sep 20, 2024

Walkthrough

The pull request introduces significant changes across multiple files, primarily focused on refactoring the client implementations from the requester package to the evm package. This includes updating struct fields, method signatures, and import statements to align with the new client structure. Additionally, new functionalities are added, such as the BlockExecutor for transaction execution in the Ethereum Virtual Machine context and caching mechanisms in the remoteLedger type. Overall, the changes enhance the organization and functionality of the codebase related to blockchain operations.

Changes

Files Change Summary
api/api.go Updated BlockChainAPI struct to use evm.EVMClient instead of requester.Requester. Modified constructor NewBlockChainAPI accordingly.
bootstrap/bootstrap.go Changed Bootstrap struct's client field to *evm.CrossSporkClient. Updated methods to use evm implementations.
services/evm/client.go Refactored Requester interface to EVMClient. Consolidated functionalities into RemoteClient. Updated method signatures.
services/evm/executor.go Introduced BlockExecutor struct for transaction execution. Added methods for running and simulating transactions.
services/evm/remote_ledger.go Enhanced remoteLedger with caching mechanisms. Changed package from requester to evm.
services/ingestion/subscriber.go Updated RPCSubscriber struct to use *evm.CrossSporkClient. Modified constructor NewRPCSubscriber.
services/ingestion/subscriber_test.go Updated test functions to use evm.NewCrossSporkClient.
Multiple files (e.g., kms_key_rotation_signer.go, pool.go, rotation_signer.go, etc.) Changed package from requester to evm.

Possibly related PRs

  • Remote ledger #362: The changes in the api/api.go file regarding the BlockChainAPI struct and its evm member type are related to the introduction of a remote ledger that retrieves execution data, which may interact with the blockchain API.
  • Update the storage solidity contract used in testing #536: The modifications in the storage contract and the introduction of new functions like blockNumber, blockTime, and blockHash are relevant as they align with the changes made in the api/api.go file, which also involves the evm package.
  • Local state index engine #537: The updates to the Bootstrap struct in bootstrap/bootstrap.go, particularly the changes to client types and the introduction of new fields, suggest a connection to the changes in the BlockChainAPI struct, which also involves the evm package.
  • Add test cases utilizing Cadence arch calls #538: The enhancements to the Storage contract and the addition of functions that interact with blockchain properties are directly related to the changes in the api/api.go file, which also focuses on the evm functionalities.

Suggested labels

Testing, EVM

Poem

🐰 In the code where bunnies hop,
Changes made, we can't stop!
From requester to evm, we leap,
With new clients, our code runs deep.
Caching values, transactions flow,
In the blockchain world, watch us grow! 🌱


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

Outside diff range and nitpick comments (11)
services/evm/remote_ledger.go (2)

19-21: Implement caching mechanism as per TODO comments.

The TODO comments suggest adding a register cache for specific cadence heights using a two-queue cache (2q) from golang-lru/v2. Implementing this cache could improve performance by reducing redundant register fetches and enhancing local state management.

Would you like assistance in implementing this caching mechanism or opening a GitHub issue to track this task?


Line range hint 112-123: Pass context from caller instead of using context.Background().

In the getRegister method, using context.Background() does not allow for request cancellation or deadlines, which can be important for resource management and responsive systems.

Modify getRegister to accept a context.Context parameter:

-func (l *remoteLedger) getRegister(registerID flow.RegisterID) ([]byte, error) {
+func (l *remoteLedger) getRegister(ctx context.Context, registerID flow.RegisterID) ([]byte, error) {

Update the method body to use the provided context:

-    response, err := l.execution.GetRegisterValues(
-        context.Background(),
+    response, err := l.execution.GetRegisterValues(
+        ctx,
         &executiondata.GetRegisterValuesRequest{
             BlockHeight: l.height,
             RegisterIds: []*entities.RegisterID{id},
         },
     )

Also, update all calls to getRegister to pass an appropriate context, potentially allowing for cancellation and timeouts:

 func (l *remoteLedger) GetValue(owner, key []byte) ([]byte, error) {
     // ...
+    ctx := /* obtain context from caller or create one */
     register, err := l.getRegister(ctx, id)
     // ...
 }
services/evm/executor.go (4)

21-21: Update StateDB to ReadOnlyView as indicated

The struct field on line 21 uses types.StateDB, but the inline comment suggests changing it to types.ReadOnlyView. Consider making this update to reflect the intended design.

Would you like assistance in refactoring the code to use types.ReadOnlyView?


139-139: Implement tracer for enhanced debugging

Line 139 sets Tracer: nil with a TODO comment about handling the tracer. Implementing a tracer can be valuable for debugging and monitoring transaction execution.

Would you like assistance in setting up a tracer or integrating tracing capabilities?


141-142: Set ExtraPrecompiledContracts if required

The commented-out line on 141 hints at potentially setting ExtraPrecompiledContracts. If your application relies on additional precompiled contracts, you should configure them here.

Do you need help determining which precompiled contracts to include and how to set them?


43-47: Handle potential ledger initialization errors gracefully

In the NewBlockExecutor function, if state.NewStateDB fails (lines 43-47), the error is returned directly. Ensure that the error provides sufficient context for troubleshooting.

Consider wrapping the error to include additional context:

 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to initialize StateDB: %w", err)
 }
bootstrap/bootstrap.go (1)

212-212: Enhance error message for clarity

When handling the error returned by evm.NewEVM, the current error message refers to "EVM requester," which may not accurately reflect the component being initialized.

Update the error message for better clarity:

	if err != nil {
-		return fmt.Errorf("failed to create EVM requester: %w", err)
+		return fmt.Errorf("failed to initialize EVM instance: %w", err)
	}
services/evm/client.go (4)

54-57: Address the TODO: Extract transaction submission logic

The TODO comment suggests that transaction submission should be extracted into another type, possibly FlowClient, while EVMClient should handle only state queries and execution of calls and gas estimations. Separating these concerns can improve code organization and clarity.

Would you like assistance in refactoring the code to implement this separation, or should I open a new GitHub issue to track this task?


Line range hint 118-194: Consider renaming NewEVM to NewRemoteClient for consistency

The function NewEVM initializes and returns a *RemoteClient. To enhance code clarity and maintain consistency, consider renaming the function to NewRemoteClient.

Apply this diff to rename the function and update references:

-func NewEVM(
+func NewRemoteClient(
     client *CrossSporkClient,
     config *config.Config,
     signer crypto.Signer,
     logger zerolog.Logger,
     blocks storage.BlockIndexer,
     txPool *TxPool,
     collector metrics.Collector,
) (*RemoteClient, error) {
    ...
}

Ensure all calls to NewEVM are updated accordingly.


Line range hint 462-480: Ensure robust address replacement in replaceAddresses function

The replaceAddresses function manually replaces import statements and addresses in the script using strings.ReplaceAll. To enhance robustness and prevent potential issues with partial matches or malformed scripts, consider using regular expressions for pattern matching and replacement.

Use regexp to accurately match import statements:

import "regexp"

// At the beginning of the function
var importRegex = regexp.MustCompile(`import\s+(\w+)`)

func (e *RemoteClient) replaceAddresses(script []byte) []byte {
    s := string(script)
    sc := systemcontracts.SystemContractsForChain(e.config.FlowNetworkID)
    contracts := []systemcontracts.SystemContract{sc.EVMContract, sc.FungibleToken, sc.FlowToken}

    for _, contract := range contracts {
        s = importRegex.ReplaceAllStringFunc(s, func(match string) string {
            if strings.Contains(match, contract.Name) {
                return fmt.Sprintf("import %s from %s", contract.Name, contract.Address.HexWithPrefix())
            }
            return match
        })
    }

    s = strings.ReplaceAll(s, "0xCOA", e.config.COAAddress.HexWithPrefix())

    return []byte(s)
}

This approach ensures only the correct import statements are replaced.


482-493: Simplify height conversion logic in evmToCadenceHeight

The function checks if height < 0 to determine if it should fetch the latest block height. Since LatestBlockHeight is a constant representing the latest height, consider simplifying the logic by directly comparing against LatestBlockHeight.

Apply this diff to simplify the condition:

 func (e *RemoteClient) evmToCadenceHeight(height int64) (uint64, error) {
-    if height < 0 {
+    if uint64(height) == LatestBlockHeight {
         h, err := e.client.GetLatestBlockHeader(context.Background(), true)
         if err != nil {
             return 0, err
         }
         return h.Height, nil
     }

This change makes the code clearer and directly relates to the LatestBlockHeight constant.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 78467d5 and 6261e47.

Files selected for processing (15)
  • api/api.go (3 hunks)
  • bootstrap/bootstrap.go (7 hunks)
  • services/evm/client.go (14 hunks)
  • services/evm/cross-spork_client.go (1 hunks)
  • services/evm/cross-spork_client_test.go (1 hunks)
  • services/evm/executor.go (1 hunks)
  • services/evm/kms_key_rotation_signer.go (1 hunks)
  • services/evm/pool.go (1 hunks)
  • services/evm/remote_ledger.go (3 hunks)
  • services/evm/remote_ledger_test.go (1 hunks)
  • services/evm/rotation_signer.go (1 hunks)
  • services/evm/rotation_signer_test.go (1 hunks)
  • services/ingestion/subscriber.go (3 hunks)
  • services/ingestion/subscriber_test.go (6 hunks)
  • services/requester/requester_test.go (0 hunks)
Files not reviewed due to no reviewable changes (1)
  • services/requester/requester_test.go
Files skipped from review due to trivial changes (2)
  • services/evm/cross-spork_client_test.go
  • services/evm/remote_ledger_test.go
Additional comments not posted (25)
services/evm/rotation_signer.go (1)

1-1: Verify the impact of the package change on the codebase.

The package change from requester to evm indicates a refactoring or reorganization of the codebase. This change is acceptable as it categorizes the file under the Ethereum Virtual Machine (EVM) functionality.

However, please ensure that:

  1. The package change is consistently applied across the codebase.
  2. Import statements in other files that depend on this file are updated accordingly.
  3. The package change does not introduce any build or runtime issues.

Run the following script to verify the package usage and imports:

Verification successful

Package change successfully verified

The package change from "requester" to "evm" has been consistently applied across the codebase. All files in the services/evm directory now use the "package evm" declaration, and there are no remnants of the old package name "requester". The change appears to be correctly implemented without any inconsistencies.

  • No import statements were found for either the old or new package names, suggesting internal usage within the same module.
  • Multiple files in the services/evm directory now use the "package evm" declaration.

The package change has been successfully refactored, and no further action is required.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the package change and its impact on the codebase.

# Test 1: Search for import statements of the old package. Expect: No occurrences.
rg --type go $'requester "github.com/onflow/flow-evm-gateway/services/evm"'

# Test 2: Search for import statements of the new package. Expect: Only valid occurrences.
rg --type go $'evm "github.com/onflow/flow-evm-gateway/services/evm"'

# Test 3: Ensure the package change is consistent across the codebase.
# 3.1: Search for files with the old package declaration. Expect: No occurrences.
rg --type go $'package requester'

# 3.2: Search for files with the new package declaration. Expect: Only valid occurrences.
rg --type go $'package evm'

Length of output: 649

services/evm/rotation_signer_test.go (2)

1-1: LGTM!

The package name change from requester to evm is consistent with the PR objective of refactoring the client implementations. This change does not affect the functionality of the tests.


5-6: Skipped commenting.

The reordering of import statements is a cosmetic change that does not affect the functionality of the code. It is a common practice to group standard library imports at the top of the import block.

services/evm/kms_key_rotation_signer.go (1)

1-1: Verify the impact of the package change on the codebase.

The package declaration change from package requester to package evm suggests a reorganization of the codebase. This aligns with the AI-generated summary.

Please ensure that:

  1. Import statements in other files that depend on this file are updated to reflect the new package.
  2. The intended functionality and usage of this file within the broader application architecture are not adversely affected by this change.

You can use the following script to search for import statements that may need to be updated:

Verification successful

Package change implemented correctly, minor updates recommended

The package change from requester to evm for the file kms_key_rotation_signer.go has been implemented correctly and consistently across the codebase. No import statements using the old package name were found, indicating that dependencies have been properly updated.

However, there are a few remaining references to "requester" in comments and error messages:

  1. In services/evm/client.go:
    • A log message
    • A comment mentioning "EVM requester"
  2. In bootstrap/bootstrap.go:
    • An error message mentioning "EVM requester"

Consider updating these references to maintain consistency with the new package name.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for import statements that may need to be updated due to the package change.

# Test: Search for import statements of the old package name. Expect: No results.
rg --type go $'requester \"github.com/onflow/flow-evm-gateway/services/evm\"'

Length of output: 76


Script:

#!/bin/bash
# Description: Perform additional checks to verify the package change impact

# Test 1: Verify the command execution by searching for a known Go keyword
echo "Test 1: Searching for 'package' keyword"
rg --type go "^package"

# Test 2: Search for any references to the old package name (requester) in Go files
echo "Test 2: Searching for 'requester' references"
rg --type go "requester"

# Test 3: Look for import statements using the new package name (evm)
echo "Test 3: Searching for new 'evm' package imports"
rg --type go "evm \"github.com/onflow/flow-evm-gateway/services/evm\""

Length of output: 3760

services/evm/cross-spork_client.go (1)

1-1: LGTM!

The package declaration change from requester to evm is appropriate and aligns the code with the Ethereum Virtual Machine (EVM) related functionality.

services/ingestion/subscriber.go (2)

13-13: LGTM!

The import statement change from requester to evm is consistent with the refactoring objective and looks good.


33-33: Looks good!

The updates to the client field type in the RPCSubscriber struct and the NewRPCSubscriber constructor parameter type are consistent with the refactoring of the client dependency from requester to evm. The changes align well with the import statement modification.

Also applies to: 43-43

services/ingestion/subscriber_test.go (5)

Line range hint 38-43: LGTM!

The updated import path and instantiation of CrossSporkClient using evm.NewCrossSporkClient are consistent with the refactoring of client implementations from the requester package to the evm package.


Line range hint 78-83: LGTM!

The updated import path and instantiation of CrossSporkClient using evm.NewCrossSporkClient are consistent with the refactoring of client implementations from the requester package to the evm package.


Line range hint 180-185: LGTM!

The updated import path and instantiation of CrossSporkClient using evm.NewCrossSporkClient are consistent with the refactoring of client implementations from the requester package to the evm package.


Line range hint 243-248: LGTM!

The updated import path and instantiation of CrossSporkClient using evm.NewCrossSporkClient are consistent with the refactoring of client implementations from the requester package to the evm package.


Line range hint 305-310: LGTM!

The updated import path and instantiation of CrossSporkClient using evm.NewCrossSporkClient are consistent with the refactoring of client implementations from the requester package to the evm package.

api/api.go (3)

28-28: Refactoring of client implementations.

The import changes indicate a refactoring of the client implementations, with the evm package from services replacing the requester package. This aligns with the subsequent changes to the BlockChainAPI struct and constructor.


86-86: BlockChainAPI struct updated to use EVMClient.

The evm field in the BlockChainAPI struct has been updated to use the EVMClient type from the evm package. This change aligns with the refactoring of the client implementations and ensures the BlockChainAPI interacts with the appropriate client.


99-99: NewBlockChainAPI constructor updated to accept EVMClient.

The evm parameter in the NewBlockChainAPI constructor has been updated to accept an EVMClient instead of a Requester. This change ensures the constructor initializes the BlockChainAPI with the appropriate client type, aligning with the refactoring of the client implementations.

services/evm/remote_ledger.go (1)

35-44: Initialization of cache maps is correct.

The newRemoteLedger function correctly initializes the diffs and slabs maps for caching, setting up the local state for efficient access.

services/evm/executor.go (3)

74-75: Clarify error handling in transaction execution

The comment on line 74 questions whether returning the error as-is is appropriate, noting that the service might restart and retry. Ensure that this error handling aligns with the desired behavior of the service, and consider implementing retry logic or more detailed error handling if necessary.

Is additional error handling or retry logic needed here to handle transient errors during bv.RunTransaction(tx)?


120-121: Verify default gas usage and gas price settings

The comment on line 120 suggests checking the values for DirectCallBaseGasUsage. Ensure that types.DefaultDirectCallBaseGasUsage and types.DefaultDirectCallGasPrice are appropriate for your network's requirements.

Are these default values suitable for your use case, or do they need to be adjusted?


115-142: Complete configuration of blockContext

Several fields in the blockContext are marked with TODO comments (lines 120, 139, 141). Ensure that all necessary fields are properly set to accurately reflect the execution context.

Review the blockContext setup to confirm that all required fields are configured and that any optional fields are addressed as needed.

bootstrap/bootstrap.go (6)

406-406: Update setupStorage to accept new client type

The setupStorage function's parameter has been updated to accept client *evm.CrossSporkClient. Ensure that the function uses this client correctly for storage setup and that all interactions with the client are compatible with its new type.


363-363: Verify all usages of setupCrossSporkClient are updated

The return type of the setupCrossSporkClient function has changed to (*evm.CrossSporkClient, error). Ensure that all callers of this function have been updated to handle the new return type correctly.

Execute the following script to locate and review all calls to setupCrossSporkClient:

#!/bin/bash
# Description: Find all usages of setupCrossSporkClient to verify proper handling of the new return type.

# Test: Search for calls to setupCrossSporkClient.
# Expect: Calls correctly handle the new return type.

rg --type go 'setupCrossSporkClient\(' -A 2

195-197: Validate signer initialization with evm package functions

The signer initialization now uses evm.NewKeyRotationSigner and evm.NewKMSKeyRotationSigner. Ensure these functions are correctly implemented and compatible with the existing signer usage. Confirm that all necessary parameters are provided and that error handling is properly managed.

Use the following script to verify the definitions and usages:

#!/bin/bash
# Description: Verify the correct implementation of signer initialization functions.

# Test: Retrieve the definitions of the new signer functions.
# Expect: Functions are properly defined with expected parameters.

rg --type go 'func NewKeyRotationSigner' -A 5
rg --type go 'func NewKMSKeyRotationSigner' -A 5

389-389: Confirm proper initialization of evm.CrossSporkClient

The evm.CrossSporkClient is being initialized with evm.NewCrossSporkClient. Verify that all required parameters are correctly provided and that the client is properly configured for cross-spork operations.

Use this script to examine the definition and initialization logic:

#!/bin/bash
# Description: Review the constructor of evm.CrossSporkClient for correct usage.

# Test: Retrieve the definition of NewCrossSporkClient.
# Expect: Parameters match expected configuration.

rg --type go 'func NewCrossSporkClient' -A 10

210-210: Avoid naming conflict with variable evm

Assigning the variable name evm to the instance created by evm.NewEVM can lead to confusion between the variable and the package name evm. This can impact code readability and maintainability.

Consider renaming the variable to something more descriptive, such as evmInstance or evmService. Apply the following diff to rename the variable:

-	evm, err := evm.NewEVM(
+	evmService, err := evm.NewEVM(

Ensure all subsequent references to this variable are updated accordingly.

Likely invalid or redundant comment.


47-47: Ensure consistent usage of *evm.CrossSporkClient

The client field in the Bootstrap struct has been updated to use *evm.CrossSporkClient. Please verify that all references to this client throughout the codebase have been updated to match the new type to prevent any potential type mismatches or runtime errors.

Run the following script to check for any outdated references to the old *requester.CrossSporkClient:

Verification successful

Verification successful: *evm.CrossSporkClient usage is consistent

The codebase has been thoroughly checked, and all references to CrossSporkClient are correctly using the evm package. The Bootstrap struct in bootstrap/bootstrap.go is properly updated to use *evm.CrossSporkClient. No instances of the old *requester.CrossSporkClient were found.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any remaining usages of the old CrossSporkClient type.

# Test: Look for occurrences of the old client type.
# Expect: No matches found.

rg --type go '\*requester\.CrossSporkClient'

Length of output: 854


Script:

#!/bin/bash
# Search for all usages of CrossSporkClient in Go files
echo "Searching for CrossSporkClient usages:"
rg --type go 'CrossSporkClient'

echo -e "\nExamining Bootstrap struct definition:"
rg --type go 'type Bootstrap struct' -A 10 bootstrap/bootstrap.go

Length of output: 3126

@@ -1,4 +1,4 @@
package requester
package evm
Copy link
Contributor

Choose a reason for hiding this comment

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

Tip

Codebase Verification

Update leftover "requester" references and review TxPool usage

The package change from requester to evm is mostly consistent, but there are some issues that need attention:

  • Update the following occurrences of "requester" to reflect the new package name:
    • Comments in services/evm/client.go
    • Error message in bootstrap/bootstrap.go

Additionally, be aware that there's another TxPool struct defined in the api package. Ensure this doesn't cause any confusion with the TxPool in the evm package.

Analysis chain

Ensure consistency in package refactoring.

The package declaration change from requester to evm suggests a refactoring or reorganization of the codebase. This change should be consistent with the overall package structure and naming conventions of the project.

Please run the following script to verify the consistency of the package change across the codebase:

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistency of the package change from `requester` to `evm`.

# Test 1: Search for import statements of the old package name. Expect: No occurrences.
rg --type go $'requester'

# Test 2: Search for references to the `TxPool` type. Expect: Only occurrences in the `evm` package.
rg --type go $'TxPool'

Length of output: 1096

Comment on lines +88 to +91
if val, ok := l.slabs[id.String()]; ok {
return val, nil
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Protect slabs map access with synchronization.

In the AllocateSlabIndex method, accessing the slabs map without synchronization can lead to concurrency issues.

Use read and write locks when accessing and modifying the slabs map:

 func (l *remoteLedger) AllocateSlabIndex(owner []byte) (atree.SlabIndex, error) {
     // ...

+    l.mu.RLock()
     if val, ok := l.slabs[id.String()]; ok {
+        l.mu.RUnlock()
         return val, nil
     }
+    l.mu.RUnlock()

     // Fetch the slab index if not in cache
     // ...

+    l.mu.Lock()
     slab := account.SlabIndex()
     l.slabs[id.String()] = slab
+    l.mu.Unlock()

     return slab, nil
 }

Also applies to: 107-108

Comment on lines +74 to +82
func (l *remoteLedger) SetValue(owner, key, value []byte) (err error) {
id := flow.RegisterID{
Key: string(key),
Owner: string(owner),
}

l.diffs[id.String()] = value
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Synchronize access when writing to cache maps.

Writing to the diffs map in the SetValue method without synchronization can cause data races.

Acquire a write lock when modifying the diffs map:

 func (l *remoteLedger) SetValue(owner, key, value []byte) error {
     id := flow.RegisterID{
         Key:   string(key),
         Owner: string(owner),
     }
+    l.mu.Lock()
     l.diffs[id.String()] = value
+    l.mu.Unlock()
     return nil
 }
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
func (l *remoteLedger) SetValue(owner, key, value []byte) (err error) {
id := flow.RegisterID{
Key: string(key),
Owner: string(owner),
}
l.diffs[id.String()] = value
return nil
}
func (l *remoteLedger) SetValue(owner, key, value []byte) (err error) {
id := flow.RegisterID{
Key: string(key),
Owner: string(owner),
}
l.mu.Lock()
l.diffs[id.String()] = value
l.mu.Unlock()
return nil
}

Comment on lines +31 to +33
diffs map[string][]byte
slabs map[string]atree.SlabIndex
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Address potential concurrency issues with unprotected maps.

The diffs and slabs maps in the remoteLedger struct are not protected by any synchronization mechanisms. If remoteLedger is accessed by multiple goroutines concurrently, this could lead to data races and undefined behavior.

Consider adding a sync.RWMutex to the struct to protect access to these maps:

+import "sync"

 type remoteLedger struct {
     execution executiondata.ExecutionDataAPIClient
     height    uint64
+    mu        sync.RWMutex
     diffs     map[string][]byte
     slabs     map[string]atree.SlabIndex
 }

Then, use the mutex in methods that read or write to these maps to ensure thread safety.

Committable suggestion was skipped due to low confidence.

Comment on lines +53 to +57
// first check local changes
if val, ok := l.diffs[id.String()]; ok {
return val, nil
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure thread safety when reading from cache maps.

In the GetValue method, reading from the diffs map without synchronization can lead to data races in a concurrent environment.

Use a read lock when accessing the diffs map:

 func (l *remoteLedger) GetValue(owner, key []byte) ([]byte, error) {
+    l.mu.RLock()
     id := flow.RegisterID{
         Key:   string(key),
         Owner: string(owner),
     }

     // first check local changes
     if val, ok := l.diffs[id.String()]; ok {
+        l.mu.RUnlock()
         return val, nil
     }
+    l.mu.RUnlock()

     // proceed to fetch register if not in cache
     // ...
 }

Committable suggestion was skipped due to low confidence.

Comment on lines 20 to 31
type BlockExecutor struct {
types.StateDB // todo change to types.ReadOnlyView
emulator types.Emulator
chainID flowGo.ChainID
block *models.Block
blocks storage.BlockIndexer
logger zerolog.Logger

// block dynamic data
txIndex uint
gasUsed uint64
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Assess thread safety of BlockExecutor

The BlockExecutor struct maintains state in txIndex and gasUsed, which are modified during execution (lines 85-86). If instances of BlockExecutor are used concurrently across goroutines, this could lead to race conditions.

If concurrency is expected, consider adding synchronization mechanisms, such as mutexes, to protect shared state.

import "sync"

type BlockExecutor struct {
    // existing fields...
    mutex   sync.Mutex
}

// In methods that modify txIndex and gasUsed:
s.mutex.Lock()
defer s.mutex.Unlock()

// Perform modifications...

Comment on lines +81 to +82
return nil, fmt.Errorf("invalid transaction %s: %w", tx.Hash(), res.ValidationError)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Improve error wrapping for invalid transactions

The error message on line 81 uses fmt.Errorf with %w to wrap res.ValidationError. Ensure that res.ValidationError implements the error interface so that the wrapping functions correctly.

Verify that res.ValidationError is an error. If not, you may need to convert it or adjust the error handling.

Comment on lines +126 to +131
panic(err)
}
h, err := b.Hash()
if err != nil {
panic(err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid using panic in production code

In the GetHashFunc, errors are handled using panic(err) on lines 126 and 130. Using panic can cause the entire application to crash. It's recommended to handle errors gracefully to improve the robustness of the application.

Consider modifying the GetHashFunc to handle errors without panicking. Here's a possible refactor:

 GetHashFunc: func(n uint64) common.Hash {
     b, err := s.blocks.GetByHeight(n)
     if err != nil {
-        panic(err)
+        s.logger.Error().Err(err).Uint64("height", n).Msg("failed to get block by height")
+        return common.Hash{}
     }
     h, err := b.Hash()
     if err != nil {
-        panic(err)
+        s.logger.Error().Err(err).Uint64("height", n).Msg("failed to compute block hash")
+        return common.Hash{}
     }

     return h
 },

This approach logs the error and returns a zero common.Hash, allowing the application to continue running.

Committable suggestion was skipped due to low confidence.

Comment on lines 355 to 374
func (e *RemoteClient) EstimateGas(ctx context.Context, data []byte, from common.Address, evmHeight int64) (uint64, error) {
executor, err := e.executorAt(evmHeight)
if err != nil {
return 0, err
}

height, err := e.evmToCadenceHeight(evmHeight)
res, err := executor.Call(from, data)
if err != nil {
return 0, err
}

scriptResult, err := e.executeScriptAtHeight(
ctx,
dryRun,
height,
[]cadence.Value{hexEncodedTx, hexEncodedAddress},
)
if err != nil {
if !errors.Is(err, errs.ErrHeightOutOfRange) {
e.logger.Error().
Err(err).
Uint64("cadence-height", height).
Int64("evm-height", evmHeight).
Str("from", from.String()).
Str("data", hex.EncodeToString(data)).
Msg("failed to execute estimateGas")
result := res.ResultSummary()
if result.ErrorCode != 0 {
if result.ErrorCode == evmTypes.ExecutionErrCodeExecutionReverted {
return 0, errs.NewRevertError(result.ReturnedData)
}
return 0, fmt.Errorf("failed to execute script at height: %d, with: %w", height, err)
}

evmResult, err := parseResult(scriptResult)
if err != nil {
return 0, err
return 0, errs.NewFailedTransactionError(result.ErrorMessage)
}

gasConsumed := evmResult.GasConsumed

e.logger.Debug().
Uint64("gas", gasConsumed).
Int64("evm-height", evmHeight).
Uint64("cadence-height", height).
Msg("estimateGas executed")

return gasConsumed, nil
return res.GasConsumed, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor duplicate error handling in EstimateGas and Call methods

The error handling logic in both EstimateGas (lines 355-374) and Call (lines 377-406) methods is similar. Refactoring this repetitive code into a shared helper function can improve maintainability and reduce duplication.

Consider creating a helper function to process the ResultSummary and handle errors:

func handleExecutionResult(result evmTypes.ResultSummary) error {
    if result.ErrorCode != 0 {
        if result.ErrorCode == evmTypes.ExecutionErrCodeExecutionReverted {
            return errs.NewRevertError(result.ReturnedData)
        }
        return errs.NewFailedTransactionError(result.ErrorMessage)
    }
    return nil
}

Then update the EstimateGas and Call methods to use this helper:

// In EstimateGas
 result := res.ResultSummary()
-if result.ErrorCode != 0 {
-    if result.ErrorCode == evmTypes.ExecutionErrCodeExecutionReverted {
-        return 0, errs.NewRevertError(result.ReturnedData)
-    }
-    return 0, errs.NewFailedTransactionError(result.ErrorMessage)
-}
+if err := handleExecutionResult(result); err != nil {
+    return 0, err
+}
// In Call
 result := res.ResultSummary()
-if result.ErrorCode != 0 {
-    if result.ErrorCode == evmTypes.ExecutionErrCodeExecutionReverted {
-        return nil, errs.NewRevertError(result.ReturnedData)
-    }
-    return nil, errs.NewFailedTransactionError(result.ErrorMessage)
-}
+if err := handleExecutionResult(result); err != nil {
+    return nil, err
+}

Also applies to: 377-406

Comment on lines 532 to 538
func (e *RemoteClient) stateAt(evmHeight int64) (evmTypes.StateDB, error) {
ledger, err := e.ledgerAt(evmHeight)
if err != nil {
return nil, fmt.Errorf("failed to hex-decode string to byte array [%s]: %w", cdcString, err)
return nil, err
}

return code, nil
return state.NewStateDB(ledger, e.storageAccount)
Copy link
Contributor

Choose a reason for hiding this comment

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

Handle potential stateDB errors after retrieval

In the stateAt function, after retrieving stateDB, errors from stateDB.Error() might occur during subsequent calls. To prevent propagating a nil error when the stateDB is nil, consider checking for errors immediately after retrieval.

Apply this diff to handle errors appropriately:

 func (e *RemoteClient) stateAt(evmHeight int64) (evmTypes.StateDB, error) {
     ledger, err := e.ledgerAt(evmHeight)
     if err != nil {
         return nil, err
     }
     stateDB, err := state.NewStateDB(ledger, e.storageAccount)
+    if err != nil {
+        return nil, err
+    }
     return stateDB, nil
 }

This ensures that any errors during the creation of stateDB are correctly handled.

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
func (e *RemoteClient) stateAt(evmHeight int64) (evmTypes.StateDB, error) {
ledger, err := e.ledgerAt(evmHeight)
if err != nil {
return nil, fmt.Errorf("failed to hex-decode string to byte array [%s]: %w", cdcString, err)
return nil, err
}
return code, nil
return state.NewStateDB(ledger, e.storageAccount)
func (e *RemoteClient) stateAt(evmHeight int64) (evmTypes.StateDB, error) {
ledger, err := e.ledgerAt(evmHeight)
if err != nil {
return nil, err
}
stateDB, err := state.NewStateDB(ledger, e.storageAccount)
if err != nil {
return nil, err
}
return stateDB, nil
}

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

Outside diff range and nitpick comments (9)
tests/e2e_web3js_test.go (2)

31-35: Update the TODO comment and follow up on the progress.

It's great to see a new test case being added for "cadence arch and environment calls". However, the TODO comment indicates that this test is currently failing due to an issue with the cadence arch replayer.

Consider updating the TODO comment with more details about the specific issue or converting it to a GitHub issue for better tracking and visibility.

Also, please check with Ramtin on the progress of the fix and update the codebase accordingly once it's available.


159-159: Clarify the reason for increasing the gas limit.

The gas limit for the contract deployment transaction has been increased from 1_250_000 to 1_550_000. While increasing the gas limit may be necessary to accommodate the complexity of the contract being deployed, it would be helpful to understand the specific reason behind this change.

Please consider:

  • Adding a comment explaining the need for the higher gas limit.
  • Evaluating the trade-offs between allowing more computational work and the increased transaction costs.
  • Adjusting the gas limit based on the contract complexity and transaction cost constraints.
go.mod (1)

91-91: LGTM!

The addition of the indirect dependency github.com/hashicorp/golang-lru/v2 v2.0.7 should not cause any issues, as it is managed by the Go module system.

As a best practice, consider reviewing the release notes or changelog of the added dependency to ensure there are no known issues or vulnerabilities.

services/evm/client.go (1)

53-57: Address the TODO comment about extracting transaction submission to a separate type.

Consider creating a new interface, such as TransactionSubmitter, to handle transaction submission responsibilities. This will help separate concerns and improve the cohesion of the EVMClient interface.

tests/fixtures/storage.sol (1)

11-11: Nitpick: Explicitly specify uint256 instead of uint for consistency

In the event declaration for BlockTime, consider using uint256 instead of uint to maintain consistency with the other event declarations and improve code clarity.

Apply this diff:

-event BlockTime(address indexed caller, uint value);
+event BlockTime(address indexed caller, uint256 value);
tests/web3js/build_evm_state_test.js (1)

176-176: Review the necessity of extending the test timeout

A timeout of 180*1000 milliseconds (180 seconds) has been added to the test case. Please confirm that this extended duration is necessary for the test to complete and consider optimizing the test to reduce execution time if possible.

tests/web3js/cadence_arch_env_test.js (3)

7-13: Improve the clarity and grammar of the introductory comments

The comments in lines 7-13 contain grammatical errors and could be rephrased for better readability and understanding.

Consider updating the comments as follows:

-// this test calls different environment and cadenc arch functions. It uses view
-// function to call and return the value which it compares with the block on the network,
-// behind the scene these causes the local client to make such a call and return the value
-// and this test makes sure the on-chain data is same as local-index data. Secondly, this
-// test also submits a transaction that emits the result, which checks the local state
-// re-execution of transaction, and makes sure both receipt matches (remote and local),
-// this in turn tests the local state re-execution.
+// This test calls different environment and Cadence architecture functions. It uses view
+// functions to call and return values, which it compares with the blocks on the network.
+// Behind the scenes, this causes the local client to make such calls and return the values,
+// ensuring that the on-chain data is the same as the local index data. Secondly, this
+// test also submits a transaction that emits the result, which checks the local state
+// re-execution of the transaction, and makes sure both receipts (remote and local) match.
+// This, in turn, tests the local state re-execution.

18-18: Prefer const over let for variables that are not reassigned

In lines 18, 32, and 51, the variables res, block, and deployed are declared with let but are not reassigned. Using const can prevent accidental reassignment and improve code clarity.

Update the variable declarations:

-        let res = await helpers.signAndSend({
+        const res = await helpers.signAndSend({
-        let block = await web3.eth.getBlock('latest')
+        const block = await web3.eth.getBlock('latest')
-        let deployed = await helpers.deployContract('storage')
+        const deployed = await helpers.deployContract('storage')

Also applies to: 32-32, 51-51


60-62: Address the TODO regarding block environment functions

The TODO comment indicates an issue where Ethereum calls are executed at the provided block height, but block environment functions (number, hash, etc.) point to the next block (the block proposal). This discrepancy may affect test accuracy.

Would you like assistance in investigating this issue or opening a GitHub issue to track and resolve this problem?

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6261e47 and 67f5825.

Files ignored due to path filters (2)
  • tests/go.sum is excluded by !**/*.sum
  • tests/web3js/package-lock.json is excluded by !**/package-lock.json
Files selected for processing (16)
  • bootstrap/bootstrap.go (7 hunks)
  • go.mod (1 hunks)
  • services/evm/client.go (13 hunks)
  • services/evm/executor.go (1 hunks)
  • tests/e2e_web3js_test.go (2 hunks)
  • tests/fixtures/storage.byte (1 hunks)
  • tests/fixtures/storage.sol (4 hunks)
  • tests/fixtures/storageABI.json (4 hunks)
  • tests/go.mod (1 hunks)
  • tests/helpers.go (3 hunks)
  • tests/web3js/build_evm_state_test.js (2 hunks)
  • tests/web3js/cadence_arch_env_test.js (1 hunks)
  • tests/web3js/eth_deploy_contract_and_interact_test.js (2 hunks)
  • tests/web3js/eth_filter_endpoints_test.js (2 hunks)
  • tests/web3js/eth_revert_reason_test.js (2 hunks)
  • tests/web3js/eth_transaction_type_fees_test.js (3 hunks)
Files skipped from review as they are similar to previous changes (2)
  • bootstrap/bootstrap.go
  • services/evm/executor.go
Additional comments not posted (53)
tests/web3js/eth_revert_reason_test.js (2)

44-44: LGTM!

The change simplifies the process of obtaining the reverted transaction by directly using the transaction hash, eliminating the need to fetch the latest block. This improves code efficiency.


74-74: Duplicate change.

This change is identical to the one at line 44. It simplifies the process of obtaining the reverted transaction by directly using the transaction hash, eliminating the need to fetch the latest block. This improves code efficiency.

tests/web3js/eth_transaction_type_fees_test.js (4)

24-24: LGTM!

The change updates the expected gas used value, which aligns with the AI-generated summary. The new value seems reasonable.


30-30: LGTM!

The change updates the expected sender balance, which aligns with the AI-generated summary. The new value seems reasonable.


75-75: LGTM!

The change updates the expected sender balance, which aligns with the AI-generated summary. The new value seems reasonable.


132-132: LGTM!

The change updates the expected sender balance, which aligns with the AI-generated summary. The new value seems reasonable.

tests/web3js/eth_deploy_contract_and_interact_test.js (2)

21-21: LGTM!

The change in the expected gas usage for the contract deployment process is valid and does not introduce any issues.


236-236: LGTM!

The change in the expected gas estimate for the contract interaction is valid and does not introduce any issues.

tests/fixtures/storageABI.json (16)

23-41: LGTM!

The BlockHash event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


42-60: LGTM!

The BlockNumber event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


61-79: LGTM!

The BlockTime event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


111-129: LGTM!

The ChainID event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


149-167: LGTM!

The Random event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


168-186: LGTM!

The Retrieved event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


187-205: LGTM!

The VerifyArchCallToFlowBlockHeight event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


206-224: LGTM!

The VerifyArchCallToRandomSource event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


225-243: LGTM!

The VerifyArchCallToRevertibleRandom event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


244-262: LGTM!

The VerifyArchCallToVerifyCOAOwnershipProof event is well-defined with clear input names and appropriate types. Indexing the caller input is a good practice for efficient event filtering.


355-367: LGTM!

The emitBlockHash function is well-defined with a clear parameter name and appropriate type. The nonpayable modifier is suitable for a function that emits an event without modifying the contract state.


368-374: LGTM!

The emitBlockNumber function is well-defined with a clear name. The nonpayable modifier is suitable for a function that emits an event without modifying the contract state.


375-381: LGTM!

The emitBlockTime function is well-defined with a clear name. The nonpayable modifier is suitable for a function that emits an event without modifying the contract state.


382-388: LGTM!

The emitChainID function is well-defined with a clear name. The nonpayable modifier is suitable for a function that emits an event without modifying the contract state.


389-395: LGTM!

The emitRandom function is well-defined with a clear name. The nonpayable modifier is suitable for a function that emits an event without modifying the contract state.


396-402: LGTM!

The emitRetrieve function is well-defined with a clear name. The nonpayable modifier is suitable for a function that emits an event without modifying the contract state.

tests/helpers.go (2)

65-68: LGTM!

The changes to the testLogWriter function look good. The function now creates a new zerolog.ConsoleWriter instance, sets the global time field format to time.RFC3339Nano, and configures the writer's time format to "04:05.0000" before returning the writer.


338-339: Looks good!

The change to the evmSign function signature, moving the data []byte parameter to a new line, improves readability without altering the function's behavior.

tests/go.mod (1)

156-156: Verify compatibility of the dependency update.

The github.com/onflow/flow/protobuf/go/flow dependency has been updated from version v0.4.6 to v0.4.7.

While minor version updates are generally safe, it's important to ensure that this update is compatible with the rest of the project dependencies and doesn't introduce any breaking changes or issues.

Run the following script to check if the update causes any issues:

tests/web3js/eth_filter_endpoints_test.js (2)

364-364: LGTM!

The updated transaction hash looks good and matches the expected format.


417-417: Looks good!

The updated hash and value fields in the expected transaction object are valid and match the Ethereum transaction format.

Also applies to: 422-422

services/evm/client.go (10)

93-102: LGTM!

The RemoteClient struct has the appropriate dependencies and fields to implement the EVMClient interface. The naming and organization of the fields are clear and follow Go conventions.


Line range hint 120-197: LGTM!

The NewEVM function properly initializes the RemoteClient instance with the provided dependencies. The checks for the COA account balance and the creation of the COA resource based on the configuration flag are useful safeguards. The function logic is clear and follows best practices.


Line range hint 201-259: LGTM!

The SendRawTransaction method follows the expected steps for sending a raw transaction. The validation of the transaction, the check for the minimum gas price, and the building of the Flow transaction are all good practices. The method logic is clear and well-structured. The logging of the transaction details provides good visibility into the process.


Line range hint 260-308: LGTM!

The buildTransaction method follows the necessary steps to build a valid Flow transaction. Retrieving the latest block and signer information concurrently using an error group is an efficient approach. Setting the transaction fields with the appropriate values and signing the transaction envelope with the configured signer ensures a properly constructed and authorized transaction. The error handling and formatting of error messages are appropriate.


310-321: LGTM!

The GetBalance method retrieves the balance of an address at a given EVM height using the stateAt method to get the state database. Retrieving the balance using the GetBalance method of the state database is the correct approach. The method returns the balance as a *big.Int, which is the expected type for balances in Go-Ethereum. The method logic is clear and follows best practices.


323-334: LGTM!

The GetNonce method retrieves the nonce of an address at a given EVM height using the stateAt method to get the state database. Retrieving the nonce using the GetNonce method of the state database is the correct approach. The method returns the nonce as a uint64, which is the expected type for nonces in Go-Ethereum. The method logic is clear and follows best practices.


Line range hint 336-348: LGTM!

The GetStorageAt method retrieves the storage value at a given address and hash at a specific EVM height using the stateAt method to get the state database. Retrieving the storage value using the GetState method of the state database is the correct approach. The method returns the storage value as a common.Hash, which is the expected type for storage values in Go-Ethereum. The method logic is clear and follows best practices.


350-357: LGTM!

The GetCode method retrieves the code at a given address at a specific EVM height using the stateAt method to get the state database. Retrieving the code using the GetCode method of the state database is the correct approach. The method returns the code as a byte slice, which is the expected type for code in Go-Ethereum. The method logic is clear and follows best practices.


359-379: LGTM!

The EstimateGas method estimates the gas required for a given transaction data at a specific EVM height using the executorAt method to get the block executor. Calling the Call method of the block executor to execute the transaction and get the gas consumed is the correct approach. The method handles the error cases and returns the appropriate error type based on the execution result, which is a good practice. The method logic is clear and follows best practices.


381-411: LGTM!

The Call method executes a given transaction data at a specific EVM height using the executorAt method to get the block executor. Calling the Call method of the block executor to execute the transaction and get the result is the correct approach. The method handles the error cases and returns the appropriate error type based on the execution result, which is a good practice. Ensuring that the returned data is an empty slice if it is nil is a good practice to match the behavior of the remote client. The method logic is clear and follows best practices.

tests/fixtures/storage.sol (10)

46-48: Function emitRetrieve correctly emits Retrieved event

The emitRetrieve function properly emits the Retrieved event with the caller's address and the stored number.


60-62: Function emitBlockNumber correctly emits BlockNumber event

The emitBlockNumber function properly emits the BlockNumber event with the caller's address and the current block number.


68-70: Function emitBlockTime correctly emits BlockTime event

The emitBlockTime function properly emits the BlockTime event with the caller's address and the current block timestamp.


84-86: Function emitRandom correctly emits Random event

The emitRandom function properly emits the Random event with the caller's address and the block.prevrandao value.


92-94: Function emitChainID correctly emits ChainID event

The emitChainID function properly emits the ChainID event with the caller's address and the current chain ID.


104-105: Function customError correctly uses a custom error

The customError function correctly demonstrates how to revert with the custom error MyCustomError.


115-118: Function emitVerifyArchCallToRandomSource correctly emits event

The emitVerifyArchCallToRandomSource function correctly calls verifyArchCallToRandomSource and emits the VerifyArchCallToRandomSource event with the caller's address and the output.


127-130: Function emitVerifyArchCallToRevertibleRandom correctly emits event

The emitVerifyArchCallToRevertibleRandom function correctly calls verifyArchCallToRevertibleRandom and emits the VerifyArchCallToRevertibleRandom event with the caller's address and the output.


139-142: Function emitVerifyArchCallToFlowBlockHeight correctly emits event

The emitVerifyArchCallToFlowBlockHeight function correctly calls verifyArchCallToFlowBlockHeight and emits the VerifyArchCallToFlowBlockHeight event with the caller's address and the output.


151-154: Function emitVerifyArchCallToVerifyCOAOwnershipProof correctly emits event

The emitVerifyArchCallToVerifyCOAOwnershipProof function correctly calls verifyArchCallToVerifyCOAOwnershipProof and emits the VerifyArchCallToVerifyCOAOwnershipProof event with the caller's address and the output.

tests/web3js/build_evm_state_test.js (2)

158-158: Confirm that the increased estimated gas value is expected

The estimated gas value has been updated to 29338n. Please verify that this increase is intentional and aligns with the expected changes in the contract or gas estimation logic.


165-165: Confirm that the increased contract code length is expected

The length of the contract code retrieved at the latest block has increased to 12180. This significant change suggests alterations in the contract's bytecode. Please ensure that this is expected and corresponds to the updates made.

tests/web3js/cadence_arch_env_test.js (2)

74-76: Address the TODO regarding block environment functions

The same issue regarding block environment functions pointing to the next block is mentioned here. It's important to resolve this to ensure test reliability.


90-92: Address the TODO regarding block environment functions

This TODO repeats the concern about block environment functions pointing to the next block instead of the provided block height. Resolving this will enhance the accuracy of your tests.

Comment on lines +76 to +78
function emitBlockHash(uint num) public {
emit BlockHash(msg.sender, blockhash(num));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Add input validation for num parameter in emitBlockHash

The blockhash function only returns meaningful values for the 256 most recent blocks. To prevent unexpected results, consider adding input validation to ensure that num is within the valid range (block.number - 256 <= num < block.number).

Apply this diff:

 function emitBlockHash(uint num) public {
+    require(num >= block.number - 256 && num < block.number, "Invalid block number");
     emit BlockHash(msg.sender, blockhash(num));
 }
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 emitBlockHash(uint num) public {
emit BlockHash(msg.sender, blockhash(num));
}
function emitBlockHash(uint num) public {
require(num >= block.number - 256 && num < block.number, "Invalid block number");
emit BlockHash(msg.sender, blockhash(num));
}

Comment on lines +80 to +82
web3.eth.abi.decodeParameter('uint', res.value).toString(),
(prev.timestamp+1n).toString(), // investigate why timestamp is increasing by 1
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Prevent TypeError due to mixing BigInt and Number types

The expression (prev.timestamp + 1n).toString() may cause a TypeError because prev.timestamp is a Number, and 1n is a BigInt.

Convert prev.timestamp to a BigInt before the addition:

-                (prev.timestamp+1n).toString(),  // investigate why timestamp is increasing by 1
+                (BigInt(prev.timestamp) + 1n).toString(),  // investigate why timestamp is increasing by 1
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
web3.eth.abi.decodeParameter('uint', res.value).toString(),
(prev.timestamp+1n).toString(), // investigate why timestamp is increasing by 1
)
web3.eth.abi.decodeParameter('uint', res.value).toString(),
(BigInt(prev.timestamp) + 1n).toString(), // investigate why timestamp is increasing by 1
)

Comment on lines +63 to +66
assert.equal(
web3.eth.abi.decodeParameter('uint256', res.value),
res.block.number+1n,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Prevent TypeError due to mixing BigInt and Number types

Adding a BigInt (1n) to a Number (res.block.number) can cause a TypeError in JavaScript. You cannot mix BigInt and Number types in arithmetic operations.

Convert res.block.number to a BigInt before performing the addition:

-            res.block.number+1n,
+            BigInt(res.block.number) + 1n,
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
assert.equal(
web3.eth.abi.decodeParameter('uint256', res.value),
res.block.number+1n,
)
assert.equal(
web3.eth.abi.decodeParameter('uint256', res.value),
BigInt(res.block.number) + 1n,
)

await testEmitTx(methods.emitRandom())

let res = await testCall(methods.random())
assert.isNotEmpty(web3.eth.abi.decodeParameter('uint256', res.value).toString())
Copy link
Contributor

Choose a reason for hiding this comment

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

Use a valid assertion method

The assert.isNotEmpty method may not exist in Chai's assert interface. To verify that the value is not empty, consider checking the length of the string.

Update the assertion as follows:

-            assert.isNotEmpty(web3.eth.abi.decodeParameter('uint256', res.value).toString())
+            assert.isAbove(web3.eth.abi.decodeParameter('uint256', res.value).toString().length, 0)
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
assert.isNotEmpty(web3.eth.abi.decodeParameter('uint256', res.value).toString())
assert.isAbove(web3.eth.abi.decodeParameter('uint256', res.value).toString().length, 0)

60806040526105395f819055506117c9806100195f395ff3fe608060405234801561000f575f80fd5b50600436106101c2575f3560e01c80639075ef95116100f7578063bc31124b11610095578063d0d250bd1161006f578063d0d250bd14610420578063dda3a7bd1461043e578063ea8d8ccf14610448578063fe027d1114610478576101c2565b8063bc31124b146103dc578063c550f90f146103f8578063cbaff5f914610416576101c2565b8063adc879e9116100d1578063adc879e91461038c578063af32a363146103aa578063b2821c8f146103b4578063b7ec3e5f146103d2576101c2565b80639075ef9514610322578063911007b41461032c5780639967062d1461035c576101c2565b80635ec01e4d1161016457806364fc013a1161013e57806364fc013a146102b05780636babb224146102cc57806383197ef0146102e857806385df51fd146102f2576101c2565b80635ec01e4d1461025a5780635f0f73fb146102785780636057361d14610294576101c2565b80634cbefa6a116101a05780634cbefa6a1461020c57806357e871e7146102285780635b5764f4146102465780635e4268e614610250576101c2565b80632e64cec1146101c657806346c38ab0146101e457806348b15166146101ee575b5f80fd5b6101ce610482565b6040516101db9190610f06565b60405180910390f35b6101ec61048a565b005b6101f66104da565b6040516102039190610f06565b60405180910390f35b61022660048036038101906102219190610f5a565b6104e1565b005b6102306104ea565b60405161023d9190610f06565b60405180910390f35b61024e6104f1565b005b61025861054d565b005b61026261059d565b60405161026f9190610f06565b60405180910390f35b610292600480360381019061028d9190610f5a565b6105a4565b005b6102ae60048036038101906102a99190610f5a565b6105f6565b005b6102ca60048036038101906102c59190610fc2565b6105ff565b005b6102e660048036038101906102e19190610f5a565b61065d565b005b6102f06106aa565b005b61030c60048036038101906103079190610f5a565b6106c3565b6040516103199190611005565b60405180910390f35b61032a6106cd565b005b61034660048036038101906103419190610fc2565b61071d565b6040516103539190611005565b60405180910390f35b61037660048036038101906103719190611051565b61087f565b604051610383919061109e565b60405180910390f35b6103946108e9565b6040516103a19190610f06565b60405180910390f35b6103b26108f0565b005b6103bc61094c565b6040516103c991906110c6565b60405180910390f35b6103da610aa1565b005b6103f660048036038101906103f1919061129f565b610af1565b005b610400610b53565b60405161040d91906110c6565b60405180910390f35b61041e610ca8565b005b610428610cea565b604051610435919061131a565b60405180910390f35b610446610cf7565b005b610462600480360381019061045d919061129f565b610d35565b60405161046f919061134d565b60405180910390f35b610480610e9d565b005b5f8054905090565b3373ffffffffffffffffffffffffffffffffffffffff167fcdda07d20845760c8f1960f9992eb7b5253a2e6a68eb2340137c70a30e3af38b436040516104d09190610f06565b60405180910390a2565b5f42905090565b805f8190555f80fd5b5f43905090565b5f6104fa610b53565b90503373ffffffffffffffffffffffffffffffffffffffff167f226e31c8dfdcc17bec5aa64ce3cd9856d9bb4637e48450d27f62e0bda5bca6498260405161054291906110c6565b60405180910390a250565b3373ffffffffffffffffffffffffffffffffffffffff167fb8a2de765c79a4dd09c7a683c268e826303e1bbd5425c29706963329538a7534466040516105939190610f06565b60405180910390a2565b5f44905090565b3373ffffffffffffffffffffffffffffffffffffffff167f9c5f2f6f83b58de8294bc8af0de4c9e4fdd2c335eaf0d9a2461b5a5e4b014e8682406040516105eb9190611005565b60405180910390a250565b805f8190555050565b5f6106098261071d565b90503373ffffffffffffffffffffffffffffffffffffffff167f3c1e946213ca4a4f826f561e68d2e244c2db896d9612980bf786cd7da2c6ccdf826040516106519190611005565b60405180910390a25050565b803373ffffffffffffffffffffffffffffffffffffffff167f043cc306157a91d747b36aba0e235bbbc5771d75aba162f6e5540767d22673c660405160405180910390a3805f8190555050565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b5f81409050919050565b3373ffffffffffffffffffffffffffffffffffffffff167f52481872d5402d9c11fcd282d57bfa9af8a0edcc9115a4ba1936f3bb45e286bb446040516107139190610f06565b60405180910390a2565b5f805f6801000000000000000173ffffffffffffffffffffffffffffffffffffffff168460405160240161075191906110c6565b6040516020818303038152906040527f78a75fbe000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516107db91906113b8565b5f60405180830381855afa9150503d805f8114610813576040519150601f19603f3d011682016040523d82523d5f602084013e610818565b606091505b50915091508161085d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161085490611428565b60405180910390fd5b5f81806020019051810190610872919061145a565b9050809350505050919050565b5f80828461088d91906114b2565b905082843373ffffffffffffffffffffffffffffffffffffffff167f76efea95e5da1fa661f235b2921ae1d89b99e457ec73fb88e34a1d150f95c64b846040516108d7919061109e565b60405180910390a48091505092915050565b5f46905090565b5f6108f961094c565b90503373ffffffffffffffffffffffffffffffffffffffff167f7f3eb80b1815b51402bef9f6393921916f5c7391ff4f5e82e2f5d7f866c65fb78260405161094191906110c6565b60405180910390a250565b5f805f6801000000000000000173ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f705fab20000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516109ff91906113b8565b5f60405180830381855afa9150503d805f8114610a37576040519150601f19603f3d011682016040523d82523d5f602084013e610a3c565b606091505b509150915081610a81576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a789061153d565b60405180910390fd5b5f81806020019051810190610a96919061156f565b905080935050505090565b3373ffffffffffffffffffffffffffffffffffffffff167f05a74f03de8d43b274ce924e4542bad549dea8f3572574a2b81d6ba62fc717b442604051610ae79190610f06565b60405180910390a2565b5f610afd848484610d35565b90503373ffffffffffffffffffffffffffffffffffffffff167f19481a9edff48c370d941b1f368fd2198a0f3117e18748a56d5e193b36dc569a82604051610b45919061134d565b60405180910390a250505050565b5f805f6801000000000000000173ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f53e87d66000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c0691906113b8565b5f60405180830381855afa9150503d805f8114610c3e576040519150601f19603f3d011682016040523d82523d5f602084013e610c43565b606091505b509150915081610c88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7f90611428565b60405180910390fd5b5f81806020019051810190610c9d919061156f565b905080935050505090565b5f610ce8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cdf906115e4565b60405180910390fd5b565b6801000000000000000181565b60056040517f9195785a000000000000000000000000000000000000000000000000000000008152600401610d2c919061168e565b60405180910390fd5b5f805f6801000000000000000173ffffffffffffffffffffffffffffffffffffffff16868686604051602401610d6d93929190611702565b6040516020818303038152906040527f5ee837e7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610df791906113b8565b5f60405180830381855afa9150503d805f8114610e2f576040519150601f19603f3d011682016040523d82523d5f602084013e610e34565b606091505b509150915081610e79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e709061153d565b60405180910390fd5b5f81806020019051810190610e8e9190611768565b90508093505050509392505050565b3373ffffffffffffffffffffffffffffffffffffffff167f094703abe6f34e06c217139505bcc40e39f606853962e503a74d776a28f1148f5f54604051610ee49190610f06565b60405180910390a2565b5f819050919050565b610f0081610eee565b82525050565b5f602082019050610f195f830184610ef7565b92915050565b5f604051905090565b5f80fd5b5f80fd5b610f3981610eee565b8114610f43575f80fd5b50565b5f81359050610f5481610f30565b92915050565b5f60208284031215610f6f57610f6e610f28565b5b5f610f7c84828501610f46565b91505092915050565b5f67ffffffffffffffff82169050919050565b610fa181610f85565b8114610fab575f80fd5b50565b5f81359050610fbc81610f98565b92915050565b5f60208284031215610fd757610fd6610f28565b5b5f610fe484828501610fae565b91505092915050565b5f819050919050565b610fff81610fed565b82525050565b5f6020820190506110185f830184610ff6565b92915050565b5f819050919050565b6110308161101e565b811461103a575f80fd5b50565b5f8135905061104b81611027565b92915050565b5f806040838503121561106757611066610f28565b5b5f6110748582860161103d565b92505060206110858582860161103d565b9150509250929050565b6110988161101e565b82525050565b5f6020820190506110b15f83018461108f565b92915050565b6110c081610f85565b82525050565b5f6020820190506110d95f8301846110b7565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611108826110df565b9050919050565b611118816110fe565b8114611122575f80fd5b50565b5f813590506111338161110f565b92915050565b61114281610fed565b811461114c575f80fd5b50565b5f8135905061115d81611139565b92915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6111b18261116b565b810181811067ffffffffffffffff821117156111d0576111cf61117b565b5b80604052505050565b5f6111e2610f1f565b90506111ee82826111a8565b919050565b5f67ffffffffffffffff82111561120d5761120c61117b565b5b6112168261116b565b9050602081019050919050565b828183375f83830152505050565b5f61124361123e846111f3565b6111d9565b90508281526020810184848401111561125f5761125e611167565b5b61126a848285611223565b509392505050565b5f82601f83011261128657611285611163565b5b8135611296848260208601611231565b91505092915050565b5f805f606084860312156112b6576112b5610f28565b5b5f6112c386828701611125565b93505060206112d48682870161114f565b925050604084013567ffffffffffffffff8111156112f5576112f4610f2c565b5b61130186828701611272565b9150509250925092565b611314816110fe565b82525050565b5f60208201905061132d5f83018461130b565b92915050565b5f8115159050919050565b61134781611333565b82525050565b5f6020820190506113605f83018461133e565b92915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f61139282611366565b61139c8185611370565b93506113ac81856020860161137a565b80840191505092915050565b5f6113c38284611388565b915081905092915050565b5f82825260208201905092915050565b7f756e7375636365737366756c2063616c6c20746f2061726368200000000000005f82015250565b5f611412601a836113ce565b915061141d826113de565b602082019050919050565b5f6020820190508181035f83015261143f81611406565b9050919050565b5f8151905061145481611139565b92915050565b5f6020828403121561146f5761146e610f28565b5b5f61147c84828501611446565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6114bc8261101e565b91506114c78361101e565b92508282019050828112155f8312168382125f8412151617156114ed576114ec611485565b5b92915050565b7f756e7375636365737366756c2063616c6c20746f2061726368000000000000005f82015250565b5f6115276019836113ce565b9150611532826114f3565b602082019050919050565b5f6020820190508181035f8301526115548161151b565b9050919050565b5f8151905061156981610f98565b92915050565b5f6020828403121561158457611583610f28565b5b5f6115918482850161155b565b91505092915050565b7f417373657274204572726f72204d6573736167650000000000000000000000005f82015250565b5f6115ce6014836113ce565b91506115d98261159a565b602082019050919050565b5f6020820190508181035f8301526115fb816115c2565b9050919050565b5f819050919050565b5f819050919050565b5f61162e61162961162484611602565b61160b565b610eee565b9050919050565b61163e81611614565b82525050565b7f56616c756520697320746f6f206c6f77000000000000000000000000000000005f82015250565b5f6116786010836113ce565b915061168382611644565b602082019050919050565b5f6040820190506116a15f830184611635565b81810360208301526116b28161166c565b905092915050565b5f82825260208201905092915050565b5f6116d482611366565b6116de81856116ba565b93506116ee81856020860161137a565b6116f78161116b565b840191505092915050565b5f6060820190506117155f83018661130b565b6117226020830185610ff6565b818103604083015261173481846116ca565b9050949350505050565b61174781611333565b8114611751575f80fd5b50565b5f815190506117628161173e565b92915050565b5f6020828403121561177d5761177c610f28565b5b5f61178a84828501611754565b9150509291505056fea264697066735822122088b3fe8589df5bd1c9d7d46b543867f57d179028bd99eeec4aca768ba9581a3f64736f6c634300081a0033
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider excluding generated bytecode from version control

Including compiled bytecode (storage.byte) in version control is generally discouraged. It can lead to larger repository sizes and potential merge conflicts when the bytecode changes. It's best practice to generate bytecode during the build or testing process.

Consider removing storage.byte from the repository and adding it to .gitignore to prevent future commits:

+ echo "tests/fixtures/storage.byte" >> .gitignore

Committable suggestion was skipped due to low confidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 👀 In Review
Development

Successfully merging this pull request may close these issues.

1 participant