fix(evmrpc): limit listener max open connections, configurable via max_open_connections (PLT-704)#3637
Conversation
PR SummaryMedium Risk Overview Operators configure Config loading, defaults, and the TOML template are updated; Reviewed by Cursor Bugbot for commit 4666ad5. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
…connection-config
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3637 +/- ##
==========================================
- Coverage 59.16% 58.15% -1.02%
==========================================
Files 2262 2176 -86
Lines 187009 176891 -10118
==========================================
- Hits 110650 102869 -7781
+ Misses 66424 64929 -1495
+ Partials 9935 9093 -842
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…connection-config
There was a problem hiding this comment.
A small, well-tested change that wraps the EVM HTTP/WS listeners with netutil.LimitListener, configurable via evm.max_open_connections. No blocking issues; a couple of minor robustness and formatting nits worth addressing.
Findings: 0 blocking | 4 non-blocking | 2 posted inline
Blockers
- None at the file/PR level.
Non-blocking
- cursor-review.md was empty — the Cursor second-opinion pass produced no output. REVIEW_GUIDELINES.md was also empty, so no repo-specific standards were applied.
- Per-listener budgeting means the documented default of 2000 actually permits up to ~4000 simultaneous connections across the HTTP (:8545) and WS (:8546) listeners combined. This is intended per the PR description, but operators may read
max_open_connections = 2000as a node-wide cap; consider clarifying the per-listener semantics in the app.toml comment as well (the struct doc comment already explains it, but the template comment does not). - 2 suggestion(s)/nit(s) flagged inline on specific lines.
| } | ||
| } | ||
| if v := opts.Get(flagMaxOpenConnections); v != nil { | ||
| if cfg.MaxOpenConnections, err = cast.ToIntE(v); err != nil { |
There was a problem hiding this comment.
[suggestion] A negative value (e.g. an operator typo like -1) is accepted here and then silently disables the cap, because Start() only applies LimitListener when maxOpenConns > 0. The public config text states only 0 disables the limit, so this is surprising. Consider rejecting negatives (return an error) or normalizing them to 0 explicitly so the documented contract holds. (Also raised by Codex.)
| // batched JSON-RPC call (HTTP and WebSocket). Set to 0 to disable the limit. | ||
| BatchResponseMaxSize int `mapstructure:"batch_response_max_size"` | ||
|
|
||
|
|
There was a problem hiding this comment.
[nit] Stray double blank line — there are two consecutive blank lines (180 and 181) before the MaxOpenConnections comment. gofmt collapses consecutive blank lines to one, so this is not gofmt-clean; running gofmt -s -w will remove the extra line.
Describe your changes and provide context
Bounds the number of simultaneously accepted connections on the EVM JSON-RPC HTTP (
:8545) and WebSocket (:8546) listeners to protect nodes from connection exhaustion (fd/goroutine pressure) under load or abuse.net.ListeninStart()withnetutil.LimitListener(l, maxOpenConns). Excess connections wait in the accept queue until an active connection closes.max_open_connectionsas an operator config field inevmrpc/config(evm.max_open_connectionsinapp.toml), wired throughReadConfigand the config template.HTTPServer.SetMaxOpenConns, set from config in bothNewEVMHTTPServerandNewEVMWebSocketServerbefore the listener starts.2000. Set to0to disable the limit (unbounded, prior behavior). The wrap is guarded onmaxOpenConns > 0, sincenetutil.LimitListenerwould otherwise block all connections at0.Testing performed to validate your change
TestMaxOpenConns(evmrpc): with a cap of 1, verifies a second connection is not served while the first holds the only slot, and is served once the first closes.evmrpc/configtests for the new field;go test ./evmrpc/... ./evmrpc/config/...passes.go build ./evmrpc/...andgofmt -sclean.