Skip to content

feat(jsonrpc): return code 3 for revert and 4444 for pruned history - #22

Open
0xbigapple wants to merge 12 commits into
release_v4.8.3from
feature/jsonrpc-revert-and-pruned-history
Open

0xbigapple wants to merge 12 commits into
release_v4.8.3from
feature/jsonrpc-revert-and-pruned-history

Conversation

@0xbigapple

@0xbigapple 0xbigapple commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

First of two PRs for tronprotocol#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:

  1. Contract revert returns code 3. eth_call and eth_estimateGas return code: 3 instead of -32000; other execution failures stay -32000. Wallet.callConstantContract now records contractRet on the result, so the JSON-RPC layer classifies on the enum rather than on the error message.

  2. 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 when transHistory.switch = off; otherwise on a LiteNode, heights below the lowest receipt block (the first block in transactionRetStore, read at startup). A FullNode has no such check — receipts from before June 2019 may still be served from TransactionHistoryStore, 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; data is the "{}" placeholder every java-tron JSON-RPC error has.
    • earliest resolves 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.

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 null for pruned blocks, which reads as "block does not exist", and eth_getLogs across the cutoff returns incomplete results without an error.

Breaking changes (release-note items):

  • eth_call / eth_estimateGas: a contract revert returns 3 instead of -32000.
  • LiteNode: heights below the lowest available block return 4444 instead of null on block-body methods, and instead of -32000 or incomplete results on receipt and log methods.
  • Any node with transHistory.switch = off: receipt and log queries return 4444, including for receipts already on disk.
  • earliest on 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 (jsonrpc version, non-string method, explicit id: 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 triggerConstantContract responses now carry contractRet: REVERT when the call reverts.
  • Every REVERT returns 3, including one with empty revert data; geth returns -32000 in that case.
  • Only single-block and genesis-only queries are exempt for genesis: eth_getLogs from 0x0 to a later block on a LiteNode returns 4444, as geth does.
  • Hash-based selectors, refining "null-only" from [Feature]Standardize JSON-RPC error handling(revert codes, LiteNode pruned-history responses, request fields validation) tronprotocol/java-tron#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. When eth_getBlockReceipts or eth_getLogs does find the block by hash, its number is known and the receipt rules above apply. eth_getBlockByHash, eth_getTransactionByHash and eth_getTransactionReceipt are unchanged.

- eth_call / eth_estimateGas: contract revert changes from -32000 to 3
- data a node does not have (pruned on a LiteNode, or receipts with
  transHistory.switch off) returns 4444 "Pruned history unavailable"
@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bf696168-b44e-4822-8dd4-3be69bd68667

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 23 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcPrunedHistoryException.java">

<violation number="1" location="common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcPrunedHistoryException.java:5">
P3: This javadoc says code 4444 is standardized by the Ethereum Execution API (EIP-4444), but it is a TRON-specific code — EIP-4444 specifies historical data expiry, not JSON-RPC error codes, and the PR description itself notes the 4444 extension. Reword to avoid claiming Ethereum standardization, e.g. 'returns JSON-RPC error code 4444 for pruned history (EIP-4444-inspired TRON extension)'.</violation>
</file>

<file name="chainbase/src/main/java/org/tron/core/store/TransactionRetStore.java">

<violation number="1" location="chainbase/src/main/java/org/tron/core/store/TransactionRetStore.java:51">
P1: This limits the scan before filtering key shape, so an earlier non-block key can hide all valid receipt keys and make startup classify existing history as pruned. Scan past non-8-byte keys, or enforce and validate a block-number-only key invariant before applying the limit.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

* layers, {@code getNext} does not merge deletions correctly.
*/
public OptionalLong getLowestBlockNum() {
Map<byte[], byte[]> entries = revokingDB.getNext(ByteArray.fromLong(0), 1);

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: This limits the scan before filtering key shape, so an earlier non-block key can hide all valid receipt keys and make startup classify existing history as pruned. Scan past non-8-byte keys, or enforce and validate a block-number-only key invariant before applying the limit.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At chainbase/src/main/java/org/tron/core/store/TransactionRetStore.java, line 51:

<comment>This limits the scan before filtering key shape, so an earlier non-block key can hide all valid receipt keys and make startup classify existing history as pruned. Scan past non-8-byte keys, or enforce and validate a block-number-only key invariant before applying the limit.</comment>

<file context>
@@ -37,6 +40,23 @@ public void put(byte[] key, TransactionRetCapsule item) {
+   * layers, {@code getNext} does not merge deletions correctly.
+   */
+  public OptionalLong getLowestBlockNum() {
+    Map<byte[], byte[]> entries = revokingDB.getNext(ByteArray.fromLong(0), 1);
+    for (byte[] key : entries.keySet()) {
+      if (key.length == Long.BYTES) {
</file context>

Comment thread framework/src/main/java/org/tron/core/utils/ResultCodeUtil.java Outdated

/**
* Thrown when a request targets historical state that a LiteNode has pruned.
* Maps to JSON-RPC error code 4444 "Pruned history unavailable", as standardized

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This javadoc says code 4444 is standardized by the Ethereum Execution API (EIP-4444), but it is a TRON-specific code — EIP-4444 specifies historical data expiry, not JSON-RPC error codes, and the PR description itself notes the 4444 extension. Reword to avoid claiming Ethereum standardization, e.g. 'returns JSON-RPC error code 4444 for pruned history (EIP-4444-inspired TRON extension)'.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcPrunedHistoryException.java, line 5:

<comment>This javadoc says code 4444 is standardized by the Ethereum Execution API (EIP-4444), but it is a TRON-specific code — EIP-4444 specifies historical data expiry, not JSON-RPC error codes, and the PR description itself notes the 4444 extension. Reword to avoid claiming Ethereum standardization, e.g. 'returns JSON-RPC error code 4444 for pruned history (EIP-4444-inspired TRON extension)'.</comment>

<file context>
@@ -0,0 +1,17 @@
+
+/**
+ * Thrown when a request targets historical state that a LiteNode has pruned.
+ * Maps to JSON-RPC error code 4444 "Pruned history unavailable", as standardized
+ * by the Ethereum Execution API (EIP-4444).
+ */
</file context>
Suggested change
* Maps to JSON-RPC error code 4444 "Pruned history unavailable", as standardized
* Maps to JSON-RPC error code 4444 "Pruned history unavailable", a TRON extension
* inspired by EIP-4444 historical data expiry.

- 4444 no longer carries the earliest available block in data, as geth
- remove ResultCodeUtil; constant calls record only REVERT
- test that a reverted constant call sets contractRet to REVERT
@0xbigapple
0xbigapple force-pushed the feature/jsonrpc-revert-and-pruned-history branch from d8616e8 to c3fccfc Compare September 28, 2026 06:29

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread framework/src/test/java/org/tron/core/WalletTest.java
…ove init methods to the top

- rename probeLowestBlockNumOfReceiptStore to initLowestBlockNumOfReceiptStore
- move init and initLowestBlockNumOfReceiptStore to the top of ChainBaseManager methods
…sonrpc-revert-and-pruned-history

# Conflicts:
#	framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java
#	framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java
#	framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolverTest.java
- rename TransactionRetStore.getLowestBlockNum to getLowestReceiptBlockNum
- note that transHistory.switch off disables receipt and log queries

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

- run the constant revert test with debug on to skip the cpu time limit
- clarify transHistory.switch comment in reference.conf and config.conf
- drop unused throws from getFilterChanges
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