Skip to content

fix(prover): implement eth_getBlockNumber verified request handler#9203

Open
TechFusionData wants to merge 5 commits intoChainSafe:unstablefrom
TechFusionData:fix/prover-eth-getBlockNumber-5796
Open

fix(prover): implement eth_getBlockNumber verified request handler#9203
TechFusionData wants to merge 5 commits intoChainSafe:unstablefrom
TechFusionData:fix/prover-eth-getBlockNumber-5796

Conversation

@TechFusionData
Copy link
Copy Markdown

Closes #5796. The prover was forwarding eth_getBlockNumber to the execution layer instead of serving it locally from the PayloadStore, which defeats the purpose of the verified light client proxy.

Changes:

  • Add eth_getBlockNumber handler in verified_requests/ that reads the latest block number from proofProvider.getExecutionPayload('latest') and returns it as a hex string
  • Register the handler in verifiableMethodHandlers in utils/process.ts
  • Add unit tests for happy path and verification-failed error path

Note: Implementation assisted with AI (Claude).

Motivation

The prover was forwarding eth_getBlockNumber to the execution layer instead of serving it locally, defeating the purpose of the verified light client proxy.

Implements a verified handler for eth_getBlockNumber following the same pattern as eth_getBlockByNumber. Reads the block number from proofProvider.getExecutionPayload('latest') and returns it as a hex string. Includes unit tests for both happy path and verification failure.

Closes #issue_number

AI Assistance Disclosure

Used Claude (Anthropic) to assist with implementation and writing unit tests. The approach, logic, and code were reviewed and understood by me before submission.

Resolves ChainSafe#5796. The prover was forwarding eth_getBlockNumber to the
execution layer instead of serving it locally from the PayloadStore,
which defeats the purpose of the verified light client proxy.

Changes:
- Add eth_getBlockNumber handler in verified_requests/ that reads the
  latest block number from proofProvider.getExecutionPayload('latest')
  and returns it as a hex string
- Register the handler in verifiableMethodHandlers in utils/process.ts
- Add unit tests for happy path and verification-failed error path

Note: Implementation assisted with AI (Claude).
@TechFusionData TechFusionData requested a review from a team as a code owner April 10, 2026 15:37
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new verified request handler for retrieving the latest block number. The implementation includes the handler logic, its registration in the processing utility, and corresponding unit tests. The primary feedback across all files is that the method name used, eth_getBlockNumber, should be renamed to eth_blockNumber to comply with the standard Ethereum JSON-RPC specification. This change is necessary to ensure that incoming standard-compliant requests are correctly routed to and processed by this handler.

Comment thread packages/prover/src/utils/process.ts Outdated
Comment thread packages/prover/src/utils/process.ts Outdated
Comment thread packages/prover/src/verified_requests/eth_getBlockNumber.ts Outdated
Comment thread packages/prover/src/verified_requests/eth_getBlockNumber.ts Outdated
Comment thread packages/prover/test/unit/verified_requests/eth_getBlockNumber.test.ts Outdated
Comment thread packages/prover/test/unit/verified_requests/eth_getBlockNumber.test.ts Outdated
Comment thread packages/prover/test/unit/verified_requests/eth_getBlockNumber.test.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ab28268cc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/prover/src/utils/process.ts Outdated
eth_getTransactionCount: eth_getTransactionCount,
eth_getBlockByHash: eth_getBlockByHash,
eth_getBlockByNumber: eth_getBlockByNumber,
eth_getBlockNumber: eth_getBlockNumber,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Register verified handler under eth_blockNumber

processAndVerifyRequest routes verification by exact RPC method name from verifiableMethodHandlers, but this entry is keyed as eth_getBlockNumber instead of the standard eth_blockNumber. In practice, clients call eth_blockNumber, so those requests will still be classified as non-verifiable and forwarded to EL, meaning this change does not actually implement verified block-number handling (and keeps the original trust gap).

Useful? React with 👍 / 👎.

The standard Ethereum JSON-RPC method is eth_blockNumber, not
eth_getBlockNumber. The incorrect key in verifiableMethodHandlers caused
standard-compliant requests to bypass the verified handler entirely.

Changes:
- Rename eth_getBlockNumber.ts -> eth_blockNumber.ts
- Rename eth_getBlockNumber.test.ts -> eth_blockNumber.test.ts
- Rename exported handler constant to eth_blockNumber
- Update registration key in verifiableMethodHandlers
- Update error message string to eth_blockNumber
- Update test: method field, import, and expected error message

Addresses bot review feedback on ChainSafe#9203.
Comment on lines +10 to +15
export const eth_blockNumber: ELVerifiedRequestHandler<[], string> = async ({payload, logger, proofProvider}) => {
try {
const executionPayload = await proofProvider.getExecutionPayload("latest");
const blockNumber = numberToHex(executionPayload.blockNumber);

return getResponseForRequest(payload, blockNumber);
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.

The verification process is missing in these statements, which is main motivation of the verified_requests in prover.

User request for eth_bl;ockNumber meant to fetch latest block from the EL nodes. So we should fetch that first and then verify against our CL light-client.

Fetch block number from EL node and verify against CL light client
before returning, matching the pattern used by other verified_requests
handlers. Add eth_blockNumber to ELApi type map.
@TechFusionData
Copy link
Copy Markdown
Author

Thanks for the review — you're right, the handler was only reading from the CL without fetching from the EL first. Fixed in the latest commit: now fetches eth_blockNumber from the EL, then verifies it against the CL's latest execution payload before returning. Also added eth_blockNumber to the ELApi type map.

Comment on lines +11 to +29
export const eth_blockNumber: ELVerifiedRequestHandler<[], string> = async ({payload, rpc, logger, proofProvider}) => {
try {
const elResponse = await rpc.request("eth_blockNumber", [], {raiseError: false});

if (!isValidResponse(elResponse)) {
throw new Error("Invalid response from EL for eth_blockNumber");
}

const elBlockNumber = parseInt(elResponse.result, 16);
const executionPayload = await proofProvider.getExecutionPayload("latest");
const clBlockNumber = executionPayload.blockNumber;

if (elBlockNumber < clBlockNumber) {
throw new Error(
`EL block number (${elBlockNumber}) is behind CL block number (${clBlockNumber})`
);
}

return getResponseForRequest(payload, numberToHex(elBlockNumber));
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.

Looking at this whole logic holistically, I feel it's not right.

  • el < cl means the EL is stale/inconsistent relative to your trusted CL-derived execution payload
  • el >= cl means at least the EL is not behind the trusted lower bound

But there’s still a conceptual issue:

  • if you return elBlockNumber when el > cl, that returned value is not actually CL-verified
  • it is only “not contradicted by CL”

So looking from the user perspective what he is expecting a verified latest block number and that can only mean a CL execution payload block number.

So we can do it with either 2 ways:

  1. Do not call EL at all and only return what CL verified view is
  2. Add drift window e.g. 2 blocks, so if EL is maximum 2 blocks forward then it's ok otherwise we consider that CL is too much behind to even consider it a verified latest block number.

The second approach seems more reasonable to me.

Previous logic returned EL's block number when EL >= CL, but that value
was not actually CL-verified — only 'not contradicted by CL'. Now we
return the CL block number directly and use the EL response only as a
sanity check that CL isn't too stale (drift window of 2 blocks).
@TechFusionData
Copy link
Copy Markdown
Author

Good point — you're right that returning EL's block when EL > CL means it's only "not contradicted" by CL, not actually verified. Updated to your second approach: drift window of 2 blocks. The handler now uses the EL response only as a staleness check (rejects if |EL − CL| > 2) and returns the CL-verified block number itself. Tests cover the four edge cases (within window, equal, EL behind CL, CL too stale).

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.

Verification of eth_getBlockNumber for prover should not forward request

3 participants