Skip to content

Parallel-exec: route the per-tx writeset through one faithful path; remove normalizeWriteSet/calcState; carry serial-finalize signals on ExecutionResult #21138

@mh0lt

Description

@mh0lt

Follow-up to #21136. The recurring parallel-exec-vs-serial divergences (SELFDESTRUCT/recreate, EIP-161 empty-removal, EIP-7708 burn logs, fork-transition, coinbase) all come from the post-execution wrapper re-deriving "what did this tx do" via the heuristic normalizeWriteSet(versionWritten-log) path and the calcState re-derivation, instead of using the faithful MakeWriteSet-style output that the validated worker already produces. ~half of genuine parallel-executor PRs over the last 2 months are this family. This issue is the consolidation that makes those bugs structurally impossible.

Target per-tx flow (incremental — does NOT require the full "IBS = pure transaction-state" rework)

  1. Parallel-execute txs (unchanged).
  2. Validate + serialize via BlockSTM (unchanged) — at this point we have a verified version. The validated worker's IBS already ran MakeWriteSet into a LightCollectorresult.CollectorWrites = every dirty object's final state.
  3. Per-tx serial-finalize — done from data + the writeset, no reconstructed IBS:
    • per-tx delta = filterWritesByVersionMap(result.CollectorWrites, vmWrites) (faithful, pruned to the keys the tx actually touched — both filterWritesByVersionMap and CollectorWrites already exist).
    • accumulate tip serially → final coinbase / burnt balances → patch the writeset (read pre-block balance from sd).
    • EIP-161 empty-removal: a writeset entry that's {bal=0, nonce=0, empty codehash} → convert to a delete.
    • EIP-7708 transfer/burn logs: compute from the writeset + a self-destructed-addresses list carried on ExecutionResult (see below) — delete the minIBS + postApplyMessageFunc reconstruction (exec3_parallel.go ~line 2807; the minIBS exists only to SetBalance then LogSelfDestructedAccounts reads it).
    • SD storage cascade if still needed (or it falls out of the collector's final state).
  4. Pass the finished tx output to the commitment calculator: the one writeset → applyVersionedWrites writes it into SharedDomains/sd.mem (the public DB the calc reads from), AND VersionedWrites.TouchUpdates(updates) folds it into the calc's commitment.Updates. Calc reads post-block siblings from sd.mem via asOfStateReader.

Block-end finalize (block reward, withdrawals, EIP-4788/7002/7251 syscalls) genuinely runs state transitions and keeps a real IBS — it's outside the per-tx flow and not in scope here.

Concrete changes

  • ExecutionResult gains SelfDestructedAddresses []common.Address (regardless of residual balance) — populated by the worker; consumed by per-tx serial-finalize for EIP-7708 and (potentially) the SD storage cascade.
  • txResult.writes = filterWritesByVersionMap(result.CollectorWrites, be.blockIO.WriteSet(txIndex)) instead of normalizeWriteSet(...).
  • the commitment calc consumes txResult.writes.TouchUpdates(...) — delete calcState.ApplyWrites/FlushToUpdates.
  • delete normalizeWriteSet and resolveStorageWrites (the latter is already DEPRECATED dead code).
  • unify the per-tx and block-finalize collector paths (LightCollector vs versionedWriteCollector — one of them).
  • IBS.VersionedWrites(checkDirty) stays, used only for BlockSTM read/write dependency tracking — it must stop being the apply/commitment payload.

Validation gate before deleting anything

Remove the EXEC3_PARALLEL-gated SkipLoad/t.Skips from #21136 one by one — if the consolidated path is faithful, test_double_kill, test_dynamic_create2_selfdestruct_collision, the prague test_system_contract_deployment variants, tipInsideBlock, and TestEIP7708BurnLogWhenCoinbaseSelfDestructs should all pass without per-bug heuristics. That's the success criterion.

Eventual rework (separate, larger)

Extract the whole serial flow (MakeWriteSet → commitment fold → domain write → BAL) to run post-validation as the single path; serial becomes a 1-tx-at-a-time consumer of it; IBS becomes a pure per-tx transaction-state. This issue is the stepping stone.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions