Skip to content

Design: TransactionState/BlockState separation, TxTask refactoring, cross-process TX caching #19855

Description

@mh0lt

Context

Follow-on design from #19623 (2-cache IBS refactor). While #19623 focuses on eliminating stateObject and the IBS round-trip within the current architecture, this issue captures the higher-level ownership restructuring and cross-process optimization opportunities that should inform the implementation to avoid costly future refactors.

These observations emerged during PR #19814 (direct finalize path + unit tests), where the brittleness of IBS's multiple implicit roles became apparent.

Problem

IntraBlockState serves multiple implicit roles:

  1. Execution context — per-TX state objects, journal, snapshots
  2. Version tracking — versioned reads/writes for parallel validation
  3. Finalize orchestrator — FinalizeTx / CommitBlock / MakeWriteSet
  4. BAL read generationrefreshVersionedAccount for EIP-7928

The FinalizeTx vs CommitBlock distinction is extremely subtle:

  • FinalizeTx: useBlockOrigin=false (originStorage — last written value)
  • CommitBlock: useBlockOrigin=true (blockOriginStorage — block-start value)

This exists because originStorage gets updated by each FinalizeTx, so by CommitBlock time it equals the dirty value.

1. TransactionState / BlockState Separation

TransactionState (per-TX, request-scoped)

Key design decision: TransactionState should NOT be owned by the worker and reset between TXs. It should be part of the request — a value object with immutable inputs and value-type outputs. This avoids:

  • Worker lifecycle bleeding into state lifecycle
  • Hidden state leaks between TXs (today's IBS.Reset() is fragile)
  • Coupling that prevents caching

The execution model becomes: (TransactionState, inputs) → (TransactionState, outputs)

Contains:

  • Account state objects (balance, nonce, code, storage)
  • Journal for revert snapshots
  • Dirty tracking
  • No version map, no BAL, no block-level concerns

BlockState (per-block)

Contains:

  • Version map (parallel execution)
  • Block-origin storage values
  • Accumulated block IO (reads/writes per TX)
  • BAL computation state
  • Fee-calc coordination (coinbase/burnt deltas)
  • Combine(txResult) merges TX results into block state

2. TxTask Refactoring

TxTask has grown organically serving multiple scenarios:

  • Historical queries (simpler, no dependencies)
  • Parallel speculative execution (dependencies, delayed fee calc)
  • RPC calls (eth_call, eth_estimateGas)
  • AA transaction batches

The flags shouldDelayFeeCalc, HistoryExecution, InBatch, AAValidationBatchSize are symptoms of one object doing too many jobs.

TxTask should be split into:

  • TxInput: immutable execution request (tx, header, config, gas pool)
  • TxScheduling: parallel-specific (dependencies, incarnation, version)
  • TxResult: execution output (state changes, receipt, logs, errors)

3. Cross-Process TX Caching

TX execution happens in multiple places in Erigon:

  • Block execution (serial + parallel)
  • Block building (miner/proposer)
  • TxPool validation (and future expanded validation)
  • RPC (eth_call, eth_estimateGas, trace_*)

If TransactionState is a pure function of inputs, the cache key becomes:

hash(tx_bytes, account_prestate_at_block) → TxResult

This enables:

  • TxPool → Block Building: skip re-execution of already-validated TXs
  • RPC → Recent blocks: cache recent eth_call results
  • Parallel execution: cache results across incarnations when prestate matches

4. BAL Read Generation Decoupling

Currently tightly coupled to IBS via refreshVersionedAccount. Must be decoupled so that:

  • The direct finalize path (finalizeTx) can generate correct BAL reads without IBS reconstruction
  • BAL reads become a pure function of (TxOut addresses, prestate)

Implementation Sequencing

These changes build on #19623's 5-phase plan and extend it:

Phase Description Dependency
#19623 Phases 1-5 2-cache model, eliminate stateObject Foundation
Fix finalizeTx BAL reads Direct finalize generates correct BalancePath reads #19623 Phase 2
Extract BlockState Move version map, block IO, BAL state out of IBS #19623 Phase 5
Request-scoped TransactionState Per-TX creation, pure function model, TxTask split BlockState extraction
Cross-process caching TX result cache shared across execution contexts TransactionState + serial exec deprecation

Key Files

  • execution/stagedsync/exec3_parallel.go — finalize dispatch, finalizeTx, finalizeWithIBS
  • execution/stagedsync/exec3_finalize_test.go — comparison unit tests (PR exec3_parallel: eliminate IBS round-trip in finalize path #19814)
  • execution/state/intra_block_state.go — IBS (the monolith)
  • execution/state/versionedio.go — version map, BAL computation
  • execution/state/state_object.go — account state, updateStorage
  • execution/exec/txtask.go — TxTask (the multi-purpose envelope)

Notes

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions