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

Support block overrides parameter for eth_call & debug_traceCall #691

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

m-Peter
Copy link
Collaborator

@m-Peter m-Peter commented Dec 2, 2024

Closes: #685

Description

The fields that we can support are:

  • Number
  • Time
  • Coinbase
  • Random

This allows developers to execute a contract call, at a given block, while overriding the above 4 values.


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 block overrides for Ethereum smart contract calls, enhancing transaction execution flexibility.
    • Added a new test suite for verifying block overrides in contract calls using Web3.js.
  • Bug Fixes

    • Improved error handling in transaction tracing and block provider methods.
  • Documentation

    • Updated error messages for clarity during database setup and component initialization.
  • Tests

    • Expanded test coverage with new cases for contract call overrides and block management.

Copy link
Contributor

coderabbitai bot commented Dec 2, 2024

Walkthrough

This pull request introduces support for block overrides in the Ethereum-like blockchain environment. The changes span multiple files, focusing on enhancing the eth_call and transaction tracing methods by allowing optional block-level parameter overrides. A new BlocksProvider is implemented to manage block snapshots, and modifications are made to various API methods to incorporate block override functionality, enabling more flexible transaction execution and state retrieval.

Changes

File Change Summary
api/api.go Updated Call method signature to use blockOverrides parameter
api/debug.go Modified TraceCall method to handle block overrides and improve error handling
bootstrap/bootstrap.go Updated block provider initialization and storage setup
services/requester/blocks_provider.go New file introducing BlocksProvider and blockSnapshot types
services/requester/requester.go Updated EVM methods to support block overrides
tests/e2e_web3js_test.go Added new test case for contract call overrides
tests/web3js/contract_call_overrides_test.js New test file for verifying block override functionality

Assessment against linked issues

Objective Addressed Explanation
Support blockOverrides for eth_call
Allow overriding block fields

Possibly related PRs

Suggested reviewers

  • peterargue
  • sideninja
  • ramtinms
  • zhangchiqing

Poem

🐰 Blocks of code, now more free,
Overrides dance with glee!
Parameters flex their might,
Transactions take their flight,
In blockchain's rabbit jubilee! 🚀

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

@m-Peter m-Peter force-pushed the mpeter/eth-call-block-overrides branch from 1baa591 to a4f893f Compare December 3, 2024 08:34
Base automatically changed from feature/local-tx-reexecution to main December 19, 2024 09:12
@m-Peter m-Peter force-pushed the mpeter/eth-call-block-overrides branch from a4f893f to 02ce675 Compare December 20, 2024 12:18
@m-Peter m-Peter force-pushed the mpeter/eth-call-block-overrides branch from 02ce675 to fe53fcc Compare December 20, 2024 13:27
@m-Peter m-Peter marked this pull request as ready for review December 20, 2024 14:03
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: 2

🧹 Nitpick comments (9)
services/requester/blocks_provider.go (2)

68-73: Ensure blockOverrides is never set to a stale reference
While the approach of storing the blockOverrides pointer in the BlocksProvider is flexible, consider verifying that updates to the struct instance won't lead to situations where a stale pointer is used. If the lifecycle of BlocksProvider outlives certain override references, unexpected behaviors could occur.


77-85: Initialize tracer to nil in constructor for clarity
Even though it's safe to leave tracer as a zero value, explicitly setting it to nil in the return statement can enhance readability and ensure future maintainers understand the initial state.

Here's a small illustration:

...
return &BlocksProvider{
  blocks:  blocks,
  chainID: chainID,
+ tracer:  nil,
}
api/debug.go (1)

182-182: Suggest passing tracer during NewBlocksProvider instantiation
Instead of calling SetTracer on the created instance, consider an optional parameter in the constructor, if appropriate, to reduce the potential for usage without a tracer being set.

services/requester/requester.go (4)

116-116: Potential improvement: pass chainID explicitly
You’ve already updated other references, but consider if you want to pass chainID to NewBlocksProvider in this constructor call as well, for consistency.


254-254: Suggest grouping repeated getBlockView calls
You call e.getBlockView(height, nil) in multiple locations (lines 254, 266, 279, 410, 605). If each call shares the same semantics (no block overrides), and is repeated often, consider factoring out a helper method or caching. However, if each call context is unique, remain as is.

Also applies to: 266-266, 279-279, 410-410, 605-605


332-332: Assess repeated dry-run calls for performance
Each subsequent call to dryRunTx can be expensive if the system is large. If you notice performance bottlenecks, consider caching partial results or employing a more refined approach to binary search for gas usage.

Also applies to: 357-357, 387-387


479-481: Recommend passing blockOverrides to getBlockView as a parameter
You’re already passing blockOverrides but be aware it’s also stored in the provider. The double path for overrides can be tricky. Possibly unify them: if you always pass overrides as a function argument, storing them in the provider might be unnecessary.

tests/e2e_web3js_test.go (1)

43-45: Enhance coverage with negative test cases
The new “test contract call overrides” scenario at lines 43–45 should also test for invalid or partial overrides, ensuring that the system gracefully handles or reports errors if contradictory overrides are passed.

tests/web3js/contract_call_overrides_test.js (1)

16-96: Consider refactoring for better maintainability.

The test case is thorough but contains repeated patterns that could be extracted into helper functions. Consider:

  1. Creating a helper function for the override verification pattern
  2. Defining constants for magic values like '0x2' and '0x674DB1E1'
  3. Adding comments to explain the expected behavior of each override

Example refactor:

+const BLOCK_NUMBER_OVERRIDE = '0x2'
+const BLOCK_TIME_OVERRIDE = '0x674DB1E1'
+const RANDOM_OVERRIDE = '0x7914bb5b13bac6f621bc37bbf6e406fbf4472aaaaf17ec2f309a92aca4e27fc0'
+
+async function verifyOverride(selector, defaultValueFn, override, overrideKey) {
+    // Check the default value
+    let call = createCallObject(selector)
+    let response = await helpers.callRPCMethod(
+        'eth_call',
+        [call, 'latest', null, null]
+    )
+    let defaultValue = await defaultValueFn()
+    assert.equal(web3.utils.hexToNumber(response.body.result), defaultValue)
+
+    // Apply and verify override
+    let overrides = {}
+    overrides[overrideKey] = override
+    response = await helpers.callRPCMethod(
+        'eth_call',
+        [call, 'latest', null, overrides]
+    )
+    assert.equal(web3.utils.hexToNumber(response.body.result), web3.utils.hexToNumber(override))
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6aa58b0 and fe53fcc.

📒 Files selected for processing (7)
  • api/api.go (2 hunks)
  • api/debug.go (1 hunks)
  • bootstrap/bootstrap.go (1 hunks)
  • services/requester/blocks_provider.go (1 hunks)
  • services/requester/requester.go (14 hunks)
  • tests/e2e_web3js_test.go (1 hunks)
  • tests/web3js/contract_call_overrides_test.js (1 hunks)
🔇 Additional comments (11)
services/requester/blocks_provider.go (3)

21-43: Validate error handling behavior in the block hash retrieval lambda
Within the anonymous function at lines 26–37, any retrieval error for a block or block hash silently succeeds by returning an empty hash. This might confuse downstream code because an empty hash could be interpreted as a legitimate block hash. Consider propagating an error or logging it to avoid silent failures.

Would you like me to generate a shell script to locate all code references that compare block hashes for equality with the zero-hash, to ensure no silent error misinterpretations?


45-47: Check for potential concurrency issues with shared ‘blockOverrides’
Setting the block overrides in line 46 is straightforward. However, if multiple goroutines may call BlockContext() concurrently with different overrides, you may risk concurrency conflicts. Confirm whether each BlocksProvider instance is used in a goroutine-safe way or guard shared writes with proper synchronization mechanisms.


95-108: Consider verifying retrieved block is non-nil
In the event that no block is found for the given height, line 105 returns an error. Just make sure your error message is informative and clarifies that the block was not found at the requested height.

api/debug.go (2)

178-178: Confirm the replacement of replayer.NewBlocksProvider
Line 178 uses the new requester.NewBlocksProvider. Ensure the new blocks provider meets all the same requirements as the old one (e.g., concurrency guarantees, error handling, snapshot creation logic).


183-190: Validate correctness of partial block overrides
When only a subset of block override fields is non-nil, lines 183–190 individually apply the values. This is good. Just ensure that your unit tests confirm that partial overrides do not reset any fields (e.g., time changed but coinbase remains from original block).

services/requester/requester.go (3)

68-68: Highlight new blockOverrides param
The new blockOverrides *ethTypes.BlockOverrides parameter in the Call signature allows flexible block contexts. Make sure to thoroughly test combination overrides (e.g., a changed number with an unchanged time) to confirm it behaves as intended.


98-107: Validate that blocksProvider is properly injected
Renaming blocksProvider from replayer’s to the new logic is consistent with the PR changes. Double-check that all call sites have been updated to reference the new BlocksProvider, especially in concurrency or test contexts.


292-293: Check response for revert or error
Line 294 properly handles revert attempts by checking ErrorCode. The logic is correct, but be mindful of how the internal error is surfaced to the calling code. Make sure that full revert reason data is properly logged to ease debugging.

Also applies to: 294-294

tests/web3js/contract_call_overrides_test.js (1)

1-14: LGTM! Test setup follows best practices.

The setup code properly initializes the test environment and deploys the contract in a before hook, with appropriate status verification.

bootstrap/bootstrap.go (1)

196-196: Verify the BlocksProvider implementation compatibility.

The change from replayer.NewBlocksProvider to requester.NewBlocksProvider needs verification to ensure all required interfaces are implemented correctly.

✅ Verification successful

Based on the search results, I can now provide a final response:

The change from replayer to requester BlocksProvider is compatible

Both implementations provide the core GetSnapshotAt method required by the interface. The requester version adds two additional convenience methods (SetTracer and SetBlockOverrides) while removing the OnBlockReceived method which was specific to the replayer's needs. This is a safe change as the core snapshot functionality is maintained while adapting to the requester's specific requirements.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if requester.BlocksProvider implements all methods from replayer.BlocksProvider
ast-grep --pattern 'type BlocksProvider interface {
  $$$
}'

Length of output: 62


Script:

#!/bin/bash
# Let's first find the relevant files containing BlocksProvider
rg -l "BlocksProvider"

# Then examine the implementation details
rg "BlocksProvider" -B 2 -A 5

Length of output: 18889


Script:

#!/bin/bash
# Let's check the interface implementation requirements
ast-grep --pattern 'type BlockSnapshotProvider interface {
  $$$
}'

# And check for any specific method signatures
rg "type BlockSnapshotProvider" -A 10

Length of output: 109


Script:

#!/bin/bash
# Let's look for the interface definition in types package
rg -l "BlockSnapshotProvider" types/

# And check both implementations to compare their methods
rg "func.*BlocksProvider" services/replayer/blocks_provider.go
rg "func.*BlocksProvider" services/requester/blocks_provider.go

Length of output: 596

api/api.go (1)

542-542: LGTM! Block overrides parameter properly integrated.

The addition of the blockOverrides parameter to the Call method is clean and consistent with the PR objectives.

Also applies to: 579-579

services/requester/requester.go Show resolved Hide resolved
tests/web3js/contract_call_overrides_test.js Show resolved Hide resolved
return blockContext, nil
}

type BlocksProvider struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment when to use this one and when to use replayer.BlocksProvider

bp.tracer = tracer
}

func (bp *BlocksProvider) SetBlockOverrides(blockOverrides *ethTypes.BlockOverrides) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure this is safe. It looks like we are using the blocks provider in multiple goroutines.

I would recommend changing this to something like:

func (bp *BlocksProvider) WithBlockOverrides(blockOverrides *ethTypes.BlockOverrides) evmTypes.BlockSnapshotProvider {
	return &BlocksProviderWithOverrides{
		BlocksProvider: *bp,
		blockOverrides: blockOverrides,
	}
}


type BlocksProviderWithOverrides struct {
	BlocksProvider

	blockOverrides *ethTypes.BlockOverrides
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support blockOverrides optional argument for eth_call JSON-RPC endpoint
2 participants