Skip to content

feat(eip8130): account-abstraction receipt#3753

Merged
chunter-cb merged 7 commits into
mainfrom
hh/eip-8130-rpc-receipts
Jun 25, 2026
Merged

feat(eip8130): account-abstraction receipt#3753
chunter-cb merged 7 commits into
mainfrom
hh/eip-8130-rpc-receipts

Conversation

@chunter-cb

@chunter-cb chunter-cb commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the EIP-8130 receipt surface so AA transactions
report their extra execution data through eth_getTransactionReceipt

  • Consensus receipt: a BaseReceipt::Eip8130 variant wrapping the standard
    receipt with the per-phase phaseStatuses array, plus its node-local Compact
    (de)serialization for storage.
  • Executor handoff: the EIP-8130 executor computes a per-phase status array
    while running a transaction's calls and publishes it to the receipt builder
    via a single-threaded thread-local slot (Eip8130PhaseStatuses); the receipt
    builder takes it immediately after execution. The slot is cleared at the start
    of every execute so a value leaked by an earlier transaction (e.g. a panic
    caught between its set and the builder's take) can never be misattributed.
    Rationale is documented on the type (the receipt builder is generic over the
    EVM and has no typed channel for per-tx metadata).
  • RPC fields: BaseTransactionReceipt gains the AA fields (payer,
    status, phaseStatuses, metadata), derived in the receipt response
    builder. Empty metadata is omitted rather than serialized as "0x",
    matching how empty phaseStatuses is skipped.

Test plan

  • cargo test for base-common-consensus, base-common-evm,
    base-common-rpc-types, base-execution-eip8130-rpc-node (incl. the new
    end-to-end tests/receipt.rs, covering self-pay, phase statuses, and the
    sponsored-payer precedence) — all pass.
  • cargo check --workspace --all-features
  • cargo clippy --all-features --all-targets on touched crates — clean.
  • cargo +nightly fmt --all -- --check — clean.

Add the EIP-8130 receipt surface so AA transactions report their extra
execution data through `eth_getTransactionReceipt`:

- A `BaseReceipt::Eip8130` consensus variant wrapping the standard receipt with
  the per-phase `phaseStatuses` array, plus its node-local Compact persistence.
- The executor publishes `phaseStatuses` for each EIP-8130 transaction via a
  thread-local handoff (`Eip8130PhaseStatuses`) consumed by the receipt builder.
- RPC `BaseTransactionReceipt` gains the AA fields (`payer`, `status`,
  `phaseStatuses`, `metadata`), derived in the receipt response builder.

Also relocates the balance-monitor unit tests into a sibling test module.
Comment thread crates/utilities/balance-monitor/src/tests.rs Outdated
Comment thread crates/common/evm/src/eip8130_phase_statuses.rs
Comment thread crates/common/consensus/src/reth_compat.rs
…e-status drop

Address review feedback on the receipt PR:

- Revert the balance-monitor unit tests back to a colocated `#[cfg(test)] mod
  tests` block in `monitor.rs`, per the project convention against standalone
  `tests.rs` modules. This drops the unrelated test relocation entirely.
- Add a `debug_assert!` in the `no_std` `Eip8130PhaseStatuses::set` so a future
  caller that drops non-empty statuses (which `take` could not recover) fails
  loudly instead of silently; EIP-8130 execution is `std`-gated, so statuses are
  always empty here today.
Comment thread crates/execution/rpc/src/eth/receipt.rs Outdated
Comment thread crates/common/evm/src/eip8130.rs Outdated
Move the `Eip8130PhaseStatuses::set` handoff to after the journal teardown
(`take_logs`/`checkpoint_commit`/`commit_tx`/local+frame clear), so the only code
between publishing the statuses and the receipt builder's `take` is the
allocation-free result construction. This closes the window where a panic in the
journal teardown could leave stale per-phase statuses in the thread-local slot for
the next transaction on the same thread.
Comment thread crates/execution/eip8130-rpc-node/tests/receipt.rs
Comment thread crates/common/consensus/src/reth_compat.rs
@chunter-cb chunter-cb changed the title feat(eip8130): surface account-abstraction receipt fields feat(eip8130): account-abstraction receipt Jun 24, 2026
…adata

Address review feedback on the EIP-8130 receipt PR:

- Panic safety: clear the phase-status thread-local at the start of every
  `execute` so a value leaked by an earlier transaction (e.g. a panic caught
  between its `set` and the receipt builder's `take`) can never be
  misattributed to the current transaction's receipt.
- Empty metadata: omit empty EIP-8130 metadata from `eth_getTransactionReceipt`
  rather than serializing it as `"0x"`, matching how empty `phaseStatuses` is
  skipped. Locked by an assertion in the empty-calls test.
- Add a sponsored-payer receipt test (declared payer != sender) pinning the
  `tx.payer.unwrap_or(sender)` precedence.
- Add a Compact round-trip test pinning that `eip8130_phase_statuses` survives
  encode/decode as the trailing field.
Comment thread crates/execution/rpc/src/eth/receipt.rs Outdated
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Comment thread crates/execution/rpc/src/eth/receipt.rs Outdated

@xenoliss xenoliss left a comment

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.

nit: the phase-status handoff relies on reth executing each tx as execute -> build_receipt sequentially on one thread, but no test covers >1 EIP-8130 tx per block. We might want to add a 2-tx case (one with a reverting phase) to lock the per-tx attribution against future executor changes.

Add an end-to-end test that mines two EIP-8130 transactions into a single
block — one fully successful and one whose second phase reverts — and asserts
each receipt carries its own `phaseStatuses`.

This locks the per-transaction attribution of the thread-local
executor->receipt-builder handoff (`Eip8130PhaseStatuses`), which relies on
reth driving each tx as `execute` -> `build_receipt` sequentially on one
thread. A regression that leaked or swapped one tx's statuses would surface
here even though the single-8130-tx-per-block tests would still pass.
@chunter-cb chunter-cb enabled auto-merge June 25, 2026 12:33
@github-actions

Copy link
Copy Markdown
Contributor

Review Summary

Overall: Clean implementation. The EIP-8130 receipt plumbing is well-structured, the thread-local handoff is justified by the reth receipt builder API constraints, and the backward-compatible Compact encoding is correctly designed.

Architecture

The Eip8130Receipt wrapper cleanly separates consensus-committed data (inner: Receipt<T>) from node-local metadata (phase_statuses: Vec<u8>). The RLP encoding correctly excludes phase statuses (preserving receipts-trie compatibility), while the Compact encoding includes them for database persistence. The serde(skip) on phase_statuses is consistent with the intent to surface them only via the explicit RPC receipt fields.

Thread-local handoff (Eip8130PhaseStatuses)

The set/take pattern via thread-local is inherently fragile but the mitigations are adequate:

  • clear() at the start of each execute prevents misattribution after panics
  • take() clears on read so the slot doesn't accumulate across transactions
  • The debug_assert! in the no_std path guards against silent data loss

The three receipt builders (BaseRethReceiptBuilder, UnifiedReceiptBuilder, and the build_receipt closure in BaseReceiptBuilder::new) all consistently call Eip8130PhaseStatuses::take() only in the OpTxType::Eip8130 arm.

Backward-compatible CompactPhaseStatuses

The buf.is_empty() guard in from_compact correctly handles pre-existing on-disk receipts that lack the trailing field. The to_compact returning 0 for empty statuses ensures non-8130 receipts keep byte-identical encodings. The doc comment requiring eip8130_phase_statuses to remain the last field in CompactBaseReceipt is the right approach, reinforced by the regression tests.

No new issues found

The existing inline review comments cover the low-severity observations (panic safety, no_std silent discard, minor clone). The code is well-tested with unit tests for compact roundtrips, RLP roundtrips, and comprehensive E2E tests covering self-pay, sponsored, phase statuses, and multi-tx-per-block attribution.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

✅ base-std fork tests: all 616 passed

base/base is fully in sync with the base-std spec.

Dependency Ref Commit
base-std main 4658f1b7
base-anvil 0092692587d8d064dd2c6923ce26a682c58f3694 00926925

@chunter-cb chunter-cb added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit 5b04719 Jun 25, 2026
23 checks passed
@chunter-cb chunter-cb deleted the hh/eip-8130-rpc-receipts branch June 25, 2026 13:19
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.

2 participants