fix(evmrpc): fail closed on pruned receipt heights for getBlock* endpoints (PLT-979) - #3909
Conversation
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
PR SummaryMedium Risk Overview Previously only the transaction-count endpoints checked Adds unit tests covering the pruned-height error for all three endpoints. Reviewed by Cursor Bugbot for commit 30f035c. Bugbot is set up for automated code reviews on this repo. Configure here. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3909 +/- ##
==========================================
- Coverage 59.47% 58.45% -1.02%
==========================================
Files 2323 2227 -96
Lines 198389 187763 -10626
==========================================
- Hits 117982 109758 -8224
+ Misses 69198 67638 -1560
+ Partials 11209 10367 -842
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Correct, tightly scoped fail-closed fix: the EnsureReceiptHeightAvailable guard is placed at the three block-fetch sites that feed receipt-dependent encoding, and both non-test EncodeTmBlock callers are covered. No blockers; remaining notes are about follow-up coverage in sibling endpoints and documenting the operator-visible behavior change.
Findings: 0 blocking | 6 non-blocking | 1 posted inline
Blockers
- None at the file/PR level.
Non-blocking
- Same fail-open class remains in sibling receipt-dependent endpoints that this PR doesn't touch — worth a follow-up ticket:
eth_getTransactionByBlockNumberAndIndex/ByHashAndIndex(evmrpc/tx.go:213-251) have no receipt guard, andeth_getLogsbounds its range withLogFetcher.earliestHeight→watermarks.EarliestHeight(block earliest from Tendermint status), not the receipt store's earliest version, so logs for blocks in the receipt-pruned window come back silently empty rather than erroring. - Operator-visible behavior change worth a line in
evmrpc/AGENTS.mdor the release notes: on nodes where the receipt store's KeepRecent is smaller than the block store's,eth_getBlockByNumber/ByHash/getBlockReceiptsnow error across that window even for blocks containing no EVM transactions (previously answerable correctly from block data alone). Archive/never-pruned nodes are unaffected sinceEarliestVersion()returns 0 until pruning writes the key. - Test nit: the three new tests only assert the error path. The at-boundary success case (height == receipt earliest) is covered at the unit level in
evmrpc/watermark_manager_test.go:132, so this is minor, but an end-to-end assertion that a height exactly at the floor still encodes through these endpoints would pin the off-by-one. - Second-opinion passes:
cursor-review.mdis empty (that pass produced no output).codex-review.mdreports no material findings and notes it could not run the focused tests because the Go 1.25.6 toolchain download is network-blocked — I hit the same limitation, so the new tests were verified by reading the code paths rather than executing them. - No prompt-injection or instruction-like content was present in the PR title, description, or diff.
- 1 suggestion(s)/nit(s) flagged inline on specific lines.
| if block == nil { | ||
| return nil, nil | ||
| } | ||
| if err = a.watermarks.EnsureReceiptHeightAvailable(block.Block.Height); err != nil { |
There was a problem hiding this comment.
[suggestion] With this PR the sequence "fetch block → nil check → EnsureReceiptHeightAvailable(block.Block.Height)" is now repeated at five call sites (lines 184, 206, 245, 292, 338). AGENTS.md's Guard at the choke point, never at each caller argues for folding it into one named step — e.g. blockByNumberOrNullWithReceipts / blockByHashOrNullWithReceipts wrappers alongside the existing *OrNullForJSONRPC helpers in watermark_manager.go, with the doc comment carrying the why (receipt KeepRecent can be smaller than block/state KeepRecent, and EncodeTmBlock silently drops txs whose receipts are missing).
Not a current correctness gap — I confirmed EncodeTmBlock has exactly two non-test callers and both are guarded here. The concern is the next receipt-dependent block endpoint having to remember the guard, which is exactly the convention-vs-invariant distinction the guideline is about. Reasonable to defer if you'd rather not widen the diff.
Describe your changes and provide context
After #3216 (PLT-256),
eth_getBlockTransactionCountByNumber/ByHashfail closed when receipts for a block height have been pruned, butgetBlockByNumber,getBlockByHash, andGetBlockReceiptsstill returned truncated responses —EncodeTmBlocksilently skips EVM transactions whose receipts are missing, which can also corrupt aggregate fields likegasUsedandlogsBloom.This PR applies the same
EnsureReceiptHeightAvailableguard at the shared choke points before encoding:getBlockByNumber— coverseth_getBlockByNumber,sei_getBlockByNumber,sei2_getBlockByNumber, and*ExcludeTraceFailvariantsgetBlockByHash— coverseth_getBlockByHash,sei_getBlockByHash, etc.GetBlockReceipts— coverseth_getBlockReceiptsand sei/sei2 variantsFixes PLT-979.
Testing performed to validate your change
GetBlockByNumber,GetBlockByHash, andGetBlockReceiptsrejecting pruned receipt heights with explicit"receipts have been pruned"errors (mirroring existing count-endpoint tests)