Skip to content

fix(t8n): serialize receipt root/status as mutually exclusive - #12867

Open
hudem1 wants to merge 1 commit into
masterfrom
fix/12835-receipt-root-xor-status
Open

fix(t8n): serialize receipt root/status as mutually exclusive#12867
hudem1 wants to merge 1 commit into
masterfrom
fix/12835-receipt-root-xor-status

Conversation

@hudem1

@hudem1 hudem1 commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Refs #12835 (partial — see below)

Changes

  • TxReceiptConverter.Write now emits either the post-state root (pre-Byzantium, when receipt.Root is set) or the status code (post-Byzantium), instead of always writing both with root defaulting to the zero hash. This matches EIP-658, the receipt schema in ethereum/execution-apis, and go-ethereum's marshalReceipt.
  • Added two regression tests covering the pre- and post-Byzantium cases.

Context

Issue #12835 reports (auto-generated) that many JSON-RPC fields serialize as null while the docs type them as non-null. After comparing each item against the spec (ethereum/execution-apis) and go-ethereum, 11 of the 12 items are not defects — the null values are intentional and spec-/Geth-conformant (pending blocks/transactions, to: null for contract creation, conditional trace fields). Those are at most a docs-site annotation matter and are not addressed here.

The one genuine code-level finding is the receipt root/status handling, and even there the user-facing JSON-RPC methods (eth_getTransactionReceipt, eth_getBlockReceipts, parity_getBlockReceipts, proof_getTransactionReceipt) were already correct: they serialize the ReceiptForRpc DTO, which omits the null field via JsonIgnoreCondition.WhenWritingNull.

TxReceiptConverter is the standalone converter for bare TxReceipt, used by the t8n tool (tools/Evm/T8n). It emitted both root and status, so t8n result.receipts carried a spurious "root":"0x00…00" alongside "status" for post-Byzantium receipts (t8n forces PostTransactionState = null for successful txs). This PR aligns that output with Geth's evm t8n. No JSON-RPC response changes.

Types of changes

  • Bugfix (a non-breaking change that fixes an issue)

Testing

Requires testing

  • Yes

If yes, did you write tests?

  • Yes

Notes on testing

Added Post_byzantium_receipt_serializes_status_without_root and Pre_byzantium_receipt_serializes_root_without_status in ReceiptsForRpcTests. Full ReceiptsForRpcTests and TransactionReceiptsSubscription suites pass.

Documentation

Requires documentation update

  • No

Requires explanation in Release Notes

  • No

Remarks

Scope is intentionally limited to the t8n output path; the remaining #12835 items are behavior-correct and, where actionable, belong in the docs repo (docs are auto-generated via tools/DocGen).

…tConverter

Per EIP-658, a receipt carries either a post-state `root` (pre-Byzantium) or a
`status` code (post-Byzantium), never both. `TxReceiptConverter.Write` emitted
both unconditionally, defaulting `root` to the zero hash when absent. This
diverges from the receipt schema in ethereum/execution-apis (where `root` and
`status` are optional and conditional) and from go-ethereum's marshalReceipt,
which emits exactly one.

The DTO path (ReceiptForRpc), used by eth_getTransactionReceipt,
eth_getBlockReceipts, parity_getBlockReceipts and proof_getTransactionReceipt,
was already correct via JsonIgnoreCondition.WhenWritingNull; this aligns the
standalone converter with it.

Refs #12835.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

3 participants