feat(jsonrpc): return code 3 for revert and 4444 for pruned history
0X
15d ago+1071+1071+0123456789012345678901234567890123456789-165-165-012345678901234567890123456789
First of two PRs for #6676; request validation is split out (see Follow up).
What does this PR do?
Aligns two JSON-RPC error behaviors with the Ethereum Execution API:
-
Contract revert returns code
3.eth_callandeth_estimateGasreturncode: 3instead of-32000; other execution failures stay-32000.Wallet.callConstantContractnow recordscontractReton the result, so the JSON-RPC layer classifies on the enum rather than on the error message. -
Pruned history returns
4444 "Pruned history unavailable".- Block-body methods (
eth_getBlockByNumber,eth_getBlockTransactionCountByNumber,eth_getTransactionByBlockNumberAndIndex): on a LiteNode, heights below the lowest stored block. Genesis stays queryable. - Receipt and log methods (
eth_getBlockReceipts,eth_getLogs,eth_newFilter), including when the block is selected by hash: on any node whentransHistory.switch = off; otherwise on a LiteNode, heights below the lowest receipt block (the first block intransactionRetStore, read at startup). A FullNode has no such check — receipts from before June 2019 may still be served fromTransactionHistoryStore, so the store's first key is not a lower bound — and receipt gaps on a FullNode keep the current behavior. - As in geth, 4444 carries no block number;
datais the"{}"placeholder every java-tron JSON-RPC error has. earliestresolves to the lowest block with all persisted data: on a LiteNode the lowest receipt block (the lowest stored block when receipts are not persisted), on a FullNode 0.
- Block-body methods (
Why are these changes required?
- Under
-32000, a contract revert cannot be told apart from out-of-energy or any other TVM failure. - A LiteNode returns
nullfor pruned blocks, which reads as "block does not exist", andeth_getLogsacross the cutoff returns incomplete results without an error.
Breaking changes (release-note items):
eth_call/eth_estimateGas: a contract revert returns3instead of-32000.- LiteNode: heights below the lowest available block return
4444instead ofnullon block-body methods, and instead of-32000or incomplete results on receipt and log methods. - Any node with
transHistory.switch = off: receipt and log queries return4444, including for receipts already on disk. earlieston a LiteNode resolves to the lowest available block instead of 0.
This PR has been tested by:
- Unit tests — revert classification, the pruned-history rules on both node types with the switch on and off, reading the lowest receipt block at startup, and resolver declaration-order independence.
- Manual testing — 141 JSON-RPC cases against the full and solidity endpoints, on Nile and mainnet LiteNode snapshots (switch on and off) and on a private-chain FullNode (switch on, off, and the receipt gap left after turning it back on). After the review fixes, re-run on a private-chain FullNode and a private LiteNode snapshot (switch on and off): 106/106.
Follow up
- Request-envelope validation (
jsonrpcversion, non-stringmethod, explicitid: null) in a new PR. - Toolkit: retain the snapshot window's receipts so bodies and receipts share one boundary.
Extra details
- The solidity JSON-RPC endpoint follows the same rules.
- Side effect (not breaking): gRPC/HTTP
triggerConstantContractresponses now carrycontractRet: REVERTwhen the call reverts. - Every REVERT returns
3, including one with empty revert data; geth returns-32000in that case. - Only single-block and genesis-only queries are exempt for genesis:
eth_getLogsfrom0x0to a later block on a LiteNode returns4444, as geth does. - Hash-based selectors, refining "null-only" from #6676: a pruned block cannot be found by hash, so a pruned hash cannot be told apart from an invalid one, and those lookups keep returning
null. Wheneth_getBlockReceiptsoreth_getLogsdoes find the block by hash, its number is known and the receipt rules above apply.eth_getBlockByHash,eth_getTransactionByHashandeth_getTransactionReceiptare unchanged.