Conversation
Adds `compare --strict-response-comparison` for callers replaying recorded traffic against two builds of the same client, where any byte of difference is a finding. It removes three behaviours no rule could switch off, and changes nothing when the flag is absent: * `"0x"` no longer equals an all-zero hex string (`0x0`, `0x00`, `0x00...00`), in `result` and inside `error.data`. A client that omits a value and one that returns zero are not giving the same answer. * JSON numbers are decoded with `UseNumber` and compared by their literal digits, so two integers above 2**53 that differ no longer land on the same float64. `numericCode` reads an error `code` in both decoded shapes, or every strict-mode error would classify as code 0 and move the env/real difference split. * `--block-override` leaves an `eth_getLogs` filter that carries `blockHash` alone. `blockHash` is mutually exclusive with a range, so injecting `fromBlock`/`toBlock` turns a single-block query into a range query - a different request from the one that was recorded. `comparison-provenance.json` gains `strict_response_comparison` and `wire_transformations`: the original and effective params of every call the block override rewrote, in both modes. The result artifact carries the params the caller supplied, so without this the request the answers actually belong to was recorded nowhere. Explicit rules are untouched in both modes: `ignore`, `numeric_tolerance` and the built-in `eth_estimateGas` tolerance behave exactly as before. Verification: `go build ./...` and `go vet ./runner/...` clean; `go test ./runner/comparator/` 62 tests pass (53 before), also under `-race`; `go test ./runner/...` otherwise unchanged (`runner` still fails `TestP99DataFlow`, which needs a postgres on :5432, on main too). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Note on the red Build and publish Docker image check — it is not caused by this PR. The Trivy gate fails on one finding, and it is in a third-party binary this branch does not touch:
The fix is another entry in |
Follow-up to the review of this PR. The recorder skips a call whose effective params equal the ones it was given, but no test covered the case that guard exists for: a call that already carries the block it is pinned to, where the override copies the params and changes nothing. Nor did any test drive the recorder from more than two goroutines. TestStrictIntegration_WireTransformsRecordOnlyChanges runs 60 eth_call variants at concurrency 16 -- half tagged `latest`, half already pinned to the override block -- and asserts that exactly the 30 that changed are recorded, in a stable order. It fails if the guard is dropped and passes under -race, which the single-call tests could not show. `runStrictPair` gains a concurrency parameter (`runStrictPairAt`); existing callers keep concurrency 1. Verification: `go vet ./runner/...` clean; `go test ./runner/comparator/` 63 tests pass (62 before this commit, 53 on origin/main), also under -race. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Trivy gate went red on a HIGH in google.golang.org/grpc v1.81.1. It is not a dependency of this repository — `grpc` appears nowhere in go.mod or go.sum — it is vendored into `usr/bin/k6`, which grafana/k6 ships prebuilt and nothing here rebuilds. `app/jsonrpc-bench-runner` and the Alpine layer both scan 0. No published k6 clears it: 2.1.0 (the pinned base) carries grpc 1.81.1 and 2.2.0, the newest release, carries 1.83.0, against fixes in 1.82.2 and 1.83.2. k6 `master` is already on 1.83.2, so the next release should retire this entry and the two grpc entries beside it. Bumping the base image to 2.2.0 today would move the version without clearing the finding. The entry follows the file's existing convention: scoped by purl so the same CVE in our own binary still fails the gate, with the December expiry as the backstop. GHSA-2v4p-qf9q-27wj is reachable only in a server built with `xds.NewGRPCServer()`; k6's gRPC module is a client, this suite benchmarks JSON-RPC over HTTP, and the image listens on no gRPC port. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Summary
comparegains--strict-response-comparison, for callers replaying recorded traffic against two builds of the same client, where any byte of difference is a finding. It removes three implicit normalizations that no rule could switch off, and records what the block override actually put on the wire. Nothing changes when the flag is absent — the default path is byte-for-byte the behaviour onmain, and explicitignore/numeric_tolerancerules and the built-ineth_estimateGastolerance behave identically in both modes.This is "PR-S" in the Nethermind RPC differential-testing plan;
NethermindEth/rpc-corpus-toolsalready holds the executable specification for it (tests/test_strict_comparator.py,tests/test_wire_replay.py), where these cases arexfail(strict=True)against this change.--strict-response-comparison"0x"equals any all-zero hex string (0x0,0x00,0x00…00), inresultand insideerror.data, before any rule is consultedfloat64, so two integers above 2⁵³ that differ can compare equalUseNumberand compared by their literal digits--block-overrideaddsfromBlock/toBlockto aneth_getLogsfilter carryingblockHash, turning a single-block query into a range queryblockHashis sent unchangedcomparison-provenance.jsongainsstrict_response_comparisonandwire_transformations— the original and effective params of every call the block override rewrote, written in both modes. The result artifact carries the params the caller supplied, so without this the request the answers actually belong to was recorded nowhere.One non-obvious consequence handled here: under
UseNumberan errorcodeis ajson.Number, not afloat64. Left alone,errorCodeandclassifyErrorwould read every strict-mode error as code0and quietly move the environment/real difference split.numericCodereads both shapes and is covered by a test.comparator/diff.go,comparator/rules.go(diffContext.strict)comparator/transport.go(decodeResponse),diff.go(json.Numbercase),rules.go(numericCode)eth_getLogsblockHashguardcomparator/block_override.gocomparator/comparator.go(wireTransform,Provenance)cmd/compare.go,.claude/skills/compare-nodes/references/flags.mdCI
This repository runs no Go test workflow (
build_docker_image.ymlandcodeql.ymlonly), so the evidence is the local runs below.Verification
Cross-repo, against the consumer's executable spec (
rpc-corpus-toolsat0bc6e31, this branch's binary viaRPC_CORPUS_JSON_BENCH_BIN):Those six are the consumer's signal that the change landed; they are updated on the
rpc-corpus-toolsside when it bumps its pin to this commit.🤖 Generated with Claude Code