-
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
Integrate local state index #541
Integrate local state index #541
Conversation
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThe pull request introduces significant changes across multiple files, primarily focusing on the integration of Ethereum Virtual Machine (EVM) functionalities. Key modifications include the introduction of new structs and interfaces for handling EVM operations, the refactoring of existing structures to enhance clarity and maintainability, and the addition of comprehensive testing for state execution and transaction handling. The changes also involve renaming and restructuring fields and methods to improve accessibility and consistency throughout the codebase. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ClientHandler
participant EVMClient
participant LocalClient
participant RemoteClient
participant Engine
participant BlockState
User->>ClientHandler: Send transaction
ClientHandler->>LocalClient: Execute transaction
alt LocalClient fails
ClientHandler->>RemoteClient: Execute transaction
end
ClientHandler->>Engine: Notify transaction
Engine->>BlockState: Execute transaction
BlockState-->>Engine: Return result
Engine-->>ClientHandler: Return transaction status
ClientHandler-->>User: Return transaction confirmation
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 (
|
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: 1
Outside diff range and nitpick comments (4)
storage/pebble/register_test.go (1)
55-120
: LGTM, but consider adding more examples.The subtest is correctly testing the
SetValue
andGetValue
methods for multiple accounts at different heights.However, consider adding more examples to cover additional scenarios, such as:
- Setting and getting values for the same owner and key at non-consecutive heights.
- Setting and getting values for the same owner and different keys at the same height.
- Setting and getting values for different owners and the same key at the same height.
services/state/engine.go (1)
82-85
: LGTM, but consider adding cleanup logic.The
Stop
function is correctly implemented and marks the engine as stopped.However, consider adding cleanup logic to gracefully shutdown the engine and release any resources.
services/state/state.go (2)
21-31
: LGTM, but address thetodo
comment.The struct is well-defined and contains all the necessary fields to represent the state of a block.
However, please address the
todo
comment to changetypes.StateDB
totypes.ReadOnlyView
in the future.
138-177
: LGTM, but address thetodo
comments.The function is correctly implemented and initializes the block context with the necessary fields. The
GetHashFunc
closure allows retrieving the hash of a block by height.However, please address the following
todo
comments:
- At line 161-162: Set the
Tracer
field appropriately.- At line 166-167: Consider failing and executing calls using a remote client when cadence architecture is used.
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (15)
- api/api.go (2 hunks)
- bootstrap/bootstrap.go (12 hunks)
- models/receipt.go (2 hunks)
- models/transaction.go (1 hunks)
- services/requester/client_handler.go (1 hunks)
- services/requester/evm.go (1 hunks)
- services/requester/local_client.go (1 hunks)
- services/requester/remote_client.go (17 hunks)
- services/requester/remote_client_test.go (1 hunks)
- services/state/engine.go (1 hunks)
- services/state/state.go (1 hunks)
- storage/pebble/register.go (1 hunks)
- storage/pebble/register_test.go (1 hunks)
- tests/helpers.go (2 hunks)
- tests/state_integration_test.go (1 hunks)
Files skipped from review due to trivial changes (1)
- models/transaction.go
Additional comments not posted (78)
services/requester/evm.go (8)
11-13
: LGTM!The code changes are approved.
15-17
: LGTM!The code changes are approved.
19-22
: LGTM!The code changes are approved.
24-27
: LGTM!The code changes are approved.
29-30
: LGTM!The code changes are approved.
32-34
: LGTM!The code changes are approved.
36-37
: LGTM!The code changes are approved.
39-40
: LGTM!The code changes are approved.
services/requester/local_client.go (7)
16-21
: LGTM!The code changes are approved.
28-33
: LGTM!The code changes are approved.
35-42
: LGTM!The code changes are approved.
60-71
: LGTM!The code changes are approved.
73-79
: LGTM!The code changes are approved.
81-87
: LGTM!The code changes are approved.
89-96
: LGTM!The code changes are approved.
storage/pebble/register_test.go (2)
11-26
: LGTM!The subtest is correctly testing the
SetValue
andGetValue
methods at the same height.
28-53
: LGTM!The subtest is correctly testing the
SetValue
andGetValue
methods at the latest height.services/state/engine.go (7)
19-28
: LGTM!The
Engine
struct is well-defined and has all the necessary fields for the state engine.
30-51
: LGTM!The
NewStateEngine
function is correctly implemented and initializes all the fields of theEngine
struct.
59-74
: LGTM!The
Notify
function is correctly implemented and handles the block execution.
76-80
: LGTM!The
Run
function is correctly implemented and sets up the engine to receive blocks from the publisher.
87-89
: LGTM!The
Done
function is correctly implemented and returns the done channel from the engine status.
91-93
: LGTM!The
Ready
function is correctly implemented and returns the ready channel from the engine status.
108-126
: LGTM!The
executeBlock
function is correctly implemented and executes the transactions in the block.storage/pebble/register.go (8)
16-20
: LGTM!The
Register
struct is well-defined with appropriate fields for height, store, and synchronization.
22-28
: LGTM!The
NewRegister
function correctly initializes all the fields of theRegister
struct.
30-60
: LGTM!The
GetValue
method is correctly implemented with proper locking, iterator usage, and error handling. It also adheres to the interface expectation of returning nil when the value is not found.
62-77
: LGTM!The
SetValue
method is correctly implemented with proper locking and error handling. It delegates the storage operation to the underlying store.
79-86
: LGTM!The
ValueExists
method is correctly implemented by leveraging theGetValue
method and checking the returned value.
88-122
: LGTM!The
AllocateSlabIndex
method is correctly implemented with proper locking, retrieval of the current slab index, incrementing it, and persisting the new index back to the store. It also handles the case when the slab index is not found in the store.
132-136
: LGTM!The
id
method correctly calculates the ledger ID by appending the owner, key, and height bytes, following the schema mentioned in the comments.
138-145
: LGTM!The
idUpper
andidLower
methods correctly calculate the upper and lower bounds for the ledger ID range. The upper bound is exclusive and increments the height by 1, while the lower bound always uses a height of 0.Also applies to: 147-153
tests/state_integration_test.go (1)
22-163
: Comprehensive state execution test.The test function
Test_StateExecution_Transfers
is well-structured and covers important aspects of state execution and balance updates. It follows a logical flow and tests the following scenarios:
- Setting up the emulator and required services.
- Configuring and starting the state index, API server, and event ingestion.
- Verifying the initial balance of a test address.
- Sending EVM transactions and waiting for new block events.
- Verifying the updated balances after each transaction.
- Reading balances at historic heights and verifying the expected values.
The test function is comprehensive and ensures the correctness of state execution and balance updates across different block heights.
services/state/state.go (3)
33-65
: LGTM!The function is correctly implemented and initializes all the necessary fields of the
BlockState
struct.
67-114
: LGTM, but verify the error handling behavior.The function is correctly implemented and supports executing both direct calls and transaction calls. It also verifies the result receipt against the retrieved receipt to ensure state consistency.
However, please verify the error handling behavior mentioned in the
todo
comment at line 94-95. Ensure that restarting and retrying the service on error is the desired behavior.
116-133
: LGTM!The function is correctly implemented and allows performing a call without modifying the state.
models/receipt.go (1)
74-141
: LGTM!The
EqualReceipts
function is well-structured and correctly compares thegeth
Receipt type with the customReceipt
type. It handles nil receipts, compares logs, and compares receipt data fields. The function returns a boolean indicating whether the receipts are equal and a slice of errors containing any mismatches found during the comparison.The code is readable, maintainable, and follows best practices.
services/requester/remote_client_test.go (1)
Line range hint
213-227
: LGTM!The changes to the
createEVM
test helper function are consistent with the updated return type of*RemoteClient
. The instantiation of theRemoteClient
struct uses the same fields as the previousEVM
struct, indicating that theRemoteClient
struct likely has a similar structure and functionality.The changes are localized to the test helper function and do not affect the behavior of the tests.
services/requester/client_handler.go (12)
29-37
: LGTM!The
ClientHandler
struct is well-defined with appropriate fields to handle EVM operations using remote and local clients.
39-64
: LGTM!The
NewClientHandler
function is correctly implemented and handles the creation of a newClientHandler
instance with the provided dependencies.
66-69
: LGTM!The
SendRawTransaction
method is correctly implemented and always uses the remote client to send the raw transaction.
71-86
: LGTM!The
GetBalance
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
88-104
: LGTM!The
Call
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
106-122
: LGTM!The
EstimateGas
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
124-139
: LGTM!The
GetNonce
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
141-156
: LGTM!The
GetCode
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
158-169
: LGTM!The
GetLatestEVMHeight
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
171-187
: LGTM!The
GetStorageAt
method is correctly implemented and uses thehandleCall
function to execute the call using both local and remote clients and handle errors.
189-213
: LGTM!The
localClient
method is correctly implemented and handles the creation of a newLocalClient
instance for a given block height using the retrieved block and other dependencies.
215-290
: LGTM!The
handleCall
function is well-implemented and handles the execution and error handling of local and remote calls effectively. It covers various error scenarios and returns the appropriate result based on the conditions. The use of goroutines for concurrent execution and the comparison of results in case of no errors adds to the robustness of the function.tests/helpers.go (2)
85-93
: Approve addition ofSkipTransactionValidation
field with a note of caution.The addition of the
SkipTransactionValidation
field to the emulator server configuration is approved.This field could be useful in certain test scenarios to improve performance or test specific behaviors by skipping transaction validation.
However, please ensure that skipping validation in tests does not inadvertently hide any potential issues that could occur in production where validation is enabled. Consider adding some tests with validation enabled to catch such issues.
330-331
: Approve line break change.The line break added before the closing parenthesis of the
evmSign
function parameter list is approved.This change enhances code readability without altering the function's behavior.
bootstrap/bootstrap.go (10)
36-36
: LGTM!The addition of the
Registers
field to theStorages
struct is approved.
48-57
: LGTM!The changes to the
Bootstrap
struct, including the addition of new fields and renaming of existing fields to uppercase, are approved. These changes improve the organization and consistency of the struct.
75-83
: LGTM!The changes to the
New
function, which initialize the new fields added to theBootstrap
struct, are approved. The initialization logic is correct and consistent with the struct changes.
Line range hint
93-141
: LGTM!The changes to the
StartEventIngestion
method, which update the usage of theBootstrap
struct fields to match the new public field names, are approved. The field names are used correctly and consistently throughout the method.
156-165
: LGTM!The changes to the
StartTraceDownloader
method, which update the usage of theBootstrap
struct fields to match the new public field names, are approved. The field names are used correctly and consistently throughout the method.
170-174
: LGTM!The change to the
StopTraceDownloader
method, which updates the usage of theBootstrap
struct field to match the new public field nameTraces
, is approved. The field name is used correctly.
178-183
: LGTM!The change to the
StopEventIngestion
method, which updates the usage of theBootstrap
struct field to match the new public field nameEvents
, is approved. The field name is used correctly.
185-201
: LGTM!The addition of the
StartStateIndex
method to theBootstrap
struct is approved. The method correctly initializes the state indexing engine using the newState
field and handles the startup process appropriately.
203-208
: LGTM!The addition of the
StopStateIndex
method to theBootstrap
struct is approved. The method correctly handles the stopping of the state indexing engine by checking if theState
field is nil before calling theStop
method.
Line range hint
214-341
: LGTM!The changes to the
StartAPIServer
method, which update the usage of theBootstrap
struct fields to match the new public field names and initialize therequester.NewClientHandler
with the newEVMClient
field, are approved. The field names are used correctly and consistently throughout the method, and the initialization of the client handler is valid.services/requester/remote_client.go (14)
Line range hint
84-101
: LGTM!The
RemoteClient
struct looks good. It provides a clear structure for the remote client implementation and contains all the necessary dependencies and configurations.
Line range hint
103-193
: LGTM!The
NewRemote
constructor function looks good. It properly initializes theRemoteClient
instance with the provided dependencies and configurations. It also performs necessary checks on the COA account and creates the COA resource if required.
Line range hint
195-252
: LGTM!The
SendRawTransaction
method looks good. It properly validates the transaction, checks the gas price, builds a Flow transaction with the EVM transaction data, and sends it to the transaction pool.
Line range hint
254-302
: LGTM!The
buildTransaction
method looks good. It properly builds a Flow transaction from the provided script and arguments, concurrently retrieves the necessary information, sets the transaction fields, and signs the transaction envelope.
Line range hint
304-348
: LGTM!The
GetBalance
method looks good. It properly retrieves the balance of an address at a specific EVM height by converting the height, executing a script, and returning the balance as a big integer.
Line range hint
350-401
: LGTM!The
GetNonce
method looks good. It properly retrieves the nonce of an address at a specific EVM height by converting the height, executing a script, and returning the nonce as a uint64.
Line range hint
403-424
: LGTM!The
stateAt
method looks good. It properly retrieves the state database at a specific EVM height by converting the height, creating a remote ledger, and returning a new state database instance.
Line range hint
426-439
: LGTM!The
GetStorageAt
method looks good. It properly retrieves the storage value at a specific address and hash at a specific EVM height by retrieving the state database and getting the storage value.
Line range hint
441-495
: LGTM!The
Call
method looks good. It properly executes a read-only EVM call at a specific height by converting the height, executing a script, parsing the result, and returning the returned data.
Line range hint
497-551
: LGTM!The
EstimateGas
method looks good. It properly estimates the gas consumption of an EVM transaction at a specific height by converting the height, executing a script, parsing the result, and returning the gas consumed.
Line range hint
553-605
: LGTM!The
GetCode
method looks good. It properly retrieves the code of an address at a specific EVM height by converting the height, executing a script, converting the result to bytes, and returning the code.
Line range hint
607-631
: LGTM!The
GetLatestEVMHeight
method looks good. It properly retrieves the latest EVM height by executing a script at the latest block height, converting the result to uint64, and returning the height.
Line range hint
633-658
: LGTM!The
getSignerNetworkInfo
method looks good. It properly retrieves the signer account information from the network and returns the key index and sequence number of the signer account.
Line range hint
660-678
: LGTM!The
replaceAddresses
method looks good. It properly replaces the addresses in the script based on the network by iterating over the system contracts, replacing the import statements with the actual contract addresses, and replacing the COA address if used.api/api.go (2)
86-86
: LGTM!The change to the
evm
field type fromrequester.Requester
torequester.EVMClient
is approved.Using a more specialized
EVMClient
interface improves type safety and makes the EVM interactions clearer.
99-99
: LGTM!The change to the
evm
parameter type fromrequester.Requester
torequester.EVMClient
in the constructor is approved.This change is consistent with the
BlockChainAPI
struct field type change and ensures proper instantiation.
services/requester/local_client.go
Outdated
func (l *LocalClient) Call( | ||
ctx context.Context, | ||
data []byte, | ||
from common.Address, | ||
evmHeight int64, | ||
) ([]byte, error) { | ||
res, err := l.state.Call(from, data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// todo what if it failed? | ||
|
||
return res.ReturnedData, nil | ||
} |
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.
Handle the case of a failed call.
The method is mostly implemented correctly, but the case of a failed call is not handled.
Consider adding an error check and return the error if the call fails:
res, err := l.state.Call(from, data)
if err != nil {
return nil, err
}
if res.Failed() {
return nil, fmt.Errorf("call failed: %s", res.Err)
}
return res.ReturnedData, nil
services/requester/local_client.go
Outdated
} | ||
|
||
func (l *LocalClient) GetLatestEVMHeight(ctx context.Context) (uint64, error) { | ||
return l.blocks.LatestEVMHeight() |
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 am not sure that this method makes sense for the local client. The requester would use a Cadence script to fetch the latest EVM block on the Flow network, which doesn't have to be the same as what any EVM Gateway operator has ingested.
address common.Address, | ||
evmHeight int64, | ||
) (*big.Int, error) { | ||
bal := l.state.GetBalance(address) |
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.
How do we know that the *state.BlockState
matches the given evmHeight
🤔 ? The same goes for all methods that accept historical blocks. I can see that the ClientHandler
takes care of that, it's just seems not very intuitive to have a function argument which is unused/ignored.
return err | ||
} | ||
|
||
ctx, err := s.blockContext(receipt) |
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.
ctx, err := s.blockContext(receipt) | |
ctx, err := s.blockContext(receipt) | |
if err != nil { | |
return err | |
} |
return nil, err | ||
} | ||
|
||
return bv.DryRunTransaction(tx, from) |
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.
Awesome 👏
services/state/state.go
Outdated
} | ||
|
||
if ok, errs := models.EqualReceipts(res.Receipt(), receipt); !ok { |
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 believe that we may be able to get away without this models.EqualReceipts
method, if we used the blocks'
TransactionsHashRoot
ReceiptsRoot
fields.
We do something similar:
txHashes := evmTypes.TransactionHashes{}
for _, tx := range e.transactions {
txHashes = append(txHashes, tx.Hash())
}
if e.block.TransactionHashRoot != txHashes.RootHash() {
return nil, fmt.Errorf(
"block %d references missing transaction/s",
e.block.Height,
)
}
And
b.ReceiptRoot = gethTypes.DeriveSha(receipts, gethTrie.NewStackTrie(nil))
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.
It seems to me that it is more bullet-proof, to compare them this way. But can be done in a follow-up PR.
…regor/local-state/state
# Conflicts: # services/requester/client_handler.go # services/requester/local_client.go
mreged into feature/state |
Description
Integrate local state index complying to the EVM client interface. A client handler was added which is a way to execute both remote and local client and compare results. We only use the local state result if the remote client fails. We also can then change this handler to be smarter in ways it chooses which client to use (for example as long as the state index is healthy use local otherwise use remote).
Please note there are a lot of changes that are results of renaming types.
For contributor use:
master
branchFiles changed
in the Github PR explorerSummary by CodeRabbit
New Features
ClientHandler
for enhanced EVM operations with local and remote client support.EVMClient
interface for structured EVM interactions.Engine
andBlockState
for robust blockchain state management.Bug Fixes
Documentation
Tests
Register
functionality and new integration tests for state execution.