Description
Nethermind returns one empty response item for GetBlockBodies and GetReceipts requests whose requested hash is not a known block. The minimal same-chain case uses the all-zero hash, and the same behavior also reproduced with unknown non-zero hashes in boundary hunting.
For GetBlockBodies, an unavailable block can be omitted from the response. For GetReceipts, responses should preserve request order and stop at the first unavailable block. In both cases, returning a placeholder entry for an unknown hash makes the response look like data for a known empty block.
The issue was found with WireWasp, our own devp2p/ETH wire fuzzer and replay harness. The attached bundle includes the exact WireWasp cases, run configuration, raw request/response hex, replay results, JSON-RPC control, and comparator output from Geth, Reth, Erigon, and Besu.
Steps to Reproduce
With the attached WireWasp reproduction bundle:
- Start the same-chain lab:
go run ./cmd/wasp-lab \
-config env/config.yaml \
-inventory env/inventory.samechain.yaml \
-tier samechain up
- Run the refreshed differential replay:
TARGETS='geth-s reth-s erigon-s besu-s nethermind-s' \
OUT_DIR=output/regressions/review-refresh-nethermind-zero-hash-20260417 \
scripts/regress-finding.sh \
findings/confirmed/2026-04-11-nethermind-zero-hash-bodies-receipts
- Check
evidence/artifacts/review-refresh-20260417/summary.tsv.
General reproduction without WireWasp:
- Run Nethermind on a devnet and connect with any devp2p test peer that can speak RLPx and
eth/69.
- Complete RLPx hello and ETH status.
- Send
GetBlockBodies with request id 1 and one hash: 0x0000000000000000000000000000000000000000000000000000000000000000.
- Repeat on a fresh session with
GetReceipts for the same hash.
- Use JSON-RPC
eth_getBlockByHash for the same hash as a control. In our run it returned null.
- Compare against Geth/Reth/Erigon/Besu on the same genesis.
Actual behavior
Nethermind returned one item for each unknown-hash request:
GetBlockBodies: block_bodies request=1 count=1
GetReceipts: receipts request=1 count=1
The raw minimized request payload for both cases is:
e301e1a00000000000000000000000000000000000000000000000000000000000000000
The observed Nethermind response payload is:
On the same chain, Geth, Reth, Erigon, and Besu returned count 0 for both request families. JSON-RPC on the Nethermind node reported the all-zero hash as absent:
{"jsonrpc":"2.0","result":null,"id":1}
Expected behavior
For an unknown block hash, GetBlockBodies should not include a body entry for that hash. GetReceipts should not include a receipt list for an unavailable block; if a requested block is missing, the response should end at that point rather than adding a placeholder item.
Screenshots
Not applicable. This is a wire-protocol response issue. The bundle includes raw RLP payloads, transcripts, JSON replay results, and comparator summaries.
Desktop (please complete the following information):
- Operating System: Linux
- Version:
Nethermind/v1.36.2+f5507dec/linux-x64/dotnet10.0.1
- Installation Method: Docker image
nethermind/nethermind:latest
- Consensus Client: not used in this devnet reproduction
- Network: same-chain devnet, network id
12345
- Genesis hash:
0x10bf86bf4072831c4648c9585d22c9426d998fc31962029dc57aa8aa0594751b
- Comparators: Geth v1.17.1, Reth v1.11.3, Erigon v3.1.0, Besu v26.2.0
Additional context
This is a high-confidence semantic issue, but I am reporting it as a normal protocol correctness bug rather than a security vulnerability. Boundary probes in the attached material show the behavior is not limited to the all-zero hash: unknown non-zero hashes also returned one empty body/receipt item per requested hash on Nethermind, while comparator clients returned empty responses.
Logs
The attached zip contains:
evidence/artifacts/review-refresh-20260417/summary.tsv
evidence/artifacts/review-refresh-20260417/summary.json
evidence/artifacts/review-refresh-20260417/*nethermind*.json
evidence/artifacts/samechain-block-bodies/transcript/*.hex
evidence/artifacts/samechain-block-bodies/result.json
evidence/artifacts/samechain-receipts/transcript/*.hex
evidence/artifacts/samechain-receipts/result.json
evidence/artifacts/samechain-lab/status.json
evidence/config/env.config.yaml
evidence/config/inventory.samechain.yaml
evidence/testcases/testcase.block-bodies.min.yaml
evidence/testcases/testcase.receipts.min.yaml
evidence.zip
Description
Nethermind returns one empty response item for
GetBlockBodiesandGetReceiptsrequests whose requested hash is not a known block. The minimal same-chain case uses the all-zero hash, and the same behavior also reproduced with unknown non-zero hashes in boundary hunting.For
GetBlockBodies, an unavailable block can be omitted from the response. ForGetReceipts, responses should preserve request order and stop at the first unavailable block. In both cases, returning a placeholder entry for an unknown hash makes the response look like data for a known empty block.The issue was found with WireWasp, our own devp2p/ETH wire fuzzer and replay harness. The attached bundle includes the exact WireWasp cases, run configuration, raw request/response hex, replay results, JSON-RPC control, and comparator output from Geth, Reth, Erigon, and Besu.
Steps to Reproduce
With the attached WireWasp reproduction bundle:
TARGETS='geth-s reth-s erigon-s besu-s nethermind-s' \ OUT_DIR=output/regressions/review-refresh-nethermind-zero-hash-20260417 \ scripts/regress-finding.sh \ findings/confirmed/2026-04-11-nethermind-zero-hash-bodies-receiptsevidence/artifacts/review-refresh-20260417/summary.tsv.General reproduction without WireWasp:
eth/69.GetBlockBodieswith request id1and one hash:0x0000000000000000000000000000000000000000000000000000000000000000.GetReceiptsfor the same hash.eth_getBlockByHashfor the same hash as a control. In our run it returnednull.Actual behavior
Nethermind returned one item for each unknown-hash request:
GetBlockBodies:block_bodies request=1 count=1GetReceipts:receipts request=1 count=1The raw minimized request payload for both cases is:
The observed Nethermind response payload is:
On the same chain, Geth, Reth, Erigon, and Besu returned count
0for both request families. JSON-RPC on the Nethermind node reported the all-zero hash as absent:{"jsonrpc":"2.0","result":null,"id":1}Expected behavior
For an unknown block hash,
GetBlockBodiesshould not include a body entry for that hash.GetReceiptsshould not include a receipt list for an unavailable block; if a requested block is missing, the response should end at that point rather than adding a placeholder item.Screenshots
Not applicable. This is a wire-protocol response issue. The bundle includes raw RLP payloads, transcripts, JSON replay results, and comparator summaries.
Desktop (please complete the following information):
Nethermind/v1.36.2+f5507dec/linux-x64/dotnet10.0.1nethermind/nethermind:latest123450x10bf86bf4072831c4648c9585d22c9426d998fc31962029dc57aa8aa0594751bAdditional context
This is a high-confidence semantic issue, but I am reporting it as a normal protocol correctness bug rather than a security vulnerability. Boundary probes in the attached material show the behavior is not limited to the all-zero hash: unknown non-zero hashes also returned one empty body/receipt item per requested hash on Nethermind, while comparator clients returned empty responses.
Logs
The attached zip contains:
evidence/artifacts/review-refresh-20260417/summary.tsvevidence/artifacts/review-refresh-20260417/summary.jsonevidence/artifacts/review-refresh-20260417/*nethermind*.jsonevidence/artifacts/samechain-block-bodies/transcript/*.hexevidence/artifacts/samechain-block-bodies/result.jsonevidence/artifacts/samechain-receipts/transcript/*.hexevidence/artifacts/samechain-receipts/result.jsonevidence/artifacts/samechain-lab/status.jsonevidence/config/env.config.yamlevidence/config/inventory.samechain.yamlevidence/testcases/testcase.block-bodies.min.yamlevidence/testcases/testcase.receipts.min.yamlevidence.zip