Skip to content

Improve JsonRpc plumbing#11697

Draft
benaadams wants to merge 161 commits into
masterfrom
jsonrpc
Draft

Improve JsonRpc plumbing#11697
benaadams wants to merge 161 commits into
masterfrom
jsonrpc

Conversation

@benaadams
Copy link
Copy Markdown
Member

@benaadams benaadams commented May 20, 2026

Changes

Architecture

  • Introduced a sink-based JSON-RPC response model (IJsonRpcResponseSink) with dedicated HttpJsonRpcResponseSink and SocketJsonRpcResponseSink implementations, replacing the buffered IJsonRpcBatchResult adapter path and migrating HTTP and WebSocket transports onto it.
  • Added a single-pass UTF-8 envelope reader (JsonRpcEnvelopeReader) that parses HTTP JSON-RPC documents and batches directly from collected request bodies, with strict single-document parsing and rejection of adjacent JSON documents.
  • Replaced object-typed JSON-RPC IDs with a typed JsonRpcId value (numeric, string, and raw-token preserving) threaded through requests, responses, models, sockets, and subscription messages, with safer/escaped JSON output and null-equality fixes.
  • Reworked JsonRpcProcessor and JsonRpcService around the sink path and removed legacy inbound batch wrappers, reflection-based dispatch fallbacks, and async wrappers on module rent/dispatch (ValueTask throughout).

Typed JSON-RPC response pipeline

  • Replaced the untyped JsonRpcSuccessResponse.Result = (object)data slot with a typed JsonRpcResponse<T> carrier so the static T survives from ResultWrapper<T>.Data through the sink writer; eliminates value-type boxing for long, ulong, bool, UInt256, Hash256, etc.
  • Implemented a shared typed JSON-RPC response writer used by HTTP, WebSocket, and benchmark sinks; legacy success conversion and JsonRpcSuccessResponse polymorphism are removed.
  • Added typed subscription responses, typed streamable error data, and preserved-derived-type serialization for polymorphic RPC payloads.
  • Preserved HTTP RPC quantity serialization (hex-string output for long/ulong/UInt256 through Ethereum converters) and engine-payload-typed responses in tests; primitive RPC results write directly without going through STJ.
  • Removed unused MethodName from JsonRpcResponse (method name flows via RpcReport.Method to the stats reporter) and removed dispatch reflection fallbacks now that the typed path is closed-world.
  • Specialized tiny JSON-RPC success results and reused resolved method metadata to keep the typed dispatch allocation-free on the hot path.

RPC metadata source generation

  • Added a Roslyn source generator that enumerates IRpcModule surfaces per assembly (including inherited methods) and emits the closed set of RPC result, parameter, subscription, error-data, and derived-type metadata before compile.
  • Generated metadata providers register on startup; runtime lookup helpers (generated RPC type metadata lookup, JSON-RPC parameter type metadata helper, subscription payload generation, method result metadata) feed the typed response writer with JsonTypeInfo<T> without per-call resolver-chain walks.
  • Plugin assemblies (Optimism, Taiko, Merge, etc.) are covered by per-assembly generation; the dispatcher verifies engine-payload metadata hits and tracks any fallback usage as a metric so coverage drift is observable.

Engine API direct streaming

  • Stream large Engine API responses directly for engine_getBlobsV1/V2 and engine_getPayloadBodiesByHash/Range V1/V2 via dedicated *DirectResponse writers and a shared StreamableResultWriter.
  • Use HexBytes results for eth_call and direct streaming for primitive JSON-RPC results.
  • Added ByteArrayArrayConverter and a HexBytesConverter, raised blob hex chunk size to fit max blob, batched small blob flushes, and tightened HexWriter/HexConverter paths.

Hot-path JSON-RPC tuning

  • Intern known RPC method names (KnownRpcMethodNames), order method probes by frequency, compare as UTF-8, handle segmented names, and cache resolved method metadata + parameter metadata + direct invokers (zero-parameter and small-parameter fast paths) with pooled invocation arguments.
  • Deserialize JSON-RPC params from raw UTF-8 spans/slices; reuse the UTF-8 parameter reader; reuse and validate hex parsing across UTF-16 paths; decode fixed JSON hex into spans.
  • Cache HTTP content-type header, trusted-source decisions, JSON-RPC string ID values, and the trusted HTTP fast-lane (including trusted startup setup in boundary timing); bind the HTTP JSON-RPC sink to compact options.
  • Cache and reuse JSON whitespace SearchValues with a fast-path scan; reuse single-document processing options; remove redundant envelope offset checks and the duplicate envelope skip helper.
  • Reuse the JWT validation HMAC and document its secret invariant; gate streamable success disposal; skip no-op dispose metrics; seed buffered response writer and missing body capacity; raise medium byte-array hex inline buffer.
  • Outlined JSON-RPC parser throws; removed JSON-RPC stats hot locks (lock-free recording + Lock for rotation), moved report formatting off the hot path, and removed stats task scheduling.

Metrics and observability

  • Switched JSON-RPC call latency to a histogram metric, added boundary-stage timing for HTTP JSON-RPC, post-return overhead, request/response shape tracking, and parser fallback / response flush metrics; track metadata-lookup fallback usage; report HTTP request body buffer rents.
  • Trimmed and removed unused/boundary JSON-RPC metrics; removed flush-accounting fields no longer in use; reused histogram label allocations.

HTTP/SSZ request handling

  • Reject oversized RPC bodies before renting buffers; copy HTTP bodies by read buffer; collect HTTP JSON-RPC request bodies before parsing; let HTTP RPC writes start responses; fix HTTP byte counting when no Content-Length is set.
  • SSZ middleware now returns fast exits directly with improved error handling.
  • Added configurable additional trusted networks to JsonRpcConfig.

Serialization

  • New/updated converters: ByteArrayArrayConverter, HexBytesConverter, and tightened ByteArrayConverter, Bytes32Converter, Hash256Converter, ValueHash256Converter, AddressConverter, BloomConverter, HexConverter, and StreamPipeWriter.
  • Preserve typed RPC success metadata; cache HTTP JSON-RPC response type metadata; keep streamable results off diagnostic serializers; preserve relaxed JSON-RPC error escaping and streamable ID escaping.

Tests and benchmarks

  • New/expanded coverage in Nethermind.JsonRpc.Test (envelope parsing, ID edge cases, batch limits, parameter metadata cache, processor sink path, sockets, response shape verification, typed subscription/error paths), Nethermind.Runner.Test (startup auth failure, recorder/disposal lifetimes, strict HTTP parsing, typed error serialization), Nethermind.Merge.Plugin.Test (Engine V2/V3/V4/V6 typed payload responses, byte-array-array converter), Nethermind.Core.Test, Nethermind.Monitoring.Test, and Nethermind.Sockets.Test.
  • New benchmarks: BlobsV2DirectResponseBenchmarks, ByteArrayConverterWriteBenchmarks, JSON-RPC response writer benchmarks, benchmark JSON-RPC response sink coverage.
  • Removed benchmark dependency from merge tests; cleaned up unused benchmark generator usings; JitAsm now loads the ASP.NET framework so the sink path can be inspected.

Types of changes

What types of changes does your code introduce?

  • Bugfix (a non-breaking change that fixes an issue)
  • New feature (a non-breaking change that adds functionality)
  • Breaking change (a change that causes existing functionality not to work as expected)
  • Optimization
  • Refactoring
  • Documentation update
  • Build-related changes
  • Other: Description

Testing

Requires testing

  • Yes
  • No

If yes, did you write tests?

  • Yes
  • No

Notes on testing

  • Added/updated focused tests in Nethermind.JsonRpc.Test, Nethermind.Runner.Test, Nethermind.Merge.Plugin.Test, Nethermind.Core.Test, Nethermind.Monitoring.Test, and Nethermind.Sockets.Test.
  • Added benchmark coverage in Nethermind.Benchmark and Nethermind.Merge.Plugin.Benchmark for the new serialization hot paths and the typed response writer.

Documentation

Requires documentation update

  • Yes
  • No

Requires explanation in Release Notes

  • Yes
  • No

Remarks

Valid JSON-RPC requests and responses are intended to remain wire-compatible. Invalid, malformed, or oversized HTTP inputs are rejected earlier, large Engine API responses use direct streaming paths, and the typed response pipeline keeps the static T of every RPC result alive from ResultWrapper<T>.Data to the serializer so value-type payloads do not box and source-generated JsonTypeInfo<T> is used end-to-end.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 20, 2026

Claude finished @benaadams's task in 8m 19s —— View job


Review: Improve JsonRpc plumbing

  • Load repository rules and guidelines
  • Read key changed files (JsonRpcProcessor, JsonRpcService, JsonRpcId, response sinks, startup)
  • Review correctness and edge cases
  • Review security implications
  • Review performance considerations
  • Check adherence to repo coding rules
  • Post inline comments for specific issues
  • Post final summary

Overview

This is a significant and well-structured rework of the JSON-RPC plumbing layer. The key architectural improvements are:

  • IJsonRpcResponseSink: Clean separation of transport framing from request processing. Each transport (HTTP, WebSocket, IPC) owns its own serialization, byte counting, and stat reporting, rather than those concerns bleeding into the processor.
  • JsonRpcId: Eliminates boxing of primitive IDs (long, decimal) by storing them as typed fields. The fast path for raw string tokens avoids a full serializer round-trip.
  • JsonRpcEnvelopeReader: Single-pass, zero-allocation envelope parsing for the common single-object case, falling back to JsonDocument only when needed.
  • KnownRpcMethodNames: Length-gated linear probe intern table avoids allocating a new string for every known method name.
  • JsonRpcProcessor: Better pipelining — both PipeReader and ReadOnlyMemory<byte> paths, early fast-paths for single-object and batch requests, correct JsonDocument lifecycle management in all branches.
  • HttpJsonRpcResponseSink: Avoids serializing twice by writing directly to the response PipeWriter using Utf8JsonWriter; buffered response path for Content-Length scenarios.

The overall direction is sound and the hot paths are carefully optimized. Below are specific findings.


Findings

High

  1. _jsonTypeInfoCache keyed by Type only (HttpJsonRpcResponseSink.cs:41)
    The static ConcurrentDictionary<Type, JsonTypeInfo> stores values created from an instance-level JsonSerializerOptions. If any two HttpJsonRpcResponseSink instances ever use different options objects, the second gets the first's JsonTypeInfo. Currently safe (all sinks pass EthereumJsonSerializer.JsonOptions), but the invariant is not enforced and is invisible to future maintainers. → inline comment posted.

  2. SkipComplexValue and SkipValue are identical (JsonRpcEnvelopeReader.cs:141–155)
    Both private methods have exactly the same body. Having two names for one behaviour invites them to diverge silently when either is modified. → inline comment posted.

Medium

  1. JsonRpcId.Equals(object?) returns true for null (JsonRpcId.cs:262)
    The null => IsNullLike branch violates the documented .NET contract that x.Equals(null) returns false. This can silently misbehave in LINQ, dictionary equality comparers, or any code following the contract. → inline comment posted.

  2. JsonRpcId.GetStringValue() re-deserializes on every call (JsonRpcId.cs:339)
    Called from Equals, GetHashCode, TryGetString, and ToString. Each call does JsonSerializer.Deserialize<string>(_rawValue), allocating a fresh CLR string. For equality and hashing, a direct _rawValue.AsSpan().SequenceEqual(...) / HashCode.AddBytes(...) is sufficient and allocation-free. → inline comment posted.

Low

  1. [AggressiveInlining] on a complex method (HttpJsonRpcResponseSink.cs:252)
    WriteJsonRpcResponse is too large and branchy for meaningful inlining; the attribute risks code bloat. → inline comment posted.

  2. JsonRpcProcessingOptions constructed twice in a fallback path (JsonRpcProcessor.cs:454)
    Minor struct duplication; extract to a local. → inline comment posted.


Other observations (not blocking)

  • ProcessBatchDocumentToSink / ProcessBatchMemoryToSink continue iterating after StopRequested: The loop never breaks—it replaces actual handler execution with a LimitExceeded error response for every remaining item. For very large batches, this still serializes all the error responses. Consider a hard stop after writing the first LimitExceeded entry (matching the HTTP-level response truncation behaviour).

  • SocketJsonRpcResponseSink _topLevelResponseBytes cast: _topLevelResponseBytes += (int)await jsonSerializer.SerializeAsync(...). The cast to int is safe for single items under 2 GB, which is realistic, but the field is long so dropping to int on the RHS is slightly inconsistent.

  • IJsonRpcResponseSink has no Dispose: SocketJsonRpcResponseSink<TStream> implements IDisposable to release the semaphore on exception, but the interface doesn't expose it. The current call sites use the concrete type for using, so this is fine, but it means processor code can't guarantee cleanup through the interface.

  • TryGetSingleDocumentBody parses twice (JsonRpcProcessor.cs): The fast-path for single-object requests creates a Utf8JsonReader to find the document boundaries, then JsonRpcEnvelopeReader creates a second reader to parse properties. A combined single-pass reader could save one traversal on the very hottest path, though the current approach is clear and correct.

  • Coding style: New files correctly spell out types (no var), use is null/is not null, and follow file-scoped namespaces. ✓


Summary

The architectural direction is correct and the performance improvements are well-reasoned. The two High findings should be addressed before merge (the type-info cache is a latent correctness bug; the duplicate methods invite drift). The two Medium findings affect correctness (Equals contract) and allocation on string IDs. The Low items are cosmetic.

Comment thread src/Nethermind/Nethermind.Runner/JsonRpc/HttpJsonRpcResponseSink.cs Outdated
Comment thread src/Nethermind/Nethermind.JsonRpc/JsonRpcEnvelopeReader.cs Outdated
Comment thread src/Nethermind/Nethermind.JsonRpc/JsonRpcId.cs
Comment thread src/Nethermind/Nethermind.JsonRpc/JsonRpcId.cs
Comment thread src/Nethermind/Nethermind.Runner/JsonRpc/HttpJsonRpcResponseSink.cs Outdated
Comment thread src/Nethermind/Nethermind.JsonRpc/JsonRpcProcessor.cs Outdated
@benaadams
Copy link
Copy Markdown
Member Author

@claude re-review

@benaadams benaadams requested a review from Copilot May 20, 2026 16:33
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 20, 2026

Claude finished @benaadams's task in 5m 10s —— View job


Re-review: Improve JsonRpc plumbing

  • Load repository rules and guidelines
  • Read key changed files (JsonRpcId, JsonRpcEnvelopeReader, HttpJsonRpcResponseSink, JsonRpcProcessor, SocketJsonRpcResponseSink, Startup)
  • Verify previous findings are resolved
  • Review for new issues
  • Post final summary

Previous Findings — Status

# Severity Finding Status
1 High _jsonTypeInfoCache keyed by Type only, ignoring JsonSerializerOptions ✅ Resolved — constructor no longer accepts custom options; GetJsonTypeInfo hardcodes EthereumJsonSerializer.JsonOptions directly
2 High SkipComplexValue and SkipValue were identical ✅ Resolved — SkipComplexValue removed; only SkipValue remains
3 Medium Equals(object?) returned true for null ✅ Resolved — null => false now (JsonRpcId.cs:267)
4 Medium GetStringValue() re-deserialized on every call ✅ Resolved — _stringValue is cached at construction time in both JsonRpcId(string) and JsonRpcId(byte[]) constructors; GetStringValue() now just returns the cached field
5 Low [AggressiveInlining] on complex WriteJsonRpcResponse ⚠️ Still present — inline comment posted
6 Low JsonRpcProcessingOptions constructed twice in fallback path ✅ Resolved — extracted to singleDocumentOptions local (JsonRpcProcessor.cs:453)

New Findings

No new Critical, High, or Medium issues found in the updated code. The reviewed areas were correct and well-structured:

  • SocketJsonRpcResponseSink semaphore lifecycle is safe — BeginBatchAsync acquires without a local try/finally, but EndBatchAsync.finally and the outer using in HandleRequest both call ReleaseSemaphore(), with _holdsSemaphore guarding against double-release.
  • TrustedCidr.TryParse is correct. IPv4-mapped IPv6 addresses are handled in Contains. The IPv4-only restriction for AdditionalTrustedNetworks is a reasonable config-level limitation.
  • JsonRpcId.WriteTo always has _rawValue set for String kind (both constructors initialize it), so the defensive null check is safe.
  • AdditionalTrustedNetworks bypasses middleware but not JWT authentication — confirmed in ProcessJsonRpcRequestCoreAsync.

Summary

All High and Medium findings from the previous review have been addressed. One Low finding ([AggressiveInlining] on WriteJsonRpcResponse) remains. The PR is ready to merge.

Comment thread src/Nethermind/Nethermind.Runner/JsonRpc/HttpJsonRpcResponseSink.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR refactors JSON-RPC transport plumbing to stream responses via a sink model, tighten/accelerate parsing and serialization hot paths (typed IDs, direct writers), and expand metrics/observability around request/response handling.

Changes:

  • Introduces IJsonRpcResponseSink and migrates HTTP/WebSocket JSON-RPC processing to write directly to sinks (incl. direct streaming results).
  • Adds typed JsonRpcId + strict envelope/array readers and method-name interning/caching for faster dispatch.
  • Improves serialization/converters (byte arrays, hashes, hex) and updates metrics (histograms) with expanded tests/benchmarks.

Reviewed changes

Copilot reviewed 94 out of 95 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs Updates WebSocket tests to exercise sink-based response writing and metric deltas.
src/Nethermind/Nethermind.Serialization.Json/ValueHash256Converter.cs Optimizes ValueHash256 deserialization using span-based conversion first.
src/Nethermind/Nethermind.Serialization.Json/StreamPipeWriter.cs Adds flush counting + timing instrumentation to counting pipe writers.
src/Nethermind/Nethermind.Serialization.Json/HexWriter.cs Adjusts hex chunk sizing and adds span overloads for chunked/small paths.
src/Nethermind/Nethermind.Serialization.Json/HexBytesConverter.cs Adds HexBytes JSON converter.
src/Nethermind/Nethermind.Serialization.Json/Hash256Converter.cs Optimizes hash deserialization using exact-length span parsing first.
src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs Registers new converters (HexBytes, byte[][]).
src/Nethermind/Nethermind.Serialization.Json/Bytes32Converter.cs Refactors to avoid multi-segment allocations and handles 0x-prefix stripping/padding.
src/Nethermind/Nethermind.Serialization.Json/ByteArrayArrayConverter.cs Adds fast converter for byte[][] as array of hex strings.
src/Nethermind/Nethermind.Runner/JsonRpc/HttpJsonRpcResponseSink.cs Adds HTTP sink implementation with typed result serialization and streamable result support.
src/Nethermind/Nethermind.Monitoring/Metrics/MetricsController.cs Adds support for explicit histogram metric attribute binding.
src/Nethermind/Nethermind.Monitoring.Test/MetricsTests.cs Extends metrics tests for explicit histogram creation/scrape output.
src/Nethermind/Nethermind.Merge.Plugin/SszRest/SszMiddleware.cs Refactors middleware for fast exits and PipeReader-based body handling/metrics.
src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadBodiesByRangeV2Handler.cs Reworks handler to build direct-streaming payload bodies V2 response objects.
src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadBodiesByRangeV1Handler.cs Enables returning direct-streaming wrapper for V1 range responses.
src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadBodiesByHashV2Handler.cs Implements direct-streaming V2 response with request-size limits and disposal safety.
src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadBodiesByHashV1Handler.cs Enables returning direct-streaming wrapper for V1 hash responses.
src/Nethermind/Nethermind.Merge.Plugin/Data/StreamableResultWriter.cs Adds shared flush-threshold helper for streamable JSON writers.
src/Nethermind/Nethermind.Merge.Plugin/Data/PayloadBodiesV2DirectResponse.cs Adds streamable + disposable direct JSON writer for payload bodies V2.
src/Nethermind/Nethermind.Merge.Plugin/Data/PayloadBodiesV1DirectResponse.cs Adds streamable direct JSON writer for payload bodies V1 and shared writer helpers.
src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadBodyV2Result.cs Adds creation helper for already-encoded transactions to avoid re-encoding.
src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayload.cs Adds null-guard for encoded transactions setter.
src/Nethermind/Nethermind.Merge.Plugin/Data/EngineApiJsonContext.cs Registers ByteArrayArrayConverter in source-gen context.
src/Nethermind/Nethermind.Merge.Plugin/Data/BlobsV2DirectResponse.cs Uses shared flush-threshold helper for backpressure.
src/Nethermind/Nethermind.Merge.Plugin/Data/BlobsV1DirectResponse.cs Uses shared flush-threshold helper for backpressure.
src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V6.cs Adds JSON validity test for PayloadBodiesV2DirectResponse.
src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V4.cs Adds test asserting cached typed parameter metadata for hot engine method.
src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V3.cs Adds tests for flush batching/backpressure and larger-pipe options.
src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs Adds JSON validity test for PayloadBodiesV1DirectResponse.
src/Nethermind/Nethermind.Merge.Plugin.Test/ByteArrayArrayConverterTests.cs Adds converter registration and roundtrip tests for byte[][].
src/Nethermind/Nethermind.Merge.Plugin.Benchmark/EngineBenchmarkHost.cs Updates benchmark host to sink-based processor API.
src/Nethermind/Nethermind.Merge.Plugin.Benchmark/BlobsV2DirectResponseBenchmarks.cs Adds benchmarks for direct blob-response writer including flush stats.
src/Nethermind/Nethermind.JsonRpc/WebSockets/SocketJsonRpcResponseSink.cs Adds WebSocket sink implementation with framing and stats integration.
src/Nethermind/Nethermind.JsonRpc/WebSockets/JsonRpcSocketsClient.cs Migrates socket client processing to sink-based processor API.
src/Nethermind/Nethermind.JsonRpc/ResultWrapper.cs Adds HasErrorData and makes wrapper Data nullable for error-data control.
src/Nethermind/Nethermind.JsonRpc/NullJsonRpcLocalStats.cs Updates local stats interface compliance with non-async no-op reporting.
src/Nethermind/Nethermind.JsonRpc/Nethermind.JsonRpc.csproj Formatting-only adjustment.
src/Nethermind/Nethermind.JsonRpc/Modules/Subscribe/JsonRpcSubscriptionResponse.cs Migrates subscription response IDs to typed JsonRpcId.
src/Nethermind/Nethermind.JsonRpc/Modules/RpcModuleProvider.cs Adds hot-method caching, typed param metadata caching, ValueTask module rental, direct invokers.
src/Nethermind/Nethermind.JsonRpc/Modules/NullModuleProvider.cs Updates module provider interface compliance (ValueTask rent + resolved method overloads).
src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModuleProvider.cs Updates API to return resolved method info and use ValueTask for rent/return.
src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs Changes eth_call result type to HexBytes.
src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs Implements eth_call returning HexBytes.
src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.TransactionExecutor.cs Updates Tx executor to produce HexBytes and preserve raw bytes.
src/Nethermind/Nethermind.JsonRpc/Metrics.cs Switches RPC latency metric to histogram with explicit buckets (microseconds).
src/Nethermind/Nethermind.JsonRpc/KnownRpcMethodNames.cs Adds interned known-method-name tables for faster dispatch.
src/Nethermind/Nethermind.JsonRpc/JsonRpcResult.cs Removes batch-result model and simplifies to single-entry results.
src/Nethermind/Nethermind.JsonRpc/JsonRpcResponse.cs Migrates to typed IDs and adds typed result metadata for faster serialization/disposal checks.
src/Nethermind/Nethermind.JsonRpc/JsonRpcRequest.cs Adds UTF-8 params storage + lazy JsonDocument parsing and typed IDs.
src/Nethermind/Nethermind.JsonRpc/JsonRpcProcessingOptions.cs Adds transport-level processing options record.
src/Nethermind/Nethermind.JsonRpc/JsonRpcMetricLabels.cs Adds label wrapper for per-method histogram metric observations.
src/Nethermind/Nethermind.JsonRpc/JsonRpcLocalStats.cs Refactors stats recording to lock-free + background report formatting.
src/Nethermind/Nethermind.JsonRpc/JsonRpcInputMode.cs Adds enum controlling single vs multiple top-level JSON documents acceptance.
src/Nethermind/Nethermind.JsonRpc/JsonRpcIdConverter.cs Adds converter for typed JsonRpcId.
src/Nethermind/Nethermind.JsonRpc/JsonRpcId.cs Adds typed ID value supporting numeric/string/missing/null and raw token writing.
src/Nethermind/Nethermind.JsonRpc/JsonRpcEnvelopeReader.cs Adds single-pass envelope reader for request bodies.
src/Nethermind/Nethermind.JsonRpc/JsonRpcEnvelope.cs Adds envelope struct to carry parsed top-level request details.
src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs Adds AdditionalTrustedNetworks configuration surface.
src/Nethermind/Nethermind.JsonRpc/JsonRpcArrayReader.cs Adds fast array counting and item slicing helpers.
src/Nethermind/Nethermind.JsonRpc/IResultWrapper.cs Makes wrapper Data nullable and adds HasErrorData.
src/Nethermind/Nethermind.JsonRpc/IJsonRpcService.cs Switches to ValueTask and typed JsonRpcId for error response IDs.
src/Nethermind/Nethermind.JsonRpc/IJsonRpcResponseSink.cs Adds response-sink abstraction.
src/Nethermind/Nethermind.JsonRpc/IJsonRpcProcessor.cs Changes processor API to push responses to a sink instead of yielding results.
src/Nethermind/Nethermind.JsonRpc/IJsonRpcLocalStats.cs Refactors local stats to synchronous interface and lock-free counters.
src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs Adds config doc + property for AdditionalTrustedNetworks.
src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs Fixes serializer strict-hex global state leakage across tests.
src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs Updates expected error payloads to match new error-data emission rules.
src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs Adds hot-method resolution and direct-invoker caching tests.
src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcSimulateTestsBase.cs Updates eth_call tests to compare byte payloads via HexBytes.
src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs Updates expected error payloads to match new error-data emission rules.
src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcSocketsClientTests.cs Adds sink framing/limits tests and updates processor substitutes to sink API.
src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs Adds coverage around raw UTF-8 params, typed result handling, disposal, and error-data suppression.
src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcLocalStatsTests.cs Updates stats tests for synchronous API + background report generation.
src/Nethermind/Nethermind.JsonRpc.Test/Data/IdConverterTests.cs Adds tests for typed JsonRpcId conversion/serialization edge cases.
src/Nethermind/Nethermind.JsonRpc.Test/Data/BlockParameterConverterTests.cs Makes test non-parallel and controls global strict-hex setting.
src/Nethermind/Nethermind.Core/Resettables/RecyclableStream.cs Adds overload with initial size hint for recyclable streams.
src/Nethermind/Nethermind.Core/JsonConverters/ByteArrayConverter.cs Adds span-based parsing helpers and expands inline buffers for encoding.
src/Nethermind/Nethermind.Core/JsonConverters/AddressConverter.cs Switches to exact-length span conversion via ByteArrayConverter.
src/Nethermind/Nethermind.Core/HexBytes.cs Adds a value type for hex-serialized byte payloads.
src/Nethermind/Nethermind.Core/Extensions/HexConverter.cs Adds TryCopyHexToUtf8 and refactors vector parsing into shared helper.
src/Nethermind/Nethermind.Core/BloomConverter.cs Optimizes bloom reading with span-based conversion first.
src/Nethermind/Nethermind.Core/Authentication/JwtAuthentication.cs Reuses HMAC instance for JWT validation to reduce allocations.
src/Nethermind/Nethermind.Core/Attributes/Metrics.cs Adds HistogramMetricAttribute for explicit histogram configuration.
src/Nethermind/Nethermind.Core.Test/Json/Hash256ConverterTests.cs Adds roundtrip test for ValueHash256Converter.
src/Nethermind/Nethermind.Core.Test/Json/ByteArrayConverterTests.cs Extends coverage around inline-buffer thresholds and output fidelity.
src/Nethermind/Nethermind.Core.Test/BytesTests.cs Adds tests for HexConverter.TryCopyHexToUtf8.
src/Nethermind/Nethermind.Benchmark/Core/ByteArrayConverterWriteBenchmarks.cs Adds benchmark comparing inline-buffer strategies vs production encoding.
Comments suppressed due to low confidence (5)

src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadBodiesByRangeV2Handler.cs:1

  • This handler has compile-time issues: array lengths and indices must be int, but end - start + 1 and i - start are long. Also the log message has an extra $ (\": ${error}\") which will print incorrectly. Convert the computed count/index to int (ideally with checked since MaxCount bounds it), and fix the interpolation to use {error}.
    src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadBodiesByRangeV2Handler.cs:1
  • This handler has compile-time issues: array lengths and indices must be int, but end - start + 1 and i - start are long. Also the log message has an extra $ (\": ${error}\") which will print incorrectly. Convert the computed count/index to int (ideally with checked since MaxCount bounds it), and fix the interpolation to use {error}.
    src/Nethermind/Nethermind.JsonRpc/JsonRpcIdConverter.cs:1
  • Throwing a parameterless NotSupportedException during JSON deserialization provides an unhelpful error to callers and often bypasses JsonException semantics (path/line info). Prefer throwing a JsonException (or a NotSupportedException with a clear message) describing which token types are valid for JSON-RPC IDs.
    src/Nethermind/Nethermind.Serialization.Json/StreamPipeWriter.cs:1
  • AddFlushMeasurement(startTimestamp) is not guaranteed to run if _writer.FlushAsync(...) completes synchronously but GetResult() throws (e.g., underlying stream failure). Wrap the synchronous completion path in a try/finally so measurements are recorded consistently on both success and failure (matching the async path behavior).
    src/Nethermind/Nethermind.Serialization.Json/HexBytesConverter.cs:1
  • This converter maps JSON null to an empty byte sequence, which makes null indistinguishable from \"0x\"/empty bytes at the API boundary. If null is not a valid wire value for HexBytes, it would be safer to throw JsonException on JsonTokenType.Null (or, if null should be supported, consider making the target type HexBytes? and returning null).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Nethermind/Nethermind.Core/Authentication/JwtAuthentication.cs
Comment thread src/Nethermind/Nethermind.Core/Authentication/JwtAuthentication.cs
@github-actions
Copy link
Copy Markdown
Contributor

EXPB Benchmark Comparison

Run: View workflow run

superblocks

Scenario: nethermind-flat-superblocks-jsonrpc-delay0s

Client Processing (SSE)

Metric PR Master (cached) Delta
AVG (ms) 1271.85 1261.46 +0.82%
MEDIAN (ms) 1135.4 1157.5 -1.91%
P90 (ms) 1666.7 1756.8 -5.13%
P95 (ms) 2185.8 2022.3 +8.08%
P99 (ms) 3633.4 5360.2 -32.22%
MIN (ms) 802.3 798.0 +0.54%
MAX (ms) 3633.4 5360.2 -32.22%
K6 TTFB
Metric PR Master (cached) Delta
AVG (ms) 1469.16 1514.35 -2.98%
MEDIAN (ms) 1304.15 1355.14 -3.76%
P90 (ms) 1840.81 1947.64 -5.49%
P95 (ms) 2427.99 2587.34 -6.16%
P99 (ms) 3658.45 4659.50 -21.48%
MIN (ms) 953.93 932.20 +2.33%
MAX (ms) 3812.12 5789.05 -34.15%

realblocks

Scenario: nethermind-flat-realblocks-jsonrpc-delay0s

Client Processing (SSE)

Metric PR Master (cached) Delta
AVG (ms) 35.12 34.93 +0.54%
MEDIAN (ms) 28.5 28.8 -1.04%
P90 (ms) 62.4 63.7 -2.04%
P95 (ms) 76.4 74.5 +2.55%
P99 (ms) 118.8 132.8 -10.54%
MIN (ms) 0.6 0.4 +50.00%
MAX (ms) 247.1 232.6 +6.23%
K6 TTFB
Metric PR Master (cached) Delta
AVG (ms) 41.01 40.63 +0.94%
MEDIAN (ms) 34.17 34.37 -0.58%
P90 (ms) 70.95 71.93 -1.36%
P95 (ms) 82.55 81.34 +1.49%
P99 (ms) 135.47 137.14 -1.22%
MIN (ms) 1.16 1.11 +4.50%
MAX (ms) 253.61 237.53 +6.77%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants