Skip to content

Parallel exec fixes#17319

Merged
mh0lt merged 104 commits into
mainfrom
parallel_exec_default
Feb 26, 2026
Merged

Parallel exec fixes#17319
mh0lt merged 104 commits into
mainfrom
parallel_exec_default

Conversation

@mh0lt

@mh0lt mh0lt commented Oct 1, 2025

Copy link
Copy Markdown
Contributor

No description provided.

@mh0lt mh0lt changed the title set parallel exec default true Set parallel exec default true Oct 1, 2025
@mh0lt mh0lt marked this pull request as draft October 1, 2025 19:59
mh0lt added a commit that referenced this pull request Dec 1, 2025
The parallel processing workers create an maintain thier own read
transactions. This work well with stage loop processing except for the
case where we process unwinds and we have a shared RwTx. As at the
moment unwind writes directly to the DB via this call:


https://github.com/erigontech/erigon/blob/fd4e3bd33b32c2cd245a3779216f2833437214cc/execution/stagedsync/stage_execute.go#L304

This PR changes the way that transactions are handled in the parallel
flow to make sure the Exec3 function alway's operates in inmem mode, and
expect any changes are commited to the DB before it is called so it can
see the changes.

This works on the parrallel flow and I'm currenty testing the serial
flow. Once I have confirmed it works for both I'll look to push this to
main. Once it is there I will merge it here
#17319 and get this PR to a
stage where it passed all tests and QA, at which point I think we're in
a good position to transition main to parallel exec by default.

In the meantime I'm running tip tracking on the parallel flow 

I think a more straghtfowrd change from a user code perspective is to
only call unwind on the DB once the SharedDomain is processed and
flushed with both the unwind and the subsqent block procssing included.
To do this we'll need to add the unwind change set to the SharedDomain
and qery it before the db or files are accessed. I have created an issue
to track this here: #17782.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: queryfast <queryfast@outlook.com>
Co-authored-by: Willian Mitsuda <wmitsuda@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: canepat <16927169+canepat@users.noreply.github.com>
Co-authored-by: Michelangelo Riccobene <michelangelo.riccobene@gmail.com>
Co-authored-by: antonis19 <antonis19@mail.com>
Co-authored-by: antonis19 <antonis19@users.noreply.github.com>
Co-authored-by: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com>
Co-authored-by: milen <94537774+taratorio@users.noreply.github.com>
Co-authored-by: Sahil Sojitra <88416181+Sahil-4555@users.noreply.github.com>
Co-authored-by: lupin012 <58134934+lupin012@users.noreply.github.com>
Co-authored-by: lystopad <oleksandr.lystopad@erigon.tech>
Co-authored-by: AJoX <shuraev2707@gmail.com>
Co-authored-by: davecrighton <58038715+davecrighton@users.noreply.github.com>
Co-authored-by: Doryu <anna.shuraeva16@gmail.com>
Co-authored-by: Kewei <kewei.train@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Alex Sharov <AskAlexSharov@gmail.com>
Co-authored-by: Matt Joiner <anacrolix@gmail.com>
Co-authored-by: Bhargava Shastry <bshastry@ethereum.org>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Coder <161350311+MamunC0der@users.noreply.github.com>
Co-authored-by: Somnath <snb895@outlook.com>
Co-authored-by: queryfast <113781357+queryfast@users.noreply.github.com>
Co-authored-by: Giulio rebuffo <giulio.rebuffo@gmail.com>
Co-authored-by: bloxster <40316187+bloxster@users.noreply.github.com>
Co-authored-by: Bloxster <bloxster@proton.me>
Co-authored-by: GarmashAlex <garmasholeksii@gmail.com>
Co-authored-by: sudeepdino008 <sudeepdino008@gmail.com>
Co-authored-by: Julie B. <15657735+bbjubjub2494@users.noreply.github.com>
Co-authored-by: Shoham Chakraborty <shhmchk@gmail.com>
Co-authored-by: Ilya Mikheev <54912776+JkLondon@users.noreply.github.com>
Co-authored-by: JkLondon <me@ilyamikheev.com>
mh0lt and others added 4 commits February 25, 2026 22:37
…re-org

Warmup workers read branch data before the main trie has written its updated
entries, then wrote that stale data into the shared WarmupCache. The next
CollectUpdate would merge against the stale cached entry, producing an
incorrect trie root during re-org validation with PARALLEL_EXEC=true.

Fix: branchFromCacheOrDB now only reads from cache (hit path unchanged), but
never writes back to it. Only the main trie path (CollectUpdate) populates
the cache with authoritative data.

Also re-enable SetDeferCommitmentUpdates for both serial and parallel fork
validation — the previous restriction to serial-only was too conservative.
@Giulio2002

Giulio2002 commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

ops this was me not the bot. i forgot to checkout out while reviewing

@mh0lt mh0lt requested a review from yperbasis February 26, 2026 07:08

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlockAssembler isn't used anywhere

I have just checked this it was used by the staged sync version of the minor, it seems it got removed by the merge of your refactor. I need to check what has happened to the codebase I'll move it for the moment but I need to work out what happened with the merging process - which I'll do in another branch.

Comment thread execution/protocol/rules/merge/fake.go Outdated
"github.com/erigontech/erigon/execution/protocol/rules/ethash"
)

type FakeMerge struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is also not used, so this file can be removed from this PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very weird. It was needed for the Amsterdam tests to pass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved by: 0f752b1

I'll investigate the impact by running tests on the bat-devnet-2 branch with parallel on. If there are regressions there I'll make a seperate fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I know why you no longer need it, it is because Andrew switched the "assemble tests" to not hit the public API GetAssembledBlock but instead use a non-public API GetAssembledBlockWithReceipts

one thing I have on my list is to revert that back to hitting GetAssembledBlock but we need to do some prep work for it first - e.g. we need to transition all the tests to use the merge rules engine and AllProtocolChanges - I'm planning on doing this with Claude next week

so I would say just get rid of it for now and we can address it later

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's a bit strange, also there have been some other agents changes. I think where we are now is we need to get this merged as shrove bot is running parallel fixed, which are frankly confusing. I want to get to a branch that doesn't keep having overlapping ai merges from main, that I have to merge and then may get refactored.

@mh0lt

mh0lt commented Feb 26, 2026

Copy link
Copy Markdown
Contributor Author

BlockAssembler isn't used anywhere

I have just checked this it was used by the staged sync version of the minor, it seems it got removed by the merge of your refactor. I need to check what has happened to the codebase I'll move it for the moment but I need to work out what happened with the merging process - which I'll do in another branch.

I've removed this in: 0f752b1

I'll investigate the impact by running tests on the bat-devnet-2 branch with parallel on. If there are regressions there I'll make a separate fix.

Comment thread execution/tests/block_test.go Outdated
if offSeason {
t.Skip("devnet off-season")
}
t.Skip("Osaka is already covered by TestExecutionSpecBlockchain")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this being changed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the comment the agent thinks these tests are covered by the TestExecutionSpecBlockchain, so it thinks this is a duplicate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a temporary skip I have removed it: aa1d8e4

"github.com/erigontech/erigon/execution/types"
)

type ChainReaderImpl struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we rename the file to chain_reader.go? I find it a bit confusing that it is called block_assembler.go when it only contains ChainReaderImpl

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well I need to see-insert the block assembler it has somehow gotten removed by my agent. But I don't want to re-insert it here. I can rename the file which now only contains this class.

Fixed by: 230f258

var consolidationRequestCode = common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
var consolidationRequestCodeHash = accounts.InternCodeHash(common.BytesToHash(crypto.Keccak256(consolidationRequestCode)))

func InitPraguePreDeploys(db kv.TemporalRwDB, logger log.Logger) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

@yperbasis

Copy link
Copy Markdown
Member

Claude's review:

Branch Review: parallel_exec_default

Summary

This is a large branch (~70 commits, +1433/-359 lines across 37 files) that advances parallel transaction execution support and Block Access List (BAL / EIP-7928) generation. The changes span the execution
engine, state management, block building, RPC layer, CI, and test infrastructure.


Core Changes

  1. Parallel Execution State Management (execution/state/)

versionedio.go — Major rewrite of versioned I/O tracking:

  • AsBlockAccessList() replaces the old standalone CreateBAL() function, building the BAL directly from the VersionedIO read/write sets
  • New accountState type with fieldTracker[T] and changeTracker[T] generics to track per-field (balance, nonce, code, storage) changes with deduplication
  • Filters out system addresses (beacon roots, etc.) and handles selfdestruct edge cases (no post-selfdestruct balance writes in BAL)
  • versionedReadSet gains a Merge() method for combining read sets across IOs
  • RecordAccesses now uses AccessSet (typed map) instead of map[accounts.Address]struct{}

intra_block_state.go — Many parallel execution correctness fixes:

  • HasStorage() now checks IncarnationPath in the versionMap to detect prior-tx create/destroy
  • getCode() committed-mode check tightened with hasWrite() to avoid seeing stale code from a prior tx sharing the same IBS
  • ResolveCode() changed from committed=true to committed=false — fixes stale delegation reads in parallel mode
  • setState() removes the "delete write when value == origin" optimization — it broke revert semantics in nested calls
  • Selfdestruct() now writes IncarnationPath to the versionMap
  • getStateObject() checks SelfDestructPath directly in versionMap for prior-tx selfdestructs
  • CreateAccount() significantly reworked to handle resurrection after selfdestruct, reading IncarnationPath from versionMap and ReadDeletedIncarnation from state reader
  • VersionedWrites() preserves IncarnationPath entries through selfdestruct filtering
  • ApplyVersionedWrites() handles SelfDestructPath=false (resurrection) by setting createdContract=true
  • New TxIO() helper to snapshot current tx's I/O as a VersionedIO
  • AccessedAddresses() return type changed to AccessSet

versionmap.go — Validation broadened:

  • Cross-validation of reads against AddressPath/SelfDestructPath now applies to all paths (storage, code, etc.), not just balance/nonce/incarnation/codeHash. This is correct — a prior tx's create/selfdestruct
    invalidates any property read.

rw_v3.go (BufferedWriter):

  • UpdateAccountData now copies the accounts.Account to prevent pointer aliasing with pooled stateObjects — fixes corruption when the stateObject pool reuses memory
  • ReadAccountCode fixes a bug: was returning so.code instead of the local code variable
  1. SharedDomains Data Race Fix (db/state/execctx/domain_shared.go)
  • Removes currentStep field entirely — it was a race target between SetTxNum (apply goroutine) and GetLatest readers
  • temporalGetter now snapshots step at construction time
  • New getLatest() internal method takes an explicit cacheStep parameter
  • State cache hits now return the snapshotted cacheStep instead of 0
  1. Block Access List Types (execution/types/block_access_list.go)
  • New Normalize() method on AccountChanges — sorts and deduplicates storage changes, reads, balance/nonce/code changes
  • Generic dedupByIndex, dedupByEquality, sortByIndex, sortHashes helpers
  • DebugString() refactored to DebugPrint(io.Writer) for flexibility
  1. ChainReader Relocation (execution/exec/chain_reader.go)
  • ChainReaderImpl moved from stagedsync to execution/exec package — reduces import cycles and makes it available to blockgen
  1. Block Generation (execution/tests/blockgen/chain_makers.go)
  • BlockGen now carries versionMap and blockIO for parallel-aware BAL generation during test chain creation
  • genblock() returns BAL bytes; GenerateChain() populates ChainPack.BlockAccessLists
  • Proper InitializeBlockExecution with chainReader (was nil before)
  • FinalizeAndAssemble now receives syscall and chainreader — enables system contract calls (EIP-4788 beacon root, etc.)
  • Prague support: sets RequestsHash and random ParentBeaconBlockRoot
  • Amsterdam support: generates BAL and sets BlockAccessListHash
  • InitPraguePreDeploys() — writes withdrawal request and consolidation request contract code to state
  • AddUncle() silently ignores on PoS blocks
  1. Builder / Block Production (execution/builder/builderstages/exec.go)
  • Uses AccessSet.Merge() instead of standalone MergeAccessedAddresses()
  • getNextTransactions() now removes nonce-too-high transactions from alreadyYielded so they can be reconsidered after earlier-nonce txs land — fixes blob tx ordering issues
  1. Parallel Executor (execution/stagedsync/exec3_parallel.go, exec3.go)
  • Formatting/alignment changes in experiments.go (adds ParallelExec env var alongside existing ones)
  • exec3_parallel.go and exec3.go changes appear mostly mechanical (BAL generation integration, AccessSet type migration)

RPC / Networking Fixes

  • eth_feeHistory pending block (rpc/jsonrpc/eth_system.go): PendingBlockAndReceipts() now returns the real pending block from mining, or falls back to the latest confirmed block with receipts. Previously
    returned nil, nil, causing the fee history window to shift back incorrectly.
  • feehistory.go: Decrements blocks when pending is unavailable to preserve the same oldestBlock calculation.
  • eth_api.go: Nil-check on api.filters before calling LastPendingBlock().
  • rpchelper/config.go: Default filter limits changed from 0 (unlimited) to 10000 — prevents unbounded memory growth from abandoned subscriptions.
  • rpchelper/helper.go: ReadAccountData cache path now handles empty enc (returns nil instead of attempting deserialize).
  • System addresses (execution/protocol/params/protocol.go): New IsSystemAddress() helper and systemAddresses map.

Flaky Test / CI Fixes

  • node/eth/backend.go: StartRpcServer goroutine now tracked in bgComponentsEg — fixes TestShutterBlockBuilding flakiness.
  • p2p/discover/v4_udp.go: Close t.db on shutdown (resource leak fix).
  • polygon/heimdall/service_test.go: Close service store in teardown.
  • db/downloader/downloader_test.go: Skip on Windows; use 0o644 permissions.
  • CI workflows: continue-on-error: true on Docker login steps; macOS cleanup step expanded; upload preparing-step logs on failure.
  • .gitignore: Prevents accidental commit of locally-built erigon binary.

Test Updates

  • engine_server_test.go: Updated BAL expectations — Amsterdam-enabled chains always produce a BAL (even if empty).
  • chain_makers_test.go: Receipt validation changed from exact byte comparison to structural checks (receipt counts and cumulative gas). More resilient to hash changes from chain config evolution.
  • block_test.go: Removed devnet off-season skip.

Potential Concerns

  1. rw_v3.go:1041 — The ReadAccountCode fix (so.code -> code) looks like a real pre-existing bug. Good catch.
  2. setState revert optimization removal — The comment explains why, but this is a performance regression for writes that match origin values. Worth confirming no hot paths rely on this being cheap.
  3. ResolveCode committed=false change — The commit message says this fixes stale delegation code in parallel mode. Verify that non-parallel mode (serial execution) still works correctly with this change, since
    committed=false reads from dirty state rather than the version map.
  4. getNextTransactions nonce-too-high unyielding — This modifies the alreadyYielded set from the caller's perspective. Make sure the mapset isn't shared across goroutines without synchronization.
  5. DefaultFiltersConfig changing from 0 to 10000 — This is a behavior change for existing users who relied on unlimited subscription buffers. Worth a changelog note.
  6. CreateAccount complexity — The multiple code paths (accumulated-IBS vs fresh-IBS worker, cached stateObject vs versionMap lookup) are getting intricate. High-value area for additional test coverage.

@mh0lt mh0lt enabled auto-merge (squash) February 26, 2026 19:00
@mh0lt mh0lt merged commit 9a63f18 into main Feb 26, 2026
23 checks passed
@mh0lt mh0lt deleted the parallel_exec_default branch February 26, 2026 19:27
sudeepdino008 pushed a commit that referenced this pull request Mar 4, 2026
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com>
Co-authored-by: root <giulio.rebuffo@gmail.com>
sudeepdino008 pushed a commit that referenced this pull request Mar 4, 2026
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com>
Co-authored-by: root <giulio.rebuffo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Glamsterdam https://eips.ethereum.org/EIPS/eip-7773

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants