Skip to content

feat(evmrpc): render unavailable blocks the way geth does - #4107

Draft
alexander-sei wants to merge 1 commit into
rfc-009-geth-error-parityfrom
rfc-009-block-resolution-parity
Draft

feat(evmrpc): render unavailable blocks the way geth does#4107
alexander-sei wants to merge 1 commit into
rfc-009-geth-error-parityfrom
rfc-009-block-resolution-parity

Conversation

@alexander-sei

Copy link
Copy Markdown
Contributor

Describe your changes and provide context

Second slice of RFC 009, stacked on #4102 (base branch rfc-009-geth-error-parity): the block-resolution choke point behind every eth_*/debug_* endpoint that takes a block identifier.

Today the watermark manager and the Tendermint block lookups build a finished Sei message (requested height N is not yet available; safe latest is M: …, block not found by hash, evm module does not exist on height N, …) at the point of detection, and that one string then leaks into every endpoint family unchanged. go-ethereum renders the same condition differently per family: null from the endpoints that return a block or something inside one, header not found / header for hash not found from the state-backed ones, unknown block from eth_getLogs, request beyond head block from eth_feeHistory, block #N not found from the tracers, and (since v1.16) 4444 pruned history unavailable for pruned history.

This PR makes the producers return one typed condition, *ethrpcerrors.BlockUnavailable, and each endpoint family render it at its own entry point.

  • ethrpcerrors.BlockUnavailable with reasons ErrBlockAboveLatest, ErrBlockUnknownHash, ErrBlockNotFound, ErrHistoryPruned, ErrStatePruned; Detail() keeps the heights for logs and tests, the wire message does not (go-ethereum's does not either).
  • Producers: WatermarkManager.ResolveHeight / EnsureBlockHeightAvailable / EnsureReceiptHeightAvailable, blockByNumberWithRetry / blockByHashWithRetry, CheckVersion.
  • Renderers: IsBlockMissing (block-fetch family → null), the condition's own Error() plus ForState (state family), ForLogs (eth_getLogs), BeyondHead (eth_feeHistory), and a nil block from Backend.BlockByNumber / BlockByHash so go-ethereum's tracer API emits its own block #N not found.
  • evmrpc/AGENTS.md gains the family table and the rules that keep it true.

Client-visible changes

Endpoint family Condition Before After
eth_call, eth_estimateGas, eth_createAccessList, eth_getBalance, eth_getCode, eth_getStorageAt, eth_getTransactionCount future number -32000 requested height N is not yet available; safe latest is M: block height not yet available -32000 header not found
same unknown hash -32000 block not found by hash -32000 header for hash not found
same pruned state / no store version -32000 requested height N has been pruned… / evm module does not exist on height N -32000 missing trie node: state at height N is not available[; earliest available is M]
eth_getBlockBy*, eth_getBlockReceipts, eth_getBlockTransactionCountBy*, eth_getTransactionByBlock*AndIndex block store has no block at an in-window height -32000 could not find block for height … null
same pruned blocks or receipts -32000 requested height N has been pruned… / …receipts have been pruned… 4444 pruned history unavailable
eth_getLogs unknown or zero blockHash [] -32000 unknown block
eth_getLogs range below earliest kept block -32000 requested fromBlock N is before earliest available block M 4444 pruned history unavailable
eth_feeHistory newest block above head -32000 requested last block N is not yet available; safe latest is M -32000 request beyond head block: requested N, head M
eth_feeHistory newest block below earliest -32000 requested last block is before earliest available height 4444 pruned history unavailable
debug_traceBlockBy*, debug_traceCall future number / unknown hash watermark text -32000 block #N not found / block 0x… not found (go-ethereum's own)

Decisions for review

  • 4444 pruned history unavailable is go-ethereum's history.PrunedHistoryError (v1.16, where history expiry landed; go.mod already requires v1.16.8 before the fork replace). RFC 009 said "no new JSON-RPC error codes"; this is go-ethereum's code, not a Sei one, but it is new to Sei's surface. Alternative: keep -32000 with the same text.
  • missing trie node is the prefix of the trie error go-ethereum's state endpoints return when the state at a kept header is gone, with Sei's height in place of the node and root hashes. Sei has no trie (evmrpc/AGENTS.md), so this follows the RFC's nearest-sentinel rule rather than describing Sei. Alternative: header not found for pruned state too, which loses the "you need an archive node" signal indexers key on.
  • eth_getLogs with an unknown blockHash moves from [] to -32000 unknown block. The empty array was silently wrong; go-ethereum has always errored here.
  • Ordering rules in ComputeBlockBounds (fromBlock above toBlock, a range past the head) are not availability conditions and keep their text; invalid block range params and geth's clamp-to-head are separate follow-ups.

Not in this PR (from the parity audit)

eth_call bare-revert() code 3 + data: "0x"; debug_traceTransaction unknown hash → transaction not found (today transaction indexing is in progress); eth_getTransactionReceipt failed to find transaction in blocknull; RPCContextProvider panic on CreateQueryContext failure; eth_syncingfalse, eth_blobBaseFee → value; filter does not existfilter not found; eth_feeHistory percentile messages; PrepareTx ante text on debug_trace*; uncle/header/raw-tx/txpool_*/net_*/web3_sha3 inventory; .iox @ expect_error_* directives for the non-send endpoints.

Testing performed to validate your change

  • go test ./evmrpc/ ./evmrpc/tests/ ./evmrpc/ethrpcerrors/ -count=1 (full suites, green; scripts/ramtest.sh for the focused subset)
  • new evmrpc/ethrpcerrors/block_test.go: golden table per reason, IsBlockMissing / ForLogs / ForState / BeyondHead, Sei-vocabulary negative assertion, JSON-RPC round trip through go-ethereum's rpc.Server pinning 4444 survives only when the error is the top-level return
  • unit tests that pinned the old strings now select on the typed reason (watermark_manager_test.go, height_availability_test.go, filter_bounds_test.go, info_test.go, tests/state_test.go)
  • integration_test/rpc_tests: the four [divergence] cases this covers (eth_call far-future and unknown hash, eth_estimateGas far-future, eth_feeHistory far-future) are now expectSameError parity tests; eth_getTransactionCount far-future became a parity test; EARLY_STATE_ERROR follows the new state text; npx tsc --noEmit clean
  • contracts/test/lib.js tryGetReceipt matches the new text; node --check clean
  • go build ./..., go vet on the changed packages, make fmtcheck (clean), scoped golangci-lint run ./evmrpc/...
  • The live Docker RPC parity suite was not run locally; draft until CI's "EVM RPC Parity (geth reference)" job runs.

Block, receipt and state lookups return one typed condition,
ethrpcerrors.BlockUnavailable, and each endpoint family renders it the
way go-ethereum does: null from the block-fetch endpoints, "header not
found" / "header for hash not found" from the state-backed ones,
"unknown block" from eth_getLogs, "request beyond head block" from
eth_feeHistory, go-ethereum's own "block #N not found" from the tracers,
and "4444 pruned history unavailable" for pruned history. Pruned state
renders as the "missing trie node" class with Sei's height as the detail.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedSep 8, 2026, 11:24 PM

@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.45977% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.29%. Comparing base (02e7602) to head (2883090).

Files with missing lines Patch % Lines
evmrpc/utils.go 33.33% 6 Missing ⚠️
evmrpc/simulate.go 20.00% 2 Missing and 2 partials ⚠️
evmrpc/filter.go 25.00% 3 Missing ⚠️
evmrpc/ethrpcerrors/block.go 96.55% 2 Missing ⚠️
evmrpc/info.go 50.00% 1 Missing ⚠️
evmrpc/watermark_manager.go 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                      Coverage Diff                      @@
##           rfc-009-geth-error-parity    #4107      +/-   ##
=============================================================
+ Coverage                      60.28%   60.29%   +0.01%     
=============================================================
  Files                           2088     2089       +1     
  Lines                         180580   180581       +1     
=============================================================
+ Hits                          108854   108877      +23     
+ Misses                         61584    61572      -12     
+ Partials                       10142    10132      -10     
Flag Coverage Δ
sei-chain-pr 73.11% <80.45%> (+2.15%) ⬆️
sei-db 69.80% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
evmrpc/ethrpcerrors/errors.go 95.60% <ø> (ø)
evmrpc/info.go 76.68% <50.00%> (ø)
evmrpc/watermark_manager.go 85.24% <88.88%> (ø)
evmrpc/ethrpcerrors/block.go 96.55% <96.55%> (ø)
evmrpc/filter.go 77.39% <25.00%> (+0.54%) ⬆️
evmrpc/simulate.go 76.15% <20.00%> (-0.55%) ⬇️
evmrpc/utils.go 71.49% <33.33%> (-1.20%) ⬇️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant