-
Notifications
You must be signed in to change notification settings - Fork 21.5k
internal/ethapi: add transient storage override support for eth_call #32680
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
base: master
Are you sure you want to change the base?
Conversation
83a8465 to
720946f
Compare
|
@s1na do these types of overrides need to be represented in rpc specs? |
|
@hero5512 this is still a draft - is that intentional? |
Yes, there are still some issues with this PR. |
|
@s1na This pr is ready to review. Please take a look. |
@lightclient The good: they are all standardized as part of eth_simulateV1 The bad: not specified in the specs for eth_call and eth_estimateGas The ugly: I think only geth and reth support them in eth_call and eth_estimateGas |
|
I don't like adding transient storage to the state overrides. They are different. State overrides can be for a longer context than a transaction, e.g. in eth_simulateV1 you do a state override per block. I'd add it as a new parameter. |
okay. I've refactored the implementation to separate transient storage overrides into a seperate parameter. |
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.
🔍 Code Review Summary
The review covers the implementation of transient storage overrides for eth_call across JSON-RPC and GraphQL APIs. The changes are well-structured and include essential test coverage. Key findings focus on improving robustness by handling edge cases in state application, enhancing test completeness, and ensuring API consistency. Overall, the implementation is solid, and the suggestions aim to refine it for production readiness.
📋 Reviewed Changes
- core/state/statedb.go: Added
SetTransientStorageto the StateDB object to apply overrides. - ethclient/gethclient/gethclient.go: Updated the Go client's
CallContractto support transient storage overrides. - graphql/graphql.go: Exposed transient storage overrides in the GraphQL schema and resolver.
- internal/ethapi/api.go: Integrated the application of transient storage overrides within the
eth_calllogic. - internal/ethapi/api_test.go: Added end-to-end tests for
eth_callutilizing transient storage overrides. - internal/ethapi/override/override.go: Extended the
Accountoverride struct to include aTransientStoragemap. - internal/ethapi/override/override_test.go: Added unit tests for applying transient storage overrides to the state.
📊 Architecture & Flow Diagrams
Diagram 1
graph TD
subgraph "User Request"
A["eth_call with TransientStorageOverride"]
end
subgraph "Geth Node"
B[ethapi.API] --> C{"Parse Overrides"}
C --> D["Create Ephemeral StateDB"]
D --> E[statedb.SetTransientStorage]
E --> F["EVM Execution"]
F --> G["Return Call Result"]
end
A --> B
🤔 Review Quality Assessment
The review provides a comprehensive analysis of the transient storage override feature, examining its implementation from the state layer up to the API and client libraries. The focus was on correctness, robustness against edge cases, test coverage, and API consistency. Confidence in the review is high due to the localized nature of the changes and the ability to verify behavior through the newly added tests. No significant gaps were identified in the analysis, which assumes the correctness of the underlying EVM implementation of TLOAD and TSTORE.
💡 Suggestions Summary
- Inline Comments: 0 suggestions on modified code lines
- General Suggestions: 3 suggestions for overall improvements
📝 Additional Suggestions
The following suggestions apply to code outside the current PR diff:
1. 🔴 In override.go, the Apply function iterates over the TransientStorage map to set state. However, if the account for which the override is being applied does not exist in the state, s.GetOrNewStateObject(addr) will create it, but the loop continues. It's more robust and explicit to ensure the account object exists before iterating over its transient storage. This also prevents potential nil panics if the state object creation were to fail, although unlikely with GetOrNewStateObject.
File: internal/ethapi/override/override.go (Line 45)
Confidence: 90%
if account.TransientStorage != nil {
object := s.GetOrNewStateObject(addr)
for key, value := range *account.TransientStorage {
object.SetTransientState(key, value)
}
}2. 🔴 The test for transient storage overrides in api_test.go is good, but it could be more comprehensive. The current test should be expanded to verify that an override can successfully overwrite an existing transient storage slot set earlier in the same call. This ensures that TSTORE and TLOAD interactions with the overridden state behave as expected within a single transaction context.
File: internal/ethapi/api_test.go (Line 2855)
Confidence: 85%
func TestTransientStorageOverride(t *testing.T) {
// This is a simplified example. The actual test code would be more complex.
service, _, _, _, contractAddr := setupCallTest(t, tstoreABI, tstoreCode)
key := common.HexToHash("0x123")
value := common.HexToHash("0xabc")
newValue := common.HexToHash("0xdef")
// TSTORE key to value, then TSTORE key to newValue, then TLOAD key.
// The final TLOAD should return newValue.
data, _ := tstoreABI.Pack("doStuffAndReturn", key, value, newValue)
override := map[common.Address]ethapi.Account{
*contractAddr: {
TransientStorage: &map[common.Hash]common.Hash{
// Pre-seed a value to ensure overrides work even if the slot is not empty.
key: common.HexToHash("0xdeadbeef"),
},
},
}
args := ðapi.CallArgs{
To: contractAddr,
Data: data,
StateOverride: override,
}
res, err := service.Call(context.Background(), *args, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), nil)
if err != nil {
t.Fatalf("call failed: %v", err)
}
got := common.BytesToHash(res)
if got != newValue {
t.Errorf("expected 0x%x, got 0x%x", newValue, got)
}
}3. 🔴 The newly added TransientStorage field in override.go lacks a comment explaining its purpose and structure. Adding a clear comment improves code documentation and maintainability for future developers.
File: internal/ethapi/override/override.go (Line 20)
Confidence: 95%
// TransientStorage is a mapping of transient storage keys to values. When
// specified, the state of these storage slots is overridden before execution.
TransientStorage *map[common.Hash]common.Hash `json:"transientStorage,omitempty"`
this pr implements #32671, adding an override for the transient storage function in eth_call.