Skip to content

Conversation

@chatton
Copy link
Contributor

@chatton chatton commented Jan 8, 2026

Overview

This PR follows the same pattern as the previous PR and creates a decorator around the eth client that injects tracing.

Sample grafana output with metrics enabled.

image image

@github-actions
Copy link
Contributor

github-actions bot commented Jan 8, 2026

The latest Buf updates on your PR. Results from workflow CI / buf-check (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed⏩ skipped✅ passed✅ passedJan 12, 2026, 3:02 PM

@claude
Copy link
Contributor

claude bot commented Jan 8, 2026

Claude finished @chatton's task in 1m 57s —— View job


Comprehensive Code Review

I've completed a thorough review of this PR which adds OpenTelemetry tracing for Ethereum RPC client interactions. The implementation follows the same decorator pattern as the Engine API tracing and is well-structured overall. Below is my detailed feedback organized by category.


Architecture & Design Patterns

Strengths:

  • Clean decorator pattern: The tracedEthRPCClient correctly wraps EthRPCClient without modifying the core implementation (execution/evm/eth_rpc_tracing.go:14-26)
  • Proper interface abstraction: The new EthRPCClient interface (execution/evm/execution.go:145-152) provides good separation of concerns and enables easier testing/mocking
  • Consistent with existing patterns: This follows the exact same structure as EngineRPCClient tracing, maintaining architectural consistency
  • Conditional decoration: Tracing is only applied when enabled (execution/evm/execution.go:240-243), avoiding overhead when not needed

Minor Observations:

  • The interface is well-scoped with only 2 methods, avoiding over-abstraction
  • The tracer name "ev-node/execution/eth-rpc" (eth_rpc_tracing.go:24) is consistent with the Engine RPC naming convention

Error Handling & Resilience

Strengths:

  • Proper error propagation: Both traced methods correctly propagate errors without modification (eth_rpc_tracing.go:45-48, 72-74)
  • Error recording: Uses span.RecordError(err) and span.SetStatus(codes.Error, err.Error()) following OpenTelemetry best practices
  • No panic risks: All code paths handle nil cases appropriately (e.g., number == nil check at eth_rpc_tracing.go:30-34)

Good Practice:

  • Error spans are properly marked with codes.Error status, making them easily filterable in tracing backends

Testing & Reliability

Strengths:

  • Comprehensive test coverage: Tests cover success cases, error cases, edge cases (nil block number, empty tx pool), and attribute validation
  • Proper test structure: Uses table-driven patterns where appropriate and clear test names
  • Mock implementation: The mockEthRPCClient (eth_rpc_tracing_test.go:41-58) is simple and functional
  • Test helper for setup: setupTestEthRPCTracing (eth_rpc_tracing_test.go:18-38) provides clean test initialization with proper cleanup
  • Attribute validation helper: requireAttribute (eth_rpc_tracing_test.go:281-301) handles multiple attribute types correctly

Issues Identified:

🔴 Critical: Test assertion logic is confusing and incomplete (eth_rpc_tracing_test.go:172-178)

The loop to verify that block header attributes are NOT set on error is hard to follow and missing the timestamp attribute check:

for _, attr := range attrs {
    key := string(attr.Key)
    require.NotEqual(t, "block_hash", key)
    require.NotEqual(t, "state_root", key)
    require.NotEqual(t, "gas_limit", key)
    require.NotEqual(t, "gas_used", key)
    // ❌ Missing: timestamp check!
}

Recommended fix (as Gemini also noted):

for _, attr := range attrs {
    switch string(attr.Key) {
    case "block_hash", "state_root", "gas_limit", "gas_used", "timestamp":
        t.Fatalf("unexpected attribute %q found on error span", attr.Key)
    }
}

This is clearer and complete. Fix this →

🟡 Medium: Inconsistent error attribute validation (eth_rpc_tracing_test.go:274-277)

The GetTxs error test uses a different pattern that could be clearer:

for _, attr := range attrs {
    require.NotEqual(t, "tx_count", string(attr.Key))
}

Recommended improvement:

for _, attr := range attrs {
    if string(attr.Key) == "tx_count" {
        t.Fatalf("unexpected attribute 'tx_count' found on error span")
    }
}

This makes the intent explicit and matches the pattern suggested above. Fix this →


Security

Good practices observed:

  • No sensitive data (credentials, private keys) exposed in traces
  • Block hashes and transaction counts are safe to include in observability data
  • The JWT secret handling remains unchanged and is not exposed through tracing
  • Context propagation via W3C headers (execution.go:200-201) is properly scoped to when tracing is enabled

No security concerns identified


Performance & Resource Efficiency

Strengths:

  • Conditional overhead: Tracing is only active when tracingEnabled=true, avoiding performance impact in production when disabled
  • Minimal allocation: Span attributes are set efficiently, and the decorator pattern adds negligible overhead
  • Reuses context: The traced context is properly passed through to inner calls (eth_rpc_tracing.go:44, 70)

Observations:

  • The block_number string conversion (eth_rpc_tracing.go:29-34) is lightweight
  • Attribute allocation is reasonable for observability use cases
  • No goroutine leaks or blocking operations introduced

No performance concerns


Code Quality & Go Idioms

Strengths:

  • Idiomatic Go: Follows effective Go guidelines (interfaces, error handling, package structure)
  • Clear naming: tracedEthRPCClient, withTracingEthRPCClient clearly indicate purpose
  • Proper use of defer: defer span.End() ensures spans are always closed (eth_rpc_tracing.go:42, 68)
  • Interface compliance check: var _ EthRPCClient = (*ethRPCClient)(nil) could be added but isn't critical (unlike engine_rpc_tracing.go:13 which has it)

Minor suggestion:
Consider adding a compile-time interface check in eth_rpc_tracing.go:

var _ EthRPCClient = (*tracedEthRPCClient)(nil)

This is a nice-to-have for catching interface changes at compile time. Add this →


Documentation & Code Comments

Strengths:

  • Clear godoc comments: Both interfaces and methods have descriptive comments
  • Inline explanations: The "latest" block number handling has a clear comment (eth_rpc_tracing.go:30-34)
  • Test documentation: Test helper functions are properly documented

Good enough ✓ - Documentation is adequate for this decorator implementation.


📊 Observability Value

The Grafana screenshots show excellent observability improvements:

  • Clear visibility into EVM execution flow with Eth.GetBlockByNumber and TxPool.GetTxs spans
  • Useful attributes captured (block hash, state root, gas metrics, tx count, timestamps)
  • Integration with existing Engine API traces provides complete execution layer visibility

The tracing implementation will be valuable for:

  • Performance debugging (identifying slow RPC calls)
  • Understanding execution patterns
  • Detecting anomalies in block fetching or transaction pool behavior

📋 Summary & Recommendations

Overall Assessment: ✅ This is a solid, well-tested implementation that maintains architectural consistency and adds valuable observability. The code is production-ready with minor test improvements recommended.

Required Changes:

  1. Fix the incomplete attribute check in TestTracedEthRPCClient_HeaderByNumber_Error (missing timestamp)

Recommended Improvements:
2. 🟡 Make error attribute validation more consistent and explicit in TestTracedEthRPCClient_GetTxs_Error
3. 🟡 Add compile-time interface check for tracedEthRPCClient

Approval Recommendation: Approve after fixing the test assertion gap (item #1). Items #2-3 are nice-to-haves.


All CI checks passing (Buf, Codecov at 57.76%)
No breaking changes
Follows repository patterns and Go best practices

Great work on maintaining consistency with the existing tracing infrastructure!


@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @chatton, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the observability of Ethereum RPC interactions within the EVM execution engine by integrating OpenTelemetry tracing. It refactors the existing EngineClient to utilize a new EthRPCClient interface, allowing for a clean separation of concerns and the introduction of a tracing decorator. This change ensures that critical Ethereum API calls, such as fetching block headers and transaction pool content, are automatically instrumented with detailed tracing information, providing better insights into performance and potential issues.

Highlights

  • New EthRPCClient Interface: Introduced an EthRPCClient interface in execution.go to abstract Ethereum JSON-RPC calls, enabling easier mocking and decoration (e.g., for tracing).
  • Concrete EthRPCClient Implementation: Added eth_rpc_client.go which provides a concrete implementation of the EthRPCClient interface, wrapping the standard go-ethereum/ethclient.
  • OpenTelemetry Tracing for EthRPCClient: Implemented eth_rpc_tracing.go which contains tracedEthRPCClient, a decorator that wraps an EthRPCClient and adds OpenTelemetry spans for HeaderByNumber and GetTxs methods, including relevant attributes and error handling.
  • Integration into EngineClient: Modified EngineClient in execution.go to use the new EthRPCClient interface. The NewEngineExecutionClient constructor now conditionally wraps the ethclient with the tracing decorator if tracing is enabled.
  • Unit Tests for Tracing: Added eth_rpc_tracing_test.go with comprehensive unit tests for the tracedEthRPCClient, verifying span creation, attribute setting, and error reporting for both successful and failed RPC calls.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces OpenTelemetry tracing for Ethereum RPC client interactions. The changes are well-structured, using a decorator pattern to add tracing capabilities without modifying the core client logic. A new EthRPCClient interface is introduced, which improves modularity and testability. The accompanying tests are thorough and cover success and error cases for the new tracing functionality. My feedback includes a couple of suggestions to improve the clarity and completeness of the test assertions.

Comment on lines +172 to +178
for _, attr := range attrs {
key := string(attr.Key)
require.NotEqual(t, "block_hash", key)
require.NotEqual(t, "state_root", key)
require.NotEqual(t, "gas_limit", key)
require.NotEqual(t, "gas_used", key)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This loop to verify that block header attributes are not set on error is confusing and incomplete. While it correctly fails if an unexpected attribute is present, its logic is hard to follow. Additionally, it's missing a check for the timestamp attribute, which is set on success.

A clearer and more complete approach is to iterate through the attributes and explicitly fail if any of the success-only attributes are found.

for _, attr := range attrs {
		switch string(attr.Key) {
		case "block_hash", "state_root", "gas_limit", "gas_used", "timestamp":
			t.Fatalf("unexpected attribute %q found on error span", attr.Key)
		}
	}

Comment on lines +275 to +277
for _, attr := range attrs {
require.NotEqual(t, "tx_count", string(attr.Key))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This loop to verify that the tx_count attribute is not set on error works, but it can be written more clearly to express the intent of checking for a specific forbidden attribute.

for _, attr := range attrs {
		if string(attr.Key) == "tx_count" {
			t.Fatalf("unexpected attribute 'tx_count' found on error span")
		}
	}

@codecov
Copy link

codecov bot commented Jan 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.83%. Comparing base (6d132bf) to head (4143bf7).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2960      +/-   ##
==========================================
- Coverage   57.87%   57.83%   -0.05%     
==========================================
  Files          97       97              
  Lines        9303     9303              
==========================================
- Hits         5384     5380       -4     
- Misses       3315     3319       +4     
  Partials      604      604              
Flag Coverage Δ
combined 57.83% <ø> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Base automatically changed from cian/add-tracing-part-3 to main January 8, 2026 15:59
@chatton chatton marked this pull request as ready for review January 12, 2026 09:46
@chatton chatton changed the title chore: adding eth client tracing feat(tracing): adding eth client tracing Jan 12, 2026
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.

2 participants