-
Notifications
You must be signed in to change notification settings - Fork 862
Add Ethereum state test runner for Giga executor validation #2707
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: main
Are you sure you want to change the base?
Conversation
## Describe your changes and provide context - adds new config for process block - instruments scripts to use new executor if flag is passed - adds ## Testing performed to validate your change ``` # run giga with OCC GIGA_EXECUTOR=true GIGA_OCC=true ./scripts/benchmark.sh # run giga without OCC (direct sequential execution with no scheduler) GIGA_EXECUTOR=true GIGA_OCC=false ./scripts/benchmark.sh # run non-giga GIGA_EXECUTOR=false ./scripts/benchmark.sh ``` --------- Co-authored-by: pdrobnjak <drobnjakpavle95@gmail.com>
## Describe your changes and provide context Refactor of the `evmc` and `geth` VM. First an improvement on the abstraction - we're working on transaction executor level, not on the VM level. Second, we can leverage the same executor implementation to cover both `evmone` and `geth` cases. Removing everything that's redundant since second point holds true. ## Testing performed to validate your change Ran `giga/tests`.
## Describe your changes and provide context - adds giga occ flag to initialize_local_chain ## Testing performed to validate your change - funds account after init local chain successfully
- Add bootstrap script to download pre-built evmone from GitHub releases - Add LoadEvmone() to load shared library from EVMONE_PATH env var - Update NewEvmoneExecutor to accept evmc.VM and pass to HostContext - Wire up evmone loading in app.go executeEVMTxWithGigaExecutor Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add EvmoneVM field to EvmKeeper to store pre-loaded VM - Load evmone at app initialization when GigaExecutor is enabled - Remove LoadEvmone call from block execution path - Pass EvmKeeper.EvmoneVM directly to NewEvmoneExecutor This avoids the first block being bottlenecked by VM initialization. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add giga/executor/lib package with InitVM() and version verification - Use runtime/debug.ReadBuildInfo to infer expected evmone version from EVMC - Add build tag files for darwin/arm64 and linux/amd64 - Include pre-built evmone 0.12.0 binaries for both platforms - Remove LoadEvmone() from executor.go (no longer needed) - Update app.go to use lib.InitVM() - Update bootstrap script with correct output filenames The version check ensures the committed binary matches the EVMC dependency in go.mod, preventing accidental version mismatches. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add three new tests that verify contract deployment and execution produce identical results between Geth and Giga executors: - TestGigaVsGeth_ContractDeployAndCall: Deploy SimpleStorage contract - TestGigaVsGeth_ContractCallsSequential: Deploy + multiple calls in same block - TestAllModes_ContractExecution: Test across all three executor modes Also adds: - CompareResultsNoGas helper for comparing results without strict gas checks (Geth and evmone may have different gas accounting) - CreateContractDeployTxs and CreateContractCallTxs helpers - SimpleStorage bytecode from example/contracts/simplestorage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When building on an unsupported OS/architecture combination, the build now fails with a descriptive error message instead of the unclear "undefined: libName" error. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add giga/tests/state_test.go: test runner that compares Giga (evmone) vs Geth execution using Ethereum's official GeneralStateTests fixtures - Fix host_context.go: convert geth errors to evmc.Error type to prevent panic when nested calls return errors The test runner: - Loads Ethereum test fixtures and rebuilds transactions with Sei's chain ID - Runs each test through both Geth and Giga executors - Compares result codes to ensure matching behavior - Includes a simple self-contained sanity test Usage: ETHEREUM_TESTS_PATH=/path/to/ethereum/tests go test -v ./giga/tests/... -run TestGigaVsGeth_StateTests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add fixtures_general_state_tests.tgz (9MB) containing full GeneralStateTests - Update state_test.go to auto-extract archive on first test run - Tests now work without ETHEREUM_TESTS_PATH environment variable - Env var override still supported for custom test paths Usage: go test -v ./giga/tests/... -run TestGigaVsGeth_StateTests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
pdrobnjak
left a comment
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: PR #2707 - Giga Executor State Tests and Bug Fix
Summary
This PR introduces a comprehensive test framework for comparing the Giga (evmone-based) EVM executor against the standard Geth interpreter. The key components are:
- State Test Runner (
giga/tests/state_test.go) - Loads and executes Ethereum's official GeneralStateTests to validate Giga vs Geth equivalence - Bug Fix (
giga/executor/internal/host_context.go) - AddedtoEvmcError()function to properly convert Go errors to EVMC error types - Test Fixtures - 9MB embedded .tgz archive containing Ethereum's official state tests
- Supporting Infrastructure - New executor framework, config, and comprehensive comparison tests
Overall, this is well-structured code that establishes important test infrastructure. However, there are several issues that should be addressed.
Critical Issues
1. [CRITICAL] Incomplete Error Mapping in toEvmcError()
File: giga/executor/internal/host_context.go (lines 293-306)
func toEvmcError(err error) error {
if err == nil {
return nil
}
if _, ok := err.(evmc.Error); ok {
return err
}
if errors.Is(err, vm.ErrExecutionReverted) {
return evmc.Revert
}
return evmc.Failure
}Problem: The function only handles vm.ErrExecutionReverted and maps all other errors to evmc.Failure. This loses important error context and may cause incorrect behavior for different error types like:
vm.ErrOutOfGas- Should map toevmc.OutOfGasvm.ErrInsufficientBalance- Has specific semanticsvm.ErrDepth- Stack depth exceededvm.ErrCodeStoreOutOfGas- Contract creation out of gas
Recommendation: Extend the error mapping to handle more geth VM errors explicitly.
Important Findings
2. [IMPORTANT] Interpreter Does Not Update Gas After Execution
File: giga/executor/internal/interpreter.go (lines 62-69)
Problem: The returned GasLeft from Execute() is being discarded. The contract's gas should be updated after execution to reflect actual gas consumed. This could lead to incorrect gas accounting in nested calls.
3. [IMPORTANT] Missing DELEGATECALL Context Handling (Multiple TODOs)
Files:
giga/executor/internal/host_context.go(line 193)giga/executor/internal/interpreter.go(line 58)
Multiple TODO comments indicate that DELEGATECALL sender/recipient propagation may not be correct. DELEGATECALL has specific semantics where msg.sender and msg.value should be preserved from the calling context, not updated. Incorrect handling could lead to security issues.
4. [IMPORTANT] Create Address Not Populated
File: giga/executor/internal/host_context.go (lines 161-167)
Contract creation returns an empty address, which breaks contracts that deploy other contracts and need to know their addresses.
Suggestions
5. [SUGGESTION] Test Subtest Naming Bug
File: giga/tests/state_test.go (lines 443-446)
subtestName := testName
if len(cancunPosts) > 1 {
subtestName = testName + "/" + string(rune('0'+i))
}Problem: For indices >= 10, string(rune('0'+i)) produces non-numeric characters.
Recommendation: Use fmt.Sprintf("%s/%d", testName, i) instead.
6. [SUGGESTION] Silent Parse Failures in parseHexBig()
Parse failures silently return zero, which could mask test data issues. Consider logging a warning or returning an error.
7. [SUGGESTION] Expand State Test Coverage
Currently only tests stArgsZeroOneBalance and stExample directories. Consider adding CI jobs to run more comprehensive state test categories.
Positive Observations
- Well-structured test framework with clear separation of concerns
- Good error recovery patterns with panic handling
- Correct OCC abort handling
- Clean platform-specific build tags for library loading
- Good use of transient store workaround for OCC mode
🤖 Generated with Claude Code
| } | ||
| if errors.Is(err, vm.ErrExecutionReverted) { | ||
| return evmc.Revert | ||
| } |
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.
[CRITICAL] Incomplete Error Mapping
The function only handles vm.ErrExecutionReverted and maps all other errors to evmc.Failure. This loses important error context.
Missing mappings:
vm.ErrOutOfGas→evmc.OutOfGasvm.ErrInsufficientBalance→ specific handlingvm.ErrDepth→ stack depth exceeded
Suggestion:
switch {
case errors.Is(err, vm.ErrExecutionReverted):
return evmc.Revert
case errors.Is(err, vm.ErrOutOfGas):
return evmc.OutOfGas
default:
return evmc.Failure
}| if len(cancunPosts) > 1 { | ||
| subtestName = testName + "/" + string(rune('0'+i)) | ||
| } | ||
|
|
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.
[SUGGESTION] Subtest Naming Bug
For indices >= 10, string(rune('0'+i)) produces non-numeric characters (e.g., ':' for i=10, ';' for i=11).
Suggestion: Use fmt.Sprintf for subtest naming:
subtestName = fmt.Sprintf("%s/%d", testName, i)| result, ok := new(big.Int).SetString(s, 16) | ||
| if !ok { | ||
| return new(big.Int) | ||
| } |
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.
[SUGGESTION] Silent Parse Failures
Parse failures silently return zero, which could mask test data issues.
result, ok := new(big.Int).SetString(s, 16)
if !ok {
return new(big.Int) // Silently returns 0 on parse failure
}Recommendation: Either log a warning or return an error when parsing fails to avoid masking issues in test fixtures.
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
Summary
Changes
New Test Infrastructure (
giga/tests/state_test.go)TestGigaVsGeth_StateTests: Runs Ethereum state tests through both executors and compares resultsTestGigaVsGeth_StateTest_Simple: Self-contained sanity test.tgzarchiveBug Fix (
giga/executor/internal/host_context.go)toEvmcError()to convert geth errors toevmc.ErrortypeTest Fixtures
fixtures_general_state_tests.tgz(9MB, 277MB uncompressed).gitignorefor extracted directoryTest Results
Usage
Test plan
TestGigaVsGeth_StateTest_Simple- sanity check passesTestGigaVsGeth_StateTests- 97.6% pass rate🤖 Generated with Claude Code