Skip to content

evmonly: parallelize OCC validation and merge behind the serial acceptance barrier - #4273

Open
bdchatham wants to merge 1 commit into
devin/1789943071-stack-3-prepare-pipelinefrom
devin/1789943071-stack-4-parallel-occ
Open

bdchatham wants to merge 1 commit into
devin/1789943071-stack-3-prepare-pipelinefrom
devin/1789943071-stack-4-parallel-occ

Conversation

@bdchatham

Copy link
Copy Markdown
Contributor

Describe your changes and provide context

Re-opens #4261 on top of #4272 (stack 4/4). With this PR applied the tree is byte-identical to today's giga-1.

OCC acceptance stays a serial barrier in block order, but the work behind it is spread across the existing worker pool (occ_shards.go):

  • every incarnation's writes are indexed by tx index up front (stateAccessIndex);
  • a parallel pass checks the pending run of transactions against that index (conflictsWithin) and reports the first one the frontier would not accept (firstUnacceptedResult); the frontier handles only that tx on the calling goroutine, then reruns from there (with a serialBackoff to avoid thrashing on hot contracts);
  • the accepted run is folded into the prefix shard by shard (occShardOf: contiguous address ranges), each incarnation recording which shards it touched so workers skip results holding nothing of theirs;
  • mergeOCCResults emits the changeset one shard at a time on the pool and concatenates shards in canonical address order, so the output is identical to the serial merge; a prefix with few keys is merged on the calling goroutine.

Determinism: acceptance decisions and the emitted changeset/receipts are the same as the serial path by construction (parity tests compare both).

Testing performed to validate your change

  • scripts/ramtest.sh -race ./giga/evmonly/... — parity vs sequential validation/merge, conflictsWithin bounds, occShardOf, cumulativeGasFrom, firstUnacceptedResult, boundary rejection at results[0].
  • make fmtcheck, make lint.

Link to Devin session: https://app.devin.ai/sessions/ff612badcded4aa5914ea408dbb41888
Open in Devin Desktop: https://app.devin.ai/desktop/session/ff612badcded4aa5914ea408dbb41888?variant=devin
Requested by: @bdchatham

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot added this pull request to stack #4274 September 20, 2026 22:34
@cursor

cursor Bot commented Sep 20, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes core Block-STM validation, conflict detection, and state merge paths that must match sequential execution; incorrect parallelism could cause wrong block results despite extensive parity tests.

Overview
Parallelizes Block-STM OCC validation and changeset merge while keeping transaction acceptance strictly serial in block order. Acceptance still happens one transaction at a time on the calling goroutine; the worker pool now does the heavy lifting around that barrier.

The write index is built up front (per-tx, sharded by address), and periodic parallel validation passes scan pending results with conflictsWithin (writes in [sourcePrefix, txIndex)) to bulk-accept a prefix before the serial frontier handles the first rejection. A serialBackoff stretches serial validation when parallel passes accept too little (e.g. hot contracts). Accepted prefix updates and final merge use 64 address shards (occShardOf), with incarnations recording touched shards so workers skip irrelevant work. Prefetch-before-merge is removed in favor of changeSetIntoParallel (serial merge below key thresholds).

Docs in README.md describe the new flow. Tests add shard/conflict/backoff coverage, a ~300-tx OCC vs sequential parity test, parallel-merge account-read behavior, and an ERC-20 load benchmark case. Merge failures on a closed worker pool fall back to sequential execution.

Reviewed by Cursor Bugbot for commit 971643c. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedSep 20, 2026, 11:20 PM

@codecov

codecov Bot commented Sep 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.51969% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.81%. Comparing base (453eb65) to head (971643c).

Files with missing lines Patch % Lines
giga/evmonly/occ.go 91.86% 10 Missing ⚠️
giga/evmonly/occ_shards.go 93.12% 9 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                              Coverage Diff                              @@
##           devin/1789943071-stack-3-prepare-pipeline    #4273      +/-   ##
=============================================================================
+ Coverage                                      83.02%   83.81%   +0.79%     
=============================================================================
  Files                                             30       32       +2     
  Lines                                           2992     4764    +1772     
=============================================================================
+ Hits                                            2484     3993    +1509     
- Misses                                           507      771     +264     
+ Partials                                           1        0       -1     
Flag Coverage Δ
sei-chain-pr 84.68% <92.51%> (+0.32%) ⬆️
sei-db 74.50% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
giga/evmonly/occ_shards.go 93.12% <93.12%> (ø)
giga/evmonly/occ.go 90.97% <91.86%> (ø)

... and 50 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@seidroid seidroid Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The parallel OCC validation and sharded merge look correct: the pre-built span index is equivalent to the old accept-as-you-go index for the only two sourcePrefix values that occur, stmFrontierAccepts reproduces the serial accept condition, shard ownership is disjoint and totally covering, and shard order preserves canonical address order. Only two non-blocking efficiency observations.

Findings: 0 blocking | 2 non-blocking | 1 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • [suggestion] occShardOf keys on addr[0] only, which is required for order-preserving concatenation but means a single-hot-contract workload puts all of that contract's storage into one shard. The erc20_single_contract benchmark this PR adds is exactly that shape, so the sharded merge will parallelize little there — worth calling out in the README alongside the existing shard description so the next reader doesn't expect merge speedup on single-contract blocks.
  • 1 suggestion(s)/nit(s) flagged inline on specific lines.

if len(results)-from < occMinParallelValidation {
return 0, nil
}
cumulative, to := cumulativeGasFrom(results, from, state.cumulativeGasUsed)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[suggestion] cumulativeGasFrom walks and allocates for the entire remaining block (len(results)-from+1 entries) on every parallel pass, on the calling goroutine — i.e. inside the serial barrier this PR is trying to shrink.

The scan in firstUnacceptedResult is self-limiting (workers bail once stop drops below their index), so a pass typically advances only a short distance, but the prefix sum is paid in full regardless. With one conflict roughly every occMinParallelValidation+ transactions the backoff never engages, so you get ~C passes each doing O(N) serial work: O(C·N) total. At N=100k with C≈1k that is ~100M writes and ~800MB of allocation churn per block, all serial.

Capping the pass window (to = min(to, from+window)) would bound both the prefix sum and the atomic stop.Load() contention, at the cost of an extra pass on wide conflict-free runs.

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.

Not changed here by design: this stack re-opens the already-merged code unmodified so the team can review what actually runs on giga-1 (the stack top equals current giga-1). Noted as a follow-up.

@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1789943071-stack-4-parallel-occ branch from a004fe1 to a96c76d Compare September 20, 2026 22:50
@bdchatham bdchatham changed the title [stack 4/4] evmonly: parallelize OCC validation and merge behind the serial acceptance barrier evmonly: parallelize OCC validation and merge behind the serial acceptance barrier Sep 20, 2026
@devin-ai-integration
devin-ai-integration Bot removed this pull request from stack #4274 September 20, 2026 23:18
…the serial acceptance barrier (#4261)""

This reverts commit 1a6a64f.
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1789943071-stack-4-parallel-occ branch from a96c76d to 971643c Compare September 20, 2026 23:18
@devin-ai-integration
devin-ai-integration Bot added this pull request to stack #4275 September 20, 2026 23:18
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.

1 participant