execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation#19595
Merged
Conversation
a277e35 to
1d0b0f9
Compare
mh0lt
approved these changes
Mar 4, 2026
mh0lt
left a comment
Contributor
There was a problem hiding this comment.
This may need a refactor when next merging main. The BALs code is now localized with versionedio.
sudeepdino008
pushed a commit
that referenced
this pull request
Mar 4, 2026
…fter post block validation and before commitment validation (#19595) DO NOT MERGE BEFORE #19528 - adds the new bal-devnet-3 test fixtures and applies the skips for failing eips - moves the bals hash check after post block validation and before commitment verification so that we can clearly see the real errors (e.g. gas mismatches/receipt mismatches/etc) instead of always seeing `block access list mismatch`
mh0lt
added a commit
that referenced
this pull request
Mar 5, 2026
…ion (#19628) ## Summary Fixes multiple issues with Block Access List (EIP-7928) computation that caused BAL hash mismatches on bal-devnet-2 when running with parallel execution (12 workers). These fixes were validated on the live devnet with 200+ consecutive blocks fork-validated without errors. These represent errors encountered on the live devnet rather than in hive tests which don't include the same issues in combination. ## Changes ### 1. Fix `AccessedAddresses()` dropping revertable flag (`intra_block_state.go`) `AccessedAddresses()` was returning `nil` for every `accessOptions` entry instead of the actual options containing the `revertable` flag. This made it impossible for downstream BAL code to distinguish gas-calculation reads from real state access. **Before:** `out[addr] = nil` **After:** `out[addr] = opts` ### 2. System address filter using non-revertable access flag (`versionedio.go`) Per EIP-7928, `SYSTEM_ADDRESS` (0xff...fe) "MUST NOT be included unless it experiences state access itself." The system address is touched during every block's system call (EIP-4788 beacon root) as `msg.sender`, creating incidental gas-calc reads. Added a `nonRevertableUserAccess` field to `accountState` that tracks whether any user transaction (txIndex >= 0) performed a non-revertable access (e.g. `evm.Call` target, `BALANCE` opcode, `SELFDESTRUCT` beneficiary). The system address is now only included in the BAL when it has actual state changes OR when a user tx explicitly accessed it. ### 3. Mark state-reading opcodes as non-revertable (`instructions.go`) Per EIP-7928, `BALANCE`, `EXTCODESIZE`, `EXTCODECOPY`, and `EXTCODEHASH` are real state access operations. Added `MarkAddressAccess(addr, false)` (non-revertable) to these opcodes so they correctly trigger system address inclusion when a user tx queries it. Previously, `EXTCODEHASH` used `MarkAddressAccess(address, true)` (revertable) and the others had no explicit access marking at all — they relied only on the implicit revertable marking from `versionRead`. ### 4. VersionMap HasBAL flag for read validation (`versionmap.go`) When a BAL is present, significant writes for BalancePath, NoncePath, CodePath and StoragePath are pre-populated in the VersionMap before execution. Added a `HasBAL` field with two validation refinements: **Path-specific bypass (MVReadResultDone):** The HasBAL validation bypass now only applies to BAL-pre-populated paths (BalancePath, NoncePath, CodePath, StoragePath). AddressPath and other paths that are NOT pre-populated by the BAL always trigger invalidation, since a new VersionMap entry for those paths indicates a real state change from a concurrent worker (e.g. account creation). **AddressPath cross-check (MVReadResultNone):** When HasBAL is true and an AddressPath read returned None (account not in DB), cross-check against BalancePath which IS pre-populated by the BAL. If BalancePath has an entry at a prior txIndex, the account was created by a prior tx and the nil AddressPath read is stale — triggering re-execution. This fixes a class of BAL mismatches where a tx speculatively reads an account as non-existent, a prior tx creates the account, but the stale read goes undetected because AddressPath writes are not flushed to the VersionMap when HasBAL is true. ### 5. Skip BAL validation when stored body is missing (`bal_create.go`) Blocks downloaded via the backward block downloader (p2p sync) do not carry BAL bodies — only blocks received via engine API have them stored. When the stored BAL is missing, `HasBAL=false` on the VersionMap, so the computed BAL may be inaccurate. Skip the computed-vs-header hash comparison in this case. Added debug dump of stored vs computed BAL on mismatch for diagnostics. This limitation goes away once eth/71 delivers BAL bodies via p2p sync. ### 6. Read BAL data with fresh tx (`exec3.go`) Changed BAL data reading from `tx.Apply()` to `te.cfg.db.View()` so the execution stage can see BAL data committed by `InsertBlocks` after the execution transaction was opened. ### 7. Replace `isChainTip` with `!isApplyingBlocks` (`exec3.go`) Replaced the `isChainTip` variable (derived from `maxBlockNum == startBlockNum`) with the existing `isApplyingBlocks` flag (derived from sync mode). These are semantically equivalent but `isApplyingBlocks` is clearer and avoids having two variables for the same condition. ### 8. Skip `test_bal_invalid_*` spec tests (`block_test.go`) Added a skip for `test_bal_invalid_*` execution spec tests. These tests require BAL structural validation (rejecting blocks with intentionally invalid BALs) which is not yet implemented. **Note:** these tests also fail on `main` (see CI run [#22680631291](https://github.com/erigontech/erigon/actions/runs/22680631291)) — they were added in #19595 without corresponding validation implementation. This skip is not a regression introduced by this PR. ## Testing - **bal-devnet-2**: 200+ consecutive blocks fork-validated with 12 parallel workers, zero BAL hash mismatches - **Unit tests**: `TestExecutionSpecBlockchainDevnet` — all pass (128s) - **Lint**: `make lint` — clean --------- Co-authored-by: Mark Holt <erigon@dev-bm-e3-ethmainnet-n4.erigon.io> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
mh0lt
pushed a commit
that referenced
this pull request
Mar 6, 2026
Extracted from #19595: moves the BAL hash-check logic out of the parallel executor's inline loop and into a dedicated ProcessBAL() function in bal_create.go. This makes BAL validation reusable and separates it from block validation ordering. Excludes the bal-devnet-3 test fixtures from the same PR.
mh0lt
added a commit
that referenced
this pull request
Mar 6, 2026
…ion (#19628) Fixes multiple issues with Block Access List (EIP-7928) computation that caused BAL hash mismatches on bal-devnet-2 when running with parallel execution (12 workers). These fixes were validated on the live devnet with 200+ consecutive blocks fork-validated without errors. These represent errors encountered on the live devnet rather than in hive tests which don't include the same issues in combination. (`intra_block_state.go`) `AccessedAddresses()` was returning `nil` for every `accessOptions` entry instead of the actual options containing the `revertable` flag. This made it impossible for downstream BAL code to distinguish gas-calculation reads from real state access. **Before:** `out[addr] = nil` **After:** `out[addr] = opts` (`versionedio.go`) Per EIP-7928, `SYSTEM_ADDRESS` (0xff...fe) "MUST NOT be included unless it experiences state access itself." The system address is touched during every block's system call (EIP-4788 beacon root) as `msg.sender`, creating incidental gas-calc reads. Added a `nonRevertableUserAccess` field to `accountState` that tracks whether any user transaction (txIndex >= 0) performed a non-revertable access (e.g. `evm.Call` target, `BALANCE` opcode, `SELFDESTRUCT` beneficiary). The system address is now only included in the BAL when it has actual state changes OR when a user tx explicitly accessed it. Per EIP-7928, `BALANCE`, `EXTCODESIZE`, `EXTCODECOPY`, and `EXTCODEHASH` are real state access operations. Added `MarkAddressAccess(addr, false)` (non-revertable) to these opcodes so they correctly trigger system address inclusion when a user tx queries it. Previously, `EXTCODEHASH` used `MarkAddressAccess(address, true)` (revertable) and the others had no explicit access marking at all — they relied only on the implicit revertable marking from `versionRead`. When a BAL is present, significant writes for BalancePath, NoncePath, CodePath and StoragePath are pre-populated in the VersionMap before execution. Added a `HasBAL` field with two validation refinements: **Path-specific bypass (MVReadResultDone):** The HasBAL validation bypass now only applies to BAL-pre-populated paths (BalancePath, NoncePath, CodePath, StoragePath). AddressPath and other paths that are NOT pre-populated by the BAL always trigger invalidation, since a new VersionMap entry for those paths indicates a real state change from a concurrent worker (e.g. account creation). **AddressPath cross-check (MVReadResultNone):** When HasBAL is true and an AddressPath read returned None (account not in DB), cross-check against BalancePath which IS pre-populated by the BAL. If BalancePath has an entry at a prior txIndex, the account was created by a prior tx and the nil AddressPath read is stale — triggering re-execution. This fixes a class of BAL mismatches where a tx speculatively reads an account as non-existent, a prior tx creates the account, but the stale read goes undetected because AddressPath writes are not flushed to the VersionMap when HasBAL is true. Blocks downloaded via the backward block downloader (p2p sync) do not carry BAL bodies — only blocks received via engine API have them stored. When the stored BAL is missing, `HasBAL=false` on the VersionMap, so the computed BAL may be inaccurate. Skip the computed-vs-header hash comparison in this case. Added debug dump of stored vs computed BAL on mismatch for diagnostics. This limitation goes away once eth/71 delivers BAL bodies via p2p sync. Changed BAL data reading from `tx.Apply()` to `te.cfg.db.View()` so the execution stage can see BAL data committed by `InsertBlocks` after the execution transaction was opened. Replaced the `isChainTip` variable (derived from `maxBlockNum == startBlockNum`) with the existing `isApplyingBlocks` flag (derived from sync mode). These are semantically equivalent but `isApplyingBlocks` is clearer and avoids having two variables for the same condition. Added a skip for `test_bal_invalid_*` execution spec tests. These tests require BAL structural validation (rejecting blocks with intentionally invalid BALs) which is not yet implemented. **Note:** these tests also fail on `main` (see CI run [#22680631291](https://github.com/erigontech/erigon/actions/runs/22680631291)) — they were added in #19595 without corresponding validation implementation. This skip is not a regression introduced by this PR. - **bal-devnet-2**: 200+ consecutive blocks fork-validated with 12 parallel workers, zero BAL hash mismatches - **Unit tests**: `TestExecutionSpecBlockchainDevnet` — all pass (128s) - **Lint**: `make lint` — clean --------- Co-authored-by: Mark Holt <erigon@dev-bm-e3-ethmainnet-n4.erigon.io> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Mar 20, 2026
DO-NOT-MERGE BEFORE #19595 closes #19102 --------- Co-authored-by: Mark Holt <135143369+mh0lt@users.noreply.github.com> Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DO NOT MERGE BEFORE #19528
block access list mismatch