Skip to content

feat: add grpc socket and flattn tx batches to allow for lower allocations#3297

Open
tac0turtle wants to merge 3 commits intomainfrom
marko/flatten_grpc
Open

feat: add grpc socket and flattn tx batches to allow for lower allocations#3297
tac0turtle wants to merge 3 commits intomainfrom
marko/flatten_grpc

Conversation

@tac0turtle
Copy link
Copy Markdown
Contributor

@tac0turtle tac0turtle commented Apr 28, 2026

Overview

Flatten tx batch to avoid allocations and add in a unix socket over grpc to avoid tcp overhead

Summary by CodeRabbit

  • New Features

    • Added Unix domain socket support for gRPC execution endpoints
    • Added transaction batching capability for more efficient transaction encoding
  • Documentation

    • Updated gRPC endpoint documentation to show both TCP and Unix socket URL schemes
    • Added examples demonstrating Unix socket endpoint configuration
  • Tests

    • Added comprehensive test coverage for Unix socket transport and transaction batching functionality

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Warning

Rate limit exceeded

@tac0turtle has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 54 minutes and 12 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a1559133-cf5f-45b0-8234-7f4645308bd1

📥 Commits

Reviewing files that changed from the base of the PR and between 58a3002 and 10f09fe.

📒 Files selected for processing (1)
  • CHANGELOG.md
📝 Walkthrough

Walkthrough

This PR extends the gRPC execution service with Unix domain socket support and introduces transaction batch encoding to optimize message transmission. Changes span protobuf definitions, client/server implementations, socket handling utilities, and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Documentation
apps/grpc/README.md, execution/grpc/README.md
Updated to document Unix socket URI schemes for client connections and server startup; clarified supported URL schemes and removed references to "remote" phrasing for generalized connectivity options.
Protobuf Definitions
proto/evnode/v1/execution.proto
Added new TxBatch message with concatenated data buffer and per-transaction size tracking; extended GetTxsResponse, ExecuteTxsRequest, and FilterTxsRequest to support optional tx_batch field alongside legacy txs.
Client Implementation
execution/grpc/client.go, execution/grpc/client_test.go
Extended NewClient to detect and handle unix:// URLs with h2c HTTP/2 client creation; updated GetTxs, ExecuteTxs, and FilterTxs to encode/decode transactions via TxBatch; added test coverage for batch fallback behavior and Unix socket connectivity.
Server Implementation
execution/grpc/server.go, execution/grpc/server_test.go
Updated GetTxs, ExecuteTxs, and FilterTxs to encode/decode transactions using TxBatch with fallback to legacy Txs for backward compatibility; expanded test suite to validate batch-based requests, legacy fallback paths, and error handling.
Unix Socket Support
execution/grpc/unix.go, execution/grpc/unix_test.go
Added ListenUnix and ListenAndServeUnix functions with stale socket cleanup and contextual error wrapping; included tests validating socket path validation and stale socket removal.
Transaction Batch Utilities
execution/grpc/tx_batch.go, execution/grpc/tx_batch_test.go
Introduced encodeTxBatch to serialize transaction slices into concatenated buffer with size metadata, and decodeTxBatch with validation for malformed inputs; added decodeTxBatchOrTxs for seamless fallback between batch and legacy formats; comprehensive test coverage for round-trip encoding/decoding and edge cases.
CLI & Module Configuration
apps/grpc/cmd/run.go, execution/grpc/go.mod
Updated grpc-executor-url flag documentation to specify both HTTP and Unix socket schemes; added local module replacement directive to resolve ev-node dependency from relative path.

Sequence Diagram(s)

sequenceDiagram
    participant Client as gRPC Client
    participant HTTP2 as HTTP/2 h2c Client
    participant UnixSocket as Unix Socket
    participant Server as gRPC Server
    
    Client->>Client: Detect unix:// URL
    Client->>HTTP2: Create h2c HTTP/2 client<br/>with unix socket dialer
    Client->>UnixSocket: Dial unix socket path
    UnixSocket->>Server: Establish connection
    Server-->>UnixSocket: Accept connection
    UnixSocket-->>HTTP2: Ready
    HTTP2-->>Client: Client ready
    Client->>Server: Send gRPC request<br/>(over HTTP/2)
    Server->>Server: Handle request
    Server-->>Client: Return gRPC response
Loading
sequenceDiagram
    participant Caller as Caller
    participant Client as gRPC Client
    participant Encoder as TxBatch Encoder
    participant Server as gRPC Server
    participant Decoder as TxBatch Decoder
    participant Executor as Executor
    
    Caller->>Client: Call ExecuteTxs(txs [][]byte)
    Client->>Encoder: encodeTxBatch(txs)
    Encoder->>Encoder: Concatenate tx data<br/>Track per-tx sizes
    Encoder-->>Client: TxBatch{data, tx_sizes}
    Client->>Server: ExecuteTxsRequest{TxBatch}
    Server->>Decoder: decodeTxBatchOrTxs(TxBatch)
    Decoder->>Decoder: Validate sizes & data<br/>Reconstruct txs
    Decoder-->>Server: [][]byte txs
    Server->>Executor: Execute transactions
    Executor-->>Server: Result
    Server-->>Client: Response
    Client-->>Caller: Result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • chatton
  • tuxcanfly

Poem

🐰 A rabbit's burrow, now with doors so neat,
Unix sockets swift, and batch tx compete,
No TCP hops through the network so wide,
Just messages bundled with care deep inside,
Connection complete, our gRPC spring flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main changes: adding gRPC Unix socket support and flattening transaction batches for lower allocations.
Description check ✅ Passed Description provides clear overview of goals (flatten tx batches, add Unix socket for gRPC) but lacks detail on implementation, testing, or specific rationale.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch marko/flatten_grpc

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 28, 2026

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed⏩ skipped✅ passed✅ passedApr 28, 2026, 3:44 PM

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 68.54839% with 39 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.68%. Comparing base (389e904) to head (10f09fe).

Files with missing lines Patch % Lines
execution/grpc/unix.go 35.48% 17 Missing and 3 partials ⚠️
execution/grpc/tx_batch.go 81.25% 5 Missing and 4 partials ⚠️
execution/grpc/client.go 75.75% 4 Missing and 4 partials ⚠️
execution/grpc/server.go 83.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3297      +/-   ##
==========================================
+ Coverage   62.48%   62.68%   +0.20%     
==========================================
  Files         122      124       +2     
  Lines       13047    13163     +116     
==========================================
+ Hits         8152     8251      +99     
- Misses       4009     4013       +4     
- Partials      886      899      +13     
Flag Coverage Δ
combined 62.68% <68.54%> (+0.20%) ⬆️

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.

@tac0turtle tac0turtle marked this pull request as ready for review April 28, 2026 15:31
Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (3)
proto/evnode/v1/execution.proto (1)

63-67: Clarify precedence when both txs and tx_batch are populated.

Please document a single authoritative rule (e.g., "tx_batch takes precedence; txs is legacy fallback") to avoid cross-client ambiguity during migration.

Also applies to: 84-85, 142-143

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@proto/evnode/v1/execution.proto` around lines 63 - 67, The proto comments for
the repeated bytes field txs and the TxBatch field tx_batch are ambiguous about
which to use when both are populated; update the comments for txs and tx_batch
(including the other occurrences at the ranges noted) to state a single
authoritative rule: tx_batch takes precedence and txs is a legacy fallback
(i.e., when tx_batch is present, implementations MUST ignore txs; when tx_batch
is absent, clients MAY use txs for backward compatibility). Ensure the same
wording is applied to every message where txs and tx_batch appear to avoid
cross-client ambiguity.
execution/grpc/unix.go (1)

33-47: Consider documenting that http.Serve blocks until error.

The function works correctly, but callers should understand this blocks. The defer order is correct (LIFO): socket cleanup runs after listener close.

Minor note: ignoring errors from listener.Close() and removeStaleUnixSocket in defers is acceptable for cleanup, but logging could help debugging shutdown issues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@execution/grpc/unix.go` around lines 33 - 47, Update the ListenAndServeUnix
doc comment to explicitly state that http.Serve blocks until it returns an error
and that the deferred listener.Close() and removeStaleUnixSocket() run when
Serve returns (LIFO order); mention callers must expect blocking behavior and
handle cancellation accordingly. While optional, add a brief note that errors
from listener.Close() and removeStaleUnixSocket() are currently ignored in the
defers and could be logged for shutdown diagnostics; reference
ListenAndServeUnix, http.Serve, listener.Close, removeStaleUnixSocket, and
NewExecutorServiceHandler when making this documentation change.
execution/grpc/client.go (1)

50-64: Consider validating socket path at creation time.

The empty socket path check inside DialTLSContext (line 56-58) will only trigger on the first dial attempt rather than at client creation. Since clientTransportForTarget already extracts the path, validation could happen there to fail fast.

That said, this is defensive coding within the closure, and the path extraction in unixSocketPath (line 74-79) already ensures a non-empty path when the prefix is present. The check here guards against misuse if newUnixHTTP2Client("") is called directly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@execution/grpc/client.go` around lines 50 - 64, The client builder
newUnixHTTP2Client currently defers an empty-socket check until DialTLSContext;
change it to validate socketPath up-front and return an error instead of
creating a client for an empty path. Update newUnixHTTP2Client signature to
return (*http.Client, error), check if socketPath == "" at the start and return
a clear error, and then construct the http.Client as before. Propagate the
change to callers such as clientTransportForTarget (which calls
newUnixHTTP2Client) so they handle the error and fail fast when unixSocketPath
extraction yields an empty string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/grpc/README.md`:
- Line 3: Update the README intro sentence to use the correct indefinite
article: replace the phrase "a Evolve node" with "an Evolve node" in the README
content so the sentence reads "This application runs an Evolve node with a
single sequencer..." (look for the README sentence containing "a Evolve node" to
make the change).

In `@execution/grpc/server.go`:
- Around line 85-87: GetTxsResponse currently only sets TxBatch and drops the
legacy txs field; update the server handler that returns GetTxsResponse (the
GetTxs implementation in grpc/server.go) to also populate the legacy txs field
with an equivalent flattened slice of transactions derived from txBatch (or a
converted form matching the old txs element type) so older clients continue to
see the expected list; ensure both fields are kept in sync (construct txs from
txBatch before returning) and preserve existing types/names used in
GetTxsResponse, tx_batch, and txs.

---

Nitpick comments:
In `@execution/grpc/client.go`:
- Around line 50-64: The client builder newUnixHTTP2Client currently defers an
empty-socket check until DialTLSContext; change it to validate socketPath
up-front and return an error instead of creating a client for an empty path.
Update newUnixHTTP2Client signature to return (*http.Client, error), check if
socketPath == "" at the start and return a clear error, and then construct the
http.Client as before. Propagate the change to callers such as
clientTransportForTarget (which calls newUnixHTTP2Client) so they handle the
error and fail fast when unixSocketPath extraction yields an empty string.

In `@execution/grpc/unix.go`:
- Around line 33-47: Update the ListenAndServeUnix doc comment to explicitly
state that http.Serve blocks until it returns an error and that the deferred
listener.Close() and removeStaleUnixSocket() run when Serve returns (LIFO
order); mention callers must expect blocking behavior and handle cancellation
accordingly. While optional, add a brief note that errors from listener.Close()
and removeStaleUnixSocket() are currently ignored in the defers and could be
logged for shutdown diagnostics; reference ListenAndServeUnix, http.Serve,
listener.Close, removeStaleUnixSocket, and NewExecutorServiceHandler when making
this documentation change.

In `@proto/evnode/v1/execution.proto`:
- Around line 63-67: The proto comments for the repeated bytes field txs and the
TxBatch field tx_batch are ambiguous about which to use when both are populated;
update the comments for txs and tx_batch (including the other occurrences at the
ranges noted) to state a single authoritative rule: tx_batch takes precedence
and txs is a legacy fallback (i.e., when tx_batch is present, implementations
MUST ignore txs; when tx_batch is absent, clients MAY use txs for backward
compatibility). Ensure the same wording is applied to every message where txs
and tx_batch appear to avoid cross-client ambiguity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: acfb26c3-ba2a-423a-832a-163fd34eb7d3

📥 Commits

Reviewing files that changed from the base of the PR and between 389e904 and 58a3002.

⛔ Files ignored due to path filters (1)
  • types/pb/evnode/v1/execution.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (13)
  • apps/grpc/README.md
  • apps/grpc/cmd/run.go
  • execution/grpc/README.md
  • execution/grpc/client.go
  • execution/grpc/client_test.go
  • execution/grpc/go.mod
  • execution/grpc/server.go
  • execution/grpc/server_test.go
  • execution/grpc/tx_batch.go
  • execution/grpc/tx_batch_test.go
  • execution/grpc/unix.go
  • execution/grpc/unix_test.go
  • proto/evnode/v1/execution.proto

Comment thread apps/grpc/README.md
# gRPC Single Sequencer App

This application runs a Evolve node with a single sequencer that connects to a remote execution client via gRPC. It allows you to use any execution layer that implements the Evolve execution gRPC interface.
This application runs a Evolve node with a single sequencer that connects to an execution client via gRPC. It allows you to use any execution layer that implements the Evolve execution gRPC interface.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix article in intro sentence.

Use “an Evolve node” instead of “a Evolve node” for grammatical correctness.

✏️ Proposed doc fix
-This application runs a Evolve node with a single sequencer that connects to an execution client via gRPC. It allows you to use any execution layer that implements the Evolve execution gRPC interface.
+This application runs an Evolve node with a single sequencer that connects to an execution client via gRPC. It allows you to use any execution layer that implements the Evolve execution gRPC interface.
📝 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
This application runs a Evolve node with a single sequencer that connects to an execution client via gRPC. It allows you to use any execution layer that implements the Evolve execution gRPC interface.
This application runs an Evolve node with a single sequencer that connects to an execution client via gRPC. It allows you to use any execution layer that implements the Evolve execution gRPC interface.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/grpc/README.md` at line 3, Update the README intro sentence to use the
correct indefinite article: replace the phrase "a Evolve node" with "an Evolve
node" in the README content so the sentence reads "This application runs an
Evolve node with a single sequencer..." (look for the README sentence containing
"a Evolve node" to make the change).

Comment thread execution/grpc/server.go
Comment on lines 85 to 87
return connect.NewResponse(&pb.GetTxsResponse{
Txs: txs,
TxBatch: txBatch,
}), nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

GetTxs currently drops legacy txs payload and can break older consumers.

GetTxsResponse still defines txs, but this response now only sets tx_batch. Any client not yet upgraded to decode tx_batch will observe an empty tx list.

🔁 Compatibility-safe response shape
 return connect.NewResponse(&pb.GetTxsResponse{
+    Txs:     txs, // legacy compatibility during migration
     TxBatch: txBatch,
 }), nil
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@execution/grpc/server.go` around lines 85 - 87, GetTxsResponse currently only
sets TxBatch and drops the legacy txs field; update the server handler that
returns GetTxsResponse (the GetTxs implementation in grpc/server.go) to also
populate the legacy txs field with an equivalent flattened slice of transactions
derived from txBatch (or a converted form matching the old txs element type) so
older clients continue to see the expected list; ensure both fields are kept in
sync (construct txs from txBatch before returning) and preserve existing
types/names used in GetTxsResponse, tx_batch, and txs.

Copy link
Copy Markdown
Member

@julienrbrt julienrbrt left a comment

Choose a reason for hiding this comment

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

ACK.

We should rename the grpc service specifically (the service and the file imho), as it is only used there and because the execution/grpc is an adaption of the execution interface.
We could even move the proto definition under execution/grpc but that's more a nit that is annoying to do.

option go_package = "github.com/evstack/ev-node/types/pb/evnode/v1";

// ExecutorService defines the execution layer interface for EVNode
service ExecutorService {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
service ExecutionGRPCService {

message FilterTxsRequest {
// All transactions (force-included + mempool)
// All transactions (force-included + mempool).
repeated bytes txs = 1;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's kill the ones we don't use.

Comment thread CHANGELOG.md
### Changes

- Optimization of mutex usage in cache for reaper [#3286](https://github.com/evstack/ev-node/pull/3286)
- Add Unix domain socket support for gRPC execution endpoints via `unix:///path/to/socket`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Missing PR name.

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