8000 Frame refactor by roninjin10 · Pull Request #1668 · evmts/tevm-monorepo · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Frame refactor #1668

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

Merged
merged 4 commits into from
May 16, 2025
Merged

Frame refactor #1668

merged 4 commits into from
May 16, 2025

Conversation

roninjin10
Copy link
Collaborator
@roninjin10 roninjin10 commented May 16, 2025

Description

Refactored the EVM frame implementation into a modular directory structure to improve code organization and maintainability. The previously monolithic frame.zig file has been split into multiple specialized components in a new Frame directory, with each component handling a specific aspect of EVM execution.

Key changes:

  • Created dedicated files for each frame component (Memory, Stack, ExecutionState, etc.)
  • Implemented proper module exports through a central frame.zig file
  • Maintained backward compatibility through re-exports
  • Updated import paths in dependent files

Testing

The existing test cases have been updated to work with the new structure, ensuring that the refactoring doesn't break existing functionality. The tests verify frame initialization and simple execution with the STOP opcode.

Additional Information

Your ENS/address:

Summary by CodeRabbit

  • New Features
    • Modularized the EVM frame system, introducing separate components for execution state, stack, memory, frame input, results, and state management.
    • Added robust enums and structs to represent call types, execution results, and frame outcomes for improved clarity and error handling.
    • Added support for the CREATE2 opcode semantics in EVM execution, including frame creation, execution, and result handling.
  • Refactor
    • Restructured the codebase to move frame-related logic into individual files, enhancing maintainability and modularity.
  • Tests
    • Introduced comprehensive unit and integration tests for EVM frame initialization, execution, stack, and memory operations.
    • Added new tests covering CREATE2 contract creation and updated existing tests accordingly.
  • Chores
    • Updated build scripts and file paths to align with new file naming conventions and structure.

Copy link
vercel bot commented May 16, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
tevm-monorepo-app ✅ Ready (Inspect) Visit Preview May 16, 2025 4:26am
2 Skipped Deployments
Name Status Preview Updated (UTC)
tevm-monorepo-tevm ⬜️ Ignored (Inspect) May 16, 2025 4:26am
node ⬜️ Skipped (Inspect) May 16, 2025 4:26am

@vercel vercel bot temporarily deployed to Preview – node May 16, 2025 03:59 Inactive
Copy link
changeset-bot bot commented May 16, 2025

⚠️ No Changeset found

Latest commit: 7c12f63

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor
coderabbitai bot commented May 16, 2025

Warning

Rate limit exceeded

@roninjin10 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 42 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between a7059b0 and 7c12f63.

📒 Files selected for processing (2)
  • src/Evm/Frame/Frame.zig (1 hunks)
  • src/Evm/frame.zig (1 hunks)

Walkthrough

The codebase has been refactored to modularize the EVM frame logic by splitting previously monolithic implementations into dedicated files under a Frame subdirectory. Each core component (such as stack, memory, execution state, results, and input types) now resides in its own file, with a central frame.zig acting as a re-export hub. The test suite has been similarly moved and updated for consistency. Additionally, support for the CREATE2 opcode has been added in the EVM execution flow, including frame creation, execution, and result handling, along with new tests.

Changes

File(s) Change Summary
src/Evm/Frame/CallScheme.zig Introduced CallScheme enum to represent EVM call types: Call, CallCode, DelegateCall, and StaticCall.
src/Evm/Frame/ExecutionState.zig Added ExecutionState struct encapsulating memory, stack, program counter, gas tracking, and return data; includes initialization and deinitialization methods.
src/Evm/Frame/Frame.zig Defined Frame struct modeling an EVM execution context, with methods for initialization, cleanup, debugging, and execution.
src/Evm/Frame/FrameInput.zig Added FrameInput union enum for call and create input variants (Call, Create, Create2), with a method to retrieve the gas limit.
src/Evm/Frame/FrameOrCall.zig Introduced FrameOrCall union enum to represent either a frame execution result or a directive to initiate a new call.
src/Evm/Frame/FrameResult.zig Added FrameResult union enum for call and create outcomes, including execution status, return data, gas usage, and (for create) created address.
src/Evm/Frame/InstructionResult.zig Introduced InstructionResult enum for instruction execution outcomes such as success, revert, out-of-gas, and various errors.
src/Evm/Frame/JournalCheckpoint.zig Added JournalCheckpoint as a type alias for usize, representing a state checkpoint.
src/Evm/Frame/Memory.zig Implemented Memory struct for frame memory management, with methods for initialization, cleanup, storing, and loading bytes.
src/Evm/Frame/Stack.zig Added Stack struct for EVM stack operations with push/pop methods and error handling for overflow/underflow.
src/Evm/Frame/StateManager.zig Introduced a mock StateManager struct with placeholder state checkpoint and code loading methods.
src/Evm/evm.zig Updated imports and type references to use new modularized frame components; adjusted function signatures and usage to match new types; added support for CREATE2 opcode including execution and result handling; added tests for CREATE2.
src/Evm/frame.zig Replaced full implementation with exports of entities from individual Frame subdirectory files, centralizing public API.
src/Evm/frame_test.zig Removed the old frame module test suite.
build.zig Updated test file path and comment to use Frame_test.zig (capitalized) instead of frame_test.zig.
src/Evm/Frame_test.zig Added new comprehensive test suite covering frame initialization, execution, stack/memory operations, and EVM integration, adapted to the new modular structure, including tests for CREATE2.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Evm
    participant Frame
    participant StateManager

    User->>Evm: createFrame(input, code, depth)
    Evm->>Frame: Frame.init(allocator, input, code, depth, checkpoint)
    Frame-->>Evm: Frame instance

    User->>Frame: execute(stateManager)
    Frame->>Frame: (runs code, updates state)
    Frame-->>User: FrameOrCall (Result or Call)
Loading

Poem

🐇
In modular burrows, code now hops,
Each frame and stack in tidy shops.
Memory grows and tests delight,
Execution flows from byte to byte.
With enums, structs, and types anew—
The EVM’s garden freshly grew!
—Rabbit 🥕


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@roninjin10 roninjin10 marked this pull request as ready for review May 16, 2025 03:59
Copy link
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Contributor
@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (5)
src/Evm/Frame/CallScheme.zig (1)

2-7: Enhancement: Document individual variants
Consider adding inline doc comments above each variant to detail subtle differences, for improved readability and generated documentation. For example:

pub const CallScheme = enum {
    /// Standard external call with new context
    Call,
    /// Execute only the callee's code in caller context
    CallCode,
    /// Delegate call inheriting caller and value
    DelegateCall,
    /// Read-only call disallowing state modifications
    StaticCall,
};
src/Evm/Frame/Stack.zig (1)

1-30: Implementation looks good with a minor optimization opportunity

The Stack implementation is clean and appropriate for EVM operations, with proper error handling for overflow/underflow conditions. A few suggestions:

  1. The error handling in the pop method contains redundancy - line 28 has both pop() followed by orelse return error.StackUnderflow, but you've already checked for empty stack at line 25.

  2. Consider adding helper methods that would be useful for EVM operations:

    • peek to view the top element without popping
    • Methods to access elements at specific positions (for DUP and SWAP operations)
    • A getter for current stack size
// Simplified pop method
 pub fn pop(self: *Stack) !u256 {
     if (self.data.items.len == 0) {
         return error.StackUnderflow;
     }
-    return self.data.pop() orelse return error.StackUnderflow;
+    return self.data.pop();
 }

+// Add these useful methods for EVM operations
+pub fn peek(self: *Stack) !u256 {
+    if (self.data.items.len == 0) {
+        return error.StackUnderflow;
+    }
+    return self.data.items[self.data.items.len - 1];
+}
+
+pub fn at(self: *Stack, pos: usize) !u256 {
+    if (pos >= self.data.items.len) {
+        return error.StackUnderflow;
+    }
+    return self.data.items[self.data.items.len - 1 - pos];
+}
+
+pub fn size(self: *Stack) usize {
+    return self.data.items.len;
+}
src/Evm/Frame/StateManager.zig (1)

1-33: Mock implementation needs better initialization and documentation

The StateManager implementation provides a simple mock for testing, which is appropriate at this stage. A few improvements would make it more usable:

  1. Add an init method to configure the mock with test data
  2. Clearly document that the journaling methods are non-functional placeholders
  3. Add better documentation on how this mock would be used in tests
 /// State manager handles the EVM state (balances, code, storage)
 pub const StateManager = struct {
     // Simple implementation for testing
     mockCode: ?Bytes = null,
     
+    /// Initialize a mock state manager with optional test code
+    pub fn init(code: ?Bytes) StateManager {
+        return StateManager{
+            .mockCode = code,
+        };
+    }
+    
     pub fn checkpoint(_: *StateManager) JournalCheckpoint {
-        // Create a checkpoint in the state journal
+        // MOCK: This is a no-op mock implementation
+        // In a real implementation, this would create a checkpoint in the state journal
         return 0; // Placeholder
     }

Also, consider adding a TODO comment indicating that this will be replaced with a real implementation in the future. This helps clarify the temporary nature of this code.

src/Evm/Frame/ExecutionState.zig (1)

6-34: ExecutionState struct needs additional utility methods

The ExecutionState struct provides a solid foundation for tracking EVM execution state, but it lacks methods for manipulating the state during execution. This will likely make the code that uses this struct more verbose.

Consider adding methods for:

  1. Gas management (consume, refund)
  2. Return data manipulation
  3. Program counter manipulation
 /// EVM execution state 
 pub const ExecutionState = struct {
     memory: Memory,
     stack: Stack,
     pc: usize,
     gas: struct {
         remaining: u64, // Gas units remaining
         refunded: u64,  // Gas units refunded
     },
     returnData: Bytes,
     
     pub fn init(allocator: std.mem.Allocator, gasLimit: u64) ExecutionState {
         return ExecutionState{
             .memory = Memory.init(allocator),
             .stack = Stack.init(allocator),
             .pc = 0,
             .gas = .{
                 .remaining = gasLimit,
                 .refunded = 0,
             },
             .returnData = &[_]u8{},
         };
     }
     
     pub fn deinit(self: *ExecutionState) void {
         self.memory.deinit();
         self.stack.deinit();
     }
+    
+    // Gas management methods
+    pub fn consumeGas(self: *ExecutionState, amount: u64) !void {
+        if (amount > self.gas.remaining) {
+            return error.OutOfGas;
+        }
+        self.gas.remaining -= amount;
+    }
+    
+    pub fn refundGas(self: *ExecutionState, amount: u64) void {
+        self.gas.refunded += amount;
+    }
+    
+    // Program counter methods
+    pub fn advancePC(self: *ExecutionState, amount: usize) void {
+        self.pc += amount;
+    }
+    
+    pub fn jumpTo(self: *ExecutionState, target: usize) void {
+        self.pc = target;
+    }
+    
+    // Return data methods
+    pub fn setReturnData(self: *ExecutionState, data: Bytes) void {
+        self.returnData = data;
+    }
 };
src/Evm/Frame/FrameInput.zig (1)

5-34: FrameInput design is solid with minor documentation needs

The FrameInput union enum is well-structured for representing both calls and contract creations. A few suggestions:

  1. Add documentation for what "isStatic" means in EVM context
  2. Consider using a more explicit representation for CREATE vs CREATE2 than a nullable salt
     /// Standard call to address
     Call: struct {
         callData: Bytes,
         gasLimit: u64,
         target: address.Address,
         codeAddress: address.Address, // Address where code is loaded from
         caller: address.Address,
         value: u256,
         callType: CallScheme,
-        isStatic: bool,
+        isStatic: bool, // When true, state-changing operations are prohibited (used in STATICCALL)
     },
     
     /// Contract creation
     Create: struct {
         initCode: Bytes,
         gasLimit: u64,
         caller: address.Address,
         value: u256,
-        salt: ?[32]u8, // NULL for regular CREATE, non-null for CREATE2
+        salt: ?[32]u8, // NULL for regular CREATE (opcode 0xF0), non-null for CREATE2 (opcode 0xF5)
     },

Consider adding a utility method to get the caller address since it's common to both variants, similar to how you implemented getGasLimit.

+    pub fn getCaller(self: FrameInput) address.Address {
+        return switch (self) {
+            .Call => |call| call.caller,
+            .Create => |create| create.caller,
+        };
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c6d0cf1 and f9e7d3e.

📒 Files selected for processing (15)
  • src/Evm/Frame/Bytes.zig (1 hunks)
  • src/Evm/Frame/CallScheme.zig (1 hunks)
  • src/Evm/Frame/ExecutionState.zig (1 hunks)
  • src/Evm/Frame/Frame.zig (1 hunks)
  • src/Evm/Frame/FrameInput.zig (1 hunks)
  • src/Evm/Frame/FrameOrCall.zig (1 hunks)
  • src/Evm/Frame/FrameResult.zig (1 hunks)
  • src/Evm/Frame/InstructionResult.zig (1 hunks)
  • src/Evm/Frame/JournalCheckpoint.zig (1 hunks)
  • src/Evm/Frame/Memory.zig (1 hunks)
  • src/Evm/Frame/Stack.zig (1 hunks)
  • src/Evm/Frame/StateManager.zig (1 hunks)
  • src/Evm/evm.zig (2 hunks)
  • src/Evm/frame.zig (1 hunks)
  • src/Evm/frame_test.zig (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Nx Cloud Agents (1)
  • GitHub Check: Nx Cloud Agents (3)
  • GitHub Check: Nx Cloud Agents (6)
  • GitHub Check: Nx Cloud Agents (2)
  • GitHub Check: Nx Cloud Agents (5)
  • GitHub Check: Nx Cloud Agents (4)
  • GitHub Check: Nx Cloud - Main Job
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (23)
src/Evm/Frame/Bytes.zig (1)

1-1: Clear and concise type alias
The alias Bytes = []const u8 correctly represents an immutable byte slice for code, calldata, and return data throughout the frame modules.

src/Evm/Frame/JournalCheckpoint.zig (1)

1-2: Appropriate checkpoint alias
Defining JournalCheckpoint = usize clearly denotes a checkpoint index for journaling state changes. This will improve readability when managing commit/revert operations.

src/Evm/frame_test.zig (4)

3-4: Update imports for modular structure
The relative paths for address ("../Address/address.zig") and frame ("Frame.zig") now accurately reflect the new directory layout.


8-8: Disambiguate Frame reference with alias
Introducing ActualFrame = @import("Frame/Frame.zig").Frame avoids ambiguity between the re-export module and the concrete Frame struct.


29-35: Use ActualFrame.init for initialization
Switching from frame.Frame.init to ActualFrame.init ensures tests target the newly modularized Frame type.


65-72: Consistent use of ActualFrame in STOP execution test
Similarly updating the STOP opcode test to ActualFrame.init maintains consistency across all frame initialization tests.

src/Evm/Frame/FrameOrCall.zig (1)

1-10: Define FrameOrCall union for execution flow control
The FrameOrCall union enum cleanly models either a FrameResult or a follow-up FrameInput, aligning with the refactored execution pipeline. Imports for FrameResult and FrameInput are correctly referenced.

src/Evm/Frame/CallScheme.zig (1)

1-7: Introduce CallScheme enum to classify call types
The CallScheme enum covers all essential EVM call variants (Call, CallCode, DelegateCall, StaticCall). The type-level doc comment improves discoverability.

src/Evm/Frame/InstructionResult.zig (1)

1-12: Well-defined enum for instruction execution results.

This enum cleanly captures all the possible outcomes of EVM instruction execution, with clear, descriptive names following standard EVM terminology. The struct is properly documented and follows good Zig conventions.

src/Evm/evm.zig (3)

4-4: Import path updated to match new directory structure.

The capitalization change from "frame.zig" to "Frame.zig" aligns with the new modular file organization.


118-118: Return type now references explicit module path.

The return type is now explicitly importing from "Frame/Frame.zig" instead of using the imported frame module. This is consistent with the refactoring approach of modularizing the frame components.


123-123: Function call updated to use explicit module path.

The initialization now correctly references the Frame struct from its new location.

src/Evm/Frame/FrameResult.zig (2)

1-4: Appropriate imports for frame result dependencies.

The imports correctly reference the necessary dependencies for the frame result type, including the address module, instruction result enum, and bytes type.


5-21: Well-structured union enum for frame execution results.

The FrameResult type cleanly separates call and create operation results while sharing common fields (status, returnData, gas metrics). The addition of the optional createdAddress field for the Create variant is appropriate.

src/Evm/Frame/Memory.zig (3)

1-16: Well-implemented memory management with proper initialization/cleanup.

The Memory struct is properly initialized with an ArrayList and includes appropriate deinitialization to avoid memory leaks. Good Zig practices for memory management are followed.


17-25: Effective memory store implementation with auto-resizing.

The store method correctly handles resizing the underlying memory buffer when needed and uses efficient memory copying for the actual data storage.


27-34: Safe memory load implementation with bounds checking.

The load method safely handles out-of-bounds requests by returning an empty slice and properly clamps the end position to avoid overruns. This approach is appropriate for EVM memory access patterns.

src/Evm/frame.zig (1)

1-19: Well-structured modular design with clear organization

The refactoring of this file into a central re-export module demonstrates excellent software engineering practices. Breaking down the monolithic file into focused components while maintaining backward compatibility with usingnamespace is a solid approach. The clear comments also help document the purpose of this file as the main entry point for the Frame module.

src/Evm/Frame/Frame.zig (5)

1-22: Clean import structure with appropriate scoping

The import structure is well-organized, clearly separated into standard library imports, address imports, frame component imports, and logging configuration. Using a scoped logger for Frame-related logs will help with debugging and log filtering.


23-36: Well-documented Frame struct with clear field descriptions

The Frame struct design effectively encapsulates all the components needed for an EVM execution context. Each field has a descriptive comment explaining its purpose, which enhances readability and maintainability.


37-54: Clean initialization pattern

The init function follows a clear pattern for initialization, extracting the gas limit from the input and properly initializing all fields. This approach ensures the Frame is always in a valid state when created.


56-58: Proper resource cleanup

The deinit method appropriately calls deinit on the state to ensure all resources are properly cleaned up, which is essential for memory management.


60-111: Comprehensive debug logging implementation

The debug method provides extensive logging of frame state, making it valuable for troubleshooting. The use of pattern matching on the input type to display relevant information is particularly well-implemented.

Comment on lines 113 to 166
/// Execute the frame until completion or a new call is needed
pub fn execute(self: *Frame, stateManager: *StateManager) !FrameOrCall {
// Simple implementation for initial tests
// Just check for basic opcodes and handle them
log.debug("Starting execution", .{});
_ = stateManager; // Silence unused parameter warning

if (self.code.len == 0) {
log.debug("Empty code, returning success", .{});
// Empty code returns success
return FrameOrCall{
.Result = FrameResult{
.Call = .{
.status = .Success,
.returnData = &[_]u8{},
.gasUsed = self.input.getGasLimit() - self.state.gas.remaining,
.gasRefunded = self.state.gas.refunded,
}
}
};
}

log.debug("Code length is {d}, first byte: {x:0>2}", .{self.code.len, self.code[0]});

// In a real implementation, we would loop through the bytecode and interpret opcodes
// but for this simplified version, we'll just check for STOP (0x00)
if (self.code[0] == 0x00) {
log.debug("Found STOP opcode, returning success", .{});
// STOP opcode
return FrameOrCall{
.Result = FrameResult{
.Call = .{
.status = .Success,
.returnData = &[_]u8{},
.gasUsed = self.input.getGasLimit() - self.state.gas.remaining,
.gasRefunded = self.state.gas.refunded,
}
}
};
}

log.debug("Unknown opcode, returning InvalidOpcode", .{});
// Default response for other opcodes (not yet implemented)
return FrameOrCall{
.Result = FrameResult{
.Call = .{
.status = .InvalidOpcode,
.returnData = &[_]u8{},
.gasUsed = self.input.getGasLimit() - self.state.gas.remaining,
.gasRefunded = self.state.gas.refunded,
}
}
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Simplified execution logic needs expansion

The execute method provides a simplified implementation that handles only basic cases (empty code and STOP opcode). While this is a good starting point for the refactoring, it will need to be expanded to handle the full range of EVM opcodes.

Consider documenting the roadmap for implementing the full EVM opcode set, either as TODOs in the code or in a separate document. This would help track progress and ensure no opcodes are missed during implementation.


🏁 Script executed:

#!/bin/bash
# Check if there's any documentation or TODOs about implementing the remaining opcodes
echo "Searching for documentation about opcode implementation..."
rg -i "todo|implement|opcode|evm instruction" --glob "*.{zig,md}" ./src/Evm

Length of output: 8334


Reference the existing opcode roadmap in code and docs

The high-level roadmap for implementing the full EVM instruction set already lives in src/Evm/README.md (see “Instruction Set: Implementation of all EVM opcodes”) and is fleshed out in src/Evm/README-COMPLETE.md. To tie the simplified execute stub to that roadmap and make progress visible:

  • In src/Evm/Frame/Frame.zig (lines 113–166), add a // TODO: comment above the placeholder logic, e.g.:
    // TODO: replace this stub with a full opcode interpreter as per
    //       src/Evm/README.md#instruction-set
  • Optionally expand README.md (or a new checklist) with a per-opcode implementation status, so teams can tick off groups (arithmetic, bitwise, memory, control flow, etc.) as they’re done.
  • Keep README-COMPLETE.md in sync with each completed opcode or group.
🤖 Prompt for AI Agents
In src/Evm/Frame/Frame.zig around lines 113 to 166, the execute function
currently only handles empty code and the STOP opcode, lacking implementation
for the full EVM opcode set. Add a TODO comment above the existing placeholder
logic indicating that this stub should be replaced with a full opcode
interpreter referencing src/Evm/README.md#instruction-set. Optionally, update
README.md with a per-opcode implementation status checklist to track progress
and keep README-COMPLETE.md synchronized with completed opcodes.

@vercel vercel bot temporarily deployed to Preview – node May 16, 2025 04:18 Inactive
Copy link
Contributor
@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (2)
src/Evm/evm.zig (1)

117-124: Consider using type aliases instead of direct imports in function signatures.

The direct imports to "Frame/Frame.zig" in both the return type and function call create a tight coupling to the file structure, which could be problematic if the directory structure changes.

- pub fn createFrame(self: Evm, input: frame.FrameInput, code: []const u8, depth: u16) !@import("Frame/Frame.zig").Frame {
+ pub fn createFrame(self: Evm, input: frame.FrameInput, code: []const u8, depth: u16) !frame.Frame {

And then update line 123 similarly:

- return try @import("Frame/Frame.zig").Frame.init(self.allocator, input, code, depth, checkpoint);
+ return try frame.Frame.init(self.allocator, input, code, depth, checkpoint);

This assumes that frame.zig re-exports the Frame type from Frame/Frame.zig.

src/Evm/Frame_test.zig (1)

7-14: Consider using re-exported types instead of direct imports.

Similar to the suggestion for evm.zig, consider using the types re-exported through frame.zig instead of direct imports from specific files to reduce coupling to the file structure.

- // Use this to avoid ambiguous reference
- const ActualFrame = @import("Frame/Frame.zig").Frame;
+ // Use the re-exported Frame type
+ const ActualFrame = frame.Frame;

This would make the code more resilient to future changes in the file organization.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c8e2b83 and a7059b0.

📒 Files selected for processing (3)
  • src/Evm/Frame/FrameInput.zig (1 hunks)
  • src/Evm/Frame_test.zig (1 hunks)
  • src/Evm/evm.zig (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Nx Cloud Agents (5)
  • GitHub Check: Nx Cloud Agents (3)
  • GitHub Check: Nx Cloud Agents (2)
  • GitHub Check: Nx Cloud Agents (6)
  • GitHub Check: Nx Cloud Agents (4)
  • GitHub Check: Nx Cloud Agents (1)
  • GitHub Check: Nx Cloud - Main Job
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (11)
src/Evm/Frame/FrameInput.zig (3)

1-42: Well-structured union enum design for frame inputs.

The FrameInput union enum is designed with clear separation of concerns for different call types. The inclusion of detailed comments explaining each variant is helpful, and the getGasLimit utility method provides consistent access to the gas limit across all variants.


26-33: Good addition of CREATE2 support.

The CREATE2 variant with its salt parameter is properly implemented, enhancing the EVM functionality to support this important opcode. The documentation comment clearly indicates its purpose.


35-41: Clean implementation of the getGasLimit method.

The getGasLimit method provides a clean abstraction that encapsulates implementation details of each variant, making it easier for calling code to access gas limits without needing to handle each variant separately.

src/Evm/evm.zig (4)

4-4: Import path updated for the new modular structure.

The import of the frame module has been updated to use the new structure, maintaining backward compatibility through re-exports.


145-151: Proper handling of CREATE2 variant in execute function.

The CREATE2 variant is handled consistently with the CREATE variant, with good logging of relevant details including gas limit, code length, and salt.


177-178: Consistent handling of both CREATE and CREATE2 results.

The condition has been updated to handle both CREATE and CREATE2 inputs consistently when converting between result types, which is correct.


303-334: Good test coverage for CREATE2 functionality.

The new test for the CREATE2 variant provides appropriate coverage for this new feature, ensuring that it works correctly with the rest of the system.

src/Evm/Frame_test.zig (4)

15-49: Thorough test for frame initialization with Call input.

The test provides good coverage for frame initialization with Call input, checking all the essential values like depth, gas, and code.


51-84: Comprehensive test for frame initialization with Create input.

The test thoroughly verifies frame initialization with Create input, including checking the getGasLimit method.


275-296: Good test for frame debugging with CREATE2 input.

The test verifies that debugging doesn't crash with both standard Call input and the new CREATE2 input, which is important for code stability.


1-388: Comprehensive test suite for frame functionality.

The test file provides excellent coverage for the frame functionality, including initialization, execution, debugging, stack and memory operations, and simple EVM execution. This ensures that the refactored code works as expected.

Comment on lines +389 to +417
test "EVM simple execution - create" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

var stateManager = frame.StateManager{};
var testEvm = evm.Evm.init(allocator, &stateManager);

const createInput = FrameInput{
.Create = .{
.initCode = &[_]u8{0x00}, // Simple STOP opcode
.gasLimit = 100000,
.caller = address.ZERO_ADDRESS,
.value = 0,
.salt = null, // Regular CREATE (not CREATE2)
},
};

// Execute the frame to create a contract
const result = try testEvm.execute(createInput);

try testing.expect(result == .Create);
switch (result) {
.Create => |createResult| {
try testing.expectEqual(InstructionResult.Success, createResult.status);
},
else => unreachable,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Issue with salt field in Create variant.

The Create variant in the test includes a salt: null field, but according to the FrameInput definition in FrameInput.zig, the Create variant doesn't have a salt field.

const createInput = FrameInput{
    .Create = .{
        .initCode = &[_]u8{0x00},  // Simple STOP opcode
        .gasLimit = 100000,
        .caller = address.ZERO_ADDRESS,
        .value = 0,
-       .salt = null, // Regular CREATE (not CREATE2)
    },
};

This field should be removed as it doesn't exist in the Create variant and could lead to compilation errors.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test "EVM simple execution - create" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var stateManager = frame.StateManager{};
var testEvm = evm.Evm.init(allocator, &stateManager);
const createInput = FrameInput{
.Create = .{
.initCode = &[_]u8{0x00}, // Simple STOP opcode
.gasLimit = 100000,
.caller = address.ZERO_ADDRESS,
.value = 0,
.salt = null, // Regular CREATE (not CREATE2)
},
};
// Execute the frame to create a contract
const result = try testEvm.execute(createInput);
try testing.expect(result == .Create);
switch (result) {
.Create => |createResult| {
try testing.expectEqual(InstructionResult.Success, createResult.status);
},
else => unreachable,
}
}
test "EVM simple execution - create" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var stateManager = frame.StateManager{};
var testEvm = evm.Evm.init(allocator, &stateManager);
const createInput = FrameInput{
.Create = .{
.initCode = &[_]u8{0x00}, // Simple STOP opcode
.gasLimit = 100000,
.caller = address.ZERO_ADDRESS,
.value = 0,
},
};
// Execute the frame to create a contract
const result = try testEvm.execute(createInput);
try testing.expect(result == .Create);
switch (result) {
.Create => |createResult| {
try testing.expectEqual(InstructionResult.Success, createResult.status);
},
else => unreachable,
}
}
🤖 Prompt for AI Agents
In src/Evm/Frame_test.zig between lines 389 and 417, the test code for the
Create variant incorrectly includes a salt field, which is not defined in the
FrameInput Create variant. Remove the salt: null field from the createInput
initialization to match the FrameInput definition and avoid compilation errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant
0