[vm] Extract FuzzerBackend abstraction from evmone types#2192
[vm] Extract FuzzerBackend abstraction from evmone types#2192
Conversation
cb698c8 to
2839551
Compare
|
@claude review |
|
Claude finished @Baltoli's task in 1m 49s —— View job Code Review: [vm] Extract FuzzerBackend abstraction from evmone types
Well-structured PR. The abstraction layer is clean and the decomposition sets up the future State comparison: fields dropped from the old codeThe old // Old assertions.cpp — these were compared:
MONAD_ASSERT(a.destructed == b.destructed);
MONAD_ASSERT(a.erase_if_empty == b.erase_if_empty);
MONAD_ASSERT(a.just_created == b.just_created);
MONAD_ASSERT(a.access_status == b.access_status);The new This is likely intentional — these are transient/internal evmone bookkeeping fields that don't make sense in a backend-agnostic interface, and comparisons happen after normalize/rollback where destructs and empty accounts have already been pruned. Worth confirming this reasoning is correct, since divergences in these fields between backends would now go undetected.
|
There was a problem hiding this comment.
Code Review: [vm] Extract FuzzerBackend abstraction from evmone types
Well-structured refactoring that cleanly separates the fuzzer's core logic from evmone-specific types. The abstraction is well-designed for the stated multi-step migration plan. A few notes below.
Include ordering in fuzzer_backend.hpp
<category/core/int.hpp> is placed after the third-party <evmc/evmc.hpp> header. Project headers should be grouped before third-party headers:
// Current:
#include <category/core/byte_string.hpp>
#include <category/execution/ethereum/core/address.hpp>
#include <evmc/evmc.hpp>
#include <category/core/int.hpp> // ← out of group
// Suggested:
#include <category/core/byte_string.hpp>
#include <category/core/int.hpp>
#include <category/execution/ethereum/core/address.hpp>
#include <evmc/evmc.hpp>Sorted views hold const & to backend internals — lifetime contract worth documenting
EvmoneSortedStateView and EvmoneSortedMapView store const & references to the underlying unordered_maps. In the current code this is safe because assert_backend_states_equal creates and consumes both views in a single expression before any mutation occurs. But future backends or callers could easily introduce a use-after-mutate bug. Consider adding a comment on sorted_view() in the base class or the evmone implementation noting that the returned view borrows the backend's state and must not outlive any mutation.
Good improvements bundled in
A few subtle improvements worth calling out as positive:
#pragma onceadded toassertions.hpp— the old header was missing an include guard entirely. Good catch.MONAD_DEBUG_ASSERT→MONAD_ASSERTindeploy()for thestate_.find(create_address) == nullptrcheck. This is a critical invariant (deploying to an already-occupied address would silently corrupt state), so unconditional assertion is correct.- Magic bytes
{0xef, 0x01, 0x00}replaced withvm::evm::delegation_indicator_prefix()indeploy_delegated. If the EIP-7702 prefix ever changes, this avoids divergence between the fuzzer and production code. #include <bits/chrono.h>removed — this was a GCC-internal header that shouldn't have been included directly.block_gas_limitexplicitly typed asstd::int64_t— the oldautodeducedint(32-bit), which was technically narrower than the gas arithmetic it feeds into.
CursorIterator post-increment returning void
CursorIterator::operator++(int) returns void, which is fine for std::input_iterator in C++20 (the static_asserts at the bottom of fuzzer_view.hpp confirm this), but may surprise callers who try auto old = it++. The static_assert(!std::copyable<...>) checks neatly prevent this misuse at compile time. Good defensive design.
Minor: normalize() called unconditionally on both success and failure
In fuzz_iteration, normalize() is called after both success and failure paths (after potential rollback). This matches the old clean_storage() behavior, so no behavioral change, but it does mean we normalize the successful-execution state too (which may contain no zero-cold slots). The cost is negligible for fuzzer-sized states, but noting it for future backend authors who might have more expensive normalization.
Overall
Clean decomposition. The view/cursor abstraction with move-only iterators is well-designed for std::views::zip usage, and the static_assert concept checks at the bottom of fuzzer_view.hpp are a nice touch for catching regressions at compile time. The main actionable item is the include ordering in fuzzer_backend.hpp.
There was a problem hiding this comment.
Pull request overview
This PR refactors the VM fuzzer to execute and compare state via a new FuzzerBackend abstraction, encapsulating evmone state/execution details behind an interface as a first step toward removing evmone as a dependency.
Changes:
- Added
FuzzerBackend+ state view/cursor abstractions (SortedStateView,SortedView, virtual cursors, move-only iterators). - Implemented
EvmoneBackendto provideFuzzerBackendoverevmone::state::State. - Rewrote the fuzzer run loop and state comparison to use the backend abstraction and sorted lockstep iteration (
std::views::zip).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/vm/fuzzer/fuzzer.cpp | Switches fuzzer loop to backend-based execution/deploy/state queries. |
| test/vm/fuzzer/fuzzer_view.hpp | Introduces cursor + sorted view iterator abstraction used during comparison. |
| test/vm/fuzzer/fuzzer_backend.hpp | Defines FuzzerBackend interface and genesis constants. |
| test/vm/fuzzer/fuzzer_backend.cpp | Implements shared backend helper (deploy_delegated). |
| test/vm/fuzzer/evmone_backend.hpp | Declares EvmoneBackend implementing FuzzerBackend. |
| test/vm/fuzzer/evmone_backend.cpp | Implements evmone-backed execution, normalization, and sorted state views. |
| test/vm/fuzzer/assertions.hpp | Updates assertions to compare backend views rather than evmone types directly. |
| test/vm/fuzzer/assertions.cpp | Implements lockstep sorted comparison via zip for accounts/storage/transient storage. |
| test/vm/fuzzer/CMakeLists.txt | Adds new backend/view sources to the fuzzer target. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
40b356e to
c76f81c
Compare
Introduce a FuzzerBackend interface that abstracts state management and execution away from evmone-specific types. The fuzzer's core run loop now programs against this interface, with EvmoneBackend as the concrete implementation. This is step 1 of removing evmone as a dependency: the evmone state types (State, Account, StorageValue, Host, Transaction, BlockInfo, TestState, TestBlockHashes) are now confined to evmone_backend.cpp. The fuzzer core only sees FuzzerBackend, SortedStateView, and EVMC types. State comparison uses a sorted-view model with virtual cursors wrapped in move-only C++ input iterators, enabling std::views::zip for lockstep comparison of storage and transient storage across backends. New files: - fuzzer_backend.hpp: FuzzerBackend abstract class - fuzzer_view.hpp/cpp: SortedStateView, SortedStorageView, SortedTransientStorageView, Cursor<T>, CursorIterator<T>, assert_states_equal - evmone_backend.hpp/cpp: EvmoneBackend implementation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
c76f81c to
53d1273
Compare
Summary
FuzzerBackendabstract interface that encapsulates state management and execution, hiding evmone-specific types behind the abstractionEvmoneBackendas the concrete backend, wrappingevmone::state::Stateand parameterised over anevmc::VMFuzzerBackend— evmone types no longer leak into the core logicstd::views::zipfor lockstep comparison of storage, transient storage, and account fieldsThis is step 1 of a multi-step transition to remove evmone as a dependency:
MonadBackendusing monad's ownBlockState/State/EvmcHost/VMOcamlBackendvia C FFI, replacing evmone entirelyTest plan
MONAD_COMPILER_TESTING=ON(GCC 15, RelWithDebInfo)--seed 12345 -i 5 --implementation compiler)--implementation compilerand--implementation interpreter🤖 Generated with Claude Code