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 13, 2026, 11:28 AM

@claude
Copy link
Contributor

claude bot commented Jan 8, 2026

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


Code Review Complete ✅

I've performed a comprehensive review of the eth client tracing implementation. Overall, this is a well-crafted PR that follows the established patterns from the engine RPC tracing work. The decorator pattern is applied consistently, tests are thorough, and the implementation is production-ready.


Summary

Verdict: ✅ Approve with Minor Suggestions

This PR successfully extends OpenTelemetry tracing to the Ethereum RPC client using the same decorator pattern established in the previous PR. The code quality is high, testing is comprehensive, and the implementation follows Go best practices.


Detailed Findings

Code Quality & Architecture

Strengths:

  • Excellent use of decorator pattern: The tracedEthRPCClient cleanly wraps the base client without modification
  • Strong interface abstraction: EthRPCClient interface enables testability and clean separation of concerns
  • Consistent with existing patterns: Perfectly mirrors the EngineRPCClient tracing implementation from the previous PR
  • Proper dependency injection: Tracing is conditionally applied in NewEngineExecutionClient based on tracingEnabled flag
  • Good tracer naming: "ev-node/execution/eth-rpc" follows the established convention

Observations:

  • The interface extraction and decorator layering is textbook clean architecture
  • Integration point in execution.go:236-242 shows proper composition of base client → traced client when enabled
  • No cyclic dependencies, package boundaries are respected

Error Handling & Resilience

Strengths:

  • Proper error propagation: Errors are recorded and returned without modification
  • Consistent error recording pattern: All errors use span.RecordError(err) + span.SetStatus(codes.Error, err.Error())
  • No error swallowing: Every error path properly records to span and returns to caller
  • Context propagation: ctx is properly threaded through the decorator for cancellation support

Observations:

  • Error handling matches the engine RPC tracing patterns exactly (good consistency)
  • nil handling for number parameter in HeaderByNumber is safe and correct (eth_rpc_tracing.go:30-34)

Security

No security concerns identified.

  • No credential handling in traced code
  • Block hashes, state roots, and transaction counts are safe to log
  • No user input validation needed (delegated to inner client)
  • Context cancellation is properly supported

Performance & Resource Efficiency

Strengths:

  • Zero allocations overhead when tracing is disabled (interface check is negligible)
  • Minimal span attribute allocations: Only essential attributes recorded
  • Efficient span lifecycle: defer span.End() ensures cleanup even on panic
  • No blocking operations: All tracing is non-blocking

Observations:

  • Success attributes are only set after successful RPC calls (eth_rpc_tracing.go:51-57, 77-79)
  • This avoids wasted work when RPCs fail
  • No goroutine leaks possible (no goroutines spawned)

Testing & Reliability

Strengths:

  • Excellent test coverage: 6 test cases covering success, error, and edge cases
  • Proper test isolation: Uses tracetest.SpanRecorder for deterministic span verification
  • Clean test helpers: setupTestEthRPCTracing and mockEthRPCClient reduce boilerplate
  • Edge case coverage:
    • Latest block query (nil number) - eth_rpc_tracing_test.go:102-135
    • Empty transaction pool - eth_rpc_tracing_test.go:213-239
    • Error scenarios for both methods
  • Assertion quality: Comprehensive checks for span names, status codes, attributes, and error events

Minor Suggestions:

  1. Test assertion clarity (eth_rpc_tracing_test.go:172-178): The loop checking that header attributes aren't set on error is slightly confusing and misses timestamp. Consider Gemini's suggestion:

    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)
        }
    }
  2. Test assertion clarity (eth_rpc_tracing_test.go:274-277): Similar issue with tx_count check. Gemini's suggestion is clearer:

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

These are style suggestions only - the current tests are functionally correct.

Documentation & Developer Experience

Strengths:

  • Clear interface documentation: EthRPCClient interface has good inline comments (execution.go:145-152)
  • Descriptive function names: withTracingEthRPCClient, NewEthRPCClient are self-documenting
  • Package-level consistency: Naming matches engine RPC patterns

Minor Observations:

  • The decorator function withTracingEthRPCClient is package-private (lowercase), which is appropriate
  • No exported symbols need additional documentation (all are well-named)

Comparison with Engine RPC Tracing

The implementation is remarkably consistent with the engine RPC tracing from the previous PR:

Aspect Engine RPC Eth RPC Match?
Interface abstraction
Decorator pattern
Tracer naming convention engine-rpc eth-rpc
Error handling RecordError + SetStatus RecordError + SetStatus
Success attributes Set after success Set after success
Test coverage ❌ (no tests) ✓ (6 tests) ⚠️ Better!

Notable: This PR actually has better test coverage than the engine RPC tracing, which has no dedicated unit tests.


Additional Observations

Go Idioms ✅

  • Proper use of defer span.End() for cleanup
  • Interface satisfaction verified with var _ EthRPCClient = (*ethRPCClient)(nil)
  • Unexported struct fields with exported methods
  • No naked returns, explicit error handling

Concurrency Safety ✅

  • No shared state in traced client (tracer is read-only)
  • Context properly propagated for cancellation
  • No race conditions possible

Integration Quality ✅

  • Clean integration in NewEngineExecutionClient (execution.go:184-256)
  • Proper conditional wrapping based on tracingEnabled flag
  • HTTP client propagation for W3C trace context headers (execution.go:198-202)

Recommendations

Required: None ✅

The code is production-ready as-is.

Optional Improvements:

  1. Test assertion clarity: Consider adopting Gemini's suggestions for clearer error-case attribute checks (see Testing section above)
  2. Consider adding engine RPC tracing tests: Since this PR has excellent test patterns, they could be backported to test engine_rpc_tracing.go

Security Checklist ✅

  • No hardcoded secrets or credentials
  • No sensitive data in span attributes
  • Proper error message handling (no info leakage)
  • Context cancellation respected
  • No SQL injection, XSS, or command injection vectors

Performance Checklist ✅

  • No unnecessary allocations in hot path
  • Efficient span lifecycle management
  • No blocking operations added
  • Zero overhead when tracing disabled

Testing Checklist ✅

  • Unit tests for success cases
  • Unit tests for error cases
  • Edge cases covered (nil params, empty results)
  • Span attributes verified
  • Error recording verified

Conclusion

This is exemplary work that demonstrates:

  • Strong understanding of Go idioms and patterns
  • Attention to testing and edge cases
  • Consistency with established codebase patterns
  • Production-ready code quality

The minor suggestions from Gemini about test assertions are valid style improvements but don't affect correctness. The PR is ready to merge as-is.

Great job! 🎉


@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.75%. Comparing base (ddf8f31) to head (9f121d5).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2960   +/-   ##
=======================================
  Coverage   57.75%   57.75%           
=======================================
  Files          97       97           
  Lines        9303     9303           
=======================================
  Hits         5373     5373           
  Misses       3326     3326           
  Partials      604      604           
Flag Coverage Δ
combined 57.75% <ø> (ø)

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
@chatton chatton requested a review from tac0turtle January 13, 2026 08:59
@chatton chatton enabled auto-merge January 13, 2026 13:49
@chatton
Copy link
Contributor Author

chatton commented Jan 13, 2026

adding to merge queue as the forced inclusion test failure is occurring on main, it can be fixed in a follow up

@tac0turtle tac0turtle disabled auto-merge January 13, 2026 13:58
@tac0turtle tac0turtle merged commit 07dd5d1 into main Jan 13, 2026
57 of 63 checks passed
@tac0turtle tac0turtle deleted the cian/add-tracing-part-4 branch January 13, 2026 13:58
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.

3 participants