Skip to content

rpc/jsonrpc, rpc/gasprice: gate block-data and replay endpoints on the data they read - #23760

Merged
AskAlexSharov merged 7 commits into
mainfrom
lupin012/gate_block_data_endpoints
Sep 5, 2026
Merged

rpc/jsonrpc, rpc/gasprice: gate block-data and replay endpoints on the data they read#23760
AskAlexSharov merged 7 commits into
mainfrom
lupin012/gate_block_data_endpoints

Conversation

@lupin012

@lupin012 lupin012 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #23322, same defect class as #21965: an endpoint that gates on state history refuses data that was never pruned away.

  • debug_getRawBlock, debug_getRawTransaction and erigon_getBlockByTimestamp read the body and nothing else, so they now gate on Mode.Blocks instead of Mode.History.
  • eth_feeHistory had no gate. Headers carry the base-fee and gas-used series, so only the reward-percentile path is gated, on the oldest block of the resolved range, via a new OracleBackend.CheckBlockReceiptsAvailable.
  • The endpoints that replay a block read its transactions as well as the state history before it, and gated on history alone: trace_block, trace_transaction, trace_filter, trace_replayTransaction, trace_replayBlockTransactions, debug_traceBlockByNumber, debug_traceBlockByHash, debug_traceTransaction, the Otterscan searches and the Otterscan tracer helper. They now gate on both boundaries. The *_call endpoints execute against the state a block leaves behind and stay on history.

In the named presets history is always the stricter boundary, which is why the missing blocks leg stayed invisible. It shows up with --prune.mode=archive --prune.distance.blocks=N.

Tests: the prune-gating table gains rows for the header, block-data, fee-history, trace and Otterscan-search endpoints, plus an archive_blocks_window mode row — without a mode where blocks is stricter than history, the blocks leg cannot be observed.

…e data they read

Follow-up to #23322, same defect class as #21965: an endpoint that gates on
state history refuses data that was never pruned away.

1. The endpoints that need a block body and nothing else -- debug_getRawBlock,
debug_getRawTransaction and erigon_getBlockByTimestamp -- gated on
Mode.History, so under --prune.mode=blocks they refused bodies the node still
holds. They now gate on Mode.Blocks.

2. eth_feeHistory had no gate at all. The base-fee and gas-used series come
from headers, which no retention shape takes away, but reward percentiles are
computed from each block's transactions and the gas their receipts report. The
oracle now checks the oldest block of the resolved range through a new
OracleBackend method when percentiles are requested, so a range reaching below
retention answers with the prune error instead of a truncated result.

3. The endpoints that replay a block read its transactions on top of the state
history preceding it, and gated on history alone: the trace and debug tracing
entry points (trace_block, trace_transaction, trace_filter,
trace_replayTransaction, trace_replayBlockTransactions, debug_traceBlockBy*,
debug_traceTransaction), the Otterscan searches, and the Otterscan tracer
helper. They now gate on both boundaries. debug_traceCall, trace_call,
trace_callMany and trace_rawTransaction execute against the state a block
leaves behind and stay on history.

The endpoint table gains rows for the header, block-data, fee-history, trace
and Otterscan-search endpoints, plus a prune-mode row where the blocks
boundary is stricter than the history one (--prune.mode=archive
--prune.distance.blocks=N). That row is what makes the blocks leg observable;
it also showed the two by-address log rows were declared as history-only when
the query reads bodies as well.
…ata_endpoints

# Conflicts:
#	rpc/jsonrpc/check_prune_gates_test.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Timestamp and Otterscan edge paths still apply the blocks gate to the wrong effective block.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates RPC pruning gates to match the block, receipt, or state data each endpoint reads.

Changes:

  • Gates block-data and replay endpoints on correct retention boundaries.
  • Adds receipt availability checks for fee-history rewards.
  • Expands prune-mode endpoint coverage.
File summaries
File Description
rpc/jsonrpc/tracing.go Gates debug replay endpoints on blocks and history.
rpc/jsonrpc/trace_filtering.go Updates trace endpoint gates.
rpc/jsonrpc/trace_adhoc.go Updates replay endpoint gates.
rpc/jsonrpc/prune_gating_test.go Expands endpoint and prune-mode coverage.
rpc/jsonrpc/otterscan_api.go Adds block availability to Otterscan gates.
rpc/jsonrpc/eth_system.go Exposes receipt availability to the gas oracle.
rpc/jsonrpc/erigon_block.go Changes timestamp lookup to the blocks gate.
rpc/jsonrpc/debug_api.go Corrects raw block and transaction gates.
rpc/jsonrpc/check_prune_gates_test.go Tests fee-history range gating.
rpc/gasprice/gasprice.go Extends the oracle backend interface.
rpc/gasprice/gasprice_test.go Updates the oracle mock.
rpc/gasprice/feehistory.go Gates reward percentile data.
rpc/gasprice/feehistory_truncate_test.go Updates the truncation test backend.
Review details
  • Files reviewed: 13/13 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rpc/jsonrpc/erigon_block.go Outdated
Comment thread rpc/jsonrpc/otterscan_api.go Outdated
…ata_endpoints

# Conflicts:
#	rpc/gasprice/feehistory_truncate_test.go
#	rpc/gasprice/gasprice.go
#	rpc/gasprice/gasprice_test.go
erigon_getBlockByTimestamp resolved the block number on three separate
paths, each with its own buildBlockResponse, and the blocks gate sat on
the last one only. A timestamp at or before the genesis one took the
early return and answered with null instead of PrunedError when the
retention window prunes genesis. blockNumByTimestamp now resolves the
number for all three cases, leaving one gate and one response path.

The Otterscan searches passed the paginating blockNum straight to the
gate, where 0 is the sentinel for the newest (or oldest) page rather
than a request for genesis, so the first page of
ots_searchTransactionsBefore failed on archive history with a blocks
window. The sentinel is excluded from the entry gate and
buildSearchResults gates every block the scan reaches, once per block
and before reading its body, so a sparse page cannot cross the cutoff
unnoticed.
@lupin012
lupin012 marked this pull request as ready for review September 3, 2026 18:47
@lupin012
lupin012 requested a review from yperbasis as a code owner September 3, 2026 18:47
@AskAlexSharov

Copy link
Copy Markdown
Collaborator

Complexity-only pass: the production diff is mostly a swap between gate helpers that already exist on main, so what is left to cut sits in the test file.

rpc/jsonrpc/prune_gating_test.go:605-623: shrink: TestSearchTransactionsBeforeNewestPage and TestSearchTransactionsBeforeGatesScannedBlocks have identical setup and differ only in pageSize (3 vs 25). One test with two calls — and one setupPruneGating instead of two, which is the expensive part.

rpc/jsonrpc/otterscan_api.go:222 and :253: shrink: the same if blockNum != 0 guard, with the sentinel rationale spelled out at both sites. Full comment at the first, a terse pointer at the second (CLAUDE.md: state the why once).

rpc/jsonrpc/prune_gating_test.go:222-233: yagni: the three notGated header rows pin endpoints this PR does not touch — no gate exists there to break. Optional: they are cheap and they do bracket the spectrum. notGated itself stays, eth_feeHistory needs it.

net: -23 lines possible.

One thing I looked at and would not cut: OracleBackend.CheckBlockReceiptsAvailable. The gate needs oldestBlock, which only exists after FeeHistory resolves the range, so hoisting it to the eth_system.go caller would duplicate that resolution. The interface method is the shorter of the two.

@AskAlexSharov
AskAlexSharov added this pull request to the merge queue Sep 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 4, 2026
…nel comment

Review follow-up. The two SearchTransactionsBefore tests differed only in
page size and paid for setupPruneGating twice; one test with two calls keeps
both legs and one setup. The blockNum == 0 rationale now lives at
SearchTransactionsBefore alone, with a pointer from SearchTransactionsAfter.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The fee-history gate can admit pruned receipt metadata and return incorrect reward percentiles.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread rpc/jsonrpc/eth_system.go Outdated
}

func (b *GasPriceOracleBackend) CheckBlockReceiptsAvailable(ctx context.Context, blockNumber uint64) error {
return b.baseApi.checkBlockReceiptsAvailable(ctx, b.tx, blockNumber)
The reward percentiles read the gas used through GetReceiptsGasUsed, which
resolves it from ReceiptDomain (retired with state history) and never from
RCacheDomain, so gating on the receipt-cache retention let a range below the
history cutoff through and resolved its gas used from pruned history.

Gate on blocks plus history instead, and rename the backend method so it names
the data the oracle actually reads.
@AskAlexSharov
AskAlexSharov added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit f7d1c9c Sep 5, 2026
138 checks passed
@AskAlexSharov
AskAlexSharov deleted the lupin012/gate_block_data_endpoints branch September 5, 2026 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants