Skip to content

fix(jsonrpc): accept "input" as alias for "data" in call args#6722

Open
waynercheung wants to merge 1 commit intotronprotocol:developfrom
waynercheung:fix/jsonrpc-eth-call-input-param-6517
Open

fix(jsonrpc): accept "input" as alias for "data" in call args#6722
waynercheung wants to merge 1 commit intotronprotocol:developfrom
waynercheung:fix/jsonrpc-eth-call-input-param-6517

Conversation

@waynercheung
Copy link
Copy Markdown
Collaborator

@waynercheung waynercheung commented Apr 28, 2026

What does this PR do?

Accept input alongside data on eth_call, eth_estimateGas, and buildTransaction call arguments, matching the Ethereum execution-apis spec and resolving #6517.

  • Add input (raw field) to CallArguments and BuildArguments.
  • Resolve calldata via resolveData() - pure precedence resolution with input winning over data, mirroring go-ethereum's TransactionArgs.data().
  • On the build path, conflicts between input and data (both set, not equal) are detected at BuildArguments.getContractType() - mirroring geth's data() / setDefaults split. The error message uses go-ethereum's wording verbatim. The query path stays lenient (input wins silently).
  • Switch five production read sites in TronJsonRpcImpl from getData() to resolveData().
  • Hex validation is mode-driven via JsonRpcApiUtil.requireValidHex (HexMode.STRICT / HexMode.LENIENT):
    • input is STRICT: follows the execution-apis BYTES schema (^0x[0-9a-f]*$, even length; "" is accepted as empty bytes per geth's hexutil.Bytes.UnmarshalText).
    • data keeps LENIENT parsing via ByteArray.fromHexString (accepts bare hex and odd length) for backward compatibility with existing callers - notably BuildTransactionTest.testCreateSmartContract, which submits bare-hex bytecode.
  • The resolver is named resolveData() - verb prefix, not getXxx - so Jackson's and FastJSON's JavaBean introspection skips it with no per-serializer annotations needed.
  • The Lombok-generated positional constructors widen by one slot (CallArguments 7->8 args, BuildArguments 16->17 args). The named-JSON deserialisation path is unaffected.

Why are these changes required?

The Ethereum execution-apis spec uses input as the canonical calldata field; data is the legacy alias. go-ethereum accepts both, with input winning when equal and erroring when not. Notably, go-ethereum's ethclient has emitted only input since ethereum/go-ethereum#28078, so any tron RPC user upgrading their geth client side hits this.

Before this PR, java-tron only read data. A spec-compliant client carrying only input failed two ways:

  1. Jackson rejected the unknown property (FAIL_ON_UNKNOWN_PROPERTIES=true), returning -32603 instead of executing the call.
  2. Even when the field was tolerated, contract-creation paths (no to) tripped invalid json request because calldata appeared absent.

Both symptoms are captured in #6517.

This PR has been tested by:

  • Unit tests
  • Integration tests
  • Manual tests

CallArgumentsTest (23 tests) + BuildArgumentsTest (29 tests) = 52 total. Coverage:

  • Single-field cases: input only, data only, neither.
  • Both fields equal — precedence resolves cleanly.
  • Both fields not equal: CallArguments returns input silently; BuildArguments.getContractType() throws with geth-equivalent wording.
  • Empty-string "" is presence (matches geth).
  • 0x (zero-length payload) is presence and never collapses to absent.
  • Case-insensitive byte equality (0xDEAD == 0xdead).
  • Strict input validation rejects bare hex, odd length, non-hex chars.
  • Lenient data validation still accepts bare hex and odd length; BuildTransactionTest.testCreateSmartContract still passes.
  • Loser-field validation: malformed data is rejected even when input is the precedence winner, and vice versa.
  • Jackson + FastJSON serialisation: resolveData never appears as a wire property and serialisation never throws even with conflicting input / data (regression guard for the verb-prefix naming).
  • Are there plans to support parameter passing via the input field for eth_call? #6517 reproductions: Jackson deserialisation of {"input": "0xdeadbeef"} succeeds; contract-creation via input (no to) resolves to CreateSmartContract.

Follow up

  • Add a JsonRpcServer-level integration test exercising the full Jackson -> handler -> response path for both input and data payloads. Useful but not blocking - the unit-level path is fully covered.
  • Tighten ByteArray.fromHexString to the execution-apis BYTES schema, then drop the asymmetric branch in requireValidHex. Behaviour-changing for non-RPC callers, so deferred to a separate change.

Closes tronprotocol#6517.

JSON-RPC requests using the execution-apis field name `input` were
rejected with UnrecognizedPropertyException, blocking spec-compliant
clients -- notably go-ethereum's ethclient since
ethereum/go-ethereum#28078, which only emits `input`.

CallArguments and BuildArguments now declare both fields. A new
resolveData() does pure precedence resolution -- `input` wins over
`data` -- mirroring go-ethereum's TransactionArgs.data(). Five call
sites in TronJsonRpcImpl use the resolver instead of getData(). The
verb-prefix name (not getXxx) keeps Jackson and FastJSON's JavaBean
introspection from picking the method up as a `resolveData` wire
property; two serialisation tests pin this as a regression guard.

Hex validation is mode-driven via JsonRpcApiUtil.requireValidHex
(HexMode.STRICT / HexMode.LENIENT):

- `input` (new field) is STRICT: follows the execution-apis BYTES
  schema -- requires `0x` prefix and even length; "" is accepted as
  empty bytes per geth's hexutil.Bytes.UnmarshalText.
- `data` retains LENIENT parsing via ByteArray.fromHexString for
  backward compatibility with existing callers (e.g.
  BuildTransactionTest.testCreateSmartContract uses bare-hex
  bytecode).

Conflict between `input` and `data` (both set, not equal) is
detected on the build path at BuildArguments.getContractType(),
mirroring geth's data() / setDefaults split. The error message
matches go-ethereum's setDefaults wording verbatim. Comparison is
byte-level so case differences are not flagged. The query path
(CallArguments.resolveData()) stays lenient -- input wins silently.

Tested by 52 unit tests including Jackson/FastJSON serialisation
safety guards; BuildTransactionTest.testCreateSmartContract still
passes; checkstyle clean.
@waynercheung waynercheung force-pushed the fix/jsonrpc-eth-call-input-param-6517 branch from 0b55d1a to 8df76fe Compare April 29, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Are there plans to support parameter passing via the input field for eth_call?

2 participants