-
Notifications
You must be signed in to change notification settings - Fork 10
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
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe pull request introduces comprehensive changes to support block overrides across multiple components of the Ethereum-like API implementation. The modifications primarily focus on enhancing the Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Poem
Finishing Touches
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
1baa591
to
a4f893f
Compare
02ce675
to
fe53fcc
Compare
There was a problem hiding this 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 theblockOverrides
pointer in theBlocksProvider
is flexible, consider verifying that updates to the struct instance won't lead to situations where a stale pointer is used. If the lifecycle ofBlocksProvider
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 duringNewBlocksProvider
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 calle.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 passingblockOverrides
to getBlockView as a parameter
You’re already passingblockOverrides
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:
- Creating a helper function for the override verification pattern
- Defining constants for magic values like '0x2' and '0x674DB1E1'
- 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
📒 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
return blockContext, nil | ||
} | ||
|
||
type BlocksProvider struct { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea 👍 I added descriptions on both implementations in da79cd3 .
bp.tracer = tracer | ||
} | ||
|
||
func (bp *BlocksProvider) SetBlockOverrides(blockOverrides *ethTypes.BlockOverrides) { |
There was a problem hiding this comment.
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
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch 💯 I have updated the API in da79cd3 . The requester
type doesn't need to hold a single BlocksProvider
object, it's safe to use a new one, and inject the optional objects as needed (tracer & block overrides).
fe53fcc
to
da79cd3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
services/requester/blocks_provider.go (3)
14-17
: Consider composition over embedding forblockSnapshot
.The struct embeds
*BlocksProvider
which could lead to method name collisions ifBlocksProvider
implements methods that match theevmTypes.BlockSnapshot
interface. Consider using composition instead of embedding to make the dependencies explicit.type blockSnapshot struct { - *BlocksProvider + provider *BlocksProvider block models.Block }
26-37
: Improve error handling in hash calculation.The closure silently returns an empty hash on errors. This could mask issues and make debugging difficult. Consider logging the errors or using a different error handling strategy.
func(n uint64) gethCommon.Hash { block, err := bs.blocks.GetByHeight(n) if err != nil { + bs.provider.logger.Debug().Err(err).Uint64("height", n).Msg("failed to get block by height") return gethCommon.Hash{} } blockHash, err := block.Hash() if err != nil { + bs.provider.logger.Debug().Err(err).Uint64("height", n).Msg("failed to calculate block hash") return gethCommon.Hash{} } return blockHash }
68-72
: Enhance documentation forBlocksProvider
usage.While the comment explains the endpoints where this provider is used, it would be helpful to:
- Document why this implementation is separate from
replayer.BlocksProvider
- Explain the key differences between the two implementations
- Provide guidance on when to use each implementation
services/requester/requester.go (2)
439-447
: Consider caching block providers.Creating a new
BlocksProvider
instance for eachgetBlockView
call could impact performance. Consider caching providers based on their configuration (height + overrides) or implementing a provider pool.
251-251
: Consider future block overrides support.Methods like
GetBalance
,GetNonce
,GetStorageAt
, andGetCode
currently passnil
for block overrides. Consider if these methods should also support block overrides in the future for consistency.Also applies to: 263-263, 276-276, 407-407
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
api/api.go
(2 hunks)api/debug.go
(1 hunks)bootstrap/bootstrap.go
(0 hunks)services/replayer/blocks_provider.go
(1 hunks)services/requester/blocks_provider.go
(1 hunks)services/requester/requester.go
(13 hunks)tests/e2e_web3js_test.go
(1 hunks)tests/web3js/contract_call_overrides_test.js
(1 hunks)
💤 Files with no reviewable changes (1)
- bootstrap/bootstrap.go
✅ Files skipped from review due to trivial changes (1)
- services/replayer/blocks_provider.go
🚧 Files skipped from review as they are similar to previous changes (3)
- tests/e2e_web3js_test.go
- tests/web3js/contract_call_overrides_test.js
- api/api.go
🔇 Additional comments (3)
services/requester/blocks_provider.go (1)
91-109
: LGTM! Concurrency-safe implementation.The implementation is thread-safe as it creates new instances instead of modifying shared state. This immutable approach ensures that multiple goroutines can safely use different configurations without interference.
api/debug.go (1)
178-189
: LGTM! Clean implementation of block overrides support.The changes correctly implement block overrides support by:
- Using the new
requester.NewBlocksProvider
- Configuring the provider with tracer and block overrides
- Maintaining consistent parameter handling
services/requester/requester.go (1)
67-69
: LGTM! Interface updated correctly.The
Call
method signature is updated to include theblockOverrides
parameter, maintaining consistency with the PR objectives.
// `debug_traceCall` JSON-RPC endpoints. It accepts optional `Tracer` & | ||
// `BlockOverrides` objects, which are used when constructing the | ||
// `BlockContext` object. | ||
type BlocksProvider struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename it to OverridableBlocksProvider
to be different from the replayer.BlockProvider, so that it is obvious when OverridableBlocksProvider
is being used in a wrong place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea 👍 Renamed the type in 6566fba .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
services/requester/requester.go (1)
Line range hint
329-357
: IncludeblockOverrides
inEstimateGas
method calls.In the
EstimateGas
method, when callingdryRunTx
,blockOverrides
is passed asnil
. IfblockOverrides
are relevant for gas estimation, consider passing them accordingly.Apply this diff to include
blockOverrides
:result, err = e.dryRunTx(tx, from, height, stateOverrides, nil) +// Pass blockOverrides if applicable +result, err = e.dryRunTx(tx, from, height, stateOverrides, blockOverrides)
🧹 Nitpick comments (8)
services/requester/overridable_blocks_provider.go (1)
91-109
: Avoid unnecessary allocations inWithTracer
andWithBlockOverrides
.The methods
WithTracer
andWithBlockOverrides
create new instances ofOverridableBlocksProvider
on each call, which can lead to increased memory usage and potential performance issues. SinceOverridableBlocksProvider
is not modified elsewhere, consider modifying the methods to update the existing instance instead of creating a new one.Apply this diff to update the methods:
func (bp *OverridableBlocksProvider) WithTracer(tracer *tracers.Tracer) *OverridableBlocksProvider { - return &OverridableBlocksProvider{ - blocks: bp.blocks, - chainID: bp.chainID, - tracer: tracer, - blockOverrides: bp.blockOverrides, - } + bp.tracer = tracer + return bp } func (bp *OverridableBlocksProvider) WithBlockOverrides( blockOverrides *ethTypes.BlockOverrides, ) *OverridableBlocksProvider { - return &OverridableBlocksProvider{ - blocks: bp.blocks, - chainID: bp.chainID, - tracer: bp.tracer, - blockOverrides: blockOverrides, - } + bp.blockOverrides = blockOverrides + return bp }api/debug.go (1)
182-189
: Avoid redundant nesting in block override assignments.The block override assignments can be simplified by directly passing
config.BlockOverrides
toWithBlockOverrides
, as they share the same structure.Apply this diff to simplify the code:
if config.BlockOverrides != nil { blocksProvider = blocksProvider.WithBlockOverrides(ðTypes.BlockOverrides{ - Number: config.BlockOverrides.Number, - Time: config.BlockOverrides.Time, - Coinbase: config.BlockOverrides.Coinbase, - Random: config.BlockOverrides.Random, + *config.BlockOverrides }) }services/requester/requester.go (6)
68-68
: Update interface documentation forCall
method.The
Call
method signature has been updated to includeblockOverrides
. Update the interface documentation to reflect this change for better clarity.Apply this diff to update the documentation:
// Call executes the given signed transaction data on the state for the given EVM block height. // Note, this function doesn't make any changes in the state/blockchain and is // useful to execute and retrieve values. func (e *EVM) Call( tx *types.DynamicFeeTx, from common.Address, height uint64, stateOverrides *ethTypes.StateOverride, + blockOverrides *ethTypes.BlockOverrides, ) ([]byte, error) {
Line range hint
251-255
: Ensure consistent handling ofblockOverrides
inGetBalance
.In the
GetBalance
method,blockOverrides
is passed asnil
. Consider allowingblockOverrides
as a parameter if future use cases require balance retrieval with block overrides.
Line range hint
263-267
: Ensure consistent handling ofblockOverrides
inGetNonce
.Similar to
GetBalance
, consider allowingblockOverrides
as a parameter inGetNonce
to maintain consistency and accommodate future needs.
Line range hint
276-280
: Ensure consistent handling ofblockOverrides
inGetStorageAt
.For consistency across methods, consider allowing
blockOverrides
as a parameter inGetStorageAt
.
Line range hint
407-411
: Ensure consistent handling ofblockOverrides
inGetCode
.Consider allowing
blockOverrides
as a parameter inGetCode
to maintain consistency and future flexibility.
Line range hint
604-608
: Ensure consistent handling ofblockOverrides
in state validation.In
validateTransactionWithState
,getBlockView
is called withoutblockOverrides
. If transaction validation requires block overrides, consider passing them.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
api/debug.go
(1 hunks)services/requester/overridable_blocks_provider.go
(1 hunks)services/requester/requester.go
(13 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Test
🔇 Additional comments (2)
api/debug.go (1)
178-189
: Ensure thread safety when modifyingOverridableBlocksProvider
.In the
TraceCall
method, theblocksProvider
is modified withWithTracer
andWithBlockOverrides
. IfTraceCall
can be called concurrently, this may lead to race conditions. Ensure thatOverridableBlocksProvider
modifications are thread-safe.Check if
TraceCall
is accessed concurrently and consider synchronizing access or creating independent instances for each call.services/requester/requester.go (1)
439-448
: Address potential concurrency issues ingetBlockView
.Previously, setting
blockOverrides
on a sharedblocksProvider
led to concurrency issues. In the updated code, a newblocksProvider
is created ingetBlockView
. This change seems to resolve the concurrency concerns.
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:
master
branchFiles changed
in the Github PR explorerSummary by CodeRabbit
Release Notes
New Features
eth_call
anddebug_traceCall
methodsImprovements
Testing
The release introduces more granular control over block and transaction execution, allowing developers to override specific block parameters during runtime.