8000 ✨ feat: implement isomorphic logging system and add comprehensive debug logging by roninjin10 · Pull Request #1798 · evmts/tevm-monorepo · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

✨ feat: implement isomorphic logging system and add comprehensive debug logging #1798

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 1 commit into from
Jun 8, 2025

Conversation

roninjin10
Copy link
Collaborator
@roninjin10 roninjin10 commented Jun 8, 2025

Description

Added comprehensive logging infrastructure to the EVM implementation to improve debugging and traceability. The changes include:

  1. Enhanced the log.zig module with isomorphic logging that works across all target architectures (native, WASI, WASM)
  2. Added detailed debug logging in critical EVM components:
    • Storage operations in evm_state.zig
    • Opcode execution in jump_table.zig
    • Memory operations in memory.zig
    • Stack operations in stack.zig
    • VM initialization and execution in vm.zig
  3. Implemented a new std_options.zig file with a custom logging function that adapts to different environments
  4. Added WASM-specific logging capabilities with buffer management and JavaScript interop

Testing

The logging system has been tested across multiple platforms to ensure consistent behavior. Debug logs are optimized away in release builds to maintain performance. The implementation follows best practices for thread safety with mutex protection for the shared log buffer.

Additional Information

Your ENS/address:

Summary by CodeRabbit

  • New Features

    • Introduced enhanced logging capabilities, including debug, info, warning, and error logs, with improved support across native, WASI, and WASM environments.
    • Added platform-adaptive logging that works seamlessly in browser-based WASM, including a JavaScript console log bridge and log buffer access.
  • Improvements

    • Added detailed runtime logging for EVM state, memory, stack, and VM lifecycle events to aid in diagnostics and traceability.
    • Expanded logging APIs for more granular control and visibility during execution.

@vercel vercel bot temporarily deployed to Preview – node June 8, 2025 00:31 Inactive
Copy link
vercel bot commented Jun 8, 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 Jun 8, 2025 1:04am
2 Skipped Deployments
Name Status Preview Updated (UTC)
tevm-monorepo-tevm ⬜️ Ignored (Inspect) Jun 8, 2025 1:04am
node ⬜️ Skipped (Inspect) Jun 8, 2025 1:04am

Copy link
changeset-bot bot commented Jun 8, 2025

⚠️ No Changeset found

Latest commit: 2dcf0be

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 Jun 8, 2025

Walkthrough

This change introduces comprehensive debug and informational logging throughout the EVM codebase. Logging statements are added to key operations in modules such as state, memory, stack, VM, and jump table, providing runtime diagnostics and traceability. A new isomorphic logging infrastructure is implemented to support consistent logging across native, WASI, and WASM platforms.

Changes

File(s) Change Summary
src/evm/evm_state.zig, src/evm/vm.zig Added debug logging to initialization, execution, and storage access functions for traceability.
src/evm/jump_table.zig Inserted detailed debug logs in opcode execution for diagnostics, including error and gas consumption logs.
src/evm/memory.zig Added debug logs to memory resizing and byte-setting functions for tracking memory operations.
src/evm/stack.zig Introduced debug logs for stack overflow, underflow, push, and pop events in stack operations.
src/evm/log.zig Replaced previous logger with a new API supporting debug, info, warn, and error levels, using std.log.
src/std_options.zig New file: Implements platform-adaptive logging, including WASM log buffer, and exposes buffer accessors.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant EVM_Module
    participant Logger
    participant Platform (Native/WASI/WASM)

    User->>EVM_Module: Invoke operation (e.g., stack.push, vm.init)
    EVM_Module->>Logger: Call log function (debug/info/warn/err)
    Logger->>Platform: Dispatch to platform-appropriate log handler
    Platform-->>Logger: Log message handled (console, buffer, stderr, etc.)
Loading

Possibly related PRs

  • evmts/tevm-monorepo#1724: Refactors the Stack module, which is also affected by added logging in this PR.
  • evmts/tevm-monorepo#1774: Implements and tests the JumpTable.execute function, which now receives additional debug logging in this PR.

Poem

🐇
In bytes and stacks, the logs now gleam,
Across WASM, native, every scheme.
Debug and info, warn and err,
Now every hop is seen, not just inferred.
The EVM’s heart beats clear and bright—
With logs, we trace each rabbit’s flight!


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 June 8, 2025 00:33
Base automatically changed from no-inline to main June 8, 2025 00:59
…ug logging

Implement cross-platform logging system using std_options.logFn that works consistently across
all target architectures including native platforms, WASI, and WASM environments. Add comprehensive
debug logging throughout core EVM components for better development experience and debugging.

## Implementation Strategy

### Step 1: Create std_options configuration
- Created src/std_options.zig with custom logFn for multi-platform support
- Compile-time target detection for zero runtime overhead
- Platform-specific backends: native (stderr), WASI (stderr), WASM (buffer + JS interop)
- Dead code elimination removes unused backends

### Step 2: Platform-specific logging backends
- Native platforms: Use std.log.defaultLog for stderr/stdout
- WASI: stderr writer with proper error handling
- WASM (freestanding): Dual approach with buffer + optional JS console interop
- Export functions for JS integration: getLogBuffer(), getLogBufferLen(), clearLogBuffer()
- Thread-safe buffer management with mutex protection

### Step 3: Update existing logging module
- Modified src/evm/log.zig to use std.log for isomorphic behavior
- Removed inline keywords for consistent bundle size optimization
- Added info() function for general information logging
- Maintained EVM-specific log prefixing for easy identification

### Step 4: Add comprehensive debug logging
- VM execution: initialization, interpretation context, depth tracking
- Jump table: opcode execution, gas consumption, validation errors
- State management: storage operations, initialization tracking
- Stack operations: push/pop operations, overflow/underflow detection
- Memory management: resize operations, byte access, limit enforcement

## Technical Specifications

### File Structure
- src/std_options.zig (new): Isomorphic logging configuration
- src/evm/log.zig (modified): Updated API using std.log
- src/evm/vm.zig (modified): Added VM execution logging
- src/evm/jump_table.zig (modified): Added opcode dispatch logging
- src/evm/evm_state.zig (modified): Added state operation logging
- src/evm/stack.zig (modified): Added stack operation logging
- src/evm/memory.zig (modified): Added memory operation logging

### Target Platform Support
- linux, macos, windows, freebsd: Native stderr/stdout logging
- wasi: WASM with system interface support
- freestanding + wasm32/wasm64: Browser/Node.js WASM environments
- Other platforms: Fallback to default or no-op logging

### Performance Considerations
- Compile-time target detection (zero runtime overhead)
- Debug logs optimized away in release builds
- Efficient buffer management for WASM (8KB buffer with wraparound)
- Mutex protection for thread-safe buffer access
- Minimal memory footprint for embedded targets

### Error Handling
- All logging errors are non-fatal
- Graceful fallback when JS interop unavailable
- Buffer overflow protection with safe wraparound
- Memory allocation failure handling
- Silent operation in resource-constrained environments

## Success Criteria Achieved

### Functional
✅ Logging works identically across all target platforms
✅ WASM builds compile and run without logging errors
✅ Existing codebase requires no changes to logging calls
✅ JavaScript can read logs from WASM modules via exported functions
✅ Comprehensive debug logging added to core EVM components

### Quality
✅ Code follows project style guidelines (snake_case, 120 char width)
✅ Implementation is maintainable and well-documented
✅ Performance overhead is minimal (compile-time optimization)
✅ Error handling is robust and non-intrusive
✅ All tests pass (zig build test-all)

### Integration
✅ Seamless replacement of existing logging system
✅ No disruption to development workflow
✅ Clear path for future logging enhancements
✅ Compatible with existing build system and CI
✅ Maintains API compatibility while improving functionality

The isomorphic logging system enables consistent debugging across all deployment targets
while the comprehensive debug logging provides detailed insights into EVM execution flow,
making development and troubleshooting significantly more effective.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
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/std_options.zig (2)

136-140: Consider making the JS message buffer size configurable

The fixed buffer size of 2048 bytes might be insufficient for complex log messages with multiple arguments. While truncation is handled gracefully, important debugging information could be lost.

Consider making this configurable or using a larger default:

-    var buf: [2048]u8 = undefined;
+    const js_log_buffer_size = if (@hasDecl(@import("root"), "js_log_buffer_size")) 
+        @import("root").js_log_buffer_size 
+    else 
+        4096;
+    var buf: [js_log_buffer_size]u8 = undefined;

14-48: Excellent isomorphic logging architecture!

The platform detection and dispatching logic provides comprehensive coverage across different target architectures. The separation of platform-specific implementations makes the code maintainable and extensible.

For future enhancements, consider:

  1. Adding log rotation for long-running WASM applications
  2. Implementing configurable log levels per module/scope
  3. Adding structured logging support for easier parsing by external tools
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 716a06f and 2dcf0be.

📒 Files selected for processing (7)
  • src/evm/evm_state.zig (4 hunks)
  • src/evm/jump_table.zig (2 hunks)
  • src/evm/log.zig (1 hunks)
  • src/evm/memory.zig (2 hunks)
  • src/evm/stack.zig (3 hunks)
  • src/evm/vm.zig (2 hunks)
  • src/std_options.zig (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Nx Cloud - Main Job
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: CI Checks
🔇 Additional comments (10)
src/evm/memory.zig (2)

154-159: LGTM: Clear and useful debug logging for memory operations.

The debug logs provide valuable visibility into memory resize operations and limit violations without affecting the core logic. Format strings correctly match the provided arguments.


246-246: LGTM: Helpful debug logging for memory write operations.

The hex formatting of the byte value (0x{x:0>2}) provides clear visibility into memory writes during debugging.

src/evm/vm.zig (2)

74-74: LGTM: Clear VM initialization lifecycle logging.

The debug logs provide useful tracing of VM initialization start and completion, enhancing observability without affecting functionality.

Also applies to: 82-82


144-144: LGTM: Comprehensive execution context logging.

The debug log captures key execution parameters (depth, gas, static mode) that are essential for debugging EVM execution flows.

src/evm/evm_state.zig (3)

92-92: LGTM: Consistent state initialization logging.

The debug logs follow the same clear pattern as VM initialization, providing useful lifecycle tracing for the EVM state component.

Also applies to: 112-112


167-169: LGTM: Valuable storage read tracing.

The debug logging provides excellent visibility into storage access patterns. The use of Address.to_u256(address) for consistent address formatting is appropriate.


190-190: LGTM: Consistent storage write logging.

The debug log maintains consistency with the get_storage logging format, providing complete traceability for storage operations.

src/evm/jump_table.zig (1)

127-127: LGTM: Comprehensive opcode execution tracing.

The debug logging provides excellent visibility into opcode execution flow:

  • Execution context (opcode, PC, gas, stack size)
  • Invalid opcode detection
  • Gas consumption tracking
  • Execution completion status

All format strings correctly match their arguments and the logging enhances debugging capabilities without affecting performance in release builds.

Also applies to: 130-130, 139-139, 144-144

src/evm/stack.zig (1)

2-2: Well-placed debug logging for stack operations!

The debug logging additions provide excellent visibility into stack operations:

  • Overflow/underflow conditions are logged with current state
  • Successful operations log the values and new size
  • All debug logs will be optimized out in release builds

Also applies to: 104-108, 144-151

src/evm/log.zig (1)

1-29: Clean and idiomatic logging API!

The refactored logging module properly leverages Zig's standard logging system with appropriate EVM-specific prefixing. The direct use of std.log functions ensures platform compatibility through the std_options configuration.

Comment on lines +79 to +125
/// Global log buffer for WASM environments
var log_buffer: [8192]u8 = undefined;
var log_buffer_pos: usize = 0;
var log_buffer_mutex: std.Thread.Mutex = .{};

/// Write log message to buffer that JavaScript can read
fn writeToLogBuffer(
comptime level: std.log.Level,
comptime scope: @Type(.enum_literal),
comptime format: []const u8,
args: anytype,
) void {
log_buffer_mutex.lock();
defer log_buffer_mutex.unlock();

// Reserve space for potential wraparound
const available_space = log_buffer.len - log_buffer_pos;
if (available_space < 512) {
log_buffer_pos = 0; // Wrap around if near end
}

var fbs = std.io.fixedBufferStream(log_buffer[log_buffer_pos..]);
const writer = fbs.writer();

writer.print("[{s}] ({s}): " ++ format ++ "\n", .{
@tagName(level), @tagName(scope)
} ++ args) catch return;

log_buffer_pos += fbs.pos;
}

/// Export function to get log buffer pointer for JavaScript
export fn getLogBuffer() [*]const u8 {
return &log_buffer;
}

/// Export function to get current log buffer length
export fn getLogBufferLen() usize {
return log_buffer_pos;
}

/// Export function to clear the log buffer
export fn clearLogBuffer() void {
log_buffer_mutex.lock();
defer log_buffer_mutex.unlock();
log_buffer_pos = 0;
}
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

❓ Verification inconclusive

Thread safety concern in WASM log buffer implementation

The mutex only protects write operations but not the exported read functions. This could lead to race conditions where JavaScript reads partially written or corrupted data while Zig is writing.

Additionally, the wraparound logic at lines 95-98 silently discards old logs without any indication. Consider implementing a proper circular buffer or at least adding a marker to indicate log truncation.

Apply this diff to add read protection:

 export fn getLogBuffer() [*]const u8 {
+    log_buffer_mutex.lock();
+    defer log_buffer_mutex.unlock();
     return &log_buffer;
 }
 
 export fn getLogBufferLen() usize {
+    log_buffer_mutex.lock();
+    defer log_buffer_mutex.unlock();
     return log_buffer_pos;
 }

Note: This assumes JavaScript calls are synchronous. If async access is needed, consider implementing a double-buffering strategy.


Improve WASM log buffer initialization, wraparound handling, and read consistency

A few safety and observability issues remain in the current implementation:

  • Uninitialized buffer:
    var log_buffer: [8192]u8 = undefined; exposes arbitrary memory on the first read.
  • Silent wraparound:
    When available_space < 512, the code resets log_buffer_pos = 0 without any marker, losing the fact that older entries were discarded.
  • Inconsistent reads:
    Separately exporting getLogBuffer() and getLogBufferLen() allows logs to be written between calls, leading to mismatched pointer/length and potential corruption.

Suggested fixes:

• Initialize the buffer (e.g. zero it out) either at declaration or in clearLogBuffer().
• At wraparound, write a truncation marker (e.g. "[...truncated...]\n") before resetting, or convert to a true circular buffer.
• Replace the two getters with a single snapshot function that locks, copies the active slice under one lock, then returns both pointer and length atomically.

Pinpoint locations:

  • src/std_options.zig: line 79 (var log_buffer: [8192]u8 = undefined;)
  • src/std_options.zig: lines 95–98 (wraparound logic)
  • src/std_options.zig: lines 107–113 (getLogBuffer() / getLogBufferLen())

Example snapshot API:

pub fn snapshotLogBuffer(allocator: *std.mem.Allocator) ![]u8 {
    log_buffer_mutex.lock();
    defer log_buffer_mutex.unlock();
    const len = log_buffer_pos;
    var out = try allocator.alloc(u8, len);
    std.mem.copy(u8, out, log_buffer[0..len]);
    return out;
}
🤖 Prompt for AI Agents
In src/std_options.zig around lines 79 to 125, fix the uninitialized log_buffer
by zero-initializing it at declaration or in clearLogBuffer(). Modify the
wraparound logic at lines 95-98 to write a truncation marker like
"[...truncated...]\n" before resetting log_buffer_pos to 0 to indicate discarded
logs. Replace the separate getLogBuffer() and getLogBufferLen() functions at
lines 107-113 with a single snapshotLogBuffer() function that locks the mutex,
copies the current log slice into a newly allocated buffer, and returns it
atomically to ensure consistent reads without race conditions.

@roninjin10 roninjin10 merged commit dc41cd4 into main Jun 8, 2025
10 checks passed
@roninjin10 roninjin10 deleted the isomorphic branch June 8, 2025 01:47
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